aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2024-01-29 21:19:33 -0800
committerXin Li <delphij@google.com>2024-01-29 21:19:33 -0800
commit5da47bce8c0c1d22fb4801b5f773554df03c3e05 (patch)
tree901d28f60bbc5213a61abb55a527906eb6d7bb46
parent76f16eedeb439084dcd71a8ae1132b77109949f7 (diff)
parentdd6812f5375184cafc2834da6d5e4208b2f821ca (diff)
downloadchre-5da47bce8c0c1d22fb4801b5f773554df03c3e05.tar.gz
Merge Android 24Q1 Release (ab/11220357)
Bug: 319669529 Merged-In: I12e0fbad4cb34fa11eaf6e022ea61b59c4a0d7d3 Change-Id: If5c6f78ee9a08a1caae56c56426d329b0ec3b5ce
-rw-r--r--Android.bp281
-rw-r--r--Android.mk48
-rw-r--r--Makefile6
-rw-r--r--PREUPLOAD.cfg4
-rw-r--r--api_parser/.gitignore1
-rw-r--r--api_parser/README.md (renamed from chpp/api_parser/README.md)0
-rw-r--r--api_parser/api_parser.py150
-rw-r--r--[-rwxr-xr-x]api_parser/chpp_code_generator.py (renamed from chpp/api_parser/chre_api_to_chpp.py)851
-rw-r--r--api_parser/chre_api_annotations.json316
-rwxr-xr-xapi_parser/chre_api_to_chpp.py70
-rw-r--r--api_parser/parser_defines.h (renamed from chpp/api_parser/parser_defines.h)0
-rw-r--r--api_parser/requirements.txt2
-rw-r--r--api_parser/utils.py57
-rw-r--r--apps/ble_world/ble_world.cc6
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/adv_report_cache.cc20
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/adv_report_cache.h9
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_main.cc2
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_manager.cc213
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_manager.h33
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/ble_scanner.cc1
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/ble_scanner.h10
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/fast_pair_account_data.cc2
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/fast_pair_filter.cc6
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter.cc6
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter_extension.cc144
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter_extension.h70
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension.c39
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension.h33
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension_support_lib.cc11
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/ble_filter.proto3
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.options15
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.proto115
-rw-r--r--apps/nearby/location/lbs/contexthub/nanoapps/proto/filter.proto6
-rw-r--r--apps/rpc_world/src/rpc_world_manager.cc6
-rw-r--r--apps/test/chqts/src/general_test/basic_ble_test.cc5
-rw-r--r--apps/test/chqts/src/general_test/send_event_stress_test.cc8
-rw-r--r--apps/test/common/chre_api_test/chre_api_test.mk2
-rw-r--r--apps/test/common/chre_api_test/inc/chre_api_test_manager.h68
-rw-r--r--apps/test/common/chre_api_test/rpc/chre_api_test.options4
-rw-r--r--apps/test/common/chre_api_test/rpc/chre_api_test.proto72
-rw-r--r--apps/test/common/chre_api_test/src/chre_api_test_manager.cc167
-rw-r--r--apps/test/common/chre_api_test/src/chre_api_test_service.cc176
-rw-r--r--apps/test/common/chre_cross_validator_wifi/inc/chre_cross_validator_wifi_manager.h16
-rw-r--r--apps/test/common/chre_cross_validator_wifi/src/chre_cross_validator_wifi_manager.cc6
-rw-r--r--apps/test/common/chre_settings_test/inc/chre_settings_test_manager.h4
-rw-r--r--apps/test/common/chre_settings_test/src/chre_settings_test_manager.cc108
-rw-r--r--apps/test/common/rpc_service_test/inc/rpc_service_manager.h5
-rw-r--r--apps/test/common/rpc_service_test/src/rpc_service_manager.cc4
-rw-r--r--apps/test/common/rpc_service_test/src/rpc_service_test.cc1
-rw-r--r--build/build_template.mk30
-rw-r--r--build/clang.mk2
-rw-r--r--build/common.mk5
-rw-r--r--build/nanoapp/app.mk13
-rw-r--r--build/nanopb.mk304
-rw-r--r--build/rust/common_rust_config.mk4
-rw-r--r--build/variant/aosp_riscv55e03_tinysys.mk5
-rw-r--r--chpp/Android.bp14
-rw-r--r--chpp/RELEASE_NOTES.md75
-rw-r--r--chpp/api_parser/.gitignore1
-rw-r--r--chpp/api_parser/chre_api_annotations.json297
-rw-r--r--chpp/api_parser/requirements.txt2
-rw-r--r--chpp/app.c815
-rw-r--r--chpp/clients.c338
-rw-r--r--chpp/clients/discovery.c6
-rw-r--r--chpp/clients/gnss.c56
-rw-r--r--chpp/clients/loopback.c20
-rw-r--r--chpp/clients/timesync.c12
-rw-r--r--chpp/clients/wifi.c76
-rw-r--r--chpp/clients/wwan.c48
-rw-r--r--chpp/include/chpp/app.h488
-rw-r--r--chpp/include/chpp/clients.h265
-rw-r--r--chpp/include/chpp/clients/gnss.h4
-rw-r--r--chpp/include/chpp/clients/wifi.h4
-rw-r--r--chpp/include/chpp/clients/wwan.h4
-rw-r--r--chpp/include/chpp/notifier.h2
-rw-r--r--chpp/include/chpp/services.h207
-rw-r--r--chpp/include/chpp/transport.h2
-rw-r--r--chpp/services.c121
-rw-r--r--chpp/services/discovery.c6
-rw-r--r--chpp/services/gnss.c78
-rw-r--r--chpp/services/timesync.c2
-rw-r--r--chpp/services/wifi.c106
-rw-r--r--chpp/services/wwan.c62
-rw-r--r--chpp/test/app_discovery_test.cpp332
-rw-r--r--chpp/test/app_notification_test.cpp333
-rw-r--r--chpp/test/app_req_resp_test.cpp488
-rw-r--r--chpp/test/app_test.cpp14
-rw-r--r--chpp/test/app_test_base.cpp12
-rw-r--r--chpp/test/app_timeout_test.cpp538
-rw-r--r--chpp/test/app_timeout_test.h (renamed from chpp/test/clients_test.h)4
-rw-r--r--chpp/test/clients_test.cpp363
-rw-r--r--chpp/test/fake_link_sync_test.cpp10
-rw-r--r--chpp/test/transport_test.cpp4
-rw-r--r--chpp/transport.c303
-rwxr-xr-xchre_api/archive_chre_api.sh34
-rw-r--r--chre_api/include/chre_api/chre/audio.h3
-rw-r--r--chre_api/include/chre_api/chre/ble.h206
-rw-r--r--chre_api/include/chre_api/chre/common.h8
-rw-r--r--chre_api/include/chre_api/chre/event.h13
-rw-r--r--chre_api/include/chre_api/chre/gnss.h3
-rw-r--r--chre_api/include/chre_api/chre/nanoapp.h3
-rw-r--r--chre_api/include/chre_api/chre/re.h5
-rw-r--r--chre_api/include/chre_api/chre/sensor.h3
-rw-r--r--chre_api/include/chre_api/chre/sensor_types.h51
-rw-r--r--chre_api/include/chre_api/chre/toolchain.h6
-rw-r--r--chre_api/include/chre_api/chre/user_settings.h3
-rw-r--r--chre_api/include/chre_api/chre/version.h23
-rw-r--r--chre_api/include/chre_api/chre/wifi.h3
-rw-r--r--chre_api/include/chre_api/chre/wwan.h3
-rw-r--r--chre_api/legacy/v1_8/chre.h201
-rw-r--r--chre_api/legacy/v1_8/chre/audio.h429
-rw-r--r--chre_api/legacy/v1_8/chre/ble.h851
-rw-r--r--chre_api/legacy/v1_8/chre/common.h193
-rw-r--r--chre_api/legacy/v1_8/chre/event.h948
-rw-r--r--chre_api/legacy/v1_8/chre/gnss.h604
-rw-r--r--chre_api/legacy/v1_8/chre/nanoapp.h93
-rw-r--r--chre_api/legacy/v1_8/chre/re.h437
-rw-r--r--chre_api/legacy/v1_8/chre/sensor.h1119
-rw-r--r--chre_api/legacy/v1_8/chre/sensor_types.h468
-rw-r--r--chre_api/legacy/v1_8/chre/toolchain.h66
-rw-r--r--chre_api/legacy/v1_8/chre/user_settings.h145
-rw-r--r--chre_api/legacy/v1_8/chre/version.h257
-rw-r--r--chre_api/legacy/v1_8/chre/wifi.h1313
-rw-r--r--chre_api/legacy/v1_8/chre/wwan.h591
-rw-r--r--chre_daemon.rc3
-rw-r--r--chre_flags.aconfig36
-rw-r--r--core/ble_request.cc128
-rw-r--r--core/ble_request_manager.cc270
-rw-r--r--core/ble_request_multiplexer.cc6
-rw-r--r--core/event_loop.cc89
-rw-r--r--core/event_loop_manager.cc12
-rw-r--r--core/host_comms_manager.cc24
-rw-r--r--core/include/chre/core/ble_request.h30
-rw-r--r--core/include/chre/core/ble_request_manager.h141
-rw-r--r--core/include/chre/core/ble_request_multiplexer.h6
-rw-r--r--core/include/chre/core/event_loop.h40
-rw-r--r--core/include/chre/core/event_loop_common.h3
-rw-r--r--core/include/chre/core/event_loop_manager.h5
-rw-r--r--core/include/chre/core/gnss_manager.h4
-rw-r--r--core/include/chre/core/host_endpoint_manager.h2
-rw-r--r--core/include/chre/core/nanoapp.h86
-rw-r--r--core/include/chre/core/request_multiplexer_impl.h8
-rw-r--r--core/include/chre/core/system_health_monitor.h2
-rw-r--r--core/include/chre/core/timer_pool.h6
-rw-r--r--core/log.cc4
-rw-r--r--core/nanoapp.cc192
-rw-r--r--core/telemetry_manager.cc23
-rw-r--r--core/tests/ble_request_test.cc99
-rw-r--r--core/tests/memory_manager_test.cc14
-rw-r--r--core/timer_pool.cc20
-rw-r--r--doc/porting_guide.md2
-rw-r--r--external/pigweed/pw_rpc.mk241
-rw-r--r--external/pigweed/pw_tokenizer.mk6
-rw-r--r--external/pigweed/pw_trace.mk17
-rw-r--r--host/common/chre_aidl_hal_client.cc433
-rw-r--r--host/common/daemon_base.cc97
-rw-r--r--host/common/fbs_daemon_base.cc52
-rw-r--r--host/common/fragmented_load_transaction.cc7
-rw-r--r--host/common/hal_client.cc180
-rw-r--r--host/common/host_protocol_host.cc5
-rw-r--r--host/common/include/chre_host/daemon_base.h15
-rw-r--r--host/common/include/chre_host/fragmented_load_transaction.h9
-rw-r--r--host/common/include/chre_host/generated/host_messages_generated.h398
-rw-r--r--host/common/include/chre_host/hal_client.h236
-rw-r--r--host/common/include/chre_host/host_protocol_host.h8
-rw-r--r--host/common/include/chre_host/log.h42
-rw-r--r--host/common/include/chre_host/metrics_reporter.h100
-rw-r--r--host/common/include/chre_host/pigweed/hal_channel_output.h59
-rw-r--r--host/common/include/chre_host/pigweed/hal_rpc_client.h202
-rw-r--r--host/common/include/chre_host/preloaded_nanoapp_loader.h48
-rw-r--r--host/common/include/chre_host/socket_server.h24
-rw-r--r--host/common/include/chre_host/time_syncer.h14
-rw-r--r--host/common/log.cc37
-rw-r--r--host/common/metrics_reporter.cc168
-rw-r--r--host/common/pigweed/hal_channel_output.cc57
-rw-r--r--host/common/pigweed/hal_rpc_client.cc228
-rw-r--r--host/common/preloaded_nanoapp_loader.cc118
-rw-r--r--host/common/socket_client.cc4
-rw-r--r--host/common/socket_server.cc4
-rw-r--r--host/common/test/chre_test_client.cc120
-rw-r--r--host/common/test/chre_test_rpc.cc148
-rw-r--r--host/common/test/power_test/chre_power_test_client.cc5
-rw-r--r--host/common/time_syncer.cc18
-rw-r--r--host/hal_generic/Android.bp41
-rw-r--r--host/hal_generic/aidl/android.hardware.contexthub-service.generic.xml2
-rw-r--r--host/hal_generic/aidl/generic_context_hub_aidl.cc16
-rw-r--r--host/hal_generic/aidl/generic_context_hub_aidl.h3
-rw-r--r--host/hal_generic/common/hal_chre_socket_connection.cc120
-rw-r--r--host/hal_generic/common/hal_chre_socket_connection.h13
-rw-r--r--host/hal_generic/common/hal_client_id.h4
-rw-r--r--host/hal_generic/common/hal_client_manager.cc422
-rw-r--r--host/hal_generic/common/hal_client_manager.h280
-rw-r--r--host/hal_generic/common/hal_error.h42
-rw-r--r--host/hal_generic/common/multi_client_context_hub_base.cc242
-rw-r--r--host/hal_generic/common/multi_client_context_hub_base.h63
-rw-r--r--host/test/hal_generic/common/hal_client_manager_test.cc552
-rw-r--r--host/test/hal_generic/common/hal_client_test.cc212
-rw-r--r--host/tinysys/hal/Android.bp6
-rw-r--r--host/tinysys/hal/android.hardware.contexthub-service.tinysys.xml2
-rw-r--r--host/tinysys/hal/tinysys_chre_connection.cc16
-rw-r--r--host/tinysys/hal/tinysys_chre_connection.h29
-rw-r--r--host/tinysys/hal/tinysys_context_hub.cc21
-rw-r--r--host/tinysys/hal/tinysys_context_hub.h2
-rw-r--r--java/test/audio_concurrency/Android.bp2
-rw-r--r--java/test/audio_concurrency/src/com/google/android/chre/test/audioconcurrency/ContextHubAudioConcurrencyTestExecutor.java36
-rw-r--r--java/test/ble_concurrency/src/com/google/android/chre/test/bleconcurrency/ContextHubBleConcurrencyTestExecutor.java208
-rw-r--r--java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubBleTestExecutor.java400
-rw-r--r--java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubChreApiTestExecutor.java9
-rw-r--r--java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubGeneralTestExecutor.java70
-rw-r--r--java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubHostEndpointInfoTestExecutor.java60
-rw-r--r--java/test/chqts/src/com/google/android/chre/test/chqts/multidevice/ContextHubMultiDeviceBleBeaconTestExecutor.java108
-rw-r--r--java/test/chre_concurrency/src/com/google/android/chre/test/chreconcurrency/ContextHubChreConcurrencyTestExecutor.java46
-rw-r--r--java/test/cross_validation/Android.bp2
-rw-r--r--java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorBase.java11
-rw-r--r--java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorSensor.java23
-rw-r--r--java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorWifi.java38
-rw-r--r--java/test/permissions/Android.bp2
-rw-r--r--java/test/rpc_service/Android.bp2
-rw-r--r--java/test/rpc_service/src/com/google/android/chre/test/rpc_service/ContextHubRpcServiceTestExecutor.java2
-rw-r--r--java/test/settings/Android.bp2
-rw-r--r--java/test/settings/src/com/google/android/chre/test/setting/ContextHubBleSettingsTestExecutor.java20
-rw-r--r--java/test/settings/src/com/google/android/chre/test/setting/ContextHubGnssSettingsTestExecutor.java9
-rw-r--r--java/test/settings/src/com/google/android/chre/test/setting/ContextHubMicDisableSettingsTestExecutor.java5
-rw-r--r--java/test/settings/src/com/google/android/chre/test/setting/ContextHubSettingsTestExecutor.java20
-rw-r--r--java/test/settings/src/com/google/android/chre/test/setting/ContextHubWifiSettingsTestExecutor.java23
-rw-r--r--java/test/settings/src/com/google/android/chre/test/setting/ContextHubWwanSettingsTestExecutor.java6
-rw-r--r--java/test/stress/Android.bp2
-rw-r--r--java/test/stress/src/com/google/android/chre/test/stress/ContextHubStressTestExecutor.java25
-rw-r--r--java/test/utils/Android.bp5
-rw-r--r--java/test/utils/src/com/google/android/utils/chre/ChreApiTestUtil.java80
-rw-r--r--java/test/utils/src/com/google/android/utils/chre/ContextHubHostTestUtil.java362
-rw-r--r--java/test/utils/src/com/google/android/utils/chre/ContextHubServiceTestHelper.java12
-rw-r--r--java/test/utils/src/com/google/android/utils/chre/SettingsUtil.java28
-rw-r--r--java/utils/pigweed/Android.bp1
-rw-r--r--java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreCallbackHandler.java16
-rw-r--r--java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreChannelOutput.java7
-rw-r--r--java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreIntentHandler.java12
-rw-r--r--java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreRpcClient.java38
-rw-r--r--pal/include/chre/pal/ble.h37
-rw-r--r--pal/tests/src/audio_pal_impl_test.cc3
-rw-r--r--pal/tests/src/ble_pal_impl_test.cc30
-rw-r--r--pal/tests/src/sensor_pal_impl_test.cc26
-rw-r--r--platform/exynos/host_link.cc2
-rw-r--r--platform/include/chre/platform/assert.h43
-rw-r--r--platform/include/chre/platform/atomic.h2
-rw-r--r--platform/include/chre/platform/fatal_error.h3
-rw-r--r--platform/include/chre/platform/platform_ble.h13
-rw-r--r--platform/include/chre/platform/tracing.h104
-rw-r--r--platform/linux/include/chre/platform/linux/task_util/task.h32
-rw-r--r--platform/linux/include/chre/platform/linux/task_util/task_manager.h19
-rw-r--r--platform/linux/include/chre/target_platform/assert.h22
-rw-r--r--platform/linux/pal_audio.cc9
-rw-r--r--platform/linux/pal_ble.cc122
-rw-r--r--platform/linux/pal_gnss.cc31
-rw-r--r--platform/linux/pal_sensor.cc7
-rw-r--r--platform/linux/pal_wifi.cc36
-rw-r--r--platform/linux/pal_wwan.cc3
-rw-r--r--platform/linux/task_util/task.cc18
-rw-r--r--platform/linux/task_util/task_manager.cc5
-rw-r--r--platform/linux/tests/task_manager_test.cc120
-rw-r--r--platform/linux/tests/task_test.cc18
-rw-r--r--platform/platform.mk8
-rw-r--r--platform/shared/audio_pal/platform_audio.cc6
-rw-r--r--platform/shared/chre_api_ble.cc43
-rw-r--r--platform/shared/dram_vote_client.cc17
-rw-r--r--platform/shared/host_link.cc9
-rw-r--r--platform/shared/host_protocol_chre.cc18
-rw-r--r--platform/shared/idl/host_messages.fbs28
-rw-r--r--platform/shared/include/chre/platform/shared/assert_func.h43
-rw-r--r--platform/shared/include/chre/platform/shared/bt_snoop_log.h3
-rw-r--r--platform/shared/include/chre/platform/shared/dram_vote_client.h2
-rw-r--r--platform/shared/include/chre/platform/shared/generated/host_messages_generated.h199
-rw-r--r--platform/shared/include/chre/platform/shared/host_protocol_chre.h17
-rw-r--r--platform/shared/include/chre/platform/shared/log_buffer.h62
-rw-r--r--platform/shared/include/chre/platform/shared/log_buffer_manager.h5
-rw-r--r--platform/shared/include/chre/target_platform/platform_ble_base.h1
-rw-r--r--platform/shared/log_buffer.cc187
-rw-r--r--platform/shared/log_buffer_manager.cc19
-rw-r--r--platform/shared/nanoapp/nanoapp_stack_check.cc48
-rw-r--r--platform/shared/nanoapp/nanoapp_support_lib_dso.cc26
-rw-r--r--platform/shared/nanoapp_loader.cc7
-rw-r--r--platform/shared/platform_ble.cc23
-rw-r--r--platform/shared/pw_trace/include/chre/target_platform/tracing.h247
-rw-r--r--platform/shared/pw_trace/include/chre/target_platform/tracing_util.h134
-rw-r--r--platform/shared/sensor_pal/platform_sensor_manager.cc6
-rw-r--r--platform/slpi/host_link.cc2
-rw-r--r--platform/slpi/include/chre/target_platform/assert.h22
-rw-r--r--platform/tests/log_buffer_test.cc223
-rw-r--r--platform/tests/trace_test.cc338
-rw-r--r--platform/tinysys/authentication.cc7
-rw-r--r--platform/tinysys/condition_variable_base.cc5
-rw-r--r--platform/tinysys/host_link.cc220
-rw-r--r--platform/tinysys/include/chre/target_platform/condition_variable_base.h3
-rwxr-xr-xrun_pal_impl_tests.sh20
-rwxr-xr-xrun_sim.sh5
-rwxr-xr-xrun_tests.sh19
-rw-r--r--test/simulation/README.md102
-rw-r--r--test/simulation/audio_test.cc49
-rw-r--r--test/simulation/ble_test.cc339
-rw-r--r--test/simulation/gnss_test.cc416
-rw-r--r--test/simulation/host_endpoint_notification_test.cc51
-rw-r--r--test/simulation/inc/rpc_test.h11
-rw-r--r--test/simulation/inc/test_base.h20
-rw-r--r--test/simulation/inc/test_util.h157
-rw-r--r--test/simulation/memory_test.cc97
-rw-r--r--test/simulation/rpc_test.cc258
-rw-r--r--test/simulation/sensor_test.cc112
-rw-r--r--test/simulation/settings_test.cc7
-rw-r--r--test/simulation/test_base.cc31
-rw-r--r--test/simulation/test_util.cc138
-rw-r--r--test/simulation/timer_test.cc69
-rw-r--r--test/simulation/wifi_nan_test.cc544
-rw-r--r--test/simulation/wifi_scan_test.cc294
-rw-r--r--test/simulation/wifi_test.cc229
-rw-r--r--test/simulation/wifi_timeout_test.cc430
-rw-r--r--util/dynamic_vector_base.cc6
-rw-r--r--util/include/chre/util/array_queue_impl.h3
-rw-r--r--util/include/chre/util/dynamic_vector_impl.h8
-rw-r--r--util/include/chre/util/intrusive_list_base.h2
-rw-r--r--util/include/chre/util/macros.h44
-rw-r--r--util/include/chre/util/nanoapp/app_id.h6
-rw-r--r--util/include/chre/util/nanoapp/ble.h9
-rw-r--r--util/include/chre/util/nanoapp/math.h3
-rw-r--r--util/include/chre/util/nanoapp/string.h40
-rw-r--r--util/include/chre/util/pigweed/chre_channel_output.h46
-rw-r--r--util/include/chre/util/pigweed/rpc_client.h15
-rw-r--r--util/include/chre/util/pigweed/rpc_common.h (renamed from platform/shared/tracing.cc)31
-rw-r--r--util/include/chre/util/pigweed/rpc_helper.h10
-rw-r--r--util/include/chre/util/pigweed/rpc_server.h14
-rw-r--r--util/include/chre/util/segmented_queue.h4
-rw-r--r--util/include/chre/util/segmented_queue_impl.h25
-rw-r--r--util/include/chre/util/synchronized_expandable_memory_pool_impl.h2
-rw-r--r--util/include/chre/util/synchronized_memory_pool.h2
-rw-r--r--util/include/chre/util/synchronized_memory_pool_impl.h2
-rw-r--r--util/include/chre/util/system/ble_util.h39
-rw-r--r--util/include/chre/util/system/stats_container.h8
-rw-r--r--util/include/chre/util/time.h3
-rw-r--r--util/nanoapp/ble.cc24
-rw-r--r--util/nanoapp/string.cc39
-rw-r--r--util/pigweed/chre_channel_output.cc27
-rw-r--r--util/pigweed/rpc_client.cc9
-rw-r--r--util/pigweed/rpc_server.cc26
-rw-r--r--util/system/ble_util.cc69
-rw-r--r--util/tests/array_queue_test.cc24
-rw-r--r--util/tests/ble_util_test.cc34
-rw-r--r--util/tests/string_test.cc132
-rw-r--r--util/tests/synchronized_expandable_memory_pool_test.cc3
-rw-r--r--util/tests/synchronized_memory_pool_test.cc63
-rw-r--r--util/util.mk3
-rw-r--r--variant/exynos-embos/variant.mk3
-rw-r--r--variant/tinysys/variant.mk3
351 files changed, 25469 insertions, 6667 deletions
diff --git a/Android.bp b/Android.bp
index 05f54d34..c869c274 100644
--- a/Android.bp
+++ b/Android.bp
@@ -18,20 +18,6 @@ package {
default_applicable_licenses: ["system_chre_license"],
}
-// Added automatically by a large-scale-change that took the approach of
-// 'apply every license found to every target'. While this makes sure we respect
-// every license restriction, it may not be entirely correct.
-//
-// e.g. GPL in an MIT project might only apply to the contrib/ directory.
-//
-// Please consider splitting the single license below into multiple licenses,
-// taking care not to lose any license_kind information, and overriding the
-// default license using the 'licenses: [...]' property on targets as needed.
-//
-// For unused files, consider creating a 'fileGroup' with "//visibility:private"
-// to attach the license to, and including a comment whether the files may be
-// used in the current project.
-// See: http://go/android-license-faq
license {
name: "system_chre_license",
visibility: [":__subpackages__"],
@@ -45,22 +31,36 @@ license {
}
filegroup {
- name: "contexthub_generic_aidl_hal_core",
+ name: "contexthub_hal_socket",
+ srcs: ["host/common/socket_server.cc"]
+}
+
+filegroup {
+ name: "contexthub_hal_wifi",
+ srcs: ["host/common/wifi_ext_hal_handler.cc"]
+}
+
+filegroup {
+ name: "contexthub_hal_core",
srcs: [
- "host/common/preloaded_nanoapp_loader.cc",
- "host/common/time_syncer.cc",
+ "host/common/bt_snoop_log_parser.cc",
"host/common/config_util.cc",
+ "host/common/log.cc",
"host/common/log_message_parser.cc",
- "host/common/bt_snoop_log_parser.cc",
- "host/hal_generic/common/permissions_util.cc",
+ "host/common/preloaded_nanoapp_loader.cc",
+ "host/common/time_syncer.cc",
"host/hal_generic/common/hal_client_manager.cc",
"host/hal_generic/common/multi_client_context_hub_base.cc",
+ "host/hal_generic/common/permissions_util.cc",
],
}
cc_library_static {
name: "chre_client",
vendor_available: true,
+ local_include_dirs: [
+ "chre_api/include/chre_api",
+ ],
export_include_dirs: [
"host/common/include",
"platform/shared/include",
@@ -69,17 +69,55 @@ cc_library_static {
srcs: [
"host/common/file_stream.cc",
"host/common/fragmented_load_transaction.cc",
+ "host/common/hal_client.cc",
"host/common/host_protocol_host.cc",
+ "host/common/log.cc",
+ "host/common/pigweed/hal_channel_output.cc",
+ "host/common/pigweed/hal_rpc_client.cc",
"host/common/socket_client.cc",
"platform/shared/host_protocol_common.cc",
],
header_libs: ["chre_flatbuffers"],
export_header_lib_headers: ["chre_flatbuffers"],
shared_libs: [
+ "android.hardware.contexthub-V3-ndk",
+ "libbinder_ndk",
"libcutils",
"liblog",
"libutils",
],
+ cflags: [
+ "-DCHRE_IS_HOST_BUILD",
+ "-DCHRE_MESSAGE_TO_HOST_MAX_SIZE=4000", // Needed to import CHRE APIs.
+ "-Wall",
+ "-Werror",
+ "-Wthread-safety", // Need to be explicitly set
+ ],
+ defaults: [
+ "pw_rpc_cflags_chre",
+ "pw_rpc_nanopb_lib_dependencies",
+ ],
+}
+
+cc_library {
+ name: "chre_metrics_reporter",
+ export_include_dirs: [
+ "host/common/include",
+ ],
+ srcs: [
+ "host/common/metrics_reporter.cc",
+ "host/common/log.cc",
+ ],
+ shared_libs: [
+ "android.frameworks.stats-V1-ndk",
+ "chremetrics-cpp",
+ "chre_atoms_log",
+ "libbinder_ndk",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+ vendor: true,
cflags: ["-Wall", "-Werror"]
}
@@ -99,7 +137,76 @@ cc_binary {
"liblog",
"libutils",
],
- static_libs: ["chre_client"],
+ static_libs: [
+ "chre_client",
+ "chre_host_common"
+ ],
+}
+
+genrule {
+ name: "rpc_world_proto_header",
+ defaults: [
+ "pw_rpc_generate_nanopb_proto",
+ ],
+ srcs: ["apps/rpc_world/rpc/rpc_world.proto"],
+ out: [
+ "rpc_world.pb.h",
+ ],
+}
+
+genrule {
+ name: "rpc_world_proto_source",
+ defaults: [
+ "pw_rpc_generate_nanopb_proto",
+ ],
+ srcs: ["apps/rpc_world/rpc/rpc_world.proto"],
+ out: [
+ "rpc_world.pb.c",
+ ],
+}
+
+genrule {
+ name: "rpc_world_rpc_header",
+ defaults: [
+ "pw_rpc_generate_nanopb_rpc_header",
+ ],
+ srcs: ["apps/rpc_world/rpc/rpc_world.proto"],
+ out: [
+ "rpc_world.rpc.pb.h",
+ ],
+}
+
+cc_binary {
+ name: "chre_test_rpc",
+ vendor: true,
+ local_include_dirs: [
+ "chre_api/include/chre_api",
+ "util/include",
+ ],
+ srcs: [
+ "host/common/test/chre_test_rpc.cc",
+ ],
+ cflags: ["-Wall", "-Werror"],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "chre_client",
+ "libprotobuf-c-nano",
+ ],
+ generated_sources: [
+ "rpc_world_proto_source",
+ ],
+ generated_headers: [
+ "rpc_world_proto_header",
+ "rpc_world_rpc_header",
+ ],
+ defaults: [
+ "pw_rpc_cflags_chre",
+ "pw_rpc_nanopb_lib_dependencies",
+ ],
}
cc_binary {
@@ -130,23 +237,33 @@ filegroup {
cc_binary {
name: "chre_aidl_hal_client",
vendor: true,
+ cpp_std: "c++20",
local_include_dirs: [
"host/common/include",
"chre_api/include",
],
srcs: [
- "host/common/file_stream.cc",
"host/common/chre_aidl_hal_client.cc",
+ "host/common/file_stream.cc",
+ "host/common/log.cc",
],
shared_libs: [
- "android.hardware.contexthub-V2-ndk",
+ "android.hardware.contexthub-V3-ndk",
"libbase",
"libbinder_ndk",
"libjsoncpp",
"liblog",
"libutils",
],
- cflags: ["-Wall", "-Werror", "-fexceptions"],
+ static_libs: [
+ "chre_client",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-fexceptions",
+ "-DLOG_TAG=\"CHRE.HAL.CLIENT\"",
+ ],
}
cc_test {
@@ -313,7 +430,7 @@ cc_library_static {
"host/common/include",
],
shared_libs: [
- "android.hardware.contexthub-V2-ndk",
+ "android.hardware.contexthub-V3-ndk",
"libcutils",
"libutils",
],
@@ -327,27 +444,65 @@ cc_library_static {
],
}
+cc_library_static {
+ name: "chre_host_common",
+ vendor: true,
+ host_supported: true,
+ cpp_std: "c++20",
+ srcs: [
+ "host/common/log.cc",
+ ],
+ local_include_dirs: [
+ "util/include",
+ "host/common/include",
+ ],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-DCHRE_IS_HOST_BUILD",
+ ],
+}
+
cc_test_host {
name: "hal_unit_tests",
vendor: true,
srcs: [
"host/test/**/*_test.cc",
+ "host/hal_generic/common/hal_client_manager.cc",
+ "host/common/fragmented_load_transaction.cc",
+ "host/common/hal_client.cc",
],
local_include_dirs: [
- "util/include",
"host/common/include",
+ "host/hal_generic/common/",
+ "util/include/",
+ "host/hal_generic/aidl/",
+ "platform/shared/include/",
],
static_libs: [
- "android.hardware.contexthub-V2-ndk",
+ "android.hardware.contexthub-V3-ndk",
+ "chre_flags_c_lib",
+ "chre_host_common",
"event_logger",
"libgmock",
],
shared_libs: [
"libcutils",
"libutils",
+ "android.hardware.contexthub-V3-ndk",
+ "liblog",
+ "libjsoncpp",
+ "libbinder_ndk",
+ "server_configurable_flags",
],
header_libs: [
"chre_flatbuffers",
+ "chre_api",
],
defaults: [
"chre_linux_cflags",
@@ -357,6 +512,9 @@ cc_test_host {
"-Werror",
"-DCHRE_IS_HOST_BUILD",
],
+ test_options: {
+ unit_test: true,
+ },
}
genrule {
@@ -504,15 +662,20 @@ cc_test_host {
"platform/include",
"platform/linux/include",
"platform/shared/include",
+ "platform/shared/pw_trace/include",
"util/include",
],
cflags: [
"-DCHRE_MESSAGE_TO_HOST_MAX_SIZE=4096",
"-DCHRE_MINIMUM_LOG_LEVEL=CHRE_LOG_LEVEL_DEBUG",
"-DCHRE_ASSERTIONS_ENABLED=true",
+ "-DCHRE_BLE_SUPPORT_ENABLED=true",
"-DCHRE_FILENAME=__FILE__",
"-DGTEST",
],
+ header_libs: [
+ "chre_flatbuffers",
+ ],
static_libs: [
"chre_linux",
"libgmock",
@@ -522,23 +685,39 @@ cc_test_host {
},
}
-// pw_rpc rules instantiation
+// PW_RPC rules.
cc_defaults {
name: "pw_rpc_cflags_chre",
cflags: [
"-DPW_RPC_USE_GLOBAL_MUTEX=0",
- "-DPW_RPC_CLIENT_STREAM_END_CALLBACK",
+ "-DPW_RPC_COMPLETION_REQUEST_CALLBACK",
"-DPW_RPC_DYNAMIC_ALLOCATION",
],
}
+// Lib dependencies for apps and libs using PW_RPC with nanopb.
+cc_defaults {
+ name: "pw_rpc_nanopb_lib_dependencies",
+ static_libs: [
+ "pw_containers",
+ "pw_protobuf",
+ "pw_rpc_chre",
+ "pw_rpc_nanopb_chre",
+ "pw_status",
+ "pw_stream",
+ "pw_varint",
+ ],
+}
+
cc_library_static {
name: "pw_rpc_chre",
defaults: [
"pw_rpc_cflags_chre",
"pw_rpc_defaults",
],
+ host_supported: true,
+ vendor_available: true,
}
cc_library_static {
@@ -555,6 +734,8 @@ cc_library_static {
"pw_rpc_raw_chre",
"pw_rpc_chre",
],
+ host_supported: true,
+ vendor_available: true,
}
cc_library_static {
@@ -566,6 +747,8 @@ cc_library_static {
static_libs: [
"pw_rpc_chre",
],
+ host_supported: true,
+ vendor_available: true,
}
genrule {
@@ -588,7 +771,6 @@ genrule {
out: [
"rpc_test.pb.c",
],
-
}
genrule {
@@ -608,7 +790,9 @@ cc_test_host {
isolated: false,
test_suites: ["general-tests"],
srcs: [
- "test/simulation/*.cc",
+ "test/simulation/test_base.cc",
+ "test/simulation/test_util.cc",
+ "test/simulation/*_test.cc",
],
generated_sources: [
"rpc_test_proto_source",
@@ -625,16 +809,11 @@ cc_test_host {
"chre_linux",
"chre_pal_linux",
"libprotobuf-c-nano",
- "pw_containers",
- "pw_protobuf",
- "pw_rpc_nanopb_chre",
- "pw_rpc_chre",
- "pw_stream",
- "pw_varint",
],
defaults: [
"chre_linux_cflags",
"pw_rpc_cflags_chre",
+ "pw_rpc_nanopb_lib_dependencies",
],
sanitize: {
address: true,
@@ -707,7 +886,6 @@ cc_library_static {
"platform/shared/platform_gnss.cc",
"platform/shared/platform_wifi.cc",
"platform/shared/system_time.cc",
- "platform/shared/tracing.cc",
"platform/shared/version.cc",
"platform/shared/sensor_pal/platform_sensor.cc",
"platform/shared/sensor_pal/platform_sensor_type_helpers.cc",
@@ -761,10 +939,11 @@ cc_defaults {
"-DCHRE_SENSORS_SUPPORT_ENABLED",
"-DCHRE_WIFI_SUPPORT_ENABLED",
"-DCHRE_WIFI_NAN_SUPPORT_ENABLED",
- "-DCHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS=3000000000",
- "-DCHRE_TEST_WIFI_RANGING_RESULT_TIMEOUT_NS=3000000000",
- "-DCHRE_TEST_ASYNC_RESULT_TIMEOUT_NS=3000000000",
+ "-DCHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS=300000000",
+ "-DCHRE_TEST_WIFI_RANGING_RESULT_TIMEOUT_NS=300000000",
+ "-DCHRE_TEST_ASYNC_RESULT_TIMEOUT_NS=300000000",
"-DCHRE_BLE_READ_RSSI_SUPPORT_ENABLED",
+ "-Wextra-semi",
],
}
@@ -799,9 +978,12 @@ cc_defaults {
"libjsoncpp",
"libutils",
"liblog",
+ "chre_metrics_reporter",
+ "server_configurable_flags",
],
static_libs: [
"chre_config_util",
+ "chre_flags_c_lib",
]
}
@@ -855,8 +1037,12 @@ java_library_static {
host_supported: true,
proto: {
type: "lite",
+ include_dirs: ["external/protobuf/src"],
},
- srcs: ["apps/test/common/chre_api_test/rpc/chre_api_test.proto"],
+ srcs: [
+ "apps/test/common/chre_api_test/rpc/chre_api_test.proto",
+ ":libprotobuf-internal-protos",
+ ],
sdk_version: "current",
}
@@ -875,3 +1061,16 @@ cc_library_static {
],
cflags: ["-Wall", "-Werror"]
}
+
+aconfig_declarations {
+ name: "chre_flags",
+ package: "android.chre.flags",
+ srcs: ["chre_flags.aconfig"],
+}
+
+cc_aconfig_library {
+ name: "chre_flags_c_lib",
+ aconfig_declarations: "chre_flags",
+ host_supported: true,
+ vendor: true,
+}
diff --git a/Android.mk b/Android.mk
index f1145ad8..a25d1ca4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -98,7 +98,12 @@ LOCAL_SHARED_LIBRARIES := \
chremetrics-cpp \
chre_atoms_log \
android.frameworks.stats-V1-ndk \
- libbinder_ndk
+ libbinder_ndk \
+ chre_metrics_reporter \
+ server_configurable_flags
+
+LOCAL_STATIC_LIBRARIES := \
+ chre_flags_c_lib
LOCAL_SRC_FILES += $(MSM_SRC_FILES)
LOCAL_C_INCLUDES += $(MSM_INCLUDES)
@@ -107,20 +112,33 @@ LOCAL_CPPFLAGS += -std=c++20
LOCAL_CFLAGS += -Wno-sign-compare
LOCAL_CFLAGS += -Wno-c++11-narrowing
LOCAL_CFLAGS += -Wno-deprecated-volatile
-PIGWEED_DIR = external/pigweed
-PIGWEED_DIR_RELPATH = ../../$(PIGWEED_DIR)
-LOCAL_CFLAGS += -I$(PIGWEED_DIR)/pw_bytes/public
-LOCAL_CFLAGS += -I$(PIGWEED_DIR)/pw_polyfill/public
-LOCAL_CFLAGS += -I$(PIGWEED_DIR)/pw_polyfill/public_overrides
-LOCAL_CFLAGS += -I$(PIGWEED_DIR)/pw_polyfill/standard_library_public
-LOCAL_CFLAGS += -I$(PIGWEED_DIR)/pw_preprocessor/public
-LOCAL_CFLAGS += -I$(PIGWEED_DIR)/pw_tokenizer/public
-LOCAL_CFLAGS += -I$(PIGWEED_DIR)/pw_varint/public
-LOCAL_CFLAGS += -I$(PIGWEED_DIR)/pw_span/public
-
-LOCAL_SRC_FILES += $(PIGWEED_DIR_RELPATH)/pw_tokenizer/detokenize.cc
-LOCAL_SRC_FILES += $(PIGWEED_DIR_RELPATH)/pw_tokenizer/decode.cc
-LOCAL_SRC_FILES += $(PIGWEED_DIR_RELPATH)/pw_varint/varint.cc
+
+# Pigweed (PW)
+PW_DIR = external/pigweed
+PW_DIR_RELPATH = ../../$(PW_DIR)
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_assert/assert_compatibility_public_overrides
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_assert/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_base64/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_bytes/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_containers/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_log_tokenized/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_log/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_polyfill/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_polyfill/public_overrides
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_polyfill/standard_library_public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_preprocessor/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_result/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_span/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_status/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_string/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_tokenizer/public
+LOCAL_CFLAGS += -I$(PW_DIR)/pw_varint/public
+LOCAL_CFLAGS += -I$(PW_DIR)/third_party/fuchsia/repo/sdk/lib/stdcompat/include
+
+LOCAL_SRC_FILES += $(PW_DIR_RELPATH)/pw_tokenizer/decode.cc
+LOCAL_SRC_FILES += $(PW_DIR_RELPATH)/pw_tokenizer/detokenize.cc
+LOCAL_SRC_FILES += $(PW_DIR_RELPATH)/pw_varint/varint_c.c
+LOCAL_SRC_FILES += $(PW_DIR_RELPATH)/pw_varint/varint.cc
ifeq ($(CHRE_DAEMON_USE_SDSPRPC),true)
LOCAL_SHARED_LIBRARIES += libsdsprpc
diff --git a/Makefile b/Makefile
index 604c4ac2..c3543d18 100644
--- a/Makefile
+++ b/Makefile
@@ -68,6 +68,12 @@ COMMON_CFLAGS += -DCHRE_TOKENIZED_LOGGING_ENABLED
include $(CHRE_PREFIX)/external/pigweed/pw_tokenizer.mk
endif
+# Optional tokenized tracing support.
+ifeq ($(CHRE_TRACING_ENABLED), true)
+COMMON_CFLAGS += -DCHRE_TRACING_ENABLED
+include $(CHRE_PREFIX)/external/pigweed/pw_trace.mk
+endif
+
# Optional on-device unit tests support
include $(CHRE_PREFIX)/test/test.mk
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 64a49d54..ca8b740e 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -11,4 +11,6 @@ checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py
todo_checker_hook = ${REPO_ROOT}/system/chre/tools/todo_checker.py
-run_sim = ${REPO_ROOT}/system/chre/run_sim.sh -b \ No newline at end of file
+run_sim = ${REPO_ROOT}/system/chre/run_sim.sh -b
+run_tests = ${REPO_ROOT}/system/chre/run_tests.sh -b
+run_pal_impl_tests = ${REPO_ROOT}/system/chre/run_pal_impl_tests.sh -b \ No newline at end of file
diff --git a/api_parser/.gitignore b/api_parser/.gitignore
new file mode 100644
index 00000000..48fb1936
--- /dev/null
+++ b/api_parser/.gitignore
@@ -0,0 +1 @@
+/parser_cache
diff --git a/chpp/api_parser/README.md b/api_parser/README.md
index 8d775052..8d775052 100644
--- a/chpp/api_parser/README.md
+++ b/api_parser/README.md
diff --git a/api_parser/api_parser.py b/api_parser/api_parser.py
new file mode 100644
index 00000000..343bcc90
--- /dev/null
+++ b/api_parser/api_parser.py
@@ -0,0 +1,150 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 os
+
+from collections import defaultdict
+from pyclibrary import CParser
+
+from utils import system_chre_abs_path
+
+
+class ApiParser:
+ """Given a file-specific set of annotations (extracted from JSON annotations file), parses a
+ single API header file into data structures suitable for use with code generation. This class
+ will contain the parsed representation of the headers when instantiated.
+ """
+
+ def __init__(self, json_obj):
+ """Initialize and parse the API file described in the provided JSON-derived object.
+
+ :param json_obj: Extracted file-specific annotations from JSON
+ """
+
+ self.json = json_obj
+ self.structs_and_unions = {}
+ self._parse_annotations()
+ self._parse_api()
+
+ def _parse_annotations(self):
+ # Converts annotations list to a more usable data structure: dict keyed by structure name,
+ # containing a dict keyed by field name, containing a list of annotations (as they
+ # appear in the JSON). In other words, we can easily get all of the annotations for the
+ # "version" field in "chreWwanCellInfoResult" via
+ # annotations['chreWwanCellInfoResult']['version']. This is also a defaultdict, so it's safe
+ # to access if there are no annotations for this structure + field; it'll just give you
+ # an empty list in that case.
+
+ self.annotations = defaultdict(lambda: defaultdict(list))
+ for struct_info in self.json['struct_info']:
+ for annotation in struct_info['annotations']:
+ self.annotations[struct_info['name']
+ ][annotation['field']].append(annotation)
+
+ def _files_to_parse(self):
+ """Returns a list of files to supply as input to CParser"""
+
+ # Input paths for CParser are stored in JSON relative to <android_root>/system/chre
+ # Reformulate these to absolute paths, and add in some default includes that we always
+ # supply
+ chre_project_base_dir = system_chre_abs_path()
+ default_includes = ['api_parser/parser_defines.h',
+ 'chre_api/include/chre_api/chre/version.h']
+ files = default_includes + \
+ self.json['includes'] + [self.json['filename']]
+ return [os.path.join(chre_project_base_dir, file) for file in files]
+
+ def _parse_structs_and_unions(self):
+ # Starts with the root structures (i.e. those that will appear at the top-level in one
+ # or more CHPP messages), build a data structure containing all of the information we'll
+ # need to emit the CHPP structure definition and conversion code.
+
+ structs_and_unions_to_parse = self.json['root_structs'].copy()
+ while len(structs_and_unions_to_parse) > 0:
+ type_name = structs_and_unions_to_parse.pop()
+ if type_name in self.structs_and_unions:
+ continue
+
+ entry = {
+ 'appears_in': set(), # Other types this type is nested within
+ 'dependencies': set(), # Types that are nested in this type
+ 'has_vla_member': False, # True if this type or any dependency has a VLA member
+ 'members': [], # Info about each member of this type
+ }
+ if type_name in self.parser.defs['structs']:
+ defs = self.parser.defs['structs'][type_name]
+ entry['is_union'] = False
+ elif type_name in self.parser.defs['unions']:
+ defs = self.parser.defs['unions'][type_name]
+ entry['is_union'] = True
+ else:
+ raise RuntimeError(
+ "Couldn't find {} in parsed structs/unions".format(type_name))
+
+ for member_name, member_type, _ in defs['members']:
+ member_info = {
+ 'name': member_name,
+ 'type': member_type,
+ 'annotations': self.annotations[type_name][member_name],
+ 'is_nested_type': False,
+ }
+
+ if member_type.type_spec.startswith('struct ') or \
+ member_type.type_spec.startswith('union '):
+ member_info['is_nested_type'] = True
+ member_type_name = member_type.type_spec.split(' ')[1]
+ member_info['nested_type_name'] = member_type_name
+ entry['dependencies'].add(member_type_name)
+ structs_and_unions_to_parse.append(member_type_name)
+
+ entry['members'].append(member_info)
+
+ # Flip a flag if this structure has at least one variable-length array member, which
+ # means that the encoded size can only be computed at runtime
+ if not entry['has_vla_member']:
+ for annotation in self.annotations[type_name][member_name]:
+ if annotation['annotation'] == 'var_len_array':
+ entry['has_vla_member'] = True
+
+ self.structs_and_unions[type_name] = entry
+
+ # Build reverse linkage of dependency chain (i.e. lookup between a type and the other types
+ # it appears in)
+ for type_name, type_info in self.structs_and_unions.items():
+ for dependency in type_info['dependencies']:
+ self.structs_and_unions[dependency]['appears_in'].add(
+ type_name)
+
+ # Bubble up "has_vla_member" to types each type it appears in, i.e. if this flag is set to
+ # True on a leaf node, then all its ancestors should also have the flag set to True
+ for type_name, type_info in self.structs_and_unions.items():
+ if type_info['has_vla_member']:
+ types_to_mark = list(type_info['appears_in'])
+ while len(types_to_mark) > 0:
+ type_to_mark = types_to_mark.pop()
+ self.structs_and_unions[type_to_mark]['has_vla_member'] = True
+ types_to_mark.extend(
+ list(self.structs_and_unions[type_to_mark]['appears_in']))
+
+ def _parse_api(self):
+ """
+ Parses the API and stores the structs and unions.
+ """
+
+ file_to_parse = self._files_to_parse()
+ self.parser = CParser(file_to_parse, cache='parser_cache')
+ self._parse_structs_and_unions()
diff --git a/chpp/api_parser/chre_api_to_chpp.py b/api_parser/chpp_code_generator.py
index f1bde02f..5861951e 100755..100644
--- a/chpp/api_parser/chre_api_to_chpp.py
+++ b/api_parser/chpp_code_generator.py
@@ -1,6 +1,6 @@
#!/usr/bin/python3
#
-# Copyright (C) 2020 The Android Open Source Project
+# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,43 +15,16 @@
# limitations under the License.
#
-import argparse
-import json
-import os.path
+import os
import subprocess
-from collections import defaultdict
+
from datetime import datetime
-from pyclibrary import CParser
-
-LICENSE_HEADER = """/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-"""
-
-# Paths for output, relative to system/chre
-CHPP_PARSER_INCLUDE_PATH = "chpp/include/chpp/common"
-CHPP_PARSER_SOURCE_PATH = "chpp/common"
-
-
-def system_chre_abs_path():
- """Gets the absolute path to the system/chre directory containing this script."""
- script_dir = os.path.dirname(os.path.realpath(__file__))
- # Assuming we're at system/chre/chpp/api_parser (i.e. up 2 to get to system/chre)
- chre_project_base_dir = os.path.normpath(script_dir + "/../..")
- return chre_project_base_dir
+from utils import CHPP_PARSER_INCLUDE_PATH
+from utils import CHPP_PARSER_SOURCE_PATH
+from utils import LICENSE_HEADER
+from utils import android_build_top_abs_path
+from utils import system_chre_abs_path
class CodeGenerator:
@@ -62,11 +35,12 @@ class CodeGenerator:
"""
:param api: ApiParser object
"""
+
self.api = api
self.json = api.json
# Turn "chre_api/include/chre_api/chre/wwan.h" into "wwan"
self.service_name = self.json['filename'].split('/')[-1].split('.')[0]
- self.capitalized_service_name = self.service_name[0].upper() + self.service_name[1:]
+ self.capitalized_service_name = self.service_name.capitalize()
self.commit_hash = commit_hash
# ----------------------------------------------------------------------------------------------
@@ -75,27 +49,31 @@ class CodeGenerator:
def _autogen_notice(self):
out = []
- out.append("// This file was automatically generated by {}\n".format(
+ out.append('// This file was automatically generated by {}\n'.format(
os.path.basename(__file__)))
- out.append("// Date: {} UTC\n".format(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')))
- out.append("// Source: {} @ commit {}\n\n".format(self.json['filename'], self.commit_hash))
- out.append("// DO NOT modify this file directly, as those changes will be lost the next\n")
- out.append("// time the script is executed\n\n")
+ out.append(
+ '// Date: {} UTC\n'.format(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')))
+ out.append(
+ '// Source: {} @ commit {}\n\n'.format(self.json['filename'], self.commit_hash))
+ out.append(
+ '// DO NOT modify this file directly, as those changes will be lost the next\n')
+ out.append('// time the script is executed\n\n')
return out
def _dump_to_file(self, output_filename, contents, dry_run, skip_clang_fomat):
"""Outputs contents to output_filename, or prints contents if dry_run is True"""
+
if dry_run:
- print("---- {} ----".format(output_filename))
+ print('---- {} ----'.format(output_filename))
print(contents)
- print("---- end of {} ----\n".format(output_filename))
+ print('---- end of {} ----\n'.format(output_filename))
else:
with open(output_filename, 'w') as f:
f.write(contents)
if not skip_clang_fomat:
- clang_format_path = os.path.normpath(
- "../../../../prebuilts/clang/host/linux-x86/clang-stable/bin/clang-format")
+ clang_format_path = (android_build_top_abs_path() +
+ '/prebuilts/clang/host/linux-x86/clang-stable/bin/clang-format')
args = [clang_format_path, '-i', output_filename]
result = subprocess.run(args)
result.check_returncode()
@@ -109,36 +87,40 @@ class CodeGenerator:
return type_info.declarators[0][0]
def _get_chpp_type_from_chre(self, chre_type):
- """Given 'chreWwanCellInfo' returns 'struct ChppWwanCellInfo', etc."""
+ """Returns 'struct ChppWwanCellInfo', etc. given 'chreWwanCellInfo'"""
+
prefix = self._get_struct_or_union_prefix(chre_type)
# First see if we have an explicit name override (e.g. for anonymous types)
- for annotation in self.api.annotations[chre_type]["."]:
- if annotation['annotation'] == "rename_type":
+ for annotation in self.api.annotations[chre_type]['.']:
+ if annotation['annotation'] == 'rename_type':
return prefix + annotation['type_override']
# Otherwise, use the existing type name, just replace the "chre" prefix with "Chpp"
if chre_type.startswith('chre'):
return prefix + 'Chpp' + chre_type[4:]
else:
- raise RuntimeError("Couldn't figure out new type name for {}".format(chre_type))
+ raise RuntimeError(
+ "Couldn't figure out new type name for {}".format(chre_type))
def _get_chre_type_with_prefix(self, chre_type):
- """Given 'chreWwanCellInfo' returns 'struct chreWwanCellInfo', etc."""
+ """Returns 'struct chreWwanCellInfo', etc. given 'chreWwanCellInfo'"""
+
return self._get_struct_or_union_prefix(chre_type) + chre_type
def _get_chpp_header_type_from_chre(self, chre_type):
- """Given 'chreWwanCellInfo' returns 'struct ChppWwanCellInfoWithHeader', etc."""
+ """Returns 'struct ChppWwanCellInfoWithHeader', etc. given 'chreWwanCellInfo'"""
+
return self._get_chpp_type_from_chre(chre_type) + 'WithHeader'
def _get_member_comment(self, member_info):
for annotation in member_info['annotations']:
- if annotation['annotation'] == "fixed_value":
- return " // Input ignored; always set to {}".format(annotation['value'])
- elif annotation['annotation'] == "var_len_array":
- return " // References {} instances of {}".format(
+ if annotation['annotation'] == 'fixed_value':
+ return ' // Input ignored; always set to {}'.format(annotation['value'])
+ elif annotation['annotation'] == 'var_len_array':
+ return ' // References {} instances of {}'.format(
annotation['length_field'], self._get_member_type(member_info))
- return ""
+ return ''
def _get_member_type(self, member_info, underlying_vla_type=False):
"""Gets the CHPP type specification prefix for a struct/union member.
@@ -148,6 +130,7 @@ class CodeGenerator:
'struct ChppOffset', and True to output the type that ChppOffset references
:return: type specification string that prefixes the field name, e.g. 'uint8_t'
"""
+
# 4 cases to handle:
# 1) Annotation gives explicit type that we should use
# 2) Annotation says this is a variable length array (so use ChppOffset if
@@ -155,16 +138,16 @@ class CodeGenerator:
# 3) This is a struct/union type, so use the renamed (CHPP) type name
# 4) Regular type, e.g. uint32_t, so just use the type spec as-is
for annotation in member_info['annotations']:
- if annotation['annotation'] == "rewrite_type":
+ if annotation['annotation'] == 'rewrite_type':
return annotation['type_override']
- elif not underlying_vla_type and annotation['annotation'] in ["var_len_array", "string"]:
- return "struct ChppOffset"
+ elif not underlying_vla_type and annotation['annotation'] in ['var_len_array', 'string']:
+ return 'struct ChppOffset'
if not underlying_vla_type and len(member_info['type'].declarators) > 0 and \
- member_info['type'].declarators[0] == "*":
+ member_info['type'].declarators[0] == '*':
# This case should either be handled by rewrite_type (e.g. to uint32_t as
# opaque/ignored), or var_len_array
- raise RuntimeError("Pointer types require annotation\n{}".format(
+ raise RuntimeError('Pointer types require annotation\n{}'.format(
member_info))
if member_info['is_nested_type']:
@@ -174,55 +157,62 @@ class CodeGenerator:
def _get_member_type_suffix(self, member_info):
if self._is_array_type(member_info['type']):
- return "[{}]".format(self._get_array_len(member_info['type']))
- return ""
+ return '[{}]'.format(self._get_array_len(member_info['type']))
+ return ''
def _get_struct_or_union_prefix(self, chre_type):
return 'struct ' if not self.api.structs_and_unions[chre_type]['is_union'] else 'union '
def _gen_header_includes(self):
"""Generates #include directives for use in <service>_types.h"""
- out = ["#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n"]
- includes = ["chpp/app.h", "chpp/macros.h", "chre_api/chre/version.h"]
+ out = ['#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n']
+
+ includes = ['chpp/app.h', 'chpp/macros.h', 'chre_api/chre/version.h']
includes.extend(self.json['output_includes'])
for incl in sorted(includes):
- out.append("#include \"{}\"\n".format(incl))
- out.append("\n")
+ out.append('#include "{}"\n'.format(incl))
+ out.append('\n')
return out
def _gen_struct_or_union(self, name):
- """Generates the definition for a single struct/union type"""
+ """Generates the definition for a single struct/union type."""
+
out = []
if not name.startswith('anon'):
- out.append("//! See {{@link {}}} for details\n".format(name))
- out.append("{} {{\n".format(self._get_chpp_type_from_chre(name)))
+ out.append('//! See {{@link {}}} for details\n'.format(name))
+ out.append('{} {{\n'.format(self._get_chpp_type_from_chre(name)))
for member_info in self.api.structs_and_unions[name]['members']:
- out.append(" {} {}{};{}\n".format(self._get_member_type(member_info),
+ out.append(' {} {}{};{}\n'.format(self._get_member_type(member_info),
member_info['name'],
- self._get_member_type_suffix(member_info),
+ self._get_member_type_suffix(
+ member_info),
self._get_member_comment(member_info)))
- out.append("} CHPP_PACKED_ATTR;\n\n")
+ out.append('} CHPP_PACKED_ATTR;\n\n')
return out
def _gen_header_struct(self, chre_type):
- """Generates the definition for the type with header (WithHeader)"""
+ """Generates the definition for the type with header (WithHeader)."""
+
out = []
- out.append("//! CHPP app header plus {}\n".format(
+ out.append('//! CHPP app header plus {}\n'.format(
self._get_chpp_header_type_from_chre(chre_type)))
- out.append("{} {{\n".format(self._get_chpp_header_type_from_chre(chre_type)))
- out.append(" struct ChppAppHeader header;\n")
- out.append(" {} payload;\n".format(self._get_chpp_type_from_chre(chre_type)))
- out.append("} CHPP_PACKED_ATTR;\n\n")
+ out.append('{} {{\n'.format(
+ self._get_chpp_header_type_from_chre(chre_type)))
+ out.append(' struct ChppAppHeader header;\n')
+ out.append(' {} payload;\n'.format(
+ self._get_chpp_type_from_chre(chre_type)))
+ out.append('} CHPP_PACKED_ATTR;\n\n')
return out
def _gen_structs_and_unions(self):
"""Generates definitions for all struct/union types required for the root structs."""
+
out = []
- out.append("CHPP_PACKED_START\n\n")
+ out.append('CHPP_PACKED_START\n\n')
sorted_structs = self._sorted_structs(self.json['root_structs'])
for type_name in sorted_structs:
@@ -231,7 +221,7 @@ class CodeGenerator:
for chre_type in self.json['root_structs']:
out.extend(self._gen_header_struct(chre_type))
- out.append("CHPP_PACKED_END\n\n")
+ out.append('CHPP_PACKED_END\n\n')
return out
def _sorted_structs(self, root_nodes):
@@ -241,6 +231,7 @@ class CodeGenerator:
then B will appear before A in the returned list.
:return: list of keys in self.api.structs_and_unions, sorted by dependency order
"""
+
result = []
visited = set()
@@ -266,20 +257,22 @@ class CodeGenerator:
:param member_info: a dict element from self.api.structs_and_unions[struct]['members']
:return: string
"""
+
type_name = None
if member_info['is_nested_type']:
chre_type = member_info['nested_type_name']
if self.api.structs_and_unions[chre_type]['has_vla_member']:
- return "{}(in->{})".format(self._get_chpp_sizeof_function_name(chre_type),
+ return '{}(in->{})'.format(self._get_chpp_sizeof_function_name(chre_type),
member_info['name'])
else:
type_name = self._get_chpp_type_from_chre(chre_type)
else:
type_name = member_info['type'].type_spec
- return "sizeof({})".format(type_name)
+ return 'sizeof({})'.format(type_name)
def _gen_chpp_sizeof_function(self, chre_type):
"""Generates a function to determine the encoded size of the CHRE struct, if necessary."""
+
out = []
# Note that this function *should* work with unions as well, but at the time of writing
@@ -289,25 +282,27 @@ class CodeGenerator:
# No codegen necessary, just sizeof on the CHPP structure name is sufficient
return out
- core_type_name = self._strip_prefix_and_service_from_chre_struct_name(chre_type)
+ core_type_name = self._strip_prefix_and_service_from_chre_struct_name(
+ chre_type)
parameter_name = core_type_name[0].lower() + core_type_name[1:]
chpp_type_name = self._get_chpp_header_type_from_chre(chre_type)
- out.append("//! @return number of bytes required to represent the given\n"
- "//! {} along with the CHPP header as\n"
- "//! {}\n"
+ out.append('//! @return number of bytes required to represent the given\n'
+ '//! {} along with the CHPP header as\n'
+ '//! {}\n'
.format(chre_type, chpp_type_name))
- out.append("static size_t {}(\n const {}{} *{}) {{\n"
+ out.append('static size_t {}(\n const {}{} *{}) {{\n'
.format(self._get_chpp_sizeof_function_name(chre_type),
- self._get_struct_or_union_prefix(chre_type), chre_type,
+ self._get_struct_or_union_prefix(
+ chre_type), chre_type,
parameter_name))
# sizeof(this struct)
- out.append(" size_t encodedSize = sizeof({});\n".format(chpp_type_name))
+ out.append(' size_t encodedSize = sizeof({});\n'.format(chpp_type_name))
# Plus count * sizeof(type) for each var-len array included in this struct
for member_info in self.api.structs_and_unions[chre_type]['members']:
for annotation in member_info['annotations']:
- if annotation['annotation'] == "var_len_array":
+ if annotation['annotation'] == 'var_len_array':
# If the VLA field itself contains a VLA, then we'd need to generate a for
# loop to calculate the size of each element individually - I don't think we
# have any of these in the CHRE API today, so leaving this functionality out.
@@ -317,58 +312,67 @@ class CodeGenerator:
self.api.structs_and_unions[member_info['nested_type_name']][
'has_vla_member']:
raise RuntimeError(
- "Nested variable-length arrays is not currently supported ({} "
- "in {})".format(member_info['name'], chre_type))
+ 'Nested variable-length arrays is not currently supported ({} '
+ 'in {})'.format(member_info['name'], chre_type))
- out.append(" encodedSize += {}->{} * sizeof({});\n".format(
+ out.append(' encodedSize += {}->{} * sizeof({});\n'.format(
parameter_name, annotation['length_field'],
self._get_member_type(member_info, True)))
- elif annotation['annotation'] == "string":
- out.append(" if ({}->{} != NULL) {{".format(
+ elif annotation['annotation'] == 'string':
+ out.append(' if ({}->{} != NULL) {{'.format(
parameter_name, annotation['field']))
- out.append(" encodedSize += strlen({}->{}) + 1;\n".format(
+ out.append(' encodedSize += strlen({}->{}) + 1;\n'.format(
parameter_name, annotation['field']))
- out.append(" }\n")
+ out.append(' }\n')
- out.append(" return encodedSize;\n}\n\n")
+ out.append(' return encodedSize;\n}\n\n')
return out
def _gen_chpp_sizeof_functions(self):
"""For each root struct, generate necessary functions to determine their encoded size."""
+
out = []
for struct in self.json['root_structs']:
out.extend(self._gen_chpp_sizeof_function(struct))
return out
def _gen_conversion_includes(self):
- """Generates #include directives for the conversion source file"""
- out = ["#include \"chpp/macros.h\"\n"
- "#include \"chpp/memory.h\"\n"
- "#include \"chpp/common/{}_types.h\"\n\n".format(self.service_name)]
- out.append("#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n")
+ """Generates #include directives for the conversion source file."""
+
+ out = ['#include "chpp/macros.h"\n'
+ '#include "chpp/memory.h"\n'
+ '#include "chpp/common/{}_types.h"\n\n'.format(self.service_name)]
+ out.append(
+ '#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n')
return out
def _get_chpp_sizeof_function_name(self, chre_struct):
- """Function name used to compute the encoded size of the given struct at runtime"""
- core_type_name = self._strip_prefix_and_service_from_chre_struct_name(chre_struct)
- return "chpp{}SizeOf{}FromChre".format(self.capitalized_service_name, core_type_name)
+ """Returns the function name used to compute the encoded size of the given struct at
+ runtime.
+ """
+
+ core_type_name = self._strip_prefix_and_service_from_chre_struct_name(
+ chre_struct)
+ return 'chpp{}SizeOf{}FromChre'.format(self.capitalized_service_name, core_type_name)
def _get_encoding_function_name(self, chre_type):
- core_type_name = self._strip_prefix_and_service_from_chre_struct_name(chre_type)
- return "chpp{}Convert{}FromChre".format(self.capitalized_service_name, core_type_name)
+ core_type_name = self._strip_prefix_and_service_from_chre_struct_name(
+ chre_type)
+ return 'chpp{}Convert{}FromChre'.format(self.capitalized_service_name, core_type_name)
def _gen_encoding_function_signature(self, chre_type):
out = []
- out.append("void {}(\n".format(self._get_encoding_function_name(chre_type)))
- out.append(" const {}{} *in,\n".format(
+ out.append(
+ 'void {}(\n'.format(self._get_encoding_function_name(chre_type)))
+ out.append(' const {}{} *in,\n'.format(
self._get_struct_or_union_prefix(chre_type), chre_type))
- out.append(" {} *out".format(self._get_chpp_type_from_chre(chre_type)))
+ out.append(' {} *out'.format(self._get_chpp_type_from_chre(chre_type)))
if self.api.structs_and_unions[chre_type]['has_vla_member']:
- out.append(",\n")
- out.append(" uint8_t *payload,\n")
- out.append(" size_t payloadSize,\n")
- out.append(" uint16_t *vlaOffset")
- out.append(")")
+ out.append(',\n')
+ out.append(' uint8_t *payload,\n')
+ out.append(' size_t payloadSize,\n')
+ out.append(' uint16_t *vlaOffset')
+ out.append(')')
return out
def _gen_string_encoding(self, member_info, annotation):
@@ -377,18 +381,19 @@ class CodeGenerator:
# in our API. We can assert here since there's currently no API that
# does so.
member_name = member_info['name']
- out.append(" if (in->{} != NULL) {{\n".format(member_name))
- out.append(" size_t strSize = strlen(in->{}) + 1;\n".format(member_name))
- out.append(" memcpy(&payload[*vlaOffset], in->{}, strSize);\n".format(
+ out.append(' if (in->{} != NULL) {{\n'.format(member_name))
+ out.append(
+ ' size_t strSize = strlen(in->{}) + 1;\n'.format(member_name))
+ out.append(' memcpy(&payload[*vlaOffset], in->{}, strSize);\n'.format(
member_name))
- out.append(" out->{}.length = (uint16_t)(strSize);\n".format(
+ out.append(' out->{}.length = (uint16_t)(strSize);\n'.format(
member_name))
- out.append(" out->{}.offset = *vlaOffset;\n".format(member_name))
- out.append(" *vlaOffset += out->{}.length;\n".format(member_name))
- out.append(" } else {\n")
- out.append(" out->{}.length = 0;\n".format(member_name))
- out.append(" out->{}.offset = 0;\n".format(member_name))
- out.append(" }\n\n")
+ out.append(' out->{}.offset = *vlaOffset;\n'.format(member_name))
+ out.append(' *vlaOffset += out->{}.length;\n'.format(member_name))
+ out.append(' } else {\n')
+ out.append(' out->{}.length = 0;\n'.format(member_name))
+ out.append(' out->{}.offset = 0;\n'.format(member_name))
+ out.append(' }\n\n')
return out
@@ -399,36 +404,38 @@ class CodeGenerator:
chpp_type = self._get_member_type(member_info, True)
if member_info['is_nested_type']:
- out.append("\n {} *{} = ({} *) &payload[*vlaOffset];\n".format(
+ out.append('\n {} *{} = ({} *) &payload[*vlaOffset];\n'.format(
chpp_type, variable_name, chpp_type))
- out.append(" out->{}.length = (uint16_t)(in->{} * {});\n".format(
+ out.append(' out->{}.length = (uint16_t)(in->{} * {});\n'.format(
member_info['name'], annotation['length_field'],
self._get_chpp_member_sizeof_call(member_info)))
- out.append(" CHPP_ASSERT((size_t)(*vlaOffset + out->{}.length) <= payloadSize);\n".format(
+ out.append(' CHPP_ASSERT((size_t)(*vlaOffset + out->{}.length) <= payloadSize);\n'.format(
member_info['name']))
- out.append(" if (out->{}.length > 0 &&\n"
- " *vlaOffset + out->{}.length <= payloadSize) {{\n".format(
- member_info['name'], member_info['name']))
+ out.append(' if (out->{}.length > 0 &&\n'
+ ' *vlaOffset + out->{}.length <= payloadSize) {{\n'.format(
+ member_info['name'], member_info['name']))
if member_info['is_nested_type']:
- out.append(" for (size_t i = 0; i < in->{}; i++) {{\n".format(
+ out.append(' for (size_t i = 0; i < in->{}; i++) {{\n'.format(
annotation['length_field']))
- out.append(" {}".format(
+ out.append(' {}'.format(
self._get_assignment_statement_for_field(member_info, in_vla_loop=True)))
- out.append(" }\n")
+ out.append(' }\n')
else:
- out.append("memcpy(&payload[*vlaOffset], in->{}, in->{} * sizeof({}));\n".format(
+ out.append('memcpy(&payload[*vlaOffset], in->{}, in->{} * sizeof({}));\n'.format(
member_info['name'], annotation['length_field'], chpp_type))
- out.append(" out->{}.offset = *vlaOffset;\n".format(member_info['name']))
- out.append(" *vlaOffset += out->{}.length;\n".format(member_info['name']))
+ out.append(
+ ' out->{}.offset = *vlaOffset;\n'.format(member_info['name']))
+ out.append(
+ ' *vlaOffset += out->{}.length;\n'.format(member_info['name']))
- out.append(" } else {\n")
- out.append(" out->{}.offset = 0;\n".format(member_info['name']))
- out.append(" }\n");
+ out.append(' } else {\n')
+ out.append(' out->{}.offset = 0;\n'.format(member_info['name']))
+ out.append(' }\n')
return out
@@ -451,45 +458,52 @@ class CodeGenerator:
:param decode_mode: True converts from CHPP to CHRE. False from CHRE to CHPP
:return: assignment statement as a string
"""
- array_index = "[i]" if in_vla_loop else ""
- output_accessor = "" if in_vla_loop else "out->"
- containing_field = containing_field_name + "." if containing_field_name is not None else ""
- output_variable = "{}{}{}{}".format(output_accessor, containing_field, member_info['name'],
+ array_index = '[i]' if in_vla_loop else ''
+ output_accessor = '' if in_vla_loop else 'out->'
+ containing_field = containing_field_name + \
+ '.' if containing_field_name is not None else ''
+
+ output_variable = '{}{}{}{}'.format(output_accessor, containing_field, member_info['name'],
array_index)
- input_variable = "in->{}{}{}".format(containing_field, member_info['name'], array_index)
+ input_variable = 'in->{}{}{}'.format(containing_field,
+ member_info['name'], array_index)
if decode_mode and in_vla_loop:
- output_variable = "{}Out{}".format(member_info['name'], array_index)
- input_variable = "{}In{}".format(member_info['name'], array_index)
+ output_variable = '{}Out{}'.format(
+ member_info['name'], array_index)
+ input_variable = '{}In{}'.format(member_info['name'], array_index)
if member_info['is_nested_type']:
chre_type = member_info['nested_type_name']
has_vla_member = self.api.structs_and_unions[chre_type]['has_vla_member']
if decode_mode:
# Use decoding function
- vla_params = ", inSize" if has_vla_member else ""
- out = "if (!{}(&{}, &{}{})) {{\n".format(
- self._get_decoding_function_name(chre_type), input_variable,
+ vla_params = ', inSize' if has_vla_member else ''
+ out = 'if (!{}(&{}, &{}{})) {{\n'.format(
+ self._get_decoding_function_name(
+ chre_type), input_variable,
output_variable, vla_params)
if has_vla_member:
- out += " CHPP_FREE_AND_NULLIFY({}Out);\n".format(member_info['name'])
- out += " return false;\n"
- out += "}\n"
+ out += ' CHPP_FREE_AND_NULLIFY({}Out);\n'.format(
+ member_info['name'])
+ out += ' return false;\n'
+ out += '}\n'
return out
else:
# Use encoding function
- vla_params = ", payload, payloadSize, vlaOffset" if has_vla_member else ""
- return "{}(&{}, &{}{});\n".format(
- self._get_encoding_function_name(chre_type), input_variable, output_variable,
+ vla_params = ', payload, payloadSize, vlaOffset' if has_vla_member else ''
+ return '{}(&{}, &{}{});\n'.format(
+ self._get_encoding_function_name(
+ chre_type), input_variable, output_variable,
vla_params)
elif self._is_array_type(member_info['type']):
# Array of primitive type (e.g. uint32_t[8]) - use memcpy
- return "memcpy({}, {}, sizeof({}));\n".format(output_variable, input_variable,
+ return 'memcpy({}, {}, sizeof({}));\n'.format(output_variable, input_variable,
output_variable)
else:
# Regular assignment
- return "{} = {};\n".format(output_variable, input_variable)
+ return '{} = {};\n'.format(output_variable, input_variable)
def _gen_union_variant_conversion_code(self, member_info, annotation, decode_mode):
"""Generates a switch statement to encode the "active"/"used" field within a union.
@@ -505,23 +519,25 @@ class CodeGenerator:
:param decode_mode: False encodes from CHRE to CHPP. True decodes from CHPP to CHRE
:return: list of strings
"""
+
out = []
chre_type = member_info['nested_type_name']
struct_info = self.api.structs_and_unions[chre_type]
# Start off by zeroing out the union field so any padding is set to a consistent value
- out.append(" memset(&out->{}, 0, sizeof(out->{}));\n".format(member_info['name'],
+ out.append(' memset(&out->{}, 0, sizeof(out->{}));\n'.format(member_info['name'],
member_info['name']))
# Next, generate the switch statement that will copy over the proper values
- out.append(" switch (in->{}) {{\n".format(annotation['discriminator']))
+ out.append(
+ ' switch (in->{}) {{\n'.format(annotation['discriminator']))
for value, field_name in annotation['mapping']:
- out.append(" case {}:\n".format(value))
+ out.append(' case {}:\n'.format(value))
found = False
for nested_member_info in struct_info['members']:
if nested_member_info['name'] == field_name:
- out.append(" {}".format(
+ out.append(' {}'.format(
self._get_assignment_statement_for_field(
nested_member_info,
containing_field_name=member_info['name'],
@@ -533,11 +549,11 @@ class CodeGenerator:
raise RuntimeError("Invalid mapping - couldn't find target field {} in struct {}"
.format(field_name, chre_type))
- out.append(" break;\n")
+ out.append(' break;\n')
- out.append(" default:\n"
- " CHPP_ASSERT(false);\n"
- " }\n")
+ out.append(' default:\n'
+ ' CHPP_ASSERT(false);\n'
+ ' }\n')
return out
@@ -557,73 +573,81 @@ class CodeGenerator:
return out
already_generated.add(chre_type)
- out.append("static ")
+ out.append('static ')
if decode_mode:
out.extend(self._gen_decoding_function_signature(chre_type))
else:
out.extend(self._gen_encoding_function_signature(chre_type))
- out.append(" {\n")
+ out.append(' {\n')
for member_info in self.api.structs_and_unions[chre_type]['members']:
generated_by_annotation = False
for annotation in member_info['annotations']:
- if annotation['annotation'] == "fixed_value":
+ if annotation['annotation'] == 'fixed_value':
if self._is_array_type(member_info['type']):
- out.append(" memset(&out->{}, {}, sizeof(out->{}));\n".format(
+ out.append(' memset(&out->{}, {}, sizeof(out->{}));\n'.format(
member_info['name'], annotation['value'], member_info['name']))
else:
- out.append(" out->{} = {};\n".format(member_info['name'],
+ out.append(' out->{} = {};\n'.format(member_info['name'],
annotation['value']))
generated_by_annotation = True
break
- elif annotation['annotation'] == "enum":
- # TODO: generate range verification code?
+ elif annotation['annotation'] == 'enum':
+ # Note: We could generate range verification code here, but it has not
+ # been considered necessary thus far.
pass
- elif annotation['annotation'] == "var_len_array":
+ elif annotation['annotation'] == 'var_len_array':
if decode_mode:
- out.extend(self._gen_vla_decoding(member_info, annotation))
+ out.extend(self._gen_vla_decoding(
+ member_info, annotation))
else:
- out.extend(self._gen_vla_encoding(member_info, annotation))
+ out.extend(self._gen_vla_encoding(
+ member_info, annotation))
generated_by_annotation = True
break
- elif annotation['annotation'] == "string":
+ elif annotation['annotation'] == 'string':
if decode_mode:
- out.extend(self._gen_string_decoding(member_info, annotation))
+ out.extend(self._gen_string_decoding(
+ member_info, annotation))
else:
- out.extend(self._gen_string_encoding(member_info, annotation))
+ out.extend(self._gen_string_encoding(
+ member_info, annotation))
generated_by_annotation = True
break
- elif annotation['annotation'] == "union_variant":
+ elif annotation['annotation'] == 'union_variant':
out.extend(self._gen_union_variant_conversion_code(
member_info, annotation, decode_mode))
generated_by_annotation = True
break
if not generated_by_annotation:
- out.append(" {}".format(
+ out.append(' {}'.format(
self._get_assignment_statement_for_field(member_info, decode_mode=decode_mode)))
if decode_mode:
- out.append("\n return true;\n")
+ out.append('\n return true;\n')
- out.append("}\n\n")
+ out.append('}\n\n')
return out
def _gen_conversion_functions(self, decode_mode):
out = []
already_generated = set()
for struct in self.json['root_structs']:
- out.extend(self._gen_conversion_function(struct, already_generated, decode_mode))
+ out.extend(self._gen_conversion_function(
+ struct, already_generated, decode_mode))
return out
def _strip_prefix_and_service_from_chre_struct_name(self, struct):
- """Strip 'chre' and service prefix, e.g. 'chreWwanCellResultInfo' -> 'CellResultInfo'"""
+ """Strips 'chre' and service prefix, e.g. 'chreWwanCellResultInfo' -> 'CellResultInfo'."""
+
chre_stripped = struct[4:]
- upcased_service_name = self.service_name[0].upper() + self.service_name[1:]
+ upcased_service_name = self.service_name[0].upper(
+ ) + self.service_name[1:]
if not struct.startswith('chre') or not chre_stripped.startswith(upcased_service_name):
# If this happens, we need to update the script to handle it. Right we assume struct
# naming follows the pattern "chre<Service_name><Thing_name>"
- raise RuntimeError("Unexpected structure name {}".format(struct))
+ raise RuntimeError('Unexpected structure name {}'.format(struct))
return chre_stripped[len(self.service_name):]
@@ -640,67 +664,71 @@ class CodeGenerator:
:param chre_type: CHRE type name
:return: string
"""
+
if self.api.structs_and_unions[chre_type]['has_vla_member']:
- return "{}(in)".format(self._get_chpp_sizeof_function_name(chre_type))
+ return '{}(in)'.format(self._get_chpp_sizeof_function_name(chre_type))
else:
- return "sizeof({})".format(self._get_chpp_header_type_from_chre(chre_type))
+ return 'sizeof({})'.format(self._get_chpp_header_type_from_chre(chre_type))
def _get_encode_allocation_function_name(self, chre_type):
- core_type_name = self._strip_prefix_and_service_from_chre_struct_name(chre_type)
- return "chpp{}{}FromChre".format(self.capitalized_service_name, core_type_name)
+ core_type_name = self._strip_prefix_and_service_from_chre_struct_name(
+ chre_type)
+ return 'chpp{}{}FromChre'.format(self.capitalized_service_name, core_type_name)
def _gen_encode_allocation_function_signature(self, chre_type, gen_docs=False):
out = []
if gen_docs:
- out.append("/**\n"
- " * Converts from given CHRE structure to serialized CHPP type.\n"
- " *\n"
- " * @param in Fully-formed CHRE structure.\n"
- " * @param out Upon success, will point to a buffer allocated with "
- "chppMalloc().\n"
- " * It is the responsibility of the caller to set the values of the CHPP "
- "app layer header, and to free the buffer when it is no longer needed via "
- "chppFree() or CHPP_FREE_AND_NULLIFY().\n"
- " * @param outSize Upon success, will be set to the size of the output "
- "buffer, in bytes.\n"
- " *\n"
- " * @return true on success, false if memory allocation failed.\n"
- " */\n")
- out.append("bool {}(\n".format(self._get_encode_allocation_function_name(chre_type)))
- out.append(" const {}{} *in,\n".format(
+ out.append('/**\n'
+ ' * Converts from given CHRE structure to serialized CHPP type.\n'
+ ' *\n'
+ ' * @param in Fully-formed CHRE structure.\n'
+ ' * @param out Upon success, will point to a buffer allocated with '
+ 'chppMalloc().\n'
+ ' * It is the responsibility of the caller to set the values of the CHPP '
+ 'app layer header, and to free the buffer when it is no longer needed via '
+ 'chppFree() or CHPP_FREE_AND_NULLIFY().\n'
+ ' * @param outSize Upon success, will be set to the size of the output '
+ 'buffer, in bytes.\n'
+ ' *\n'
+ ' * @return true on success, false if memory allocation failed.\n'
+ ' */\n')
+ out.append(
+ 'bool {}(\n'.format(self._get_encode_allocation_function_name(chre_type)))
+ out.append(' const {}{} *in,\n'.format(
self._get_struct_or_union_prefix(chre_type), chre_type))
- out.append(" {} **out,\n".format(self._get_chpp_header_type_from_chre(chre_type)))
- out.append(" size_t *outSize)")
+ out.append(
+ ' {} **out,\n'.format(self._get_chpp_header_type_from_chre(chre_type)))
+ out.append(' size_t *outSize)')
return out
def _gen_encode_allocation_function(self, chre_type):
out = []
out.extend(self._gen_encode_allocation_function_signature(chre_type))
- out.append(" {\n")
- out.append(" CHPP_NOT_NULL(out);\n")
- out.append(" CHPP_NOT_NULL(outSize);\n\n")
- out.append(" size_t payloadSize = {};\n".format(
+ out.append(' {\n')
+ out.append(' CHPP_NOT_NULL(out);\n')
+ out.append(' CHPP_NOT_NULL(outSize);\n\n')
+ out.append(' size_t payloadSize = {};\n'.format(
self._get_chpp_sizeof_call(chre_type)))
- out.append(" *out = chppMalloc(payloadSize);\n")
+ out.append(' *out = chppMalloc(payloadSize);\n')
- out.append(" if (*out != NULL) {\n")
+ out.append(' if (*out != NULL) {\n')
struct_info = self.api.structs_and_unions[chre_type]
if struct_info['has_vla_member']:
- out.append(" uint8_t *payload = (uint8_t *) &(*out)->payload;\n")
- out.append(" uint16_t vlaOffset = sizeof({});\n".format(
+ out.append(' uint8_t *payload = (uint8_t *) &(*out)->payload;\n')
+ out.append(' uint16_t vlaOffset = sizeof({});\n'.format(
self._get_chpp_type_from_chre(chre_type)))
- out.append(" {}(in, &(*out)->payload".format(
+ out.append(' {}(in, &(*out)->payload'.format(
self._get_encoding_function_name(chre_type)))
if struct_info['has_vla_member']:
- out.append(", payload, payloadSize, &vlaOffset")
- out.append(");\n")
- out.append(" *outSize = payloadSize;\n")
- out.append(" return true;\n")
- out.append(" }\n")
+ out.append(', payload, payloadSize, &vlaOffset')
+ out.append(');\n')
+ out.append(' *outSize = payloadSize;\n')
+ out.append(' return true;\n')
+ out.append(' }\n')
- out.append(" return false;\n}\n\n")
+ out.append(' return false;\n}\n\n')
return out
def _gen_encode_allocation_functions(self):
@@ -712,8 +740,9 @@ class CodeGenerator:
def _gen_encode_allocation_function_signatures(self):
out = []
for chre_type in self.json['root_structs']:
- out.extend(self._gen_encode_allocation_function_signature(chre_type, True))
- out.append(";\n\n")
+ out.extend(
+ self._gen_encode_allocation_function_signature(chre_type, True))
+ out.append(';\n\n')
return out
# ----------------------------------------------------------------------------------------------
@@ -721,147 +750,155 @@ class CodeGenerator:
# ----------------------------------------------------------------------------------------------
def _get_decoding_function_name(self, chre_type):
- core_type_name = self._strip_prefix_and_service_from_chre_struct_name(chre_type)
- return "chpp{}Convert{}ToChre".format(self.capitalized_service_name, core_type_name)
+ core_type_name = self._strip_prefix_and_service_from_chre_struct_name(
+ chre_type)
+ return 'chpp{}Convert{}ToChre'.format(self.capitalized_service_name, core_type_name)
def _gen_decoding_function_signature(self, chre_type):
out = []
- out.append("bool {}(\n".format(self._get_decoding_function_name(chre_type)))
- out.append(" const {} *in,\n".format(self._get_chpp_type_from_chre(chre_type)))
- out.append(" {} *out".format(self._get_chre_type_with_prefix(chre_type)))
+ out.append(
+ 'bool {}(\n'.format(self._get_decoding_function_name(chre_type)))
+ out.append(
+ ' const {} *in,\n'.format(self._get_chpp_type_from_chre(chre_type)))
+ out.append(
+ ' {} *out'.format(self._get_chre_type_with_prefix(chre_type)))
if self.api.structs_and_unions[chre_type]['has_vla_member']:
- out.append(",\n")
- out.append(" size_t inSize")
- out.append(")")
+ out.append(',\n')
+ out.append(' size_t inSize')
+ out.append(')')
return out
def _gen_string_decoding(self, member_info, annotation):
out = []
variable_name = member_info['name']
- out.append("\n")
- out.append(" if (in->{}.length == 0) {{\n".format(variable_name))
- out.append(" out->{} = NULL;\n".format(variable_name))
- out.append(" } else {\n")
- out.append(" char *{}Out = chppMalloc(in->{}.length);\n".format(
+ out.append('\n')
+ out.append(' if (in->{}.length == 0) {{\n'.format(variable_name))
+ out.append(' out->{} = NULL;\n'.format(variable_name))
+ out.append(' } else {\n')
+ out.append(' char *{}Out = chppMalloc(in->{}.length);\n'.format(
variable_name, variable_name))
- out.append(" if ({}Out == NULL) {{\n".format(variable_name))
- out.append(" return false;\n")
- out.append(" }\n\n")
- out.append(" memcpy({}Out, &((const uint8_t *)in)[in->{}.offset],\n".format(
+ out.append(' if ({}Out == NULL) {{\n'.format(variable_name))
+ out.append(' return false;\n')
+ out.append(' }\n\n')
+ out.append(' memcpy({}Out, &((const uint8_t *)in)[in->{}.offset],\n'.format(
variable_name, variable_name))
- out.append(" in->{}.length);\n".format(variable_name))
- out.append(" out->{} = {}Out;\n".format(variable_name, variable_name))
- out.append(" }\n")
+ out.append(' in->{}.length);\n'.format(variable_name))
+ out.append(' out->{} = {}Out;\n'.format(variable_name, variable_name))
+ out.append(' }\n')
return out
-
def _gen_vla_decoding(self, member_info, annotation):
out = []
variable_name = member_info['name']
chpp_type = self._get_member_type(member_info, True)
if member_info['is_nested_type']:
- chre_type = self._get_chre_type_with_prefix(member_info['nested_type_name'])
+ chre_type = self._get_chre_type_with_prefix(
+ member_info['nested_type_name'])
else:
chre_type = chpp_type
- out.append("\n")
- out.append(" if (in->{}.length == 0) {{\n".format(variable_name))
- out.append(" out->{} = NULL;\n".format(variable_name))
- out.append(" }\n")
- out.append(" else {\n")
- out.append(" if (in->{}.offset + in->{}.length > inSize ||\n".format(
+ out.append('\n')
+ out.append(' if (in->{}.length == 0) {{\n'.format(variable_name))
+ out.append(' out->{} = NULL;\n'.format(variable_name))
+ out.append(' }\n')
+ out.append(' else {\n')
+ out.append(' if (in->{}.offset + in->{}.length > inSize ||\n'.format(
variable_name, variable_name))
- out.append(" in->{}.length != in->{} * sizeof({})) {{\n".format(
+ out.append(' in->{}.length != in->{} * sizeof({})) {{\n'.format(
variable_name, annotation['length_field'], chpp_type))
- out.append(" return false;\n")
- out.append(" }\n\n")
+ out.append(' return false;\n')
+ out.append(' }\n\n')
if member_info['is_nested_type']:
- out.append(" const {} *{}In =\n".format(chpp_type, variable_name))
- out.append(" (const {} *) &((const uint8_t *)in)[in->{}.offset];\n\n".format(
+ out.append(
+ ' const {} *{}In =\n'.format(chpp_type, variable_name))
+ out.append(' (const {} *) &((const uint8_t *)in)[in->{}.offset];\n\n'.format(
chpp_type, variable_name))
- out.append(" {} *{}Out = chppMalloc(in->{} * sizeof({}));\n".format(
+ out.append(' {} *{}Out = chppMalloc(in->{} * sizeof({}));\n'.format(
chre_type, variable_name, annotation['length_field'], chre_type))
- out.append(" if ({}Out == NULL) {{\n".format(variable_name))
- out.append(" return false;\n")
- out.append(" }\n\n")
+ out.append(' if ({}Out == NULL) {{\n'.format(variable_name))
+ out.append(' return false;\n')
+ out.append(' }\n\n')
if member_info['is_nested_type']:
- out.append(" for (size_t i = 0; i < in->{}; i++) {{\n".format(
+ out.append(' for (size_t i = 0; i < in->{}; i++) {{\n'.format(
annotation['length_field'], variable_name))
- out.append(" {}".format(self._get_assignment_statement_for_field(
+ out.append(' {}'.format(self._get_assignment_statement_for_field(
member_info, in_vla_loop=True, decode_mode=True)))
- out.append(" }\n")
+ out.append(' }\n')
else:
- out.append(" memcpy({}Out, &((const uint8_t *)in)[in->{}.offset],\n".format(
+ out.append(' memcpy({}Out, &((const uint8_t *)in)[in->{}.offset],\n'.format(
variable_name, variable_name))
- out.append(" in->{} * sizeof({}));\n".format(
+ out.append(' in->{} * sizeof({}));\n'.format(
annotation['length_field'], chre_type))
- out.append(" out->{} = {}Out;\n".format(variable_name, variable_name))
- out.append(" }\n\n")
+ out.append(' out->{} = {}Out;\n'.format(variable_name, variable_name))
+ out.append(' }\n\n')
return out
def _get_decode_allocation_function_name(self, chre_type):
- core_type_name = self._strip_prefix_and_service_from_chre_struct_name(chre_type)
- return "chpp{}{}ToChre".format(self.capitalized_service_name, core_type_name)
+ core_type_name = self._strip_prefix_and_service_from_chre_struct_name(
+ chre_type)
+ return 'chpp{}{}ToChre'.format(self.capitalized_service_name, core_type_name)
def _gen_decode_allocation_function_signature(self, chre_type, gen_docs=False):
out = []
if gen_docs:
- out.append("/**\n"
- " * Converts from serialized CHPP structure to a CHRE type.\n"
- " *\n"
- " * @param in Fully-formed CHPP structure.\n"
- " * @param in Size of the CHPP structure in bytes.\n"
- " *\n"
- " * @return If successful, a pointer to a CHRE structure allocated with "
- "chppMalloc(). If unsuccessful, null.\n"
- " * It is the responsibility of the caller to free the buffer when it is no "
- "longer needed via chppFree() or CHPP_FREE_AND_NULLIFY().\n"
- " */\n")
-
- out.append("{} *{}(\n".format(
+ out.append('/**\n'
+ ' * Converts from serialized CHPP structure to a CHRE type.\n'
+ ' *\n'
+ ' * @param in Fully-formed CHPP structure.\n'
+ ' * @param in Size of the CHPP structure in bytes.\n'
+ ' *\n'
+ ' * @return If successful, a pointer to a CHRE structure allocated with '
+ 'chppMalloc(). If unsuccessful, null.\n'
+ ' * It is the responsibility of the caller to free the buffer when it is no '
+ 'longer needed via chppFree() or CHPP_FREE_AND_NULLIFY().\n'
+ ' */\n')
+
+ out.append('{} *{}(\n'.format(
self._get_chre_type_with_prefix(chre_type),
self._get_decode_allocation_function_name(chre_type)))
- out.append(" const {} *in,\n".format(self._get_chpp_type_from_chre(chre_type)))
- out.append(" size_t inSize)")
+ out.append(
+ ' const {} *in,\n'.format(self._get_chpp_type_from_chre(chre_type)))
+ out.append(' size_t inSize)')
return out
def _gen_decode_allocation_function(self, chre_type):
out = []
out.extend(self._gen_decode_allocation_function_signature(chre_type))
- out.append(" {\n")
+ out.append(' {\n')
- out.append(" {} *out = NULL;\n\n".format(
+ out.append(' {} *out = NULL;\n\n'.format(
self._get_chre_type_with_prefix(chre_type)))
- out.append(" if (inSize >= sizeof({})) {{\n".format(
+ out.append(' if (inSize >= sizeof({})) {{\n'.format(
self._get_chpp_type_from_chre(chre_type)))
- out.append(" out = chppMalloc(sizeof({}));\n".format(
+ out.append(' out = chppMalloc(sizeof({}));\n'.format(
self._get_chre_type_with_prefix(chre_type)))
- out.append(" if (out != NULL) {\n")
+ out.append(' if (out != NULL) {\n')
struct_info = self.api.structs_and_unions[chre_type]
- out.append(" if (!{}(in, out".format(self._get_decoding_function_name(chre_type)))
+ out.append(' if (!{}(in, out'.format(
+ self._get_decoding_function_name(chre_type)))
if struct_info['has_vla_member']:
- out.append(", inSize")
- out.append(")) {")
- out.append(" CHPP_FREE_AND_NULLIFY(out);\n")
- out.append(" }\n")
-
- out.append(" }\n")
- out.append(" }\n\n")
- out.append(" return out;\n")
- out.append("}\n")
+ out.append(', inSize')
+ out.append(')) {')
+ out.append(' CHPP_FREE_AND_NULLIFY(out);\n')
+ out.append(' }\n')
+
+ out.append(' }\n')
+ out.append(' }\n\n')
+ out.append(' return out;\n')
+ out.append('}\n')
return out
def _gen_decode_allocation_functions(self):
@@ -873,8 +910,9 @@ class CodeGenerator:
def _gen_decode_allocation_function_signatures(self):
out = []
for chre_type in self.json['root_structs']:
- out.extend(self._gen_decode_allocation_function_signature(chre_type, True))
- out.append(";\n\n")
+ out.extend(
+ self._gen_decode_allocation_function_signature(chre_type, True))
+ out.append(';\n\n')
return out
# ----------------------------------------------------------------------------------------------
@@ -883,219 +921,74 @@ class CodeGenerator:
def generate_header_file(self, dry_run=False, skip_clang_format=False):
"""Creates a C header file for this API and writes it to the file indicated in the JSON."""
- filename = self.service_name + "_types.h"
+
+ filename = self.service_name + '_types.h'
if not dry_run:
- print("Generating {} ... ".format(filename), end='', flush=True)
- output_file = os.path.join(system_chre_abs_path(), CHPP_PARSER_INCLUDE_PATH, filename)
+ print('Generating {} ... '.format(filename), end='', flush=True)
+ output_file = os.path.join(
+ system_chre_abs_path(), CHPP_PARSER_INCLUDE_PATH, filename)
header = self.generate_header_string()
self._dump_to_file(output_file, header, dry_run, skip_clang_format)
if not dry_run:
- print("done")
+ print('done')
def generate_header_string(self):
"""Returns a C header with structure definitions for this API."""
+
# To defer concatenation (speed things up), build the file as a list of strings then only
# concatenate once at the end
out = [LICENSE_HEADER]
- header_guard = "CHPP_{}_TYPES_H_".format(self.service_name.upper())
+ header_guard = 'CHPP_{}_TYPES_H_'.format(self.service_name.upper())
- out.append("#ifndef {}\n#define {}\n\n".format(header_guard, header_guard))
+ out.append('#ifndef {}\n#define {}\n\n'.format(
+ header_guard, header_guard))
out.extend(self._autogen_notice())
out.extend(self._gen_header_includes())
- out.append("#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n")
+ out.append('#ifdef __cplusplus\nextern "C" {\n#endif\n\n')
out.extend(self._gen_structs_and_unions())
- out.append("\n// Encoding functions (CHRE --> CHPP)\n\n")
+ out.append('\n// Encoding functions (CHRE --> CHPP)\n\n')
out.extend(self._gen_encode_allocation_function_signatures())
- out.append("\n// Decoding functions (CHPP --> CHRE)\n\n")
+ out.append('\n// Decoding functions (CHPP --> CHRE)\n\n')
out.extend(self._gen_decode_allocation_function_signatures())
- out.append("#ifdef __cplusplus\n}\n#endif\n\n")
- out.append("#endif // {}\n".format(header_guard))
+ out.append('#ifdef __cplusplus\n}\n#endif\n\n')
+ out.append('#endif // {}\n'.format(header_guard))
return ''.join(out)
def generate_conversion_file(self, dry_run=False, skip_clang_format=False):
"""Generates a .c file with functions for encoding CHRE structs into CHPP and vice versa."""
- filename = self.service_name + "_convert.c"
+
+ filename = self.service_name + '_convert.c'
if not dry_run:
- print("Generating {} ... ".format(filename), end='', flush=True)
+ print('Generating {} ... '.format(filename), end='', flush=True)
contents = self.generate_conversion_string()
- output_file = os.path.join(system_chre_abs_path(), CHPP_PARSER_SOURCE_PATH, filename)
+ output_file = os.path.join(
+ system_chre_abs_path(), CHPP_PARSER_SOURCE_PATH, filename)
self._dump_to_file(output_file, contents, dry_run, skip_clang_format)
if not dry_run:
- print("done")
+ print('done')
def generate_conversion_string(self):
"""Returns C code for encoding CHRE structs into CHPP and vice versa."""
- out = [LICENSE_HEADER, "\n"]
+
+ out = [LICENSE_HEADER, '\n']
out.extend(self._autogen_notice())
out.extend(self._gen_conversion_includes())
- out.append("\n// Encoding (CHRE --> CHPP) size functions\n\n")
+ out.append('\n// Encoding (CHRE --> CHPP) size functions\n\n')
out.extend(self._gen_chpp_sizeof_functions())
- out.append("\n// Encoding (CHRE --> CHPP) conversion functions\n\n")
+ out.append('\n// Encoding (CHRE --> CHPP) conversion functions\n\n')
out.extend(self._gen_conversion_functions(False))
- out.append("\n// Encoding (CHRE --> CHPP) top-level functions\n\n")
+ out.append('\n// Encoding (CHRE --> CHPP) top-level functions\n\n')
out.extend(self._gen_encode_allocation_functions())
- out.append("\n// Decoding (CHPP --> CHRE) conversion functions\n\n")
+ out.append('\n// Decoding (CHPP --> CHRE) conversion functions\n\n')
out.extend(self._gen_conversion_functions(True))
- out.append("\n// Decoding (CHPP --> CHRE) top-level functions\n\n")
+ out.append('\n// Decoding (CHPP --> CHRE) top-level functions\n\n')
out.extend(self._gen_decode_allocation_functions())
return ''.join(out)
-
-
-class ApiParser:
- """Given a file-specific set of annotations (extracted from JSON annotations file), parses a
- single API header file into data structures suitable for use with code generation.
- """
-
- def __init__(self, json_obj):
- """Initialize and parse the API file described in the provided JSON-derived object.
-
- :param json_obj: Extracted file-specific annotations from JSON
- """
- self.json = json_obj
- self.structs_and_unions = {}
- self._parse_annotations()
- self._parse_api()
-
- def _parse_annotations(self):
- # Convert annotations list to a more usable data structure: dict keyed by structure name,
- # containing a dict keyed by field name, containing a list of annotations (as they
- # appear in the JSON). In other words, we can easily get all of the annotations for the
- # "version" field in "chreWwanCellInfoResult" via
- # annotations['chreWwanCellInfoResult']['version']. This is also a defaultdict, so it's safe
- # to access if there are no annotations for this structure + field; it'll just give you
- # an empty list in that case.
- self.annotations = defaultdict(lambda: defaultdict(list))
- for struct_info in self.json['struct_info']:
- for annotation in struct_info['annotations']:
- self.annotations[struct_info['name']][annotation['field']].append(annotation)
-
- def _files_to_parse(self):
- """Returns a list of files to supply as input to CParser"""
- # Input paths for CParser are stored in JSON relative to <android_root>/system/chre
- # Reformulate these to absolute paths, and add in some default includes that we always
- # supply
- chre_project_base_dir = system_chre_abs_path()
- default_includes = ["chpp/api_parser/parser_defines.h",
- "chre_api/include/chre_api/chre/version.h"]
- files = default_includes + self.json['includes'] + [self.json['filename']]
- return [os.path.join(chre_project_base_dir, file) for file in files]
-
- def _parse_structs_and_unions(self):
- # Starting with the root structures (i.e. those that will appear at the top-level in one
- # or more CHPP messages), build a data structure containing all of the information we'll
- # need to emit the CHPP structure definition and conversion code.
- structs_and_unions_to_parse = self.json['root_structs'].copy()
- while len(structs_and_unions_to_parse) > 0:
- type_name = structs_and_unions_to_parse.pop()
- if type_name in self.structs_and_unions:
- continue
-
- entry = {
- 'appears_in': set(), # Other types this type is nested within
- 'dependencies': set(), # Types that are nested in this type
- 'has_vla_member': False, # True if this type or any dependency has a VLA member
- 'members': [], # Info about each member of this type
- }
- if type_name in self.parser.defs['structs']:
- defs = self.parser.defs['structs'][type_name]
- entry['is_union'] = False
- elif type_name in self.parser.defs['unions']:
- defs = self.parser.defs['unions'][type_name]
- entry['is_union'] = True
- else:
- raise RuntimeError("Couldn't find {} in parsed structs/unions".format(type_name))
-
- for member_name, member_type, _ in defs['members']:
- member_info = {
- 'name': member_name,
- 'type': member_type,
- 'annotations': self.annotations[type_name][member_name],
- 'is_nested_type': False,
- }
-
- if member_type.type_spec.startswith('struct ') or \
- member_type.type_spec.startswith('union '):
- member_info['is_nested_type'] = True
- member_type_name = member_type.type_spec.split(' ')[1]
- member_info['nested_type_name'] = member_type_name
- entry['dependencies'].add(member_type_name)
- structs_and_unions_to_parse.append(member_type_name)
-
- entry['members'].append(member_info)
-
- # Flip a flag if this structure has at least one variable-length array member, which
- # means that the encoded size can only be computed at runtime
- if not entry['has_vla_member']:
- for annotation in self.annotations[type_name][member_name]:
- if annotation['annotation'] == "var_len_array":
- entry['has_vla_member'] = True
-
- self.structs_and_unions[type_name] = entry
-
- # Build reverse linkage of dependency chain (i.e. lookup between a type and the other types
- # it appears in)
- for type_name, type_info in self.structs_and_unions.items():
- for dependency in type_info['dependencies']:
- self.structs_and_unions[dependency]['appears_in'].add(type_name)
-
- # Bubble up "has_vla_member" to types each type it appears in, i.e. if this flag is set to
- # True on a leaf node, then all its ancestors should also have the flag set to True
- for type_name, type_info in self.structs_and_unions.items():
- if type_info['has_vla_member']:
- types_to_mark = list(type_info['appears_in'])
- while len(types_to_mark) > 0:
- type_to_mark = types_to_mark.pop()
- self.structs_and_unions[type_to_mark]['has_vla_member'] = True
- types_to_mark.extend(list(self.structs_and_unions[type_to_mark]['appears_in']))
-
- def _parse_api(self):
- file_to_parse = self._files_to_parse()
- self.parser = CParser(file_to_parse, cache='parser_cache')
- self._parse_structs_and_unions()
-
-
-def run(args):
- with open('chre_api_annotations.json') as f:
- js = json.load(f)
-
- commit_hash = subprocess.getoutput("git describe --always --long --dirty --exclude '*'")
- for file in js:
- if args.file_filter:
- matched = False
- for matcher in args.file_filter:
- if matcher in file['filename']:
- matched = True
- break
- if not matched:
- print("Skipping {} - doesn't match filter(s) {}".format(file['filename'],
- args.file_filter))
- continue
- print("Parsing {} ... ".format(file['filename']), end='', flush=True)
- api_parser = ApiParser(file)
- code_gen = CodeGenerator(api_parser, commit_hash)
- print("done")
- code_gen.generate_header_file(args.dry_run, args.skip_clang_format)
- code_gen.generate_conversion_file(args.dry_run, args.skip_clang_format)
-
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser(description='Generate CHPP serialization code from CHRE APIs.')
- parser.add_argument('-n', dest='dry_run', action='store_true',
- help='Print the output instead of writing to a file')
- parser.add_argument('--skip-clang-format', dest='skip_clang_format', action='store_true',
- help='Skip running clang-format on the output files (doesn\'t apply to dry '
- 'runs)')
- parser.add_argument('file_filter', nargs='*',
- help='Filters the input files (filename field in the JSON) to generate a '
- 'subset of the typical output, e.g. "wifi" to just generate conversion'
- ' routines for wifi.h')
- args = parser.parse_args()
- run(args)
diff --git a/api_parser/chre_api_annotations.json b/api_parser/chre_api_annotations.json
new file mode 100644
index 00000000..f54ff5c1
--- /dev/null
+++ b/api_parser/chre_api_annotations.json
@@ -0,0 +1,316 @@
+[
+ {
+ "filename": "chre_api/include/chre_api/chre/wwan.h",
+ "includes": [
+ "chre_api/include/chre_api/chre/common.h"
+ ],
+ "output_includes": [
+ "chpp/common/common_types.h",
+ "chre_api/chre/wwan.h"
+ ],
+ "struct_info": [
+ {
+ "name": "chreWwanCellInfoResult",
+ "annotations": [
+ {
+ "field": "version",
+ "annotation": "fixed_value",
+ "value": "CHRE_WWAN_CELL_INFO_RESULT_VERSION"
+ },
+ {
+ "field": "errorCode",
+ "annotation": "enum",
+ "enum_type": "chreError"
+ },
+ {
+ "field": "cookie",
+ "annotation": "fixed_value",
+ "value": "0"
+ },
+ {
+ "field": "cookie",
+ "annotation": "rewrite_type",
+ "type_override": "uint32_t"
+ },
+ {
+ "field": "reserved",
+ "annotation": "fixed_value",
+ "value": "0"
+ },
+ {
+ "field": "cells",
+ "annotation": "var_len_array",
+ "length_field": "cellInfoCount"
+ }
+ ]
+ },
+ {
+ "name": "chreWwanCellInfo",
+ "annotations": [
+ {
+ "field": "cellInfoType",
+ "annotation": "enum",
+ "enum_type": "chreWwanCellInfoType"
+ },
+ {
+ "field": "CellInfo",
+ "annotation": "union_variant",
+ "discriminator": "cellInfoType",
+ "mapping": [
+ [
+ "CHRE_WWAN_CELL_INFO_TYPE_GSM",
+ "gsm"
+ ],
+ [
+ "CHRE_WWAN_CELL_INFO_TYPE_CDMA",
+ "cdma"
+ ],
+ [
+ "CHRE_WWAN_CELL_INFO_TYPE_LTE",
+ "lte"
+ ],
+ [
+ "CHRE_WWAN_CELL_INFO_TYPE_WCDMA",
+ "wcdma"
+ ],
+ [
+ "CHRE_WWAN_CELL_INFO_TYPE_TD_SCDMA",
+ "tdscdma"
+ ],
+ [
+ "CHRE_WWAN_CELL_INFO_TYPE_NR",
+ "nr"
+ ]
+ ]
+ },
+ {
+ "field": "reserved",
+ "annotation": "fixed_value",
+ "value": "0"
+ }
+ ]
+ },
+ {
+ "name": "chreWwanCellIdentityGsm",
+ "annotations": [
+ {
+ "field": "reserved",
+ "annotation": "fixed_value",
+ "value": "0"
+ }
+ ]
+ }
+ ],
+ "root_structs": [
+ "chreWwanCellInfoResult"
+ ]
+ },
+ {
+ "filename": "chre_api/include/chre_api/chre/wifi.h",
+ "includes": [
+ "chre_api/include/chre_api/chre/common.h"
+ ],
+ "output_includes": [
+ "chpp/common/common_types.h",
+ "chre_api/chre/wifi.h"
+ ],
+ "struct_info": [
+ {
+ "name": "chreWifiScanEvent",
+ "annotations": [
+ {
+ "field": "version",
+ "annotation": "fixed_value",
+ "value": "CHRE_WIFI_SCAN_EVENT_VERSION"
+ },
+ {
+ "field": "scannedFreqList",
+ "annotation": "var_len_array",
+ "length_field": "scannedFreqListLen"
+ },
+ {
+ "field": "results",
+ "annotation": "var_len_array",
+ "length_field": "resultCount"
+ }
+ ]
+ },
+ {
+ "name": "chreWifiScanResult",
+ "annotations": [
+ {
+ "field": "reserved",
+ "annotation": "fixed_value",
+ "value": "0"
+ }
+ ]
+ },
+ {
+ "name": "chreWifiScanParams",
+ "annotations": [
+ {
+ "field": "frequencyList",
+ "annotation": "var_len_array",
+ "length_field": "frequencyListLen"
+ },
+ {
+ "field": "ssidList",
+ "annotation": "var_len_array",
+ "length_field": "ssidListLen"
+ }
+ ]
+ },
+ {
+ "name": "chreWifiRangingEvent",
+ "annotations": [
+ {
+ "field": "version",
+ "annotation": "fixed_value",
+ "value": "CHRE_WIFI_RANGING_EVENT_VERSION"
+ },
+ {
+ "field": "reserved",
+ "annotation": "fixed_value",
+ "value": "0"
+ },
+ {
+ "field": "results",
+ "annotation": "var_len_array",
+ "length_field": "resultCount"
+ }
+ ]
+ },
+ {
+ "name": "chreWifiRangingResult",
+ "annotations": [
+ {
+ "field": "reserved",
+ "annotation": "fixed_value",
+ "value": "0"
+ }
+ ]
+ },
+ {
+ "name": "chreWifiRangingParams",
+ "annotations": [
+ {
+ "field": "targetList",
+ "annotation": "var_len_array",
+ "length_field": "targetListLen"
+ }
+ ]
+ },
+ {
+ "name": "chreWifiRangingTarget",
+ "annotations": [
+ {
+ "field": "reserved",
+ "annotation": "fixed_value",
+ "value": "0"
+ }
+ ]
+ },
+ {
+ "name": "chreWifiNanSubscribeConfig",
+ "annotations": [
+ {
+ "field": "subscribeType",
+ "annotation": "enum",
+ "enum_type": "chreWifiNanSubscribeType"
+ },
+ {
+ "field": "service",
+ "annotation": "string"
+ },
+ {
+ "field": "serviceSpecificInfo",
+ "annotation": "var_len_array",
+ "length_field": "serviceSpecificInfoSize"
+ },
+ {
+ "field": "matchFilter",
+ "annotation": "var_len_array",
+ "length_field": "matchFilterLength"
+ }
+ ]
+ },
+ {
+ "name": "chreWifiNanDiscoveryEvent",
+ "annotations": [
+ {
+ "field": "serviceSpecificInfo",
+ "annotation": "var_len_array",
+ "length_field": "serviceSpecificInfoSize"
+ }
+ ]
+ }
+ ],
+ "root_structs": [
+ "chreWifiScanEvent",
+ "chreWifiScanParams",
+ "chreWifiRangingEvent",
+ "chreWifiRangingParams",
+ "chreWifiNanSubscribeConfig",
+ "chreWifiNanDiscoveryEvent",
+ "chreWifiNanSessionLostEvent",
+ "chreWifiNanSessionTerminatedEvent",
+ "chreWifiNanRangingParams"
+ ]
+ },
+ {
+ "filename": "chre_api/include/chre_api/chre/gnss.h",
+ "includes": [
+ "chre_api/include/chre_api/chre/common.h"
+ ],
+ "output_includes": [
+ "chpp/common/common_types.h",
+ "chre_api/chre/gnss.h"
+ ],
+ "struct_info": [
+ {
+ "name": "chreGnssDataEvent",
+ "annotations": [
+ {
+ "field": "version",
+ "annotation": "fixed_value",
+ "value": "CHRE_GNSS_DATA_EVENT_VERSION"
+ },
+ {
+ "field": "reserved",
+ "annotation": "fixed_value",
+ "value": "0"
+ },
+ {
+ "field": "measurements",
+ "annotation": "var_len_array",
+ "length_field": "measurement_count"
+ }
+ ]
+ },
+ {
+ "name": "chreGnssLocationEvent",
+ "annotations": [
+ {
+ "field": "reserved",
+ "annotation": "fixed_value",
+ "value": "0"
+ }
+ ]
+ },
+ {
+ "name": "chreGnssClock",
+ "annotations": [
+ {
+ "field": "reserved",
+ "annotation": "fixed_value",
+ "value": "0"
+ }
+ ]
+ }
+ ],
+ "root_structs": [
+ "chreGnssDataEvent",
+ "chreGnssLocationEvent"
+ ]
+ }
+]
diff --git a/api_parser/chre_api_to_chpp.py b/api_parser/chre_api_to_chpp.py
new file mode 100755
index 00000000..c3302048
--- /dev/null
+++ b/api_parser/chre_api_to_chpp.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 argparse
+import os
+import json
+import subprocess
+
+from api_parser import ApiParser
+from chpp_code_generator import CodeGenerator
+from utils import system_chre_abs_path
+
+
+def run(args):
+ with open(system_chre_abs_path() + '/api_parser/chre_api_annotations.json') as f:
+ js = json.load(f)
+
+ commit_hash = subprocess.getoutput(
+ "git describe --always --long --dirty --exclude '*'")
+ for file in js:
+ if args.file_filter:
+ matched = False
+ for matcher in args.file_filter:
+ if matcher in file['filename']:
+ matched = True
+ break
+ if not matched:
+ print("Skipping {} - doesn't match filter(s) {}".format(file['filename'],
+ args.file_filter))
+ continue
+ print('Parsing {} ... '.format(file['filename']), end='', flush=True)
+ api_parser = ApiParser(file)
+ code_gen = CodeGenerator(api_parser, commit_hash)
+ print('done')
+ code_gen.generate_header_file(args.dry_run, args.skip_clang_format)
+ code_gen.generate_conversion_file(args.dry_run, args.skip_clang_format)
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description='Generate CHPP serialization code from CHRE APIs.')
+ parser.add_argument('-n', dest='dry_run', action='store_true',
+ help='Print the output instead of writing to a file')
+ parser.add_argument('--skip-clang-format', dest='skip_clang_format', action='store_true',
+ help='Skip running clang-format on the output files (doesn\'t apply to dry '
+ 'runs)')
+ parser.add_argument('file_filter', nargs='*',
+ help='Filters the input files (filename field in the JSON) to generate a '
+ 'subset of the typical output, e.g. "wifi" to just generate conversion'
+ ' routines for wifi.h')
+ args = parser.parse_args()
+ run(args)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/chpp/api_parser/parser_defines.h b/api_parser/parser_defines.h
index d12561e0..d12561e0 100644
--- a/chpp/api_parser/parser_defines.h
+++ b/api_parser/parser_defines.h
diff --git a/api_parser/requirements.txt b/api_parser/requirements.txt
new file mode 100644
index 00000000..e61f6e6b
--- /dev/null
+++ b/api_parser/requirements.txt
@@ -0,0 +1,2 @@
+future==0.18.3
+pyclibrary==0.2.1
diff --git a/api_parser/utils.py b/api_parser/utils.py
new file mode 100644
index 00000000..51279b3f
--- /dev/null
+++ b/api_parser/utils.py
@@ -0,0 +1,57 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 sys
+import os
+
+# Paths for output, relative to system/chre
+CHPP_PARSER_INCLUDE_PATH = 'chpp/include/chpp/common'
+CHPP_PARSER_SOURCE_PATH = 'chpp/common'
+
+LICENSE_HEADER = """/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+"""
+
+
+def android_build_top_abs_path():
+ """Gets the absolute path to the Android build top directory or exits the program."""
+
+ android_build_top = os.environ.get('ANDROID_BUILD_TOP')
+ if android_build_top == None or len(android_build_top) == 0:
+ print('ANDROID_BUILD_TOP not found. Please source build/envsetup.sh.')
+ sys.exit(1)
+
+ return android_build_top
+
+
+def system_chre_abs_path():
+ """Gets the absolute path to the system/chre directory or exits this program."""
+
+ return android_build_top_abs_path() + '/system/chre'
diff --git a/apps/ble_world/ble_world.cc b/apps/ble_world/ble_world.cc
index 63bf5fac..0470a0e0 100644
--- a/apps/ble_world/ble_world.cc
+++ b/apps/ble_world/ble_world.cc
@@ -213,6 +213,10 @@ void handleBatchCompleteEvent(const chreBatchCompleteEvent *event) {
event->eventType);
}
+void handleFlushCompleteEvent(const chreAsyncResult *event) {
+ LOGI("Received flush complete event with status 0x%" PRIx8, event->errorCode);
+}
+
void nanoappHandleEvent(uint32_t senderInstanceId, uint16_t eventType,
const void *eventData) {
LOGI("Received event 0x%" PRIx16 " from 0x%" PRIx32 " at time %" PRIu64 " ms",
@@ -230,7 +234,7 @@ void nanoappHandleEvent(uint32_t senderInstanceId, uint16_t eventType,
handleTimerEvent(eventData);
break;
case CHRE_EVENT_BLE_FLUSH_COMPLETE:
- LOGI("Received flush complete");
+ handleFlushCompleteEvent(static_cast<const chreAsyncResult *>(eventData));
break;
case CHRE_EVENT_BLE_RSSI_READ:
handleRssiEvent(static_cast<const chreBleReadRssiEvent *>(eventData));
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/adv_report_cache.cc b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/adv_report_cache.cc
index e7666393..6878e260 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/adv_report_cache.cc
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/adv_report_cache.cc
@@ -18,6 +18,7 @@
#include <utility>
+#include "chre_api/chre.h"
#include "third_party/contexthub/chre/util/include/chre/util/nanoapp/log.h"
#define LOG_TAG "[NEARBY][ADV_CACHE]"
@@ -47,18 +48,23 @@ void AdvReportCache::Refresh() {
cache_expire_nanosec_) {
// TODO(b/285043291): Refactor cache element by wrapper struct/class
// which deallocates data in its destructor.
- if (cache_reports_[index].data != nullptr) {
- chreHeapFree(const_cast<uint8_t *>(cache_reports_[index].data));
- }
- // Don't require to increase index because all elements after the indexed
- // one are moved forward one position.
- cache_reports_.erase(index);
+ chreHeapFree(const_cast<uint8_t *>(cache_reports_[index].data));
+ // The index does not need to increase because the current element is
+ // replaced by the end of the element and the list is resized.
+ cache_reports_.swap(index, cache_reports_.size() - 1);
+ cache_reports_.resize(cache_reports_.size() - 1);
} else {
++index;
}
}
}
+void AdvReportCache::RefreshIfNeeded() {
+ if (cache_reports_.size() > kRefreshCacheCountThreshold) {
+ Refresh();
+ }
+}
+
void AdvReportCache::Push(const chreBleAdvertisingReport &event_report) {
#ifdef NEARBY_PROFILE
ashProfileBegin(&profile_data_);
@@ -97,6 +103,8 @@ void AdvReportCache::Push(const chreBleAdvertisingReport &event_report) {
static_cast<uint8_t *>(chreHeapAlloc(sizeof(uint8_t) * dataLength));
if (data == nullptr) {
LOGE("Memory allocation failed!");
+ // Clean up expired cache elements for which heap memory is allocated.
+ Refresh();
return;
}
memcpy(data, event_report.data, dataLength);
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/adv_report_cache.h b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/adv_report_cache.h
index 55614835..400d0ce1 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/adv_report_cache.h
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/adv_report_cache.h
@@ -89,6 +89,10 @@ class AdvReportCache {
// Removes cached elements older than the cache timeout.
void Refresh();
+ // Removes cached elements older than the cache timeout if cache count is
+ // larger than threshold.
+ void RefreshIfNeeded();
+
private:
// Weight for a current data point in moving average.
static constexpr float kMovingAverageWeight = 0.3f;
@@ -98,6 +102,11 @@ class AdvReportCache {
static constexpr uint64_t kMaxExpireTimeNanoSec =
std::numeric_limits<uint64_t>::max();
+ // Default value for threshold cache count to trigger refresh.
+ // At the worst case, roughly 2KB ( = 255 byte * 8) could be allocated for the
+ // cache elements exired.
+ static constexpr size_t kRefreshCacheCountThreshold = 8;
+
chre::DynamicVector<chreBleAdvertisingReport> cache_reports_;
// Current cache timeout value.
uint64_t cache_expire_nanosec_ = kMaxExpireTimeNanoSec;
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_main.cc b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_main.cc
index ff01df19..7d8fe02b 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_main.cc
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_main.cc
@@ -34,7 +34,7 @@ bool nanoappStart(void) {
// Initialize the AppManager singleton.
// Must be done before invoking AppManagerSingleton::get().
::nearby::AppManagerSingleton::init();
- return true;
+ return ::nearby::AppManagerSingleton::get()->IsInitialized();
}
void nanoappEnd(void) {
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_manager.cc b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_manager.cc
index f59a8d3a..491f69d8 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_manager.cc
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_manager.cc
@@ -22,7 +22,12 @@
#include <utility>
+#include "chre_api/chre.h"
#include "location/lbs/contexthub/nanoapps/common/math/macros.h"
+#ifdef ENABLE_EXTENSION
+#include "location/lbs/contexthub/nanoapps/nearby/nearby_extension.h"
+#include "location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.nanopb.h"
+#endif
#include "location/lbs/contexthub/nanoapps/proto/filter.nanopb.h"
#include "third_party/contexthub/chre/util/include/chre/util/macros.h"
#include "third_party/contexthub/chre/util/include/chre/util/nanoapp/log.h"
@@ -41,6 +46,10 @@ AppManager::AppManager() {
false /* report_total_thread_cycles */, true /* printCsvFormat */);
#endif
}
+bool AppManager::IsInitialized() {
+ // AppManager initialized successfully only when BLE scan is available.
+ return ble_scanner_.isAvailable();
+}
void AppManager::HandleEvent(uint32_t sender_instance_id, uint16_t event_type,
const void *event_data) {
@@ -132,22 +141,22 @@ void AppManager::HandleMatchAdvReports(AdvReportCache &adv_reports_cache) {
#ifdef ENABLE_EXTENSION
// Matches extended filters.
chre::DynamicVector<FilterExtensionResult> filter_extension_results;
- chre::DynamicVector<FilterExtensionResult> screen_on_filter_extension_results;
filter_extension_.Match(adv_reports_cache.GetAdvReports(),
&filter_extension_results,
- &screen_on_filter_extension_results);
+ &screen_on_filter_extension_results_);
if (!filter_extension_results.empty()) {
SendFilterExtensionResultToHost(filter_extension_results);
}
- if (!screen_on_filter_extension_results.empty()) {
+ if (!screen_on_filter_extension_results_.empty()) {
if (screen_on_) {
LOGD("Send screen on filter extension results back");
- SendFilterExtensionResultToHost(screen_on_filter_extension_results);
- } else {
- LOGD("Update filter extension result cache");
+ SendFilterExtensionResultToHost(screen_on_filter_extension_results_);
screen_on_filter_extension_results_.clear();
- screen_on_filter_extension_results_ =
- std::move(screen_on_filter_extension_results);
+ } else {
+ for (auto &filter_result : screen_on_filter_extension_results_) {
+ filter_result.RefreshIfNeeded();
+ }
+ LOGD("Updated filter extension result cache");
}
}
#endif
@@ -179,10 +188,8 @@ void AppManager::HandleMessageFromHost(const chreMessageFromHostData *event) {
event->messageSize);
break;
#ifdef ENABLE_EXTENSION
- case lbs_FilterMessageType_MESSAGE_FILTER_EXTENSIONS:
- if (UpdateFilterExtension(event)) {
- UpdateBleScanState();
- }
+ case lbs_FilterMessageType_MESSAGE_EXT_CONFIG_REQUEST:
+ HandleHostExtConfigRequest(event);
break;
#endif
}
@@ -228,7 +235,9 @@ void AppManager::HandleHostConfigRequest(const uint8_t *message,
LOGD("received screen config %d", screen_on_);
if (screen_on_) {
fp_screen_on_sent_ = false;
- ble_scanner_.Flush();
+ if (ble_scanner_.isScanning()) {
+ ble_scanner_.Flush();
+ }
// TODO(b/255338604): used the default report delay value only because
// FP offload scan doesn't use low latency report delay.
// when the flushed packet droping issue is resolved, try to reconfigure
@@ -248,7 +257,7 @@ void AppManager::HandleHostConfigRequest(const uint8_t *message,
}
#ifdef ENABLE_EXTENSION
if (!screen_on_filter_extension_results_.empty()) {
- LOGD("send filter extension result from cache");
+ LOGD("try to send filter extension result from cache");
SendFilterExtensionResultToHost(screen_on_filter_extension_results_);
screen_on_filter_extension_results_.clear();
}
@@ -428,43 +437,87 @@ bool AppManager::EncodeFilterResult(const nearby_BleFilterResult &filter_result,
}
#ifdef ENABLE_EXTENSION
-bool AppManager::UpdateFilterExtension(const chreMessageFromHostData *event) {
+void AppManager::HandleHostExtConfigRequest(
+ const chreMessageFromHostData *event) {
chreHostEndpointInfo host_info;
- chre::DynamicVector<chreBleGenericFilter> generic_filters;
- nearby_extension_FilterConfigResult config_result =
- nearby_extension_FilterConfigResult_init_zero;
- if (chreGetHostEndpointInfo(event->hostEndpoint, &host_info)) {
- if (host_info.isNameValid) {
- LOGD("host package name %s", host_info.packageName);
- // TODO(b/283035791) replace "android" with the package name of Nearby
- // Mainline host.
- // The event is sent from Nearby Mainline host, not OEM services.
- if (strcmp(host_info.packageName, "android") == 0) {
- return false;
- }
- filter_extension_.Update(host_info, *event, &generic_filters,
- &config_result);
- if (config_result.result == CHREX_NEARBY_RESULT_OK) {
- if (!ble_scanner_.UpdateFilters(event->hostEndpoint,
- &generic_filters)) {
- config_result.result = CHREX_NEARBY_RESULT_INTERNAL_ERROR;
+ pb_istream_t stream =
+ pb_istream_from_buffer(static_cast<const uint8_t *>(event->message),
+ static_cast<size_t>(event->messageSize));
+ nearby_extension_ExtConfigRequest config =
+ nearby_extension_ExtConfigRequest_init_default;
+ nearby_extension_ExtConfigResponse config_response =
+ nearby_extension_ExtConfigResponse_init_zero;
+
+ if (!pb_decode(&stream, nearby_extension_ExtConfigRequest_fields, &config)) {
+ LOGE("Failed to decode extended config msg: %s", PB_GET_ERROR(&stream));
+ } else if (!chreGetHostEndpointInfo(event->hostEndpoint, &host_info)) {
+ LOGE("Failed to get host info.");
+ config_response.result = CHREX_NEARBY_RESULT_INTERNAL_ERROR;
+ } else if (!host_info.isNameValid) {
+ LOGE("Failed to get package name");
+ config_response.result = CHREX_NEARBY_RESULT_UNKNOWN_PACKAGE;
+ } else {
+ LOGD("*** Receiving %s extended config ***",
+ GetExtConfigNameFromTag(config.which_config));
+
+ switch (config.which_config) {
+ case nearby_extension_ExtConfigRequest_filter_config_tag:
+ if (!HandleExtFilterConfig(host_info, config.config.filter_config,
+ &config_response)) {
+ LOGE("Failed to handle extended filter config");
}
- }
- } else {
- LOGE("host package name invalid.");
- config_result.result = CHREX_NEARBY_RESULT_UNKNOWN_PACKAGE;
+ break;
+ case nearby_extension_ExtConfigRequest_service_config_tag:
+ if (!HandleExtServiceConfig(host_info, config.config.service_config,
+ &config_response)) {
+ LOGE("Failed to handle extended service config");
+ }
+ break;
+ default:
+ LOGE("Unknown extended config %d", config.which_config);
+ config_response.result = CHREX_NEARBY_RESULT_FEATURE_NOT_SUPPORTED;
+ break;
}
- } else {
- config_result.result = CHREX_NEARBY_RESULT_INTERNAL_ERROR;
- LOGE("Failed to get host info.");
}
- SendFilterExtensionConfigResultToHost(event->hostEndpoint, config_result);
+ SendExtConfigResponseToHost(config.request_id, event->hostEndpoint,
+ config_response);
+}
+
+bool AppManager::HandleExtFilterConfig(
+ const chreHostEndpointInfo &host_info,
+ const nearby_extension_ExtConfigRequest_FilterConfig &config,
+ nearby_extension_ExtConfigResponse *config_response) {
+ chre::DynamicVector<chreBleGenericFilter> generic_filters;
+
+ filter_extension_.Update(host_info, config, &generic_filters,
+ config_response);
+ if (config_response->result != CHREX_NEARBY_RESULT_OK) {
+ return false;
+ }
+ if (!ble_scanner_.UpdateFilters(host_info.hostEndpointId, &generic_filters)) {
+ config_response->result = CHREX_NEARBY_RESULT_INTERNAL_ERROR;
+ return false;
+ }
+ UpdateBleScanState();
return true;
}
-void AppManager::SendFilterExtensionConfigResultToHost(
- uint16_t host_end_point,
- const nearby_extension_FilterConfigResult &config_result) {
+bool AppManager::HandleExtServiceConfig(
+ const chreHostEndpointInfo &host_info,
+ const nearby_extension_ExtConfigRequest_ServiceConfig &config,
+ nearby_extension_ExtConfigResponse *config_response) {
+ filter_extension_.ConfigureService(host_info, config, config_response);
+ if (config_response->result != CHREX_NEARBY_RESULT_OK) {
+ return false;
+ }
+ return true;
+}
+
+void AppManager::SendExtConfigResponseToHost(
+ uint32_t request_id, uint16_t host_end_point,
+ nearby_extension_ExtConfigResponse &config_response) {
+ config_response.has_request_id = true;
+ config_response.request_id = request_id;
uint8_t *msg_buf = (uint8_t *)chreHeapAlloc(kFilterResultsBufSize);
if (msg_buf == nullptr) {
LOGE("Failed to allocate message buffer of size %zu for dispatch.",
@@ -472,23 +525,23 @@ void AppManager::SendFilterExtensionConfigResultToHost(
return;
}
size_t encoded_size;
- if (!FilterExtension::EncodeConfigResult(
- config_result, ByteArray(msg_buf, kFilterResultsBufSize),
+ if (!FilterExtension::EncodeConfigResponse(
+ config_response, ByteArray(msg_buf, kFilterResultsBufSize),
&encoded_size)) {
chreHeapFree(msg_buf);
return;
}
- auto resp_type = (config_result.result == CHREX_NEARBY_RESULT_OK
- ? lbs_FilterMessageType_MESSAGE_SUCCESS
- : lbs_FilterMessageType_MESSAGE_FAILURE);
-
if (chreSendMessageWithPermissions(
- msg_buf, encoded_size, resp_type, host_end_point,
+ msg_buf, encoded_size,
+ lbs_FilterMessageType_MESSAGE_EXT_CONFIG_RESPONSE, host_end_point,
CHRE_MESSAGE_PERMISSION_BLE,
[](void *msg, size_t /*size*/) { chreHeapFree(msg); })) {
- LOGD("Successfully sent the filter extension config result.");
+ LOGD("Successfully sent the extended config response for request %" PRIu32
+ ".",
+ request_id);
} else {
- LOGE("Failed to send filter extension config result.");
+ LOGE("Failed to send extended config response for request %" PRIu32 ".",
+ request_id);
}
}
@@ -499,29 +552,43 @@ void AppManager::SendFilterExtensionResultToHost(
if (reports.empty()) {
continue;
}
- uint8_t *msg_buf = (uint8_t *)chreHeapAlloc(kFilterResultsBufSize);
- if (msg_buf == nullptr) {
- LOGE("Failed to allocate message buffer of size %zu for dispatch.",
- kFilterResultsBufSize);
- return;
- }
- size_t encoded_size;
- if (!FilterExtension::Encode(reports,
- ByteArray(msg_buf, kFilterResultsBufSize),
- &encoded_size)) {
- chreHeapFree(msg_buf);
- return;
- }
- if (chreSendMessageWithPermissions(
- msg_buf, encoded_size, lbs_FilterMessageType_MESSAGE_FILTER_RESULTS,
- result.end_point, CHRE_MESSAGE_PERMISSION_BLE,
- [](void *msg, size_t /*size*/) { chreHeapFree(msg); })) {
- LOGD("Successfully sent the filter extension result.");
- } else {
- LOGE("Failed to send filter extension result.");
+ for (auto &report : reports) {
+ size_t encoded_size;
+ uint8_t *msg_buf = (uint8_t *)chreHeapAlloc(kFilterResultsBufSize);
+ if (msg_buf == nullptr) {
+ LOGE("Failed to allocate message buffer of size %zu for dispatch.",
+ kFilterResultsBufSize);
+ return;
+ }
+ if (!FilterExtension::EncodeAdvReport(
+ report, ByteArray(msg_buf, kFilterResultsBufSize),
+ &encoded_size)) {
+ chreHeapFree(msg_buf);
+ return;
+ }
+ if (chreSendMessageWithPermissions(
+ msg_buf, encoded_size,
+ lbs_FilterMessageType_MESSAGE_FILTER_RESULTS, result.end_point,
+ CHRE_MESSAGE_PERMISSION_BLE,
+ [](void *msg, size_t /*size*/) { chreHeapFree(msg); })) {
+ LOGD("Successfully sent the filter extension result.");
+ } else {
+ LOGE("Failed to send filter extension result.");
+ }
}
}
}
+
+const char *AppManager::GetExtConfigNameFromTag(pb_size_t config_tag) {
+ switch (config_tag) {
+ case nearby_extension_ExtConfigRequest_filter_config_tag:
+ return "FilterConfig";
+ case nearby_extension_ExtConfigRequest_service_config_tag:
+ return "ServiceConfig";
+ default:
+ return "Unknown";
+ }
+}
#endif
} // namespace nearby
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_manager.h b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_manager.h
index bed03e43..27d0f585 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_manager.h
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/app_manager.h
@@ -40,6 +40,9 @@ class AppManager {
public:
AppManager();
+ // Returns true if AppManager is initialized successfully.
+ bool IsInitialized();
+
// Handles an event from CHRE.
void HandleEvent(uint32_t sender_instance_id, uint16_t event_type,
const void *event_data);
@@ -47,10 +50,13 @@ class AppManager {
private:
// Handles a message from host.
void HandleMessageFromHost(const chreMessageFromHostData *event);
+
// Acknowledge a host's SET_FILTER_REQUEST to indicate success or failure.
void RespondHostSetFilterRequest(bool success);
+
// Handles config request from the host.
void HandleHostConfigRequest(const uint8_t *message, uint32_t message_size);
+
// Handles advertise reports to match filters.
// Advertise reports will be cleared at the end of this function.
void HandleMatchAdvReports(AdvReportCache &adv_reports);
@@ -94,12 +100,29 @@ class AppManager {
size_t &encoded_size);
#ifdef ENABLE_EXTENSION
- static void SendFilterExtensionConfigResultToHost(
- uint16_t host_end_point,
- const nearby_extension_FilterConfigResult &config_result);
+ // Handles extended config request from the host.
+ void HandleHostExtConfigRequest(const chreMessageFromHostData *event);
+
+ // Handles extended filter config request from the host.
+ bool HandleExtFilterConfig(
+ const chreHostEndpointInfo &host_info,
+ const nearby_extension_ExtConfigRequest_FilterConfig &config,
+ nearby_extension_ExtConfigResponse *config_response);
+
+ // Handles extended service config request from the host.
+ bool HandleExtServiceConfig(
+ const chreHostEndpointInfo &host_info,
+ const nearby_extension_ExtConfigRequest_ServiceConfig &config,
+ nearby_extension_ExtConfigResponse *config_response);
+
+ static void SendExtConfigResponseToHost(
+ uint32_t request_id, uint16_t host_end_point,
+ nearby_extension_ExtConfigResponse &config_response);
static void SendFilterExtensionResultToHost(
chre::DynamicVector<FilterExtensionResult> &filter_results);
+
+ static const char *GetExtConfigNameFromTag(pb_size_t config_tag);
#endif
// TODO(b/193756395): Find the optimal size or compute the size in runtime.
// Note: the nanopb API pb_get_encoded_size
@@ -114,7 +137,11 @@ class AppManager {
static constexpr size_t kFilterResultsBufSize = 300;
// Default value for Fast Pair cache to expire.
static constexpr uint64_t kFpFilterResultExpireTimeNanoSec =
+#ifdef USE_SHORT_FP_CACHE_TO
+ 3 * chre::kOneSecondInNanoseconds;
+#else
5 * chre::kOneSecondInNanoseconds;
+#endif
Filter filter_;
#ifdef ENABLE_EXTENSION
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/ble_scanner.cc b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/ble_scanner.cc
index f77c0cf4..d4e09f4a 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/ble_scanner.cc
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/ble_scanner.cc
@@ -222,6 +222,7 @@ void BleScanner::Restart() {
}
}
chreBleScanFilter scan_filter;
+ memset(&scan_filter, 0, sizeof(scan_filter));
scan_filter.rssiThreshold = CHRE_BLE_RSSI_THRESHOLD_NONE;
scan_filter.scanFilters = generic_filters.data();
scan_filter.scanFilterCount = static_cast<uint8_t>(generic_filters.size());
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/ble_scanner.h b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/ble_scanner.h
index 08c51d1e..fb06f53c 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/ble_scanner.h
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/ble_scanner.h
@@ -64,6 +64,16 @@ class BleScanner {
return is_batch_flushing_;
}
+ // Returns whether BLE scan is running.
+ bool isScanning() {
+ return is_started_;
+ }
+
+ // Returns true if BLE scan is available in the device.
+ bool isAvailable() {
+ return is_ble_scan_supported_;
+ }
+
// Returns whether BLE batch scan is supported.
bool IsBatchSupported() {
return is_batch_supported_;
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/fast_pair_account_data.cc b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/fast_pair_account_data.cc
index af8c51c2..b564cb81 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/fast_pair_account_data.cc
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/fast_pair_account_data.cc
@@ -99,7 +99,7 @@ FastPairAccountData FastPairAccountData::Parse(const ByteArray &service_data) {
}
// filter and salt are required.
if (filter.length == 0 || salt.length == 0) {
- LOGE(
+ LOGD(
"Invalid Fast Pair service data with filter length %zu and salt length "
"%zu.",
filter.length, salt.length);
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/fast_pair_filter.cc b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/fast_pair_filter.cc
index 94074953..f7513f33 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/fast_pair_filter.cc
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/fast_pair_filter.cc
@@ -154,6 +154,12 @@ bool MatchSubsequentPair(const uint8_t *account_key,
kFastPairUuid);
return false;
}
+ if (service_data.length == kFastPairModelIdLength) {
+ LOGD(
+ "Initial Pair advertisements, not proceed to subsequent pair "
+ "filtering.");
+ return false;
+ }
FastPairAccountData account_data = FastPairAccountData::Parse(
ByteArray(const_cast<uint8_t *>(service_data.data), service_data.length));
if (!account_data.is_valid) {
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter.cc b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter.cc
index 7aded384..9254217b 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter.cc
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter.cc
@@ -20,8 +20,10 @@
#include <inttypes.h>
#include <pb_decode.h>
+#include <cstdint>
#include <iterator>
+#include "chre_api/chre.h"
#include "location/lbs/contexthub/nanoapps/nearby/ble_scan_record.h"
#include "location/lbs/contexthub/nanoapps/nearby/fast_pair_filter.h"
#ifdef ENABLE_PRESENCE
@@ -111,6 +113,10 @@ void Filter::MatchBle(
// The buffer size has already been checked.
static_assert(std::size(result.bluetooth_address) == CHRE_BLE_ADDRESS_LEN);
memcpy(result.bluetooth_address, report.address, std::size(report.address));
+ result.has_timestamp_ns = true;
+ result.timestamp_ns =
+ report.timestamp +
+ static_cast<uint64_t>(chreGetEstimatedHostTimeOffset());
if (MatchFastPair(ble_filters_.filter[filter_index], record, &result)) {
LOGD("Add a matched Fast Pair filter result");
fp_filter_results->push_back(result);
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter_extension.cc b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter_extension.cc
index 11e490c9..abc004e9 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter_extension.cc
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter_extension.cc
@@ -5,8 +5,12 @@
#include <pb_encode.h>
#include <cstddef>
+#include <cstdint>
#include <utility>
+#include "chre_api/chre.h"
+#include "location/lbs/contexthub/nanoapps/nearby/nearby_extension.h"
+#include "location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.nanopb.h"
#include "third_party/contexthub/chre/util/include/chre/util/nanoapp/log.h"
#define LOG_TAG "[NEARBY][FILTER_EXTENSION]"
@@ -15,34 +19,23 @@ namespace nearby {
const size_t kChreBleGenericFilterDataSize = 29;
-constexpr nearby_extension_FilterConfig kEmptyFilterConfig =
- nearby_extension_FilterConfig_init_zero;
-
constexpr nearby_extension_FilterResult kEmptyFilterResult =
nearby_extension_FilterResult_init_zero;
void FilterExtension::Update(
- const chreHostEndpointInfo &host_info, const chreMessageFromHostData &event,
+ const chreHostEndpointInfo &host_info,
+ const nearby_extension_ExtConfigRequest_FilterConfig &filter_config,
chre::DynamicVector<chreBleGenericFilter> *generic_filters,
- nearby_extension_FilterConfigResult *config_result) {
+ nearby_extension_ExtConfigResponse *config_response) {
LOGD("Update extension filter");
- nearby_extension_FilterConfig filter_config = kEmptyFilterConfig;
- pb_istream_t stream = pb_istream_from_buffer(
- static_cast<const uint8_t *>(event.message), event.messageSize);
- if (!pb_decode(&stream, nearby_extension_FilterConfig_fields,
- &filter_config)) {
- LOGE("Failed to decode a Filters message.");
- return;
- }
const int32_t host_index = FindOrCreateHostIndex(host_info);
if (host_index < 0) {
LOGE("Failed to find or create the host.");
return;
}
- const chreHostEndpointInfo &host =
- host_list_[static_cast<size_t>(host_index)];
- config_result->has_result = true;
- config_result->has_vendor_status = true;
+ HostEndpointInfo &host = host_list_[static_cast<size_t>(host_index)];
+ config_response->has_result = true;
+ config_response->has_vendor_status = true;
// Returns hardware filters.
for (int i = 0; i < filter_config.hardware_filter_count; i++) {
@@ -64,32 +57,52 @@ void FilterExtension::Update(
chrexNearbyExtendedFilterConfig config;
config.data = filter_config.oem_filter;
config.data_length = filter_config.oem_filter_length;
+ host.cache_expire_ms = filter_config.cache_expire_ms;
- config_result->result =
- static_cast<int32_t>(chrexNearbySetExtendedFilterConfig(
- &host, &scan_filter, &config, &config_result->vendor_status));
- if (config_result->result != CHREX_NEARBY_RESULT_OK) {
- LOGE("Failed to config filters, result %" PRId32, config_result->result);
+ config_response->result = static_cast<int32_t>(
+ chrexNearbySetExtendedFilterConfig(&host.host_info, &scan_filter, &config,
+ &config_response->vendor_status));
+ if (config_response->result != CHREX_NEARBY_RESULT_OK) {
+ LOGE("Failed to config filters, result %" PRId32, config_response->result);
host_list_.erase(static_cast<size_t>(host_index));
return;
}
// Removes the host if both hardware and oem filters are empty.
if (filter_config.hardware_filter_count == 0 &&
filter_config.oem_filter_length == 0) {
- LOGD("Remove host: id (%d), package name (%s)", host.hostEndpointId,
- host.isNameValid ? host.packageName : "unknown");
+ LOGD("Remove host: id (%d), package name (%s)",
+ host.host_info.hostEndpointId,
+ host.host_info.isNameValid ? host.host_info.packageName : "unknown");
host_list_.erase(static_cast<size_t>(host_index));
}
}
+void FilterExtension::ConfigureService(
+ const chreHostEndpointInfo &host_info,
+ const nearby_extension_ExtConfigRequest_ServiceConfig &service_config,
+ nearby_extension_ExtConfigResponse *config_response) {
+ LOGD("Configure extension service");
+ config_response->has_result = true;
+ config_response->has_vendor_status = true;
+
+ chrexNearbyExtendedServiceConfig config;
+ config.data = service_config.data;
+ config.data_length = service_config.data_length;
+
+ config_response->result =
+ static_cast<int32_t>(chrexNearbySetExtendedServiceConfig(
+ &host_info, &config, &config_response->vendor_status));
+}
+
int32_t FilterExtension::FindOrCreateHostIndex(
const chreHostEndpointInfo &host_info) {
for (size_t index = 0; index < host_list_.size(); index++) {
- if (host_info.hostEndpointId == host_list_[index].hostEndpointId) {
+ if (host_info.hostEndpointId ==
+ host_list_[index].host_info.hostEndpointId) {
return static_cast<int32_t>(index);
}
}
- if (!host_list_.push_back(host_info)) {
+ if (!host_list_.push_back(HostEndpointInfo(host_info))) {
LOGE("Failed to add new host info.");
return -1;
}
@@ -101,9 +114,10 @@ int32_t FilterExtension::FindOrCreateHostIndex(
* Returns the index of the entry.
*/
size_t AddToFilterResults(
- uint16_t endponit_id,
+ const HostEndpointInfo &host,
chre::DynamicVector<FilterExtensionResult> *filter_results) {
- FilterExtensionResult result(endponit_id);
+ FilterExtensionResult result(host.host_info.hostEndpointId,
+ host.cache_expire_ms);
size_t idx = filter_results->find(result);
if (filter_results->size() == idx) {
filter_results->push_back(std::move(result));
@@ -115,12 +129,12 @@ void FilterExtension::Match(
const chre::DynamicVector<chreBleAdvertisingReport> &ble_adv_list,
chre::DynamicVector<FilterExtensionResult> *filter_results,
chre::DynamicVector<FilterExtensionResult> *screen_on_filter_results) {
- for (const chreHostEndpointInfo &host_info : host_list_) {
- size_t idx = AddToFilterResults(host_info.hostEndpointId, filter_results);
- size_t screen_on_idx =
- AddToFilterResults(host_info.hostEndpointId, screen_on_filter_results);
+ for (const HostEndpointInfo &host : host_list_) {
+ size_t idx = AddToFilterResults(host, filter_results);
+ size_t screen_on_idx = AddToFilterResults(host, screen_on_filter_results);
for (const auto &ble_adv_report : ble_adv_list) {
- switch (chrexNearbyMatchExtendedFilter(&host_info, &ble_adv_report)) {
+ switch (
+ chrexNearbyMatchExtendedFilter(&host.host_info, &ble_adv_report)) {
case CHREX_NEARBY_FILTER_ACTION_IGNORE:
continue;
case CHREX_NEARBY_FILTER_ACTION_DELIVER_ON_WAKE:
@@ -137,20 +151,20 @@ void FilterExtension::Match(
}
}
-bool FilterExtension::EncodeConfigResult(
- const nearby_extension_FilterConfigResult &config_result,
+bool FilterExtension::EncodeConfigResponse(
+ const nearby_extension_ExtConfigResponse &config_response,
ByteArray data_buf, size_t *encoded_size) {
if (!pb_get_encoded_size(encoded_size,
- nearby_extension_FilterConfigResult_fields,
- &config_result)) {
- LOGE("Failed to get filter config result size.");
+ nearby_extension_ExtConfigResponse_fields,
+ &config_response)) {
+ LOGE("Failed to get extended config response size.");
return false;
}
pb_ostream_t ostream = pb_ostream_from_buffer(data_buf.data, data_buf.length);
- if (!pb_encode(&ostream, nearby_extension_FilterConfigResult_fields,
- &config_result)) {
- LOGE("Unable to encode protobuf for FilterConfigResult, error %s",
+ if (!pb_encode(&ostream, nearby_extension_ExtConfigResponse_fields,
+ &config_response)) {
+ LOGE("Unable to encode protobuf for ExtConfigResponse, error %s",
PB_GET_ERROR(&ostream));
return false;
}
@@ -207,4 +221,52 @@ bool FilterExtension::Encode(
return true;
}
+bool FilterExtension::EncodeAdvReport(chreBleAdvertisingReport &report,
+ ByteArray data_buf,
+ size_t *encoded_size) {
+ nearby_extension_FilterResult filter_result = kEmptyFilterResult;
+ nearby_extension_ChreBleAdvertisingReport &report_proto =
+ filter_result.report[0];
+ report_proto.has_timestamp = true;
+ report_proto.timestamp =
+ report.timestamp +
+ static_cast<uint64_t>(chreGetEstimatedHostTimeOffset());
+ report_proto.has_event_type_and_data_status = true;
+ report_proto.event_type_and_data_status = report.eventTypeAndDataStatus;
+ report_proto.has_address = true;
+ for (size_t i = 0; i < 6; i++) {
+ report_proto.address[i] = report.address[i];
+ }
+ report_proto.has_tx_power = true;
+ report_proto.tx_power = report.txPower;
+ report_proto.has_rssi = true;
+ report_proto.rssi = report.rssi;
+ report_proto.has_data_length = true;
+ report_proto.data_length = report.dataLength;
+ if (report.dataLength > 0) {
+ report_proto.has_data = true;
+ }
+ for (size_t i = 0; i < report.dataLength; i++) {
+ report_proto.data[i] = report.data[i];
+ }
+ filter_result.report_count = 1;
+ filter_result.has_error_code = true;
+ filter_result.error_code = nearby_extension_FilterResult_ErrorCode_SUCCESS;
+
+ if (!pb_get_encoded_size(encoded_size, nearby_extension_FilterResult_fields,
+ &filter_result)) {
+ LOGE("Failed to get filter extension result size.");
+ return false;
+ }
+ pb_ostream_t ostream = pb_ostream_from_buffer(data_buf.data, data_buf.length);
+
+ if (!pb_encode(&ostream, nearby_extension_FilterResult_fields,
+ &filter_result)) {
+ LOGE("Unable to encode protobuf for FilterExtensionResults, error %s",
+ PB_GET_ERROR(&ostream));
+ return false;
+ }
+ return true;
+}
+
} // namespace nearby
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter_extension.h b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter_extension.h
index 996e4b93..99c9b20c 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter_extension.h
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/filter_extension.h
@@ -2,6 +2,7 @@
#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_NEARBY_FILTER_EXTENSION_H_
#include <chre.h>
+#include <cstdint>
#include <utility>
#include "location/lbs/contexthub/nanoapps/nearby/adv_report_cache.h"
@@ -13,16 +14,28 @@
namespace nearby {
-struct FilterExtensionResult {
- // Default value for filter extension result to expire.
- static constexpr uint64_t kFilterExtensionReportExpireTimeMilliSec =
- 5 * chre::kOneSecondInMilliseconds;
+// Default value for filter extension result to expire.
+static constexpr uint64_t kFilterExtensionReportExpireTimeMilliSec =
+ 5 * chre::kOneSecondInMilliseconds;
+
+struct HostEndpointInfo {
+ chreHostEndpointInfo host_info;
+ // Host-specific configurations.
+ uint32_t cache_expire_ms;
+
+ explicit HostEndpointInfo(chreHostEndpointInfo host_info)
+ : host_info(std::move(host_info)) {}
+};
+struct FilterExtensionResult {
const uint16_t end_point;
AdvReportCache reports;
- explicit FilterExtensionResult(uint16_t end_point) : end_point(end_point) {
- reports.SetCacheTimeout(kFilterExtensionReportExpireTimeMilliSec);
+ explicit FilterExtensionResult(
+ uint16_t end_point,
+ uint64_t expire_time_ms = kFilterExtensionReportExpireTimeMilliSec)
+ : end_point(end_point) {
+ reports.SetCacheTimeout(expire_time_ms);
}
FilterExtensionResult(FilterExtensionResult &&src)
@@ -40,6 +53,17 @@ struct FilterExtensionResult {
reports.Clear();
}
+ // Removes advertising reports older than the cache timeout.
+ void Refresh() {
+ reports.Refresh();
+ }
+
+ // Removes advertising reports older than the cache timeout if the cache size
+ // hits a threshold.
+ void RefreshIfNeeded() {
+ reports.RefreshIfNeeded();
+ }
+
// Returns advertise reports in cache.
chre::DynamicVector<chreBleAdvertisingReport> &GetAdvReports() {
return reports.GetAdvReports();
@@ -60,14 +84,21 @@ struct FilterExtensionResult {
class FilterExtension {
public:
- // Updates extended filters (passed in the event) for each end host.
+ // Updates extended filters for each end host.
// Returns generic_filters, which can be used to restart BLE scan.
- // If config_result->result is not CHREX_NEARBY_RESULT_OK, the returned
+ // If config_response->result is not CHREX_NEARBY_RESULT_OK, the returned
// generic_filters should be ignored.
- void Update(const chreHostEndpointInfo &host_info,
- const chreMessageFromHostData &event,
- chre::DynamicVector<chreBleGenericFilter> *generic_filters,
- nearby_extension_FilterConfigResult *config_result);
+ void Update(
+ const chreHostEndpointInfo &host_info,
+ const nearby_extension_ExtConfigRequest_FilterConfig &filter_config,
+ chre::DynamicVector<chreBleGenericFilter> *generic_filters,
+ nearby_extension_ExtConfigResponse *config_response);
+
+ // Configures OEM service data.
+ void ConfigureService(
+ const chreHostEndpointInfo &host_info,
+ const nearby_extension_ExtConfigRequest_ServiceConfig &service_config,
+ nearby_extension_ExtConfigResponse *config_response);
// Matches BLE advertisements. Returns matched advertisements in
// filter_results. If the results is only delivered when screen is on,
@@ -77,10 +108,10 @@ class FilterExtension {
chre::DynamicVector<FilterExtensionResult> *filter_results,
chre::DynamicVector<FilterExtensionResult> *screen_on_filter_results);
- // Serializes config_result into data_buf. The encoded size is filled in
- // encoded_size. Returns true for successful encoding.
- static bool EncodeConfigResult(
- const nearby_extension_FilterConfigResult &config_result,
+ // Serializes extended config response into data_buf. The encoded size is
+ // filled in encoded_size. Returns true for successful encoding.
+ static bool EncodeConfigResponse(
+ const nearby_extension_ExtConfigResponse &config_response,
ByteArray data_buf, size_t *encoded_size);
// Encodes reports into data_buf. The reports are converted to
@@ -89,6 +120,11 @@ class FilterExtension {
const chre::DynamicVector<chreBleAdvertisingReport> &reports,
ByteArray data_buf, size_t *encoded_size);
+ // Encodes a single report into data_buf. The report are converted to
+ // nearby_extension_FilterResult before the serialization.
+ static bool EncodeAdvReport(chreBleAdvertisingReport &report,
+ ByteArray data_buf, size_t *encoded_size);
+
// Whether host list is empty. The host which doesn't have filter
// configuration or was disconnected should be removed in the host list.
bool IsEmpty() const {
@@ -100,7 +136,7 @@ class FilterExtension {
int32_t FindOrCreateHostIndex(const chreHostEndpointInfo &host_info);
private:
- chre::DynamicVector<chreHostEndpointInfo> host_list_;
+ chre::DynamicVector<HostEndpointInfo> host_list_;
};
} // namespace nearby
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension.c b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension.c
index 4b9370ea..54075924 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension.c
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension.c
@@ -1,7 +1,9 @@
#include "location/lbs/contexthub/nanoapps/nearby/nearby_extension.h"
-#include "stddef.h"
+#include <string.h>
+#include "chre_api/chre.h"
+#include "stddef.h"
#include "third_party/contexthub/chre/util/include/chre/util/nanoapp/log.h"
#define LOG_TAG "[NEARBY][FILTER_EXTENSION]"
@@ -28,6 +30,7 @@ static const uint16_t EXT_FILTER_CONFIG_DATA_MASK_INDEX = 1;
static uint8_t EXT_FILTER_DATA = 0;
static uint8_t EXT_FILTER_DATA_MASK = 0;
#define MAX_GENERIC_FILTER_COUNT 10
+#define MAX_SERVICE_CONFIG_LEN 10
struct hwBleScanFilter {
int8_t rssi_threshold;
@@ -38,6 +41,7 @@ static struct hwBleScanFilter HW_SCAN_FILTER = {
.rssi_threshold = CHRE_BLE_RSSI_THRESHOLD_NONE,
.scan_filter_count = 0,
};
+static uint8_t EXT_SERVICE_CONFIG[MAX_SERVICE_CONFIG_LEN] = {0};
const char kHostPackageName[] = "com.google.android.nearby.offload.reference";
uint32_t chrexNearbySetExtendedFilterConfig(
@@ -50,7 +54,12 @@ uint32_t chrexNearbySetExtendedFilterConfig(
LOGE("Invalid scan_filter configuration");
return CHREX_NEARBY_RESULT_INTERNAL_ERROR;
}
- // Performs a deep copy of the hardware scan filter structure
+ if (!host_info->isNameValid ||
+ strcmp(host_info->packageName, kHostPackageName) != 0) {
+ LOGE("Unknown package: %s", host_info->packageName);
+ return CHREX_NEARBY_RESULT_UNKNOWN_PACKAGE;
+ }
+ // Performs a deep copy of the hardware scan filter structure.
HW_SCAN_FILTER.rssi_threshold = scan_filter->rssiThreshold;
HW_SCAN_FILTER.scan_filter_count = scan_filter->scanFilterCount;
for (size_t i = 0; i < HW_SCAN_FILTER.scan_filter_count; ++i) {
@@ -71,17 +80,33 @@ uint32_t chrexNearbySetExtendedFilterConfig(
HW_SCAN_FILTER.scan_filters[i].type,
HW_SCAN_FILTER.scan_filters[i].len);
}
- if (host_info->isNameValid &&
- strcmp(host_info->packageName, kHostPackageName) == 0) {
- EXT_FILTER_DATA = config->data[EXT_FILTER_CONFIG_DATA_INDEX];
- EXT_FILTER_DATA_MASK = config->data[EXT_FILTER_CONFIG_DATA_MASK_INDEX];
- }
+ EXT_FILTER_DATA = config->data[EXT_FILTER_CONFIG_DATA_INDEX];
+ EXT_FILTER_DATA_MASK = config->data[EXT_FILTER_CONFIG_DATA_MASK_INDEX];
*vendorStatusCode = 0;
LOGD("Set EXT_FILTER_DATA 0x%02X", EXT_FILTER_DATA);
LOGD("Set EXT_FILTER_DATA_MASK 0x%02X", EXT_FILTER_DATA_MASK);
return CHREX_NEARBY_RESULT_OK;
}
+uint32_t chrexNearbySetExtendedServiceConfig(
+ const struct chreHostEndpointInfo *host_info,
+ const struct chrexNearbyExtendedServiceConfig *config,
+ uint32_t *vendorStatusCode) {
+ if (!host_info->isNameValid ||
+ strcmp(host_info->packageName, kHostPackageName) != 0) {
+ LOGE("Unknown package: %s", host_info->packageName);
+ return CHREX_NEARBY_RESULT_UNKNOWN_PACKAGE;
+ }
+ if (config->data_length > MAX_SERVICE_CONFIG_LEN) {
+ return CHREX_NEARBY_RESULT_OUT_OF_RESOURCES;
+ }
+ // Performs a deep copy of the service configuration.
+ memcpy(EXT_SERVICE_CONFIG, config->data, config->data_length);
+ *vendorStatusCode = 0;
+ LOGD("Set EXT_SERVICE_CONFIG 0x%02X", EXT_SERVICE_CONFIG[0]);
+ return CHREX_NEARBY_RESULT_OK;
+}
+
uint32_t chrexNearbyMatchExtendedFilter(
const struct chreHostEndpointInfo *host_info,
const struct chreBleAdvertisingReport *report) {
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension.h b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension.h
index 7d26d68b..a34a1d90 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension.h
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension.h
@@ -13,6 +13,12 @@ struct chrexNearbyExtendedFilterConfig {
const uint8_t *data; //!< Vendor-defined payload
};
+//! Contains vendor-defined data for configuring vendor service in library
+struct chrexNearbyExtendedServiceConfig {
+ size_t data_length; //!< Number of bytes in data
+ const uint8_t *data; //!< Vendor-defined payload
+};
+
enum chrexNearbyResult {
//! Operation completed successfully
CHREX_NEARBY_RESULT_OK = 0,
@@ -73,6 +79,32 @@ uint32_t chrexNearbySetExtendedFilterConfig(
const struct chrexNearbyExtendedFilterConfig *config,
uint32_t *vendorStatusCode);
+/**
+ * Configures vendor-defined service data sent by a vendor/OEM service on the
+ * host. This is called by the Nearby nanoapp when it receives a
+ * ChreNearbyExtendedService message, and the result is sent back to the host
+ * endpoint that made the request. The pointers supplied for the
+ * parameters are not guaranteed to be valid after this call. The OEM library
+ * should perform a deep copy of the structure if we want to store them in the
+ * library.
+ *
+ * @param host_info The meta data for a host end point that sent the message,
+ * obtained from chreHostEndpointInfo. The implementation must ensure that
+ * messages from a given host end point are only provided to the vendor
+ * library explicitly associated with that host end point.
+ * @param config Configuration data in a vendor-defined format.
+ * @param[out] vendorStatusCode Optional vendor-defined status code that will be
+ * returned to the vendor service regardless of the return value of this
+ * function. The value 0 is reserved to indicate that a vendor status code
+ * was not provided or is not relevant. All other values have a vendor-defined
+ * meaning.
+ * @return A value from enum chrexNearbyResult.
+ */
+uint32_t chrexNearbySetExtendedServiceConfig(
+ const struct chreHostEndpointInfo *host_info,
+ const struct chrexNearbyExtendedServiceConfig *config,
+ uint32_t *vendorStatusCode);
+
enum chrexNearbyFilterAction {
//! Ignore/drop this advertising report
CHREX_NEARBY_FILTER_ACTION_IGNORE = 0,
@@ -111,6 +143,7 @@ enum chrexNearbyFilterAction {
* @param report Contains data for a BLE advertisement.
* @return A value from enum chrexNearbyFilterAction.
*/
+// TODO(b/305277310): Pass OEM extension API version to OEM library
uint32_t chrexNearbyMatchExtendedFilter(
const struct chreHostEndpointInfo *host_info,
const struct chreBleAdvertisingReport *report);
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension_support_lib.cc b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension_support_lib.cc
index 2445bd42..62634e32 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension_support_lib.cc
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/nearby_extension_support_lib.cc
@@ -49,6 +49,17 @@ uint32_t chrexNearbySetExtendedFilterConfig(
}
WEAK_SYMBOL
+uint32_t chrexNearbySetExtendedServiceConfig(
+ const struct chreHostEndpointInfo *host_info,
+ const struct chrexNearbyExtendedServiceConfig *config,
+ uint32_t *vendorStatusCode) {
+ auto *fptr = CHRE_NSL_LAZY_LOOKUP(chrexNearbySetExtendedServiceConfig);
+ return (fptr != nullptr)
+ ? fptr(host_info, config, vendorStatusCode)
+ : chrexNearbyResult::CHREX_NEARBY_RESULT_FEATURE_NOT_SUPPORTED;
+}
+
+WEAK_SYMBOL
uint32_t chrexNearbyMatchExtendedFilter(
const struct chreHostEndpointInfo *host_info,
const struct chreBleAdvertisingReport *report) {
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/ble_filter.proto b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/ble_filter.proto
index 0f938c4a..6a9e734d 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/ble_filter.proto
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/ble_filter.proto
@@ -114,6 +114,9 @@ message BleFilterResult {
repeated DataElement data_element = 7;
optional bytes ble_service_data = 8;
optional ResultType result_type = 9;
+ // Timestamp the advertisement was received, in nanoseconds, relative to
+ // Android SystemClock.elapsedRealtimeNanos().
+ optional uint64 timestamp_ns = 10;
}
message BleFilterResults {
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.options b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.options
index 769841b6..b0c8d254 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.options
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.options
@@ -11,11 +11,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-nearby_extension.FilterConfig.oem_filter max_size:512
-nearby_extension.FilterConfig.oem_filter type:FT_INLINE
+nearby_extension.ExtConfigRequest.FilterConfig.oem_filter max_size:800
+nearby_extension.ExtConfigRequest.FilterConfig.oem_filter type:FT_INLINE
-nearby_extension.FilterConfig.hardware_filter max_count:10
-nearby_extension.FilterConfig.hardware_filter type:FT_STATIC
+nearby_extension.ExtConfigRequest.FilterConfig.hardware_filter max_count:10
+nearby_extension.ExtConfigRequest.FilterConfig.hardware_filter type:FT_STATIC
+
+nearby_extension.ExtConfigRequest.ServiceConfig.data max_size:800
+nearby_extension.ExtConfigRequest.ServiceConfig.data type:FT_INLINE
nearby_extension.ChreBleGenericFilter.data max_size:29
nearby_extension.ChreBleGenericFilter.data type:FT_INLINE
@@ -23,13 +26,13 @@ nearby_extension.ChreBleGenericFilter.data type:FT_INLINE
nearby_extension.ChreBleGenericFilter.data_mask max_size:29
nearby_extension.ChreBleGenericFilter.data_mask type:FT_INLINE
-nearby_extension.FilterResult.report max_count:20
+nearby_extension.FilterResult.report max_count:1
nearby_extension.FilterResult.report type:FT_STATIC
nearby_extension.ChreBleAdvertisingReport.address max_size:6
nearby_extension.ChreBleAdvertisingReport.address type:FT_INLINE
-nearby_extension.ChreBleAdvertisingReport.data max_size:29
+nearby_extension.ChreBleAdvertisingReport.data max_size:255
nearby_extension.ChreBleAdvertisingReport.data type:FT_INLINE
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.proto b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.proto
index f289c57f..6be83528 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.proto
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.proto
@@ -21,39 +21,73 @@ package nearby_extension;
option java_package = "com.google.location.lbs.contexthub";
option java_outer_classname = "NearbyOffloadExtension";
-message FilterConfig {
- // Vendor-specific configuration data for extended filter. Byte array opaque
- // to Nearby nanoapp, which will be forwarded through
- // chrexNearbySetExtendedFilterConfig().
- // If the OEM service wishes to send more data than can fit in a single
- // message, or update previous configuration, it can send additional messages.
- optional bytes oem_filter = 1;
- optional uint32 oem_filter_length = 2;
-
- // List of Hardware filters (follows chreBleScanFilter defined in CHRE BLE
- // API). Resource for hardware filters is constrained in CHRE, and hardware
- // filtering is best effort, i.e. advertisements may still be forwarded for
- // inspection if they do not match the configured hardware filters. It is
- // expected that an OEM service will include at least one hardware filter in
- // the first message. Subsequent messages that do not include this field will
- // not impact previously configured filters. But if this field is populated in
- // a subsequent message, its contents will replace any previously set filters.
- // To remove all previously set hardware filters, reset extended filtering by
- // closing the ContextHubClient connection.
- repeated ChreBleGenericFilter hardware_filter = 3;
-
- // Maximum time to batch BLE scan results before processing in the nanoapp, in
- // milliseconds. For optimal power, specify the longest value that the use
- // case permits. If not provided, either the last provided value will continue
- // to be used, or if no previous value was given, defaults defined in the
- // Nearby nanoapp will be used.
- optional uint32 report_delay_ms = 4;
-
- // BLE scan modes identify functional scan levels without specifying or
- // guaranteeing particular scan parameters (e.g. duty cycle, interval, radio
- // chain). The actual scan parameters may be platform dependent and may change
- // without notice in real time based on contextual cues, etc.
- optional ChreBleScanMode scan_mode = 5;
+message ExtConfigRequest {
+ message FilterConfig {
+ // Vendor-specific configuration data for extended filter. Byte array opaque
+ // to Nearby nanoapp, which will be forwarded through
+ // chrexNearbySetExtendedFilterConfig().
+ // If both hardware and oem filters are empty, the scan requested by this
+ // host will stop. Otherwise, the scan will start with the scan filters.
+ // If the OEM service wishes to send more data than can fit in a single
+ // message, or update previous configuration, it can send additional
+ // messages.
+ optional bytes oem_filter = 1;
+ optional uint32 oem_filter_length = 2;
+
+ // List of Hardware filters (follows chreBleScanFilter defined in CHRE BLE
+ // API). Resource for hardware filters is constrained in CHRE, and hardware
+ // filtering is best effort, i.e. advertisements may still be forwarded for
+ // inspection if they do not match the configured hardware filters. It is
+ // expected that an OEM service will include at least one hardware filter in
+ // the first message. Subsequent messages that do not include this field
+ // will not impact previously configured filters. But if this field is
+ // populated in a subsequent message, its contents will replace any
+ // previously set filters. To remove all previously set hardware filters,
+ // reset extended filtering by closing the ContextHubClient connection.
+ repeated ChreBleGenericFilter hardware_filter = 3;
+
+ // Maximum time to batch BLE scan results before processing in the nanoapp,
+ // in milliseconds. For optimal power, specify the longest value that the
+ // use case permits. If not provided, either the last provided value will
+ // continue to be used, or if no previous value was given, defaults defined
+ // in the Nearby nanoapp will be used.
+ optional uint32 report_delay_ms = 4;
+
+ // BLE scan modes identify functional scan levels without specifying or
+ // guaranteeing particular scan parameters (e.g. duty cycle, interval, radio
+ // chain). The actual scan parameters may be platform dependent and may
+ // change without notice in real time based on contextual cues, etc.
+ optional ChreBleScanMode scan_mode = 5;
+
+ // BLE advertising report cache expires after this time period.
+ // The expired reports are descarded and not delivered to the OEM service.
+ optional uint32 cache_expire_ms = 6 [default = 5000];
+ }
+
+ message ServiceConfig {
+ // Vendor-specific configuration data for OEM service. Byte array opaque
+ // to Nearby nanoapp, which will be forwarded through
+ // chrexNearbySetServiceConfig().
+ // If OEM service cannot pass service config data through oem_filter in
+ // FilterConfig, or if OEM service want to pass it at another time, it can
+ // pass the service config data to the OEM library through ServiceConfig.
+ // ServiceConfig is only responsible for passing service config data to the
+ // OEM library, regardless of the LE scan start/stop behavior and
+ // hardware_filter.
+ // If the OEM service wishes to send more data than can fit in a single
+ // message, or update previous configuration, it can send additional
+ // messages.
+ optional bytes data = 1;
+ optional uint32 data_length = 2;
+ }
+
+ // Request ID specified by the client to pair Request/Response messages.
+ optional uint32 request_id = 1;
+
+ oneof config {
+ FilterConfig filter_config = 2;
+ ServiceConfig service_config = 3;
+ }
}
message ChreBleGenericFilter {
@@ -95,13 +129,14 @@ enum ChreBleScanMode {
CHRE_BLE_SCAN_MODE_AGGRESSIVE = 3;
}
-// Sent in response to FilterConfig
-message FilterConfigResult {
- // Value from enum chrexNearbyResult that was returned by
- // chrexNearbySetExtendedFilterConfig()
- optional int32 result = 1;
- // Vendor-defined status code provided in chrexNearbySetExtendedFilterConfig()
- optional uint32 vendor_status = 2;
+// Sent in response to ExtConfigRequest
+message ExtConfigResponse {
+ // Request ID of the corresponding Request message.
+ optional uint32 request_id = 1;
+ // Value from enum chrexNearbyResult that was returned from OEM library.
+ optional int32 result = 2;
+ // Vendor-defined status code provided from OEM library.
+ optional uint32 vendor_status = 3;
}
// Sent when one or more advertisements matched an extended filter
diff --git a/apps/nearby/location/lbs/contexthub/nanoapps/proto/filter.proto b/apps/nearby/location/lbs/contexthub/nanoapps/proto/filter.proto
index f051f54d..34be88e7 100644
--- a/apps/nearby/location/lbs/contexthub/nanoapps/proto/filter.proto
+++ b/apps/nearby/location/lbs/contexthub/nanoapps/proto/filter.proto
@@ -20,6 +20,8 @@ enum FilterMessageType {
MESSAGE_FILTER_RESULTS = 4;
// Config the filtering, including start/stop filtering.
MESSAGE_CONFIG = 5;
- // Message from host to CHRE to set Filter extensions.
- MESSAGE_FILTER_EXTENSIONS = 6;
+ // Message from host to CHRE to request extended configuration.
+ MESSAGE_EXT_CONFIG_REQUEST = 6;
+ // Message from CHRE to host for the response of extended configuration.
+ MESSAGE_EXT_CONFIG_RESPONSE = 7;
}
diff --git a/apps/rpc_world/src/rpc_world_manager.cc b/apps/rpc_world/src/rpc_world_manager.cc
index d658678e..182e0288 100644
--- a/apps/rpc_world/src/rpc_world_manager.cc
+++ b/apps/rpc_world/src/rpc_world_manager.cc
@@ -103,7 +103,7 @@ bool RpcWorldManager::start() {
mAddCall.Write(addRequest);
mAddCall.Write(addRequest);
mAddCall.Write(addRequest);
- mAddCall.CloseClientStream();
+ mAddCall.RequestCompletion();
} else {
LOGE("Error while retrieving the client");
}
@@ -146,6 +146,8 @@ void RpcWorldManager::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
}
void RpcWorldManager::end() {
+ mServer.close();
+ mClient.close();
if (mTimerId != CHRE_TIMER_INVALID) {
chreTimerCancel(mTimerId);
}
@@ -168,7 +170,7 @@ void RpcWorldManager::addStart(
reader.set_on_next([](const chre_rpc_NumberMessage &request) {
RpcWorldManagerSingleton::get()->mSum += request.number;
});
- reader.set_on_client_stream_end([]() {
+ reader.set_on_completion_requested([]() {
chre_rpc_NumberMessage response;
response.number = RpcWorldManagerSingleton::get()->mSum;
RpcWorldManagerSingleton::get()->setPermissionForNextMessage(
diff --git a/apps/test/chqts/src/general_test/basic_ble_test.cc b/apps/test/chqts/src/general_test/basic_ble_test.cc
index 891ad654..4d017220 100644
--- a/apps/test/chqts/src/general_test/basic_ble_test.cc
+++ b/apps/test/chqts/src/general_test/basic_ble_test.cc
@@ -138,6 +138,11 @@ void BasicBleTest::handleTimerEvent() {
}
mFlushWasCalled = true;
} else {
+ if (chreBleFlushAsync(&gFlushCookie)) {
+ sendFatalFailureToHost(
+ "chreBleFlushAsync should return false if batching is not supported");
+ }
+
if (!chreBleStopScanAsync()) {
sendFatalFailureToHost("Failed to stop a BLE scan session");
}
diff --git a/apps/test/chqts/src/general_test/send_event_stress_test.cc b/apps/test/chqts/src/general_test/send_event_stress_test.cc
index 6bc7e631..41e8dfe1 100644
--- a/apps/test/chqts/src/general_test/send_event_stress_test.cc
+++ b/apps/test/chqts/src/general_test/send_event_stress_test.cc
@@ -84,8 +84,12 @@ void SendEventStressTest::setUp(uint32_t messageSize,
sendFatalFailureToHost("Insufficient events available");
}
- // sCompleteCallbacksLeft may be 0 or 1 at this point. We don't care.
- // We just know we also expect all the sEventsLeft to have callbacks.
+ // If kMaxEventsToSend events are sent, we need to reset
+ // sCompleteCallbacksLeft because we only expect at most sEventsLeft to have
+ // callbacks.
+ if (sEventsLeft == kMaxEventsToSend) {
+ sCompleteCallbacksLeft = 0;
+ }
sCompleteCallbacksLeft += sEventsLeft;
sInMethod = false;
diff --git a/apps/test/common/chre_api_test/chre_api_test.mk b/apps/test/common/chre_api_test/chre_api_test.mk
index 5f8559fb..c9ad8c29 100644
--- a/apps/test/common/chre_api_test/chre_api_test.mk
+++ b/apps/test/common/chre_api_test/chre_api_test.mk
@@ -25,6 +25,7 @@ COMMON_SRCS += $(NANOAPP_PATH)/src/chre_api_test.cc
# Utilities ####################################################################
COMMON_SRCS += $(CHRE_PREFIX)/util/nanoapp/ble.cc
+COMMON_SRCS += $(CHRE_PREFIX)/util/nanoapp/string.cc
# Compiler Flags ###############################################################
@@ -44,3 +45,4 @@ CHRE_NANOAPP_USES_BLE = true
# PW RPC protos ################################################################
PW_RPC_SRCS = $(NANOAPP_PATH)/rpc/chre_api_test.proto
+PW_RPC_SRCS += $(ANDROID_BUILD_TOP)/external/protobuf/src/google/protobuf/empty.proto
diff --git a/apps/test/common/chre_api_test/inc/chre_api_test_manager.h b/apps/test/common/chre_api_test/inc/chre_api_test_manager.h
index 8380e8ae..0e4543b3 100644
--- a/apps/test/common/chre_api_test/inc/chre_api_test_manager.h
+++ b/apps/test/common/chre_api_test/inc/chre_api_test_manager.h
@@ -38,29 +38,16 @@ class ChreApiTestService final
/**
* Returns the BLE capabilities.
*/
- pw::Status ChreBleGetCapabilities(const chre_rpc_Void &request,
+ pw::Status ChreBleGetCapabilities(const google_protobuf_Empty &request,
chre_rpc_Capabilities &response);
/**
* Returns the BLE filter capabilities.
*/
- pw::Status ChreBleGetFilterCapabilities(const chre_rpc_Void &request,
+ pw::Status ChreBleGetFilterCapabilities(const google_protobuf_Empty &request,
chre_rpc_Capabilities &response);
/**
- * Starts a BLE scan.
- */
- pw::Status ChreBleStartScanAsync(
- const chre_rpc_ChreBleStartScanAsyncInput &request,
- chre_rpc_Status &response);
-
- /**
- * Stops a BLE scan.
- */
- pw::Status ChreBleStopScanAsync(const chre_rpc_Void &request,
- chre_rpc_Status &response);
-
- /**
* Finds the default sensor and returns the handle in the output.
*/
pw::Status ChreSensorFindDefault(
@@ -108,13 +95,6 @@ class ChreApiTestService final
chre_rpc_Status &response);
/**
- * Retrieve the last host endpoint notification.
- */
- pw::Status RetrieveLatestDisconnectedHostEndpointEvent(
- const chre_rpc_Void &request,
- chre_rpc_RetrieveLatestDisconnectedHostEndpointEventOutput &response);
-
- /**
* Gets the host endpoint info for a given host endpoint id.
*/
pw::Status ChreGetHostEndpointInfo(
@@ -132,7 +112,7 @@ class ChreApiTestService final
* Stops a BLE scan synchronously. Waits for the CHRE_EVENT_BLE_ASYNC_RESULT
* event.
*/
- void ChreBleStopScanSync(const chre_rpc_Void &request,
+ void ChreBleStopScanSync(const google_protobuf_Empty &request,
ServerWriter<chre_rpc_GeneralSyncMessage> &writer);
/**
@@ -174,16 +154,6 @@ class ChreApiTestService final
private:
/**
- * Copies a string from source to destination up to the length of the source
- * or the max value. Pads with null characters.
- *
- * @param destination the destination string.
- * @param source the source string.
- * @param maxChars the maximum number of chars.
- */
- void copyString(char *destination, const char *source, size_t maxChars);
-
- /**
* Sets the synchronous timeout timer for the active sync message.
*
* @return if the operation was successful.
@@ -200,17 +170,17 @@ class ChreApiTestService final
* false otherwise.
*/
bool validateInputAndCallChreBleGetCapabilities(
- const chre_rpc_Void &request, chre_rpc_Capabilities &response);
+ const google_protobuf_Empty &request, chre_rpc_Capabilities &response);
bool validateInputAndCallChreBleGetFilterCapabilities(
- const chre_rpc_Void &request, chre_rpc_Capabilities &response);
+ const google_protobuf_Empty &request, chre_rpc_Capabilities &response);
bool validateInputAndCallChreBleStartScanAsync(
const chre_rpc_ChreBleStartScanAsyncInput &request,
chre_rpc_Status &response);
- bool validateInputAndCallChreBleStopScanAsync(const chre_rpc_Void &request,
- chre_rpc_Status &response);
+ bool validateInputAndCallChreBleStopScanAsync(
+ const google_protobuf_Empty &request, chre_rpc_Status &response);
bool validateInputAndCallChreSensorFindDefault(
const chre_rpc_ChreSensorFindDefaultInput &request,
@@ -240,14 +210,24 @@ class ChreApiTestService final
const chre_rpc_ChreConfigureHostEndpointNotificationsInput &request,
chre_rpc_Status &response);
- bool validateInputAndRetrieveLatestDisconnectedHostEndpointEvent(
- const chre_rpc_Void &request,
- chre_rpc_RetrieveLatestDisconnectedHostEndpointEventOutput &response);
-
bool validateInputAndCallChreGetHostEndpointInfo(
const chre_rpc_ChreGetHostEndpointInfoInput &request,
chre_rpc_ChreGetHostEndpointInfoOutput &response);
+ /**
+ * Validates the BLE scan filters and creates a generic filter in the
+ * outputScanFilters array. scanFilters and outputScanFilters must be of size
+ * scanFilterCount or greater.
+ *
+ * @param scanFilters the input scan filters.
+ * @param outputScanFilters the output scan filters.
+ * @param scanFilterCount the number of scan filters.
+ * @return whether the validation was successful.
+ */
+ bool validateBleScanFilters(const chre_rpc_ChreBleGenericFilter *scanFilters,
+ chreBleGenericFilter *outputScanFilters,
+ uint32_t scanFilterCount);
+
constexpr static uint32_t kMaxNumEventTypes =
10; // declared in chre_api_test.options
@@ -259,12 +239,6 @@ class ChreApiTestService final
uint32_t mSyncTimerHandle = CHRE_TIMER_INVALID;
uint8_t mRequestType;
- /**
- * Variables to store disconnected host endpoint notification.
- */
- uint32_t mReceivedHostEndpointDisconnectedNum = 0;
- chreHostEndpointNotification mLatestHostEndpointNotification;
-
/*
* Variables to control synchronization for sync events calls.
* Only one sync event call may be made at a time.
diff --git a/apps/test/common/chre_api_test/rpc/chre_api_test.options b/apps/test/common/chre_api_test/rpc/chre_api_test.options
index 6ec7e7c8..6c3bc2c8 100644
--- a/apps/test/common/chre_api_test/rpc/chre_api_test.options
+++ b/apps/test/common/chre_api_test/rpc/chre_api_test.options
@@ -7,3 +7,7 @@ chre.rpc.ChreGetHostEndpointInfoOutput.endpointName max_size:51 # CHRE_MAX_ENDPO
chre.rpc.ChreGetHostEndpointInfoOutput.endpointTag max_size:51 # CHRE_MAX_ENDPOINT_TAG_LEN
chre.rpc.ChreSensorThreeAxisData.readings max_count:10
chre.rpc.GatherEventsInput.eventTypes max_count:10
+chre.rpc.ChreBleAdvertisingReport.address max_size:6 # CHRE_BLE_ADDRESS_LEN
+chre.rpc.ChreBleAdvertisingReport.directAddress max_size:6 # CHRE_BLE_ADDRESS_LEN
+chre.rpc.ChreBleAdvertisingReport.data max_size:255 # extended range is [0, 255]
+chre.rpc.ChreBleAdvertisementEvent.reports max_count:10
diff --git a/apps/test/common/chre_api_test/rpc/chre_api_test.proto b/apps/test/common/chre_api_test/rpc/chre_api_test.proto
index 57b7dbc2..54c716ea 100644
--- a/apps/test/common/chre_api_test/rpc/chre_api_test.proto
+++ b/apps/test/common/chre_api_test/rpc/chre_api_test.proto
@@ -2,26 +2,17 @@ syntax = "proto3";
package chre.rpc;
+import "google/protobuf/empty.proto";
+
option java_package = "dev.chre.rpc.proto";
service ChreApiTestService {
// Returns the BLE capabilities.
- rpc ChreBleGetCapabilities(Void) returns (Capabilities) {}
+ rpc ChreBleGetCapabilities(google.protobuf.Empty) returns (Capabilities) {}
// Returns the BLE filter capabilities.
- rpc ChreBleGetFilterCapabilities(Void) returns (Capabilities) {}
-
- /* Starts a BLE scan asynchronously. This will not wait for the
- * event but will return success if the chreBleStartScanAsync
- * function returns success.
- */
- rpc ChreBleStartScanAsync(ChreBleStartScanAsyncInput) returns (Status) {}
-
- /* Stops a BLE scan asynchronously. This will not wait for the
- * event but will return success if the chreBleStopScanAsync
- * function returns success.
- */
- rpc ChreBleStopScanAsync(Void) returns (Status) {}
+ rpc ChreBleGetFilterCapabilities(google.protobuf.Empty)
+ returns (Capabilities) {}
// Finds the default sensor for the given sensor type.
rpc ChreSensorFindDefault(ChreSensorFindDefaultInput)
@@ -49,12 +40,6 @@ service ChreApiTestService {
rpc ChreConfigureHostEndpointNotifications(
ChreConfigureHostEndpointNotificationsInput) returns (Status) {}
- // TODO(b/274791978): Deprecate this once we can capture event
- // Retrieves the latest disconnected host endpoint event and the number of
- // disconnect event received.
- rpc RetrieveLatestDisconnectedHostEndpointEvent(Void)
- returns (RetrieveLatestDisconnectedHostEndpointEventOutput) {}
-
// Gets the host endpoint info for a given host endpoint id.
rpc ChreGetHostEndpointInfo(ChreGetHostEndpointInfoInput)
returns (ChreGetHostEndpointInfoOutput) {}
@@ -74,7 +59,8 @@ service ChreApiTestService {
* function returns success and the event is seen. This will
* return the event's success field.
*/
- rpc ChreBleStopScanSync(Void) returns (stream GeneralSyncMessage) {}
+ rpc ChreBleStopScanSync(google.protobuf.Empty)
+ returns (stream GeneralSyncMessage) {}
// Returns events that match the eventType filter
rpc GatherEvents(GatherEventsInput) returns (stream GeneralEventsMessage) {}
@@ -82,9 +68,6 @@ service ChreApiTestService {
// General messages
-// Empty message (void)
-message Void {}
-
// Contains a capabilities uint32
message Capabilities {
uint32 capabilities = 1;
@@ -110,7 +93,9 @@ message GeneralSyncMessage {
// Contains event filters for gathering events
message GatherEventsInput {
repeated uint32 eventTypes = 1;
- uint32 eventTypeCount = 2;
+
+ // Deprecated: We use the built-in count variable now
+ uint32 eventTypeCount = 2 [deprecated = true];
uint32 eventCount = 3;
uint64 timeoutInNs = 4;
}
@@ -122,6 +107,8 @@ message GeneralEventsMessage {
oneof data {
ChreSensorThreeAxisData chreSensorThreeAxisData = 2;
ChreSensorSamplingStatusEvent chreSensorSamplingStatusEvent = 3;
+ ChreHostEndpointNotification chreHostEndpointNotification = 4;
+ ChreBleAdvertisementEvent chreBleAdvertisementEvent = 5;
}
}
@@ -153,7 +140,7 @@ message ChreSensorDataHeader {
uint32 reserved = 5;
}
-// Individual sample data for a three-axis sensor.
+// Individual sample data for a three-axis sensor
message ChreSensorThreeAxisSampleData {
uint32 timestampDelta = 1;
float x = 2;
@@ -161,6 +148,30 @@ message ChreSensorThreeAxisSampleData {
float z = 4;
}
+// A BLE advertising event
+message ChreBleAdvertisementEvent {
+ uint32 reserved = 1;
+ repeated ChreBleAdvertisingReport reports = 2;
+}
+
+// A BLE advertising report
+message ChreBleAdvertisingReport {
+ uint64 timestamp = 1;
+ uint32 eventTypeAndDataStatus = 2;
+ uint32 addressType = 3;
+ bytes address = 4;
+ uint32 primaryPhy = 5;
+ uint32 secondaryPhy = 6;
+ uint32 advertisingSid = 7;
+ int32 txPower = 8;
+ uint32 periodicAdvertisingInterval = 9;
+ int32 rssi = 10;
+ uint32 directAddressType = 11;
+ bytes directAddress = 12;
+ bytes data = 13;
+ uint32 reserved = 14;
+}
+
// Function specific messages
// Input value for ChreSensorFindDefault
@@ -181,6 +192,11 @@ message RetrieveLatestDisconnectedHostEndpointEventOutput {
uint32 hostEndpointId = 2;
}
+message ChreHostEndpointNotification {
+ uint32 hostEndpointId = 1;
+ uint32 notificationType = 2;
+}
+
// Input value for ChreGetHostEndpointInfo
message ChreGetHostEndpointInfoInput {
uint32 hostEndpointId = 1;
@@ -271,7 +287,9 @@ message ChreBleGenericFilter {
// Scan filter for BLE scanning
message ChreBleScanFilter {
int32 rssiThreshold = 1;
- uint32 scanFilterCount = 2;
+
+ // Deprecated: We use the built-in count variable now
+ uint32 scanFilterCount = 2 [deprecated = true];
repeated ChreBleGenericFilter scanFilters = 3;
}
diff --git a/apps/test/common/chre_api_test/src/chre_api_test_manager.cc b/apps/test/common/chre_api_test/src/chre_api_test_manager.cc
index 3e4a38fb..695255dc 100644
--- a/apps/test/common/chre_api_test/src/chre_api_test_manager.cc
+++ b/apps/test/common/chre_api_test/src/chre_api_test_manager.cc
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <algorithm>
+
#include "chre_api_test_manager.h"
#include "chre.h"
@@ -27,6 +29,7 @@ constexpr uint64_t kSyncFunctionTimeout = 2 * chre::kOneSecondInNanoseconds;
* The following constants are defined in chre_api_test.options.
*/
constexpr uint32_t kThreeAxisDataReadingsMaxCount = 10;
+constexpr uint32_t kChreBleAdvertisementReportMaxCount = 10;
/**
* Closes the writer and invalidates the writer.
@@ -86,7 +89,7 @@ void sendFailureAndFinishCloseWriter(
// Start ChreApiTestService RPC generated functions
pw::Status ChreApiTestService::ChreBleGetCapabilities(
- const chre_rpc_Void &request, chre_rpc_Capabilities &response) {
+ const google_protobuf_Empty &request, chre_rpc_Capabilities &response) {
ChreApiTestManagerSingleton::get()->setPermissionForNextMessage(
CHRE_MESSAGE_PERMISSION_NONE);
return validateInputAndCallChreBleGetCapabilities(request, response)
@@ -95,7 +98,7 @@ pw::Status ChreApiTestService::ChreBleGetCapabilities(
}
pw::Status ChreApiTestService::ChreBleGetFilterCapabilities(
- const chre_rpc_Void &request, chre_rpc_Capabilities &response) {
+ const google_protobuf_Empty &request, chre_rpc_Capabilities &response) {
ChreApiTestManagerSingleton::get()->setPermissionForNextMessage(
CHRE_MESSAGE_PERMISSION_NONE);
return validateInputAndCallChreBleGetFilterCapabilities(request, response)
@@ -103,25 +106,6 @@ pw::Status ChreApiTestService::ChreBleGetFilterCapabilities(
: pw::Status::InvalidArgument();
}
-pw::Status ChreApiTestService::ChreBleStartScanAsync(
- const chre_rpc_ChreBleStartScanAsyncInput &request,
- chre_rpc_Status &response) {
- ChreApiTestManagerSingleton::get()->setPermissionForNextMessage(
- CHRE_MESSAGE_PERMISSION_NONE);
- return validateInputAndCallChreBleStartScanAsync(request, response)
- ? pw::OkStatus()
- : pw::Status::InvalidArgument();
-}
-
-pw::Status ChreApiTestService::ChreBleStopScanAsync(
- const chre_rpc_Void &request, chre_rpc_Status &response) {
- ChreApiTestManagerSingleton::get()->setPermissionForNextMessage(
- CHRE_MESSAGE_PERMISSION_NONE);
- return validateInputAndCallChreBleStopScanAsync(request, response)
- ? pw::OkStatus()
- : pw::Status::InvalidArgument();
-}
-
pw::Status ChreApiTestService::ChreSensorFindDefault(
const chre_rpc_ChreSensorFindDefaultInput &request,
chre_rpc_ChreSensorFindDefaultOutput &response) {
@@ -193,17 +177,6 @@ pw::Status ChreApiTestService::ChreConfigureHostEndpointNotifications(
: pw::Status::InvalidArgument();
}
-pw::Status ChreApiTestService::RetrieveLatestDisconnectedHostEndpointEvent(
- const chre_rpc_Void &request,
- chre_rpc_RetrieveLatestDisconnectedHostEndpointEventOutput &response) {
- ChreApiTestManagerSingleton::get()->setPermissionForNextMessage(
- CHRE_MESSAGE_PERMISSION_NONE);
- return validateInputAndRetrieveLatestDisconnectedHostEndpointEvent(request,
- response)
- ? pw::OkStatus()
- : pw::Status::InvalidArgument();
-}
-
pw::Status ChreApiTestService::ChreGetHostEndpointInfo(
const chre_rpc_ChreGetHostEndpointInfoInput &request,
chre_rpc_ChreGetHostEndpointInfoOutput &response) {
@@ -243,7 +216,7 @@ void ChreApiTestService::ChreBleStartScanSync(
}
void ChreApiTestService::ChreBleStopScanSync(
- const chre_rpc_Void &request,
+ const google_protobuf_Empty &request,
ServerWriter<chre_rpc_GeneralSyncMessage> &writer) {
if (mWriter.has_value()) {
ChreApiTestManagerSingleton::get()->setPermissionForNextMessage(
@@ -281,26 +254,18 @@ void ChreApiTestService::GatherEvents(
return;
}
- if (request.eventTypeCount > kMaxNumEventTypes) {
- LOGE("GatherEvents: request.eventTypeCount is out of bounds");
- ChreApiTestManagerSingleton::get()->setPermissionForNextMessage(
- CHRE_MESSAGE_PERMISSION_NONE);
- writer.Finish();
- return;
- }
-
- if (request.eventTypeCount == 0) {
- LOGE("GatherEvents: request.eventTypeCount == 0");
+ if (request.eventTypes_count == 0) {
+ LOGE("GatherEvents: request.eventTypes_count == 0");
ChreApiTestManagerSingleton::get()->setPermissionForNextMessage(
CHRE_MESSAGE_PERMISSION_NONE);
writer.Finish();
return;
}
- for (uint32_t i = 0; i < request.eventTypeCount; ++i) {
+ for (uint32_t i = 0; i < request.eventTypes_count; ++i) {
if (request.eventTypes[i] < std::numeric_limits<uint16_t>::min() ||
request.eventTypes[i] > std::numeric_limits<uint16_t>::max()) {
- LOGE("GatherEvents: invalid request.eventTypes: i: %" PRIu32, i);
+ LOGE("GatherEvents: invalid request.eventTypes at index: %" PRIu32, i);
ChreApiTestManagerSingleton::get()->setPermissionForNextMessage(
CHRE_MESSAGE_PERMISSION_NONE);
writer.Finish();
@@ -321,7 +286,7 @@ void ChreApiTestService::GatherEvents(
sendFailureAndFinishCloseWriter(mEventWriter);
mEventTimerHandle = CHRE_TIMER_INVALID;
} else {
- mEventTypeCount = request.eventTypeCount;
+ mEventTypeCount = request.eventTypes_count;
mEventExpectedCount = request.eventCount;
mEventSentCount = 0;
LOGD("GatherEvents: mEventTypeCount: %" PRIu32
@@ -379,7 +344,7 @@ void ChreApiTestService::handleGatheringEvent(uint16_t eventType,
message.which_data =
chre_rpc_GeneralEventsMessage_chreSensorThreeAxisData_tag;
- const struct chreSensorThreeAxisData *data =
+ const auto *data =
static_cast<const struct chreSensorThreeAxisData *>(eventData);
message.data.chreSensorThreeAxisData.header.baseTimestamp =
data->header.baseTimestamp;
@@ -408,7 +373,7 @@ void ChreApiTestService::handleGatheringEvent(uint16_t eventType,
break;
}
case CHRE_EVENT_SENSOR_SAMPLING_CHANGE: {
- const struct chreSensorSamplingStatusEvent *data =
+ const auto *data =
static_cast<const struct chreSensorSamplingStatusEvent *>(eventData);
message.data.chreSensorSamplingStatusEvent.sensorHandle =
data->sensorHandle;
@@ -424,6 +389,78 @@ void ChreApiTestService::handleGatheringEvent(uint16_t eventType,
chre_rpc_GeneralEventsMessage_chreSensorSamplingStatusEvent_tag;
break;
}
+ case CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION: {
+ const auto *data =
+ static_cast<const struct chreHostEndpointNotification *>(eventData);
+ message.data.chreHostEndpointNotification.hostEndpointId =
+ data->hostEndpointId;
+ message.data.chreHostEndpointNotification.notificationType =
+ data->notificationType;
+
+ message.status = true;
+ message.which_data =
+ chre_rpc_GeneralEventsMessage_chreHostEndpointNotification_tag;
+ break;
+ }
+ case CHRE_EVENT_BLE_ADVERTISEMENT: {
+ const auto *data =
+ static_cast<const struct chreBleAdvertisementEvent *>(eventData);
+ message.data.chreBleAdvertisementEvent.reserved = data->reserved;
+
+ uint32_t numReports =
+ MIN(kChreBleAdvertisementReportMaxCount, data->numReports);
+ message.data.chreBleAdvertisementEvent.reports_count = numReports;
+ for (uint32_t i = 0; i < numReports; ++i) {
+ message.data.chreBleAdvertisementEvent.reports[i].timestamp =
+ data->reports[i].timestamp;
+ message.data.chreBleAdvertisementEvent.reports[i]
+ .eventTypeAndDataStatus = data->reports[i].eventTypeAndDataStatus;
+ message.data.chreBleAdvertisementEvent.reports[i].addressType =
+ data->reports[i].addressType;
+
+ message.data.chreBleAdvertisementEvent.reports[i].address.size =
+ CHRE_BLE_ADDRESS_LEN;
+ std::memcpy(
+ message.data.chreBleAdvertisementEvent.reports[i].address.bytes,
+ data->reports[i].address, CHRE_BLE_ADDRESS_LEN);
+
+ message.data.chreBleAdvertisementEvent.reports[i].primaryPhy =
+ data->reports[i].primaryPhy;
+ message.data.chreBleAdvertisementEvent.reports[i].secondaryPhy =
+ data->reports[i].secondaryPhy;
+ message.data.chreBleAdvertisementEvent.reports[i].advertisingSid =
+ data->reports[i].advertisingSid;
+ message.data.chreBleAdvertisementEvent.reports[i].txPower =
+ data->reports[i].txPower;
+ message.data.chreBleAdvertisementEvent.reports[i]
+ .periodicAdvertisingInterval =
+ data->reports[i].periodicAdvertisingInterval;
+ message.data.chreBleAdvertisementEvent.reports[i].rssi =
+ data->reports[i].rssi;
+ message.data.chreBleAdvertisementEvent.reports[i].directAddressType =
+ data->reports[i].directAddressType;
+
+ message.data.chreBleAdvertisementEvent.reports[i].directAddress.size =
+ CHRE_BLE_ADDRESS_LEN;
+ std::memcpy(message.data.chreBleAdvertisementEvent.reports[i]
+ .directAddress.bytes,
+ data->reports[i].directAddress, CHRE_BLE_ADDRESS_LEN);
+
+ message.data.chreBleAdvertisementEvent.reports[i].data.size =
+ data->reports[i].dataLength;
+ std::memcpy(
+ message.data.chreBleAdvertisementEvent.reports[i].data.bytes,
+ data->reports[i].data, data->reports[i].dataLength);
+
+ message.data.chreBleAdvertisementEvent.reports[i].reserved =
+ data->reports[i].reserved;
+ }
+
+ message.status = true;
+ message.which_data =
+ chre_rpc_GeneralEventsMessage_chreBleAdvertisementEvent_tag;
+ break;
+ }
default: {
LOGE("GatherEvents: event type: %" PRIu16 " not implemented", eventType);
}
@@ -461,34 +498,6 @@ void ChreApiTestService::handleTimerEvent(const void *cookie) {
}
}
-void ChreApiTestService::handleHostEndpointNotificationEvent(
- const chreHostEndpointNotification *data) {
- if (data->notificationType != HOST_ENDPOINT_NOTIFICATION_TYPE_DISCONNECT) {
- LOGW("Received non disconnected event");
- return;
- }
-
- ++mReceivedHostEndpointDisconnectedNum;
- mLatestHostEndpointNotification = *data;
-}
-
-void ChreApiTestService::copyString(char *destination, const char *source,
- size_t maxChars) {
- CHRE_ASSERT_NOT_NULL(destination);
- CHRE_ASSERT_NOT_NULL(source);
-
- if (maxChars == 0) {
- return;
- }
-
- uint32_t i;
- for (i = 0; i < maxChars - 1 && source[i] != '\0'; ++i) {
- destination[i] = source[i];
- }
-
- memset(&destination[i], 0, maxChars - i);
-}
-
bool ChreApiTestService::startSyncTimer() {
mSyncTimerHandle = chreTimerSet(
kSyncFunctionTimeout, &mSyncTimerHandle /* cookie */, true /* oneShot */);
@@ -510,7 +519,7 @@ bool ChreApiTestManager::start() {
}
void ChreApiTestManager::end() {
- // do nothing
+ mServer.close();
}
void ChreApiTestManager::handleEvent(uint32_t senderInstanceId,
@@ -530,10 +539,6 @@ void ChreApiTestManager::handleEvent(uint32_t senderInstanceId,
case CHRE_EVENT_TIMER:
mChreApiTestService.handleTimerEvent(eventData);
break;
- case CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION:
- mChreApiTestService.handleHostEndpointNotificationEvent(
- static_cast<const chreHostEndpointNotification *>(eventData));
- break;
default: {
// ignore
}
diff --git a/apps/test/common/chre_api_test/src/chre_api_test_service.cc b/apps/test/common/chre_api_test/src/chre_api_test_service.cc
index b045551e..56a3402f 100644
--- a/apps/test/common/chre_api_test/src/chre_api_test_service.cc
+++ b/apps/test/common/chre_api_test/src/chre_api_test_service.cc
@@ -18,7 +18,9 @@
#include "chre/util/nanoapp/ble.h"
#include "chre/util/nanoapp/log.h"
+#include "chre/util/nanoapp/string.h"
+using ::chre::copyString;
using ::chre::createBleGenericFilter;
namespace {
@@ -26,19 +28,22 @@ namespace {
/**
* The following constants are defined in chre_api_test.options.
*/
-constexpr uint32_t kMaxBleScanFilters = 10;
-constexpr uint32_t kMaxNameStringSize = 100;
+constexpr size_t kMaxNameStringBufferSize = 100;
+constexpr size_t kMaxHostEndpointNameBufferSize = 51;
+constexpr size_t kMaxHostEndpointTagBufferSize = 51;
} // namespace
bool ChreApiTestService::validateInputAndCallChreBleGetCapabilities(
- const chre_rpc_Void & /* request */, chre_rpc_Capabilities &response) {
+ const google_protobuf_Empty & /* request */,
+ chre_rpc_Capabilities &response) {
response.capabilities = chreBleGetCapabilities();
LOGD("ChreBleGetCapabilities: capabilities: %" PRIu32, response.capabilities);
return true;
}
bool ChreApiTestService::validateInputAndCallChreBleGetFilterCapabilities(
- const chre_rpc_Void & /* request */, chre_rpc_Capabilities &response) {
+ const google_protobuf_Empty & /* request */,
+ chre_rpc_Capabilities &response) {
response.capabilities = chreBleGetFilterCapabilities();
LOGD("ChreBleGetFilterCapabilities: capabilities: %" PRIu32,
response.capabilities);
@@ -48,13 +53,15 @@ bool ChreApiTestService::validateInputAndCallChreBleGetFilterCapabilities(
bool ChreApiTestService::validateInputAndCallChreBleStartScanAsync(
const chre_rpc_ChreBleStartScanAsyncInput &request,
chre_rpc_Status &response) {
- bool success = false;
if (request.mode < _chre_rpc_ChreBleScanMode_MIN ||
request.mode > _chre_rpc_ChreBleScanMode_MAX ||
request.mode == chre_rpc_ChreBleScanMode_INVALID) {
LOGE("ChreBleStartScanAsync: invalid mode");
- } else if (!request.hasFilter) {
- chreBleScanMode mode = static_cast<chreBleScanMode>(request.mode);
+ return false;
+ }
+
+ if (!request.hasFilter) {
+ auto mode = static_cast<chreBleScanMode>(request.mode);
response.status =
chreBleStartScanAsync(mode, request.reportDelayMs, nullptr);
@@ -65,68 +72,47 @@ bool ChreApiTestService::validateInputAndCallChreBleStartScanAsync(
: (mode == CHRE_BLE_SCAN_MODE_FOREGROUND ? "foreground"
: "aggressive"),
request.reportDelayMs, response.status ? "true" : "false");
- success = true;
- } else if (request.filter.rssiThreshold <
- std::numeric_limits<int8_t>::min() ||
- request.filter.rssiThreshold >
- std::numeric_limits<int8_t>::max()) {
+ return true;
+ }
+
+ if (request.filter.rssiThreshold < std::numeric_limits<int8_t>::min() ||
+ request.filter.rssiThreshold > std::numeric_limits<int8_t>::max()) {
LOGE("ChreBleStartScanAsync: invalid filter.rssiThreshold");
- } else if (request.filter.scanFilterCount == 0 ||
- request.filter.scanFilterCount > kMaxBleScanFilters) {
- LOGE("ChreBleStartScanAsync: invalid filter.scanFilterCount");
- } else {
- chreBleGenericFilter genericFilters[request.filter.scanFilterCount];
- bool validateFiltersSuccess = true;
- for (uint32_t i = 0;
- validateFiltersSuccess && i < request.filter.scanFilterCount; ++i) {
- const chre_rpc_ChreBleGenericFilter &scanFilter =
- request.filter.scanFilters[i];
- if (scanFilter.type > std::numeric_limits<uint8_t>::max() ||
- scanFilter.length > std::numeric_limits<uint8_t>::max()) {
- LOGE(
- "ChreBleStartScanAsync: invalid request.filter.scanFilters member: "
- "type: %" PRIu32 " or length: %" PRIu32,
- scanFilter.type, scanFilter.length);
- validateFiltersSuccess = false;
- } else if (scanFilter.data.size < scanFilter.length ||
- scanFilter.mask.size < scanFilter.length) {
- LOGE(
- "ChreBleStartScanAsync: invalid request.filter.scanFilters member: "
- "data or mask size");
- validateFiltersSuccess = false;
- } else {
- genericFilters[i] = createBleGenericFilter(
- scanFilter.type, scanFilter.length, scanFilter.data.bytes,
- scanFilter.mask.bytes);
- }
- }
+ return false;
+ }
- if (validateFiltersSuccess) {
- struct chreBleScanFilter filter;
- filter.rssiThreshold = request.filter.rssiThreshold;
- filter.scanFilterCount = request.filter.scanFilterCount;
- filter.scanFilters = genericFilters;
-
- chreBleScanMode mode = static_cast<chreBleScanMode>(request.mode);
- response.status =
- chreBleStartScanAsync(mode, request.reportDelayMs, &filter);
-
- LOGD("ChreBleStartScanAsync: mode: %s, reportDelayMs: %" PRIu32
- ", scanFilterCount: %" PRIu32 ", status: %s",
- mode == CHRE_BLE_SCAN_MODE_BACKGROUND
- ? "background"
- : (mode == CHRE_BLE_SCAN_MODE_FOREGROUND ? "foreground"
- : "aggressive"),
- request.reportDelayMs, request.filter.scanFilterCount,
- response.status ? "true" : "false");
- success = true;
- }
+ if (request.filter.scanFilters_count == 0) {
+ LOGE("ChreBleStartScanAsync: invalid filter.scanFilters_count");
+ return false;
+ }
+
+ chreBleGenericFilter genericFilters[request.filter.scanFilters_count];
+ if (!validateBleScanFilters(request.filter.scanFilters, genericFilters,
+ request.filter.scanFilters_count)) {
+ return false;
}
- return success;
+
+ struct chreBleScanFilter filter;
+ filter.rssiThreshold = request.filter.rssiThreshold;
+ filter.scanFilterCount = request.filter.scanFilters_count;
+ filter.scanFilters = genericFilters;
+
+ auto mode = static_cast<chreBleScanMode>(request.mode);
+ response.status = chreBleStartScanAsync(mode, request.reportDelayMs, &filter);
+
+ LOGD("ChreBleStartScanAsync: mode: %s, reportDelayMs: %" PRIu32
+ ", scanFilterCount: %" PRIu16 ", status: %s",
+ mode == CHRE_BLE_SCAN_MODE_BACKGROUND
+ ? "background"
+ : (mode == CHRE_BLE_SCAN_MODE_FOREGROUND ? "foreground"
+ : "aggressive"),
+ request.reportDelayMs, request.filter.scanFilters_count,
+ response.status ? "true" : "false");
+ return true;
}
bool ChreApiTestService::validateInputAndCallChreBleStopScanAsync(
- const chre_rpc_Void & /* request */, chre_rpc_Status &response) {
+ const google_protobuf_Empty & /* request */, chre_rpc_Status &response) {
response.status = chreBleStopScanAsync();
LOGD("ChreBleStopScanAsync: status: %s", response.status ? "true" : "false");
return true;
@@ -139,7 +125,7 @@ bool ChreApiTestService::validateInputAndCallChreSensorFindDefault(
return false;
}
- uint8_t sensorType = (uint8_t)request.sensorType;
+ auto sensorType = static_cast<uint8_t>(request.sensorType);
response.foundSensor =
chreSensorFindDefault(sensorType, &response.sensorHandle);
@@ -157,7 +143,8 @@ bool ChreApiTestService::validateInputAndCallChreGetSensorInfo(
response.status = chreGetSensorInfo(request.handle, &sensorInfo);
if (response.status) {
- copyString(response.sensorName, sensorInfo.sensorName, kMaxNameStringSize);
+ copyString(response.sensorName, sensorInfo.sensorName,
+ kMaxNameStringBufferSize);
response.sensorType = sensorInfo.sensorType;
response.isOnChange = sensorInfo.isOnChange;
response.isOneShot = sensorInfo.isOneShot;
@@ -210,8 +197,7 @@ bool ChreApiTestService::validateInputAndCallChreGetSensorSamplingStatus(
bool ChreApiTestService::validateInputAndCallChreSensorConfigure(
const chre_rpc_ChreSensorConfigureInput &request,
chre_rpc_Status &response) {
- chreSensorConfigureMode mode =
- static_cast<chreSensorConfigureMode>(request.mode);
+ auto mode = static_cast<chreSensorConfigureMode>(request.mode);
response.status = chreSensorConfigure(request.sensorHandle, mode,
request.interval, request.latency);
@@ -222,8 +208,7 @@ bool ChreApiTestService::validateInputAndCallChreSensorConfigure(
bool ChreApiTestService::validateInputAndCallChreSensorConfigureModeOnly(
const chre_rpc_ChreSensorConfigureModeOnlyInput &request,
chre_rpc_Status &response) {
- chreSensorConfigureMode mode =
- static_cast<chreSensorConfigureMode>(request.mode);
+ auto mode = static_cast<chreSensorConfigureMode>(request.mode);
response.status = chreSensorConfigureModeOnly(request.sensorHandle, mode);
LOGD("ChreSensorConfigureModeOnly: status: %s",
@@ -239,7 +224,7 @@ bool ChreApiTestService::validateInputAndCallChreAudioGetSource(
response.status = chreAudioGetSource(request.handle, &audioSource);
if (response.status) {
- copyString(response.name, audioSource.name, kMaxNameStringSize);
+ copyString(response.name, audioSource.name, kMaxNameStringBufferSize);
response.sampleRate = audioSource.sampleRate;
response.minBufferDuration = audioSource.minBufferDuration;
response.maxBufferDuration = audioSource.maxBufferDuration;
@@ -273,15 +258,6 @@ bool ChreApiTestService::
return true;
}
-bool ChreApiTestService::
- validateInputAndRetrieveLatestDisconnectedHostEndpointEvent(
- const chre_rpc_Void & /* request */,
- chre_rpc_RetrieveLatestDisconnectedHostEndpointEventOutput &response) {
- response.disconnectedCount = mReceivedHostEndpointDisconnectedNum;
- response.hostEndpointId = mLatestHostEndpointNotification.hostEndpointId;
- return true;
-}
-
bool ChreApiTestService::validateInputAndCallChreGetHostEndpointInfo(
const chre_rpc_ChreGetHostEndpointInfoInput &request,
chre_rpc_ChreGetHostEndpointInfoOutput &response) {
@@ -302,15 +278,15 @@ bool ChreApiTestService::validateInputAndCallChreGetHostEndpointInfo(
response.isTagValid = hostEndpointInfo.isTagValid;
if (hostEndpointInfo.isNameValid) {
copyString(response.endpointName, hostEndpointInfo.endpointName,
- CHRE_MAX_ENDPOINT_NAME_LEN);
+ kMaxHostEndpointNameBufferSize);
} else {
- memset(response.endpointName, 0, CHRE_MAX_ENDPOINT_NAME_LEN);
+ memset(response.endpointName, 0, kMaxHostEndpointNameBufferSize);
}
if (hostEndpointInfo.isTagValid) {
copyString(response.endpointTag, hostEndpointInfo.endpointTag,
- CHRE_MAX_ENDPOINT_TAG_LEN);
+ kMaxHostEndpointTagBufferSize);
} else {
- memset(response.endpointTag, 0, CHRE_MAX_ENDPOINT_TAG_LEN);
+ memset(response.endpointTag, 0, kMaxHostEndpointTagBufferSize);
}
LOGD("ChreGetHostEndpointInfo: status: true, hostEndpointID: %" PRIu32
@@ -325,3 +301,37 @@ bool ChreApiTestService::validateInputAndCallChreGetHostEndpointInfo(
}
return true;
}
+
+bool ChreApiTestService::validateBleScanFilters(
+ const chre_rpc_ChreBleGenericFilter *scanFilters,
+ chreBleGenericFilter *outputScanFilters, uint32_t scanFilterCount) {
+ if (scanFilters == nullptr || outputScanFilters == nullptr) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < scanFilterCount; ++i) {
+ const chre_rpc_ChreBleGenericFilter &scanFilter = scanFilters[i];
+ if (scanFilter.type > std::numeric_limits<uint8_t>::max() ||
+ scanFilter.length > std::numeric_limits<uint8_t>::max()) {
+ LOGE(
+ "validateBleScanFilters: invalid request.filter.scanFilters member: "
+ "type: %" PRIu32 " or length: %" PRIu32,
+ scanFilter.type, scanFilter.length);
+ return false;
+ }
+
+ if (scanFilter.data.size < scanFilter.length ||
+ scanFilter.mask.size < scanFilter.length) {
+ LOGE(
+ "validateBleScanFilters: invalid request.filter.scanFilters member: "
+ "data or mask size");
+ return false;
+ }
+
+ outputScanFilters[i] =
+ createBleGenericFilter(scanFilter.type, scanFilter.length,
+ scanFilter.data.bytes, scanFilter.mask.bytes);
+ }
+
+ return true;
+}
diff --git a/apps/test/common/chre_cross_validator_wifi/inc/chre_cross_validator_wifi_manager.h b/apps/test/common/chre_cross_validator_wifi/inc/chre_cross_validator_wifi_manager.h
index ffc2baed..3f47746f 100644
--- a/apps/test/common/chre_cross_validator_wifi/inc/chre_cross_validator_wifi_manager.h
+++ b/apps/test/common/chre_cross_validator_wifi/inc/chre_cross_validator_wifi_manager.h
@@ -84,22 +84,6 @@ class Manager {
bool mChreDataCollectionDone = false;
/**
- * This is the fraction of the number of results in the greater set of
- * scan results between the AP and CHRE that the lesser set can differ by.
- * Increasing this value will increase the relative amount that AP and CHRE
- * results sizes can differ by.
- *
- * Ex: AP_results_size = 8
- * CHRE_results_size = 7
- * kMaxDiffNumResultsFraction = 0.25
- *
- * CHRE_results_size is valid because it is >= 8 - 8 * 0.25 = 6
- */
- // TODO(b/185026344): Perfect this number. Consider using an abolute
- // difference instead of a percentage difference also.
- static constexpr float kMaxDiffNumResultsFraction = 0.25f;
-
- /**
* Handle a message from the host.
* @param senderInstanceId The instance id of the sender.
* @param data The message from the host's data.
diff --git a/apps/test/common/chre_cross_validator_wifi/src/chre_cross_validator_wifi_manager.cc b/apps/test/common/chre_cross_validator_wifi/src/chre_cross_validator_wifi_manager.cc
index 49af65e3..7351bc20 100644
--- a/apps/test/common/chre_cross_validator_wifi/src/chre_cross_validator_wifi_manager.cc
+++ b/apps/test/common/chre_cross_validator_wifi/src/chre_cross_validator_wifi_manager.cc
@@ -180,9 +180,11 @@ void Manager::compareAndSendResultToHost() {
LOGE("AP and CHRE wifi scan result counts differ, AP = %" PRIu8
", CHRE = %" PRIu8,
mApScanResultsSize, mChreScanResultsSize);
- } else {
- verifyScanResults(&testResult);
+
+ return;
}
+
+ verifyScanResults(&testResult);
test_shared::sendMessageToHost(
mCrossValidatorState.hostEndpoint, &testResult,
chre_test_common_TestResult_fields,
diff --git a/apps/test/common/chre_settings_test/inc/chre_settings_test_manager.h b/apps/test/common/chre_settings_test/inc/chre_settings_test_manager.h
index 89863dc1..602b60d0 100644
--- a/apps/test/common/chre_settings_test/inc/chre_settings_test_manager.h
+++ b/apps/test/common/chre_settings_test/inc/chre_settings_test_manager.h
@@ -184,6 +184,10 @@ class Manager {
//! The number of scan result received when after getting a wifi async result.
uint16_t mReceivedScanResults;
+
+ //! True if we have received a chreAudioSourceStatusEvent with suspended ==
+ //! false.
+ bool mAudioSamplingEnabled;
};
// The settings test manager singleton.
diff --git a/apps/test/common/chre_settings_test/src/chre_settings_test_manager.cc b/apps/test/common/chre_settings_test/src/chre_settings_test_manager.cc
index 77b8ac6e..2f55d309 100644
--- a/apps/test/common/chre_settings_test/src/chre_settings_test_manager.cc
+++ b/apps/test/common/chre_settings_test/src/chre_settings_test_manager.cc
@@ -44,6 +44,9 @@ constexpr uint32_t kGnssLocationCookie = 0x3456;
constexpr uint32_t kGnssMeasurementCookie = 0x4567;
constexpr uint32_t kWwanCellInfoCookie = 0x5678;
+// The default audio handle.
+constexpr uint32_t kAudioHandle = 0;
+
// Flag to verify if an audio data event was received after a valid sampling
// change event (i.e., we only got the data event after a source-enabled-and-
// not-suspended event).
@@ -182,7 +185,7 @@ bool Manager::isFeatureSupported(Feature feature) {
}
case Feature::AUDIO: {
struct chreAudioSource source;
- supported = chreAudioGetSource(0 /* handle */, &source);
+ supported = chreAudioGetSource(kAudioHandle, &source);
break;
}
case Feature::BLE_SCANNING: {
@@ -348,8 +351,8 @@ bool Manager::startTestForFeature(Feature feature) {
case Feature::AUDIO: {
struct chreAudioSource source;
- if ((success = chreAudioGetSource(0 /* handle */, &source))) {
- success = chreAudioConfigureSource(0 /* handle */, true /* enable */,
+ if ((success = chreAudioGetSource(kAudioHandle, &source))) {
+ success = chreAudioConfigureSource(kAudioHandle, true /* enable */,
source.minBufferDuration,
source.minBufferDuration);
}
@@ -547,52 +550,61 @@ void Manager::handleWwanCellInfoResult(const chreWwanCellInfoResult *result) {
void Manager::handleAudioSourceStatusEvent(
const struct chreAudioSourceStatusEvent *event) {
+ LOGI("Received sampling status event suspended %d", event->status.suspended);
+ mAudioSamplingEnabled = !event->status.suspended;
+ if (!mTestSession.has_value()) {
+ return;
+ }
+
bool success = false;
- if (mTestSession.has_value()) {
- if (mTestSession->featureState == FeatureState::ENABLED) {
- if (event->status.suspended) {
- struct chreAudioSource source;
- if (chreAudioGetSource(0 /* handle */, &source)) {
- const uint64_t duration =
- source.minBufferDuration + kOneSecondInNanoseconds;
- gAudioDataTimerHandle = chreTimerSet(duration, &kAudioDataTimerCookie,
- true /* oneShot */);
-
- if (gAudioDataTimerHandle == CHRE_TIMER_INVALID) {
- LOGE("Failed to set data check timer");
- } else {
- success = true;
- }
- } else {
- LOGE("Failed to query audio source");
- }
- } else {
- // There might be a corner case where CHRE might have queued an audio
- // available event just as the microphone disable setting change is
- // received that might wrongfully indicate that microphone access
- // wasn't disabled when it is dispatched. We add a 2 second timer to
- // allow CHRE to send the source status change event to account for
- // this, and fail the test if the timer expires without getting said
- // event.
- LOGW("Source wasn't suspended when Mic Access disabled, waiting 2 sec");
- gAudioStatusTimerHandle =
- chreTimerSet(2 * kOneSecondInNanoseconds, &kAudioStatusTimerCookie,
- true /* oneShot */);
- if (gAudioStatusTimerHandle == CHRE_TIMER_INVALID) {
- LOGE("Failed to set audio status check timer");
+ if (mTestSession->featureState == FeatureState::ENABLED) {
+ if (event->status.suspended) {
+ if (gAudioStatusTimerHandle != CHRE_TIMER_INVALID) {
+ chreTimerCancel(gAudioStatusTimerHandle);
+ gAudioStatusTimerHandle = CHRE_TIMER_INVALID;
+ }
+
+ struct chreAudioSource source;
+ if (chreAudioGetSource(kAudioHandle, &source)) {
+ const uint64_t duration =
+ source.minBufferDuration + kOneSecondInNanoseconds;
+ gAudioDataTimerHandle =
+ chreTimerSet(duration, &kAudioDataTimerCookie, true /* oneShot */);
+
+ if (gAudioDataTimerHandle == CHRE_TIMER_INVALID) {
+ LOGE("Failed to set data check timer");
} else {
- // continue the test, fail on timeout.
success = true;
}
+ } else {
+ LOGE("Failed to query audio source");
}
} else {
- gGotSourceEnabledEvent = true;
- success = true;
+ // There might be a corner case where CHRE might have queued an audio
+ // available event just as the microphone disable setting change is
+ // received that might wrongfully indicate that microphone access
+ // wasn't disabled when it is dispatched. We add a 2 second timer to
+ // allow CHRE to send the source status change event to account for
+ // this, and fail the test if the timer expires without getting said
+ // event.
+ LOGW("Source wasn't suspended when Mic Access disabled, waiting 2 sec");
+ gAudioStatusTimerHandle =
+ chreTimerSet(2 * kOneSecondInNanoseconds, &kAudioStatusTimerCookie,
+ true /* oneShot */);
+ if (gAudioStatusTimerHandle == CHRE_TIMER_INVALID) {
+ LOGE("Failed to set audio status check timer");
+ } else {
+ // continue the test, fail on timeout.
+ success = true;
+ }
}
+ } else {
+ gGotSourceEnabledEvent = true;
+ success = true;
+ }
- if (!success) {
- sendTestResult(mTestSession->hostEndpointId, success);
- }
+ if (!success) {
+ sendTestResult(mTestSession->hostEndpointId, success);
}
}
@@ -609,7 +621,7 @@ void Manager::handleAudioDataEvent(const struct chreAudioDataEvent *event) {
} else if (gGotSourceEnabledEvent) {
success = true;
}
- chreAudioConfigureSource(0 /* handle */, false /* enable */,
+ chreAudioConfigureSource(kAudioHandle, false /* enable */,
0 /* minBufferDuration */,
0 /* maxbufferDuration */);
sendTestResult(mTestSession->hostEndpointId, success);
@@ -619,18 +631,18 @@ void Manager::handleAudioDataEvent(const struct chreAudioDataEvent *event) {
void Manager::handleTimeout(const void *eventData) {
bool testSuccess = false;
auto *cookie = static_cast<const uint32_t *>(eventData);
+ // Ignore the audio status timer if the suspended status was received.
+ if (*cookie == kAudioStatusTimerCookie && !mAudioSamplingEnabled) {
+ gAudioStatusTimerHandle = CHRE_TIMER_INVALID;
+ return;
+ }
if (*cookie == kAudioDataTimerCookie) {
gAudioDataTimerHandle = CHRE_TIMER_INVALID;
testSuccess = true;
- if (gAudioStatusTimerHandle != CHRE_TIMER_INVALID) {
- chreTimerCancel(gAudioStatusTimerHandle);
- gAudioStatusTimerHandle = CHRE_TIMER_INVALID;
- }
} else if (*cookie == kAudioStatusTimerCookie) {
- LOGE("Source wasn't suspended when Mic Access was disabled");
gAudioStatusTimerHandle = CHRE_TIMER_INVALID;
- testSuccess = false;
+ LOGE("Source wasn't suspended when Mic Access was disabled");
} else {
LOGE("Invalid timer cookie: %" PRIx32, *cookie);
}
diff --git a/apps/test/common/rpc_service_test/inc/rpc_service_manager.h b/apps/test/common/rpc_service_test/inc/rpc_service_manager.h
index f092c868..4807c600 100644
--- a/apps/test/common/rpc_service_test/inc/rpc_service_manager.h
+++ b/apps/test/common/rpc_service_test/inc/rpc_service_manager.h
@@ -60,6 +60,11 @@ class RpcServiceManager {
const void *eventData);
/**
+ * Cleanup on nanoapp end.
+ */
+ void end();
+
+ /**
* Sets the permission for the next server message.
*
* @params permission Bitmasked CHRE_MESSAGE_PERMISSION_.
diff --git a/apps/test/common/rpc_service_test/src/rpc_service_manager.cc b/apps/test/common/rpc_service_test/src/rpc_service_manager.cc
index bea1036f..956aad60 100644
--- a/apps/test/common/rpc_service_test/src/rpc_service_manager.cc
+++ b/apps/test/common/rpc_service_test/src/rpc_service_manager.cc
@@ -57,6 +57,10 @@ void RpcServiceManager::handleEvent(uint32_t senderInstanceId,
}
}
+void RpcServiceManager::end() {
+ mServer.close();
+}
+
void RpcServiceManager::setPermissionForNextMessage(uint32_t permission) {
mServer.setPermissionForNextMessage(permission);
}
diff --git a/apps/test/common/rpc_service_test/src/rpc_service_test.cc b/apps/test/common/rpc_service_test/src/rpc_service_test.cc
index da709ff3..13812882 100644
--- a/apps/test/common/rpc_service_test/src/rpc_service_test.cc
+++ b/apps/test/common/rpc_service_test/src/rpc_service_test.cc
@@ -31,6 +31,7 @@ extern "C" bool nanoappStart(void) {
}
extern "C" void nanoappEnd(void) {
+ RpcServiceManagerSingleton::get()->end();
RpcServiceManagerSingleton::deinit();
}
diff --git a/build/build_template.mk b/build/build_template.mk
index 4907577f..18bf30b8 100644
--- a/build/build_template.mk
+++ b/build/build_template.mk
@@ -51,6 +51,9 @@ define BUILD_TEMPLATE
# Target Objects ###############################################################
+# Remove duplicates
+COMMON_SRCS := $(sort $(COMMON_SRCS))
+
# Source files.
$(1)_CC_SRCS = $$(filter %.cc, $(COMMON_SRCS) $(8))
$(1)_CPP_SRCS = $$(filter %.cpp, $(COMMON_SRCS) $(8))
@@ -229,18 +232,33 @@ $$($(1)_AR): $$($(1)_CC_OBJS) $$($(1)_CPP_OBJS) $$($(1)_C_OBJS) \
# Token Mapping ################################################################
$$($(1)_TOKEN_MAP): $$($(1)_AR)
- @echo " [TOKEN_MAP_GEN] $<"
- $(V)mkdir -p $(OUT)/$(1)
- $(V)$(TOKEN_MAP_GEN_CMD) $$($(1)_TOKEN_MAP) $$($(1)_AR)
- $(V)$(TOKEN_MAP_CSV_GEN_CMD) $$($(1)_TOKEN_MAP_CSV) $$($(1)_AR)
+ @echo " [TOKEN_MAP_GEN] $$@"
+ $(V)mkdir -p $$(@D)
+ $(V)$(TOKEN_MAP_GEN_CMD) $$($(1)_TOKEN_MAP) $$($(1)_AR) 2>&1
+ $(V)$(TOKEN_MAP_CSV_GEN_CMD) $$($(1)_TOKEN_MAP_CSV) $$($(1)_AR) 2>&1
+
+# Rust #########################################################################
+
+ifeq ($(IS_BUILD_REQUIRING_RUST),)
+RUST_DEPENDENCIES =
+else
+RUST_DEPENDENCIES = rust_archive_$(1)
+endif
+
+# Always invoke the cargo build, let cargo decide if updates are needed
+.PHONY: rust_archive_$(1)
+rust_archive_$(1):
+ @echo " [Rust Archive] $$@"
+ $(RUST_FLAGS) cargo +nightly build -Z build-std=core,alloc \
+ --$(RUST_OPT_LEVEL) --target $(RUST_TARGET_DIR)/$(RUST_TARGET).json
# Link #########################################################################
$$($(1)_SO): $$($(1)_CC_DEPS) \
$$($(1)_CPP_DEPS) $$($(1)_C_DEPS) $$($(1)_S_DEPS) \
$$($(1)_CC_OBJS) $$($(1)_CPP_OBJS) $$($(1)_C_OBJS) \
- $$($(1)_S_OBJS) | $$(OUT)/$(1) $$($(1)_DIRS)
- $(V)$(5) $(4) -o $$@ $(11) $$(filter %.o, $$^) $(12)
+ $$($(1)_S_OBJS) $(RUST_DEPENDENCIES) | $$(OUT)/$(1) $$($(1)_DIRS)
+ $(5) $(4) -o $$@ $(11) $$(filter %.o, $$^) $(12)
$$($(1)_BIN): $$($(1)_CC_DEPS) \
$$($(1)_CPP_DEPS) $$($(1)_C_DEPS) $$($(1)_S_DEPS) \
diff --git a/build/clang.mk b/build/clang.mk
index 8481c9dd..0b5a2652 100644
--- a/build/clang.mk
+++ b/build/clang.mk
@@ -10,5 +10,5 @@ $(error "You should supply an ANDROID_BUILD_TOP environment variable \
endif
# Clang toolchain path ########################################################
-CLANG_TOOLCHAIN_PATH=$(ANDROID_BUILD_TOP)/prebuilts/clang/host/linux-x86/clang-r475365b
+CLANG_TOOLCHAIN_PATH=$(ANDROID_BUILD_TOP)/prebuilts/clang/host/linux-x86/clang-r498229b
IS_CLANG_TOOLCHAIN=true
diff --git a/build/common.mk b/build/common.mk
index e99c67ac..38a67438 100644
--- a/build/common.mk
+++ b/build/common.mk
@@ -51,4 +51,7 @@ include $(CHRE_PREFIX)/build/tools_config.mk
include $(CHRE_PREFIX)/build/nanopb.mk
# TFLM Sources
-include $(CHRE_PREFIX)/external/tflm/tflm.mk \ No newline at end of file
+include $(CHRE_PREFIX)/external/tflm/tflm.mk
+
+# Rust config
+include $(CHRE_PREFIX)/build/rust/common_rust_config.mk \ No newline at end of file
diff --git a/build/nanoapp/app.mk b/build/nanoapp/app.mk
index 3f827784..fa35eb26 100644
--- a/build/nanoapp/app.mk
+++ b/build/nanoapp/app.mk
@@ -92,6 +92,11 @@ ifneq ($(CHRE_NANOAPP_USES_WWAN),)
COMMON_CFLAGS += -DCHRE_NANOAPP_USES_WWAN
endif
+ifneq ($(CHRE_NANOAPP_USES_TOKENIZED_LOGGING),)
+COMMON_CFLAGS += -DCHRE_TOKENIZED_LOGGING_ENABLED
+include $(CHRE_PREFIX)/external/pigweed/pw_tokenizer.mk
+endif
+
# Common Compiler Flags ########################################################
# Add the CHRE API to the include search path.
@@ -126,8 +131,9 @@ COMMON_CFLAGS += -DNANOAPP_UNSTABLE_ID="\"$(NANOAPP_UNSTABLE_ID)\""
# Variant-specific Nanoapp Support Source Files ################################
APP_SUPPORT_PATH = $(CHRE_PREFIX)/build/app_support
-DSO_SUPPORT_LIB_PATH = $(CHRE_PREFIX)/platform/shared/nanoapp
-DSO_SUPPORT_LIB_SRCS = $(DSO_SUPPORT_LIB_PATH)/nanoapp_support_lib_dso.cc
+SHARED_NANOAPP_LIB_PATH = $(CHRE_PREFIX)/platform/shared/nanoapp
+DSO_SUPPORT_LIB_SRCS = $(SHARED_NANOAPP_LIB_PATH)/nanoapp_support_lib_dso.cc
+STACK_CHECK_SRCS = $(SHARED_NANOAPP_LIB_PATH)/nanoapp_stack_check.cc
# Required includes for nanoapp_support_lib_dso.cc, but using a special prefix
# directory and symlinks to effectively hide them from nanoapps
@@ -171,9 +177,6 @@ include $(CHRE_PREFIX)/std_overrides/std_overrides.mk
include $(CHRE_PREFIX)/build/defs.mk
include $(CHRE_PREFIX)/build/common.mk
-# Pigweed module includes
-include $(CHRE_PREFIX)/external/pigweed/pw_rpc.mk
-
# CHRE API version.
include $(CHRE_PREFIX)/chre_api/chre_api_version.mk
diff --git a/build/nanopb.mk b/build/nanopb.mk
index 012d7c69..012d683a 100644
--- a/build/nanopb.mk
+++ b/build/nanopb.mk
@@ -1,16 +1,20 @@
#
-# Nanoapp/CHRE NanoPB Makefile
+# Nanoapp/CHRE NanoPB and Pigweed RPC Makefile
#
-# Include this file in your nanoapp Makefile to produce pb.c and pb.h (or
-# $NANOPB_EXTENSION.c and $NANOPB_EXTENSION.h if $NANOPB_EXTENSION is defined)
-# for .proto files specified in the NANOPB_SRCS variable. The produced pb.c or
-# $NANOPB_EXTENSION.c files are automatically added to the COMMON_SRCS variable
+# Include this file in your nanoapp Makefile to generate .c source and .h header
+# files. ($NANOPB_EXTENSION.c and $NANOPB_EXTENSION.h if $NANOPB_EXTENSION
+# is defined) for .proto files specified in the NANOPB_SRCS and PW_RPC_SRCS
+# variables.
+#
+# The generated source files are automatically added to the COMMON_SRCS variable
# for the nanoapp build.
#
+# The path to the generated header files is similarly added to the COMMON_CFLAGS.
+#
# The NANOPB_OPTIONS variable can be used to supply an .options file to use when
# generating code for all .proto files. Alternatively, if an .options file has
-# the same name as a .proto file in NANOPB_SRCS, it'll be automatically picked
-# up when generating code **only** for that .proto file.
+# the same name as a .proto file, it'll be automatically picked up when generating
+# code **only** for that .proto file.
#
# NANOPB_FLAGS can be used to supply additional command line arguments to the
# nanopb compiler. Note that this is global and applies to all protobuf
@@ -25,20 +29,34 @@
# Environment Checks ###########################################################
+HAS_PROTO_SRC = false
+
ifneq ($(NANOPB_SRCS),)
ifeq ($(NANOPB_PREFIX),)
$(error "NANOPB_SRCS is non-empty. You must supply a NANOPB_PREFIX environment \
variable containing a path to the nanopb project. Example: \
export NANOPB_PREFIX=$$HOME/path/to/nanopb/nanopb-c")
endif
+HAS_PROTO_SRC = true
+endif
+
+ifneq ($(PW_RPC_SRCS),)
+ifeq ($(NANOPB_PREFIX),)
+$(error "PW_RPC_SRCS is non-empty. You must supply a NANOPB_PREFIX environment \
+ variable containing a path to the nanopb project. Example: \
+ export NANOPB_PREFIX=$$HOME/path/to/nanopb/nanopb-c")
+endif
+HAS_PROTO_SRC = true
endif
+################################################################################
+# Common #######################################################################
+################################################################################
+
ifeq ($(PROTOC),)
PROTOC=protoc
endif
-# Generated Source Files #######################################################
-
NANOPB_GEN_PATH = $(OUT)/nanopb_gen
ifeq ($(NANOPB_EXTENSION),)
@@ -51,10 +69,16 @@ NANOPB_GEN_SRCS += $(patsubst %.proto, \
$(NANOPB_GEN_PATH)/%.$(NANOPB_EXTENSION).c, \
$(NANOPB_SRCS))
-ifneq ($(NANOPB_GEN_SRCS),)
+# Add Google proto well-known types. See https://protobuf.dev/reference/protobuf/google.protobuf/.
+PROTOBUF_DIR = $(ANDROID_BUILD_TOP)/external/protobuf
+COMMON_CFLAGS += -I$(NANOPB_GEN_PATH)/$(PROTOBUF_DIR)/src
+
+################################################################################
+# Common to nanopb & rpc #######################################################
+################################################################################
+
+ifeq ($(HAS_PROTO_SRC),true)
COMMON_CFLAGS += -I$(NANOPB_PREFIX)
-COMMON_CFLAGS += -I$(NANOPB_GEN_PATH)
-COMMON_CFLAGS += $(addprefix -I$(NANOPB_GEN_PATH)/, $(NANOPB_INCLUDES))
ifneq ($(NANOPB_INCLUDE_LIBRARY),false)
COMMON_SRCS += $(NANOPB_PREFIX)/pb_common.c
@@ -62,14 +86,22 @@ COMMON_SRCS += $(NANOPB_PREFIX)/pb_decode.c
COMMON_SRCS += $(NANOPB_PREFIX)/pb_encode.c
endif
+# NanoPB Compiler Flags
+ifneq ($(NANOPB_INCLUDE_LIBRARY),false)
+COMMON_CFLAGS += -DPB_NO_PACKED_STRUCTS=1
endif
-# NanoPB Compiler Flags ########################################################
+NANOPB_PROTOC = $(NANOPB_PREFIX)/generator/protoc-gen-nanopb
+
+endif # ifeq ($(HAS_PROTO_SRC),true)
+
+################################################################################
+# nanopb #######################################################################
+################################################################################
ifneq ($(NANOPB_GEN_SRCS),)
-ifneq ($(NANOPB_INCLUDE_LIBRARY),false)
-COMMON_CFLAGS += -DPB_NO_PACKED_STRUCTS=1
-endif
+COMMON_CFLAGS += -I$(NANOPB_GEN_PATH)
+COMMON_CFLAGS += $(addprefix -I$(NANOPB_GEN_PATH)/, $(NANOPB_INCLUDES))
endif
# NanoPB Generator Setup #######################################################
@@ -78,7 +110,7 @@ NANOPB_GENERATOR_SRCS = $(NANOPB_PREFIX)/generator/proto/nanopb_pb2.py
NANOPB_GENERATOR_SRCS += $(NANOPB_PREFIX)/generator/proto/plugin_pb2.py
$(NANOPB_GENERATOR_SRCS):
- cd $(NANOPB_PREFIX)/generator/proto && make
+ cd $(NANOPB_PREFIX)/generator/proto && $(MAKE)
ifneq ($(NANOPB_OPTIONS),)
NANOPB_OPTIONS_FLAG = --options-file=$(NANOPB_OPTIONS)
@@ -100,10 +132,12 @@ $(NANOPB_GEN_PATH)/%.$(NANOPB_EXTENSION).c \
$(NANOPB_GENERATOR_SRCS)
@echo " [NANOPB] $<"
$(V)mkdir -p $(dir $@)
- $(V)$(PROTOC) --plugin=protoc-gen-nanopb=$(NANOPB_PROTOC) \
+ $(V)PYTHONPATH=$(PYTHONPATH) $(PROTOC) \
+ --plugin=protoc-gen-nanopb=$(NANOPB_PROTOC) \
--proto_path=$(abspath $(dir $<)) \
$(NANOPB_FLAGS) \
- --nanopb_out="$(NANOPB_GENERATOR_FLAGS) --options-file=$(basename $<).options:$(dir $@)" \
+ --nanopb_out="$(NANOPB_GENERATOR_FLAGS) \
+ --options-file=$(basename $<).options:$(dir $@)" \
$(abspath $<)
$(NANOPB_GEN_PATH)/%.$(NANOPB_EXTENSION).c \
@@ -112,8 +146,238 @@ $(NANOPB_GEN_PATH)/%.$(NANOPB_EXTENSION).c \
$(NANOPB_GENERATOR_SRCS)
@echo " [NANOPB] $<"
$(V)mkdir -p $(dir $@)
- $(V)$(PROTOC) --plugin=protoc-gen-nanopb=$(NANOPB_PROTOC) \
+ $(V)PYTHONPATH=$(PYTHONPATH) $(PROTOC) \
+ --plugin=protoc-gen-nanopb=$(NANOPB_PROTOC) \
--proto_path=$(abspath $(dir $<)) \
$(NANOPB_FLAGS) \
--nanopb_out="$(NANOPB_GENERATOR_FLAGS) $(NANOPB_OPTIONS_FLAG):$(dir $@)" \
$(abspath $<)
+
+################################################################################
+# Specific to pigweed RPC ######################################################
+################################################################################
+ifneq ($(PW_RPC_SRCS),)
+
+# Location of various Pigweed modules
+PIGWEED_DIR = $(ANDROID_BUILD_TOP)/external/pigweed
+PROTOBUF_DIR = $(ANDROID_BUILD_TOP)/external/protobuf
+CHRE_PREFIX = $(ANDROID_BUILD_TOP)/system/chre
+CHRE_UTIL_DIR = $(CHRE_PREFIX)/util
+CHRE_API_DIR = $(CHRE_PREFIX)/chre_api
+PIGWEED_CHRE_DIR=$(CHRE_PREFIX)/external/pigweed
+PIGWEED_CHRE_UTIL_DIR = $(CHRE_UTIL_DIR)/pigweed
+
+PW_RPC_GEN_PATH = $(OUT)/pw_rpc_gen
+
+# Create proto used for header generation ######################################
+
+PW_RPC_PROTO_GENERATOR = $(PIGWEED_DIR)/pw_protobuf_compiler/py/pw_protobuf_compiler/generate_protos.py
+PW_RPC_GENERATOR_PROTO = $(PIGWEED_DIR)/pw_rpc/internal/packet.proto
+PW_RPC_GENERATOR_COMPILED_PROTO = $(PW_RPC_GEN_PATH)/py/pw_rpc/internal/packet_pb2.py
+PW_PROTOBUF_PROTOS = $(PIGWEED_DIR)/pw_protobuf/pw_protobuf_protos/common.proto \
+ $(PIGWEED_DIR)/pw_protobuf/pw_protobuf_protos/field_options.proto \
+ $(PIGWEED_DIR)/pw_protobuf/pw_protobuf_protos/status.proto
+
+# Modifies PYTHONPATH so that python can see all of pigweed's modules used by
+# their protoc plugins
+PW_RPC_GENERATOR_CMD = PYTHONPATH=$$PYTHONPATH:$(PW_RPC_GEN_PATH)/py:$\
+ $(PIGWEED_DIR)/pw_status/py:$(PIGWEED_DIR)/pw_protobuf/py:$\
+ $(PIGWEED_DIR)/pw_protobuf_compiler/py $(PYTHON)
+
+$(PW_RPC_GENERATOR_COMPILED_PROTO): $(PW_RPC_GENERATOR_PROTO)
+ @echo " [PW_RPC] $<"
+ $(V)mkdir -p $(PW_RPC_GEN_PATH)/py/pw_rpc/internal
+ $(V)mkdir -p $(PW_RPC_GEN_PATH)/py/pw_protobuf_codegen_protos
+ $(V)mkdir -p $(PW_RPC_GEN_PATH)/py/pw_protobuf_protos
+ $(V)cp -R $(PIGWEED_DIR)/pw_rpc/py/pw_rpc $(PW_RPC_GEN_PATH)/py/
+
+ $(PROTOC) -I$(PIGWEED_DIR)/pw_protobuf/pw_protobuf_protos \
+ --experimental_allow_proto3_optional \
+ --python_out=$(PW_RPC_GEN_PATH)/py/pw_protobuf_protos \
+ $(PW_PROTOBUF_PROTOS)
+
+ $(PROTOC) -I$(PIGWEED_DIR)/pw_protobuf/pw_protobuf_codegen_protos \
+ --experimental_allow_proto3_optional \
+ --python_out=$(PW_RPC_GEN_PATH)/py/pw_protobuf_codegen_protos \
+ $(PIGWEED_DIR)/pw_protobuf/pw_protobuf_codegen_protos/codegen_options.proto
+
+ $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
+ --out-dir=$(PW_RPC_GEN_PATH)/py/pw_rpc/internal \
+ --compile-dir=$(dir $<) --sources $(PW_RPC_GENERATOR_PROTO) \
+ --language python
+
+ $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
+ --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) \
+ --plugin-path=$(PIGWEED_DIR)/pw_protobuf/py/pw_protobuf/plugin.py \
+ --compile-dir=$(dir $<) --sources $(PW_RPC_GENERATOR_PROTO) \
+ --language pwpb
+
+# Generated PW RPC Files #######################################################
+
+PW_RPC_GEN_SRCS = $(patsubst %.proto, \
+ $(PW_RPC_GEN_PATH)/%.pb.c, \
+ $(PW_RPC_SRCS))
+
+# Include to-be-generated files
+COMMON_CFLAGS += -I$(PW_RPC_GEN_PATH)
+COMMON_CFLAGS += -I$(PW_RPC_GEN_PATH)/$(PIGWEED_DIR)
+
+# Add include paths to reference protos directly
+COMMON_CFLAGS += $(addprefix -I$(PW_RPC_GEN_PATH)/, $(abspath $(dir $(PW_RPC_SRCS))))
+
+# Add include paths to import protos
+ifneq ($(PW_RPC_INCLUDE_DIRS),)
+COMMON_CFLAGS += $(addprefix -I$(PW_RPC_GEN_PATH)/, $(abspath $(PW_RPC_INCLUDE_DIRS)))
+endif
+
+# Add Google proto well-known types. See https://protobuf.dev/reference/protobuf/google.protobuf/.
+COMMON_CFLAGS += -I$(PW_RPC_GEN_PATH)/$(PROTOBUF_DIR)/src
+
+COMMON_SRCS += $(PW_RPC_GEN_SRCS)
+
+# PW RPC library ###############################################################
+
+# Pigweed RPC include paths
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_assert/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_bytes/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_containers/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_function/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_log/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_polyfill/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_polyfill/public_overrides
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_polyfill/standard_library_public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_preprocessor/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_protobuf/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_result/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_rpc/nanopb/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_rpc/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_rpc/pwpb/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_rpc/raw/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_span/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_span/public_overrides
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_status/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_stream/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_string/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_sync/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_toolchain/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_varint/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/third_party/fuchsia/repo/sdk/lib/fit/include
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/third_party/fuchsia/repo/sdk/lib/stdcompat/include
+
+# Pigweed RPC sources
+COMMON_SRCS += $(PIGWEED_DIR)/pw_assert_log/assert_log.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_containers/intrusive_list.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_protobuf/decoder.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_protobuf/encoder.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_protobuf/stream_decoder.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/call.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/channel.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/channel_list.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/client.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/client_call.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/endpoint.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/packet.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/server.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/server_call.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/service.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/nanopb/common.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/nanopb/method.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/nanopb/server_reader_writer.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/pwpb/server_reader_writer.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_stream/memory_stream.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_varint/stream.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_varint/varint_c.c
+COMMON_SRCS += $(PIGWEED_DIR)/pw_varint/varint.cc
+# Pigweed configuration
+COMMON_CFLAGS += -DPW_RPC_USE_GLOBAL_MUTEX=0
+COMMON_CFLAGS += -DPW_RPC_YIELD_MODE=PW_RPC_YIELD_MODE_BUSY_LOOP
+
+# Enable closing a client stream.
+COMMON_CFLAGS += -DPW_RPC_COMPLETION_REQUEST_CALLBACK
+
+# Use dynamic channel allocation
+COMMON_CFLAGS += -DPW_RPC_DYNAMIC_ALLOCATION
+COMMON_CFLAGS += -DPW_RPC_DYNAMIC_CONTAINER\(type\)="chre::DynamicVector<type>"
+COMMON_CFLAGS += -DPW_RPC_DYNAMIC_CONTAINER_INCLUDE='"chre/util/dynamic_vector.h"'
+
+# Add CHRE Pigweed util sources since nanoapps should always use these
+COMMON_SRCS += $(PIGWEED_CHRE_UTIL_DIR)/chre_channel_output.cc
+COMMON_SRCS += $(PIGWEED_CHRE_UTIL_DIR)/rpc_client.cc
+COMMON_SRCS += $(PIGWEED_CHRE_UTIL_DIR)/rpc_helper.cc
+COMMON_SRCS += $(PIGWEED_CHRE_UTIL_DIR)/rpc_server.cc
+COMMON_SRCS += $(CHRE_UTIL_DIR)/nanoapp/callbacks.cc
+COMMON_SRCS += $(CHRE_UTIL_DIR)/dynamic_vector_base.cc
+
+# CHRE Pigweed overrides
+COMMON_CFLAGS += -I$(PIGWEED_CHRE_DIR)/pw_log_nanoapp/public_overrides
+COMMON_CFLAGS += -I$(PIGWEED_CHRE_DIR)/pw_assert_nanoapp/public_overrides
+
+# Generate PW RPC headers ######################################################
+
+$(PW_RPC_GEN_PATH)/%.pb.c \
+ $(PW_RPC_GEN_PATH)/%.pb.h \
+ $(PW_RPC_GEN_PATH)/%.rpc.pb.h \
+ $(PW_RPC_GEN_PATH)/%.raw_rpc.pb.h: %.proto \
+ %.options \
+ $(NANOPB_GENERATOR_SRCS) \
+ $(PW_RPC_GENERATOR_COMPILED_PROTO)
+ @echo " [PW_RPC] $<"
+ $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
+ --plugin-path=$(NANOPB_PROTOC) \
+ --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language nanopb \
+ --sources $<
+
+ $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
+ --plugin-path=$(PIGWEED_DIR)/pw_protobuf/py/pw_protobuf/plugin.py \
+ --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language pwpb \
+ --sources $<
+
+ $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
+ --plugin-path=$(PIGWEED_DIR)/pw_rpc/py/pw_rpc/plugin_nanopb.py \
+ --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language nanopb_rpc \
+ --sources $<
+
+ $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
+ --plugin-path=$(PIGWEED_DIR)/pw_rpc/py/pw_rpc/plugin_raw.py \
+ --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language raw_rpc \
+ --sources $<
+
+ $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
+ --plugin-path=$(PIGWEED_DIR)/pw_rpc/py/pw_rpc/plugin_pwpb.py \
+ --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language pwpb_rpc \
+ --sources $<
+
+$(PW_RPC_GEN_PATH)/%.pb.c \
+ $(PW_RPC_GEN_PATH)/%.pb.h \
+ $(PW_RPC_GEN_PATH)/%.rpc.pb.h \
+ $(PW_RPC_GEN_PATH)/%.raw_rpc.pb.h: %.proto \
+ $(NANOPB_OPTIONS) \
+ $(NANOPB_GENERATOR_SRCS) \
+ $(PW_RPC_GENERATOR_COMPILED_PROTO)
+ @echo " [PW_RPC] $<"
+ $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
+ --plugin-path=$(NANOPB_PROTOC) \
+ --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language nanopb \
+ --sources $<
+
+ $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
+ --plugin-path=$(PIGWEED_DIR)/pw_protobuf/py/pw_protobuf/plugin.py \
+ --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language pwpb \
+ --sources $<
+
+ $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
+ --plugin-path=$(PIGWEED_DIR)/pw_rpc/py/pw_rpc/plugin_nanopb.py \
+ --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language nanopb_rpc \
+ --sources $<
+
+ $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
+ --plugin-path=$(PIGWEED_DIR)/pw_rpc/py/pw_rpc/plugin_raw.py \
+ --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language raw_rpc \
+ --sources $<
+
+ $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
+ --plugin-path=$(PIGWEED_DIR)/pw_rpc/py/pw_rpc/plugin_pwpb.py \
+ --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language pwpb_rpc \
+ --sources $<
+
+endif # ifneq ($(PW_RPC_SRCS),)
diff --git a/build/rust/common_rust_config.mk b/build/rust/common_rust_config.mk
new file mode 100644
index 00000000..c562445c
--- /dev/null
+++ b/build/rust/common_rust_config.mk
@@ -0,0 +1,4 @@
+RUST_TARGET_DIR = $(CHRE_PRIV_DIR)/build/rust
+RUST_OPT_LEVEL = release
+# Required for linking of composite Rust + C binaries
+RUST_FLAGS = RUSTFLAGS='-C relocation-model=pic' \ No newline at end of file
diff --git a/build/variant/aosp_riscv55e03_tinysys.mk b/build/variant/aosp_riscv55e03_tinysys.mk
index 5513f95a..92d8a626 100644
--- a/build/variant/aosp_riscv55e03_tinysys.mk
+++ b/build/variant/aosp_riscv55e03_tinysys.mk
@@ -34,11 +34,10 @@ TARGET_CFLAGS += -DCHRE_32_BIT_WORD_SIZE
# chre platform
TARGET_CFLAGS += -DCHRE_FIRST_SUPPORTED_API_VERSION=CHRE_API_VERSION_1_7
-# TODO(b/254121302): Needs to confirm with MTK about the max message size below
TARGET_CFLAGS += -DCHRE_MESSAGE_TO_HOST_MAX_SIZE=4096
TARGET_CFLAGS += -DCHRE_USE_BUFFERED_LOGGING
-# TODO(b/256870101): create mutex on heap for now
-TARGET_CFLAGS += -DCHRE_CREATE_MUTEX_ON_HEAP
+# enable static allocation in freertos
+TINYSYS_CFLAGS += -DCFG_STATIC_ALLOCATE
# Compiling flags ##############################################################
diff --git a/chpp/Android.bp b/chpp/Android.bp
index 0560224d..11db9f1d 100644
--- a/chpp/Android.bp
+++ b/chpp/Android.bp
@@ -52,6 +52,8 @@ cc_defaults {
"-D_POSIX_C_SOURCE=199309L",
// Required for pthread_setname_np()
"-D_GNU_SOURCE",
+ // Enable assert (i.e. CHPP_ASSERT, ...)
+ "-UNDEBUG",
],
conlyflags: [
"-std=c11",
@@ -155,7 +157,10 @@ cc_test_host {
"test/app_test.cpp",
"test/gnss_test.cpp",
"test/transport_test.cpp",
- "test/clients_test.cpp",
+ "test/app_timeout_test.cpp",
+ "test/app_discovery_test.cpp",
+ "test/app_req_resp_test.cpp",
+ "test/app_notification_test.cpp",
],
static_libs: [
"chre_chpp_linux",
@@ -186,9 +191,10 @@ cc_test_host {
name: "chre_chpp_fake_link_sync_tests",
defaults: ["chre_chpp_core_without_link"],
cflags: [
- // Speed up tests by setting timeouts to 10 ms
- "-DCHPP_TRANSPORT_TX_TIMEOUT_NS=10000000",
- "-DCHPP_TRANSPORT_RX_TIMEOUT_NS=10000000",
+ // Speed up tests by setting timeouts to 50 ms.
+ // Note: the value shouldn't be too low to avoid timeouts on slow test servers.
+ "-DCHPP_TRANSPORT_TX_TIMEOUT_NS=50000000",
+ "-DCHPP_TRANSPORT_RX_TIMEOUT_NS=50000000",
],
local_include_dirs: [
"include",
diff --git a/chpp/RELEASE_NOTES.md b/chpp/RELEASE_NOTES.md
index 75d44408..bc1cf4df 100644
--- a/chpp/RELEASE_NOTES.md
+++ b/chpp/RELEASE_NOTES.md
@@ -263,4 +263,77 @@ void chppRegisterService(struct ChppAppState *appContext, void *serviceContext,
The handle which used to be returned is now populated in `serviceState`.
`service->appContext` is also initialized to the passed `appContext`.
-This change makes the signature and behavior consistent with `chreRegisterClient`. \ No newline at end of file
+This change makes the signature and behavior consistent with `chreRegisterClient`.
+
+### 2023-08
+
+Services can now send requests and receive responses from clients.
+
+The changes to the public API of the different layers are described below.
+Check the inline documentation for more information.
+
+**Breaking changes**
+
+- `ChppClientState` and `ChppServiceState` have been unified into `ChppEndpointState`.
+
+#### app.c / app.h
+
+**Breaking changes**
+
+- Move all sync primitives to a new `struct ChppSyncResponse`,
+- Renamed `ChppClient.rRStateCount` to `ChppClient.outReqCount`. The content and meaning stay the same,
+- Split `struct ChppRequestResponseState` to `struct ChppOutgoingRequestState` and `struct ChppIncomingRequestState`. Both the struct have the same layout and usage as the former `struct`. Having different types is only to make code clearer as both clients and services now support both incoming and outgoing requests,
+- Renamed `ChppAppState.nextClientRequestTimeoutNs` to `ChppAppState.nextRequestTimeoutNs`. The content and meaning stay the same,
+- Renamed `CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE` to `CHPP_REQUEST_TIMEOUT_INFINITE`.
+
+**Added APIs**
+
+- Added `chppAllocResponseTypedArray` and `chppAllocResponseFixed` to allocate responses. Those can be used by both clients and services. They call the added `chppAllocResponse`,
+- Added `CHPP_MESSAGE_TYPE_SERVICE_REQUEST` and `CHPP_MESSAGE_TYPE_CLIENT_RESPONSE` to the message types (`ChppMessageType`). Used for requests sent by the services and the corresponding responses sent by the client,
+- Added `ChppService.responseDispatchFunctionPtr` to handle client responses,
+- Added `ChppService.outReqCount` holding the number of commands supported by the service (0 when the service can not send requests),
+- Added `ChppClient.requestDispatchFunctionPtr` to handle service requests,
+- Added `ChppAppState.registeredServiceStates` to track service states,
+- Added `ChppAppState.nextServiceRequestTimeoutNs` to track when the next service sent request will timeout,
+- Added `chppTimestampIncomingRequest` to be used by both clients and services,
+- Added `chppTimestampOutgoingRequest` to be used by both clients and services,
+- Added `chppTimestampIncomingResponse` to be used by both clients and services,
+- Added `chppTimestampOutgoingResponse` to be used by both clients and services,
+- Added `chppSendTimestampedResponseOrFail` to be used by both clients and services,
+- Added `chppSendTimestampedRequestOrFail` to be used by both clients and services,
+- Added `chppWaitForResponseWithTimeout` to be used by both clients and services.
+
+#### clients.c / clients.h
+
+**Breaking changes**
+
+- Renamed `ChppClientState.rRStates` to `outReqStates` - the new type is `ChppOutgoingRequestState`. The content and meaning stay the same,
+- Nest all sync primitive in `ChppClientState` into a `struct ChppSyncResponse syncResponse`,
+- `chppRegisterClient` takes a `ChppOutgoingRequestState` instead of the former `ChppRequestResponseState`,
+- `chppClientTimestampRequest` is replaced with `chppTimestampOutgoingRequest` in the app layer. Parameters are different,
+- `chppClientTimestampResponse` is replaced with `chppTimestampIncomingResponse` in the app layer. Parameters are different,
+- `chppSendTimestampedRequestOrFail` is renamed to `chppClientSendTimestampedRequestOrFail`. It takes a `ChppOutgoingRequestState` instead of the former `ChppRequestResponseState`,
+- `chppSendTimestampedRequestAndWait` is renamed to `chppClientSendTimestampedRequestAndWait`. It takes a `ChppOutgoingRequestState` instead of the former `ChppRequestResponseState`,
+- `chppSendTimestampedRequestAndWaitTimeout` is renamed to `chppClientSendTimestampedRequestAndWaitTimeout`. It takes a `ChppOutgoingRequestState` instead of the former `ChppRequestResponseState`,
+- `chppClientSendOpenRequest` takes a `ChppOutgoingRequestState` instead of the former `ChppRequestResponseState`.
+
+#### services.c / services.h
+
+**Breaking changes**
+
+- Replaced `chppAllocServiceResponseTypedArray` with `chppAllocResponseTypedArray` in the app layer,
+- Replaced `chppAllocServiceResponseFixed` with `chppAllocResponseFixed` in the app layer,
+- Replaced `chppAllocServiceResponse` with `chppAllocResponse` in the app layer,
+- `chppRegisterService` now takes and additional `struct ChppOutgoingRequestState *` to track outgoing requests. `NULL` when the service do not send requests.
+
+**Added APIs**
+
+- Added `chppAllocServiceRequestFixed` and `chppAllocServiceRequestTypedArray` to allocate service requests. They call the added `chppAllocServiceRequest`,
+- Added `ChppServiceState.outReqStates` to track outgoing requests,
+- Added `ChppServiceState.transaction` to track app layer packet number,
+- Added `ChppServiceState.syncResponse` for sync responses,
+- Added `chppAllocServiceRequest`,
+- Added `chppAllocServiceRequestCommand`,
+- Added `chppServiceSendTimestampedRequestOrFail`,
+- Added `chppServiceSendTimestampedRequestAndWaitTimeout`,
+- Added `chppServiceCloseOpenRequests` to close pending requests on reset.
diff --git a/chpp/api_parser/.gitignore b/chpp/api_parser/.gitignore
deleted file mode 100644
index e431c531..00000000
--- a/chpp/api_parser/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-parser_cache
diff --git a/chpp/api_parser/chre_api_annotations.json b/chpp/api_parser/chre_api_annotations.json
deleted file mode 100644
index c396bb5a..00000000
--- a/chpp/api_parser/chre_api_annotations.json
+++ /dev/null
@@ -1,297 +0,0 @@
-[
- {
- "filename": "chre_api/include/chre_api/chre/wwan.h",
- "includes": [
- "chre_api/include/chre_api/chre/common.h"
- ],
- "output_includes": [
- "chpp/common/common_types.h",
- "chre_api/chre/wwan.h"
- ],
- "struct_info": [
- {
- "name": "chreWwanCellInfoResult",
- "annotations": [
- {
- "field": "version",
- "annotation": "fixed_value",
- "value": "CHRE_WWAN_CELL_INFO_RESULT_VERSION"
- },
- {
- "field": "errorCode",
- "annotation": "enum",
- "enum_type": "chreError"
- },
- {
- "field": "cookie",
- "annotation": "fixed_value",
- "value": "0"
- },
- {
- "field": "cookie",
- "annotation": "rewrite_type",
- "type_override": "uint32_t"
- },
- {
- "field": "reserved",
- "annotation": "fixed_value",
- "value": "0"
- },
- {
- "field": "cells",
- "annotation": "var_len_array",
- "length_field": "cellInfoCount"
- }
- ]
- },
- {
- "name": "chreWwanCellInfo",
- "annotations": [
- {
- "field": "cellInfoType",
- "annotation": "enum",
- "enum_type": "chreWwanCellInfoType"
- },
- {
- "field": "CellInfo",
- "annotation": "union_variant",
- "discriminator": "cellInfoType",
- "mapping": [
- ["CHRE_WWAN_CELL_INFO_TYPE_GSM", "gsm"],
- ["CHRE_WWAN_CELL_INFO_TYPE_CDMA", "cdma"],
- ["CHRE_WWAN_CELL_INFO_TYPE_LTE", "lte"],
- ["CHRE_WWAN_CELL_INFO_TYPE_WCDMA", "wcdma"],
- ["CHRE_WWAN_CELL_INFO_TYPE_TD_SCDMA", "tdscdma"],
- ["CHRE_WWAN_CELL_INFO_TYPE_NR", "nr"]
- ]
- },
- {
- "field": "reserved",
- "annotation": "fixed_value",
- "value": "0"
- }
- ]
- },
- {
- "name": "chreWwanCellIdentityGsm",
- "annotations": [
- {
- "field": "reserved",
- "annotation": "fixed_value",
- "value": "0"
- }
- ]
- }
- ],
- "root_structs": [
- "chreWwanCellInfoResult"
- ]
-},
-{
- "filename": "chre_api/include/chre_api/chre/wifi.h",
- "includes": [
- "chre_api/include/chre_api/chre/common.h"
- ],
- "output_includes": [
- "chpp/common/common_types.h",
- "chre_api/chre/wifi.h"
- ],
- "struct_info": [
- {
- "name": "chreWifiScanEvent",
- "annotations": [
- {
- "field": "version",
- "annotation": "fixed_value",
- "value": "CHRE_WIFI_SCAN_EVENT_VERSION"
- },
- {
- "field": "scannedFreqList",
- "annotation": "var_len_array",
- "length_field": "scannedFreqListLen"
- },
- {
- "field": "results",
- "annotation": "var_len_array",
- "length_field": "resultCount"
- }
- ]
- },
- {
- "name": "chreWifiScanResult",
- "annotations": [
- {
- "field": "reserved",
- "annotation": "fixed_value",
- "value": "0"
- }
- ]
- },
- {
- "name": "chreWifiScanParams",
- "annotations": [
- {
- "field": "frequencyList",
- "annotation": "var_len_array",
- "length_field": "frequencyListLen"
- },
- {
- "field": "ssidList",
- "annotation": "var_len_array",
- "length_field": "ssidListLen"
- }
- ]
- },
- {
- "name": "chreWifiRangingEvent",
- "annotations": [
- {
- "field": "version",
- "annotation": "fixed_value",
- "value": "CHRE_WIFI_RANGING_EVENT_VERSION"
- },
- {
- "field": "reserved",
- "annotation": "fixed_value",
- "value": "0"
- },
- {
- "field": "results",
- "annotation": "var_len_array",
- "length_field": "resultCount"
- }
- ]
- },
- {
- "name": "chreWifiRangingResult",
- "annotations": [
- {
- "field": "reserved",
- "annotation": "fixed_value",
- "value": "0"
- }
- ]
- },
- {
- "name": "chreWifiRangingParams",
- "annotations": [
- {
- "field": "targetList",
- "annotation": "var_len_array",
- "length_field": "targetListLen"
- }
- ]
- },
- {
- "name": "chreWifiRangingTarget",
- "annotations": [
- {
- "field": "reserved",
- "annotation": "fixed_value",
- "value": "0"
- }
- ]
- },
- {
- "name": "chreWifiNanSubscribeConfig",
- "annotations": [
- {
- "field": "subscribeType",
- "annotation": "enum",
- "enum_type": "chreWifiNanSubscribeType"
- },
- {
- "field": "service",
- "annotation": "string"
- },
- {
- "field": "serviceSpecificInfo",
- "annotation": "var_len_array",
- "length_field": "serviceSpecificInfoSize"
- },
- {
- "field": "matchFilter",
- "annotation": "var_len_array",
- "length_field": "matchFilterLength"
- }
- ]
- },
- {
- "name": "chreWifiNanDiscoveryEvent",
- "annotations": [
- {
- "field": "serviceSpecificInfo",
- "annotation": "var_len_array",
- "length_field": "serviceSpecificInfoSize"
- }
- ]
- }
- ],
- "root_structs": [
- "chreWifiScanEvent",
- "chreWifiScanParams",
- "chreWifiRangingEvent",
- "chreWifiRangingParams",
- "chreWifiNanSubscribeConfig",
- "chreWifiNanDiscoveryEvent",
- "chreWifiNanSessionLostEvent",
- "chreWifiNanSessionTerminatedEvent",
- "chreWifiNanRangingParams"
- ]
-},
-{
- "filename": "chre_api/include/chre_api/chre/gnss.h",
- "includes": [
- "chre_api/include/chre_api/chre/common.h"
- ],
- "output_includes": [
- "chpp/common/common_types.h",
- "chre_api/chre/gnss.h"
- ],
- "struct_info": [
- {
- "name": "chreGnssDataEvent",
- "annotations": [
- {
- "field": "version",
- "annotation": "fixed_value",
- "value": "CHRE_GNSS_DATA_EVENT_VERSION"
- },
- {
- "field": "reserved",
- "annotation": "fixed_value",
- "value": "0"
- },
- {
- "field": "measurements",
- "annotation": "var_len_array",
- "length_field": "measurement_count"
- }
- ]
- },
- {
- "name": "chreGnssLocationEvent",
- "annotations": [
- {
- "field": "reserved",
- "annotation": "fixed_value",
- "value": "0"
- }
- ]
- },
- {
- "name": "chreGnssClock",
- "annotations": [
- {
- "field": "reserved",
- "annotation": "fixed_value",
- "value": "0"
- }
- ]
- }
- ],
- "root_structs": [
- "chreGnssDataEvent",
- "chreGnssLocationEvent"
- ]
-}]
diff --git a/chpp/api_parser/requirements.txt b/chpp/api_parser/requirements.txt
deleted file mode 100644
index 9b9ec0a5..00000000
--- a/chpp/api_parser/requirements.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-future==0.18.2
-pyclibrary==0.1.4
diff --git a/chpp/app.c b/chpp/app.c
index 81aadfdb..a25bcdf4 100644
--- a/chpp/app.c
+++ b/chpp/app.c
@@ -25,6 +25,7 @@
#include "chpp/clients.h"
#include "chpp/clients/discovery.h"
+#include "chpp/services.h"
#ifdef CHPP_CLIENT_ENABLED_LOOPBACK
#include "chpp/clients/loopback.h"
#endif
@@ -40,7 +41,7 @@
#include "chpp/services/loopback.h"
#include "chpp/services/nonhandle.h"
#include "chpp/services/timesync.h"
-#include "chre_api/chre/common.h"
+#include "chpp/time.h"
/************************************************
* Prototypes
@@ -50,31 +51,28 @@ static bool chppProcessPredefinedClientRequest(struct ChppAppState *context,
uint8_t *buf, size_t len);
static bool chppProcessPredefinedServiceResponse(struct ChppAppState *context,
uint8_t *buf, size_t len);
-static bool chppProcessPredefinedClientNotification(
- struct ChppAppState *context, uint8_t *buf, size_t len);
-static bool chppProcessPredefinedServiceNotification(
- struct ChppAppState *context, uint8_t *buf, size_t len);
static bool chppDatagramLenIsOk(struct ChppAppState *context,
- struct ChppAppHeader *rxHeader, size_t len);
-ChppDispatchFunction *chppGetDispatchFunction(struct ChppAppState *context,
- uint8_t handle,
- enum ChppMessageType type);
-ChppNotifierFunction *chppGetClientResetNotifierFunction(
+ const struct ChppAppHeader *rxHeader,
+ size_t len);
+static ChppDispatchFunction *chppGetDispatchFunction(
+ struct ChppAppState *context, uint8_t handle, enum ChppMessageType type);
+#ifdef CHPP_CLIENT_ENABLED_DISCOVERY
+static ChppNotifierFunction *chppGetClientResetNotifierFunction(
struct ChppAppState *context, uint8_t index);
-ChppNotifierFunction *chppGetServiceResetNotifierFunction(
+#endif // CHPP_CLIENT_ENABLED_DISCOVERY
+static ChppNotifierFunction *chppGetServiceResetNotifierFunction(
struct ChppAppState *context, uint8_t index);
static inline const struct ChppService *chppServiceOfHandle(
struct ChppAppState *appContext, uint8_t handle);
static inline const struct ChppClient *chppClientOfHandle(
struct ChppAppState *appContext, uint8_t handle);
-static inline void *chppServiceContextOfHandle(struct ChppAppState *appContext,
- uint8_t handle);
-static inline void *chppClientContextOfHandle(struct ChppAppState *appContext,
- uint8_t handle);
-static void *chppClientServiceContextOfHandle(struct ChppAppState *appContext,
- uint8_t handle,
- enum ChppMessageType type);
+static inline struct ChppEndpointState *chppServiceStateOfHandle(
+ struct ChppAppState *appContext, uint8_t handle);
+static inline struct ChppEndpointState *chppClientStateOfHandle(
+ struct ChppAppState *appContext, uint8_t handle);
+static struct ChppEndpointState *chppClientOrServiceStateOfHandle(
+ struct ChppAppState *appContext, uint8_t handle, enum ChppMessageType type);
static void chppProcessPredefinedHandleDatagram(struct ChppAppState *context,
uint8_t *buf, size_t len);
@@ -89,7 +87,7 @@ static void chppProcessNegotiatedHandleDatagram(struct ChppAppState *context,
* Processes a client request that is determined to be for a predefined CHPP
* service.
*
- * @param context Maintains status for each app layer instance.
+ * @param context State of the app layer.
* @param buf Input data. Cannot be null.
* @param len Length of input data in bytes.
*
@@ -97,7 +95,7 @@ static void chppProcessNegotiatedHandleDatagram(struct ChppAppState *context,
*/
static bool chppProcessPredefinedClientRequest(struct ChppAppState *context,
uint8_t *buf, size_t len) {
- struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
+ const struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
bool handleValid = true;
bool dispatchResult = true;
@@ -134,7 +132,7 @@ static bool chppProcessPredefinedClientRequest(struct ChppAppState *context,
* Processes a service response that is determined to be for a predefined CHPP
* client.
*
- * @param context Maintains status for each app layer instance.
+ * @param context State of the app layer.
* @param buf Input data. Cannot be null.
* @param len Length of input data in bytes.
*
@@ -142,12 +140,12 @@ static bool chppProcessPredefinedClientRequest(struct ChppAppState *context,
*/
static bool chppProcessPredefinedServiceResponse(struct ChppAppState *context,
uint8_t *buf, size_t len) {
+ CHPP_DEBUG_NOT_NULL(buf);
// Possibly unused if compiling without the clients below enabled
UNUSED_VAR(context);
- UNUSED_VAR(buf);
UNUSED_VAR(len);
- struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
+ const struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
bool handleValid = true;
bool dispatchResult = true;
@@ -188,55 +186,21 @@ static bool chppProcessPredefinedServiceResponse(struct ChppAppState *context,
}
/**
- * Processes a client notification that is determined to be for a predefined
- * CHPP service.
- *
- * @param context Maintains status for each app layer instance.
- * @param buf Input data. Cannot be null.
- * @param len Length of input data in bytes.
- *
- * @return False if handle is invalid. True otherwise.
- */
-static bool chppProcessPredefinedClientNotification(
- struct ChppAppState *context, uint8_t *buf, size_t len) {
- UNUSED_VAR(context);
- UNUSED_VAR(len);
- UNUSED_VAR(buf);
- // No predefined services support these.
- return false;
-}
-
-/**
- * Processes a service notification that is determined to be for a predefined
- * CHPP client.
- *
- * @param context Maintains status for each app layer instance.
- * @param buf Input data. Cannot be null.
- * @param len Length of input data in bytes.
- *
- * @return False if handle is invalid. True otherwise.
- */
-static bool chppProcessPredefinedServiceNotification(
- struct ChppAppState *context, uint8_t *buf, size_t len) {
- UNUSED_VAR(context);
- UNUSED_VAR(len);
- UNUSED_VAR(buf);
- // No predefined clients support these.
- return false;
-}
-
-/**
* Verifies if the length of a Rx Datagram from the transport layer is
- * sufficient for the associated service.
+ * sufficient for the associated service/client.
*
- * @param context Maintains status for each app layer instance.
+ * @param context State of the app layer.
* @param rxHeader The pointer to the datagram RX header.
* @param len Length of the datagram in bytes.
*
* @return true if length is ok.
*/
static bool chppDatagramLenIsOk(struct ChppAppState *context,
- struct ChppAppHeader *rxHeader, size_t len) {
+ const struct ChppAppHeader *rxHeader,
+ size_t len) {
+ CHPP_DEBUG_NOT_NULL(context);
+ CHPP_DEBUG_NOT_NULL(rxHeader);
+
size_t minLen = SIZE_MAX;
uint8_t handle = rxHeader->handle;
@@ -259,6 +223,7 @@ static bool chppDatagramLenIsOk(struct ChppAppState *context,
default:
// len remains SIZE_MAX
CHPP_LOGE("Invalid H#%" PRIu8, handle);
+ return false;
}
} else { // Negotiated
@@ -267,6 +232,7 @@ static bool chppDatagramLenIsOk(struct ChppAppState *context,
switch (messageType) {
case CHPP_MESSAGE_TYPE_CLIENT_REQUEST:
+ case CHPP_MESSAGE_TYPE_CLIENT_RESPONSE:
case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
const struct ChppService *service =
chppServiceOfHandle(context, handle);
@@ -276,6 +242,7 @@ static bool chppDatagramLenIsOk(struct ChppAppState *context,
break;
}
case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
+ case CHPP_MESSAGE_TYPE_SERVICE_REQUEST:
case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
const struct ChppClient *client = chppClientOfHandle(context, handle);
if (client != NULL) {
@@ -283,117 +250,128 @@ static bool chppDatagramLenIsOk(struct ChppAppState *context,
}
break;
}
- default: {
- break;
- }
- }
-
- if (minLen == SIZE_MAX) {
- CHPP_LOGE("Invalid type=%d or H#%" PRIu8, messageType, handle);
+ default:
+ CHPP_LOGE("Invalid type=%d or H#%" PRIu8, messageType, handle);
+ return false;
}
}
- if ((len < minLen) && (minLen != SIZE_MAX)) {
+ if (len < minLen) {
CHPP_LOGE("Datagram len=%" PRIuSIZE " < %" PRIuSIZE " for H#%" PRIu8, len,
minLen, handle);
+ return false;
}
- return (len >= minLen) && (minLen != SIZE_MAX);
+
+ return true;
}
/**
* Returns the dispatch function of a particular negotiated client/service
- * handle and message type. This shall be null if it is unsupported by the
- * service.
+ * handle and message type.
+ *
+ * Returns null if it is unsupported by the service.
*
- * @param context Maintains status for each app layer instance.
+ * @param context State of the app layer.
* @param handle Handle number for the client/service.
* @param type Message type.
*
* @return Pointer to a function that dispatches incoming datagrams for any
* particular client/service.
*/
-ChppDispatchFunction *chppGetDispatchFunction(struct ChppAppState *context,
- uint8_t handle,
- enum ChppMessageType type) {
+static ChppDispatchFunction *chppGetDispatchFunction(
+ struct ChppAppState *context, uint8_t handle, enum ChppMessageType type) {
+ CHPP_DEBUG_NOT_NULL(context);
// chppDatagramLenIsOk() has already confirmed that the handle # is valid.
// Therefore, no additional checks are necessary for chppClientOfHandle(),
- // chppServiceOfHandle(), or chppClientServiceContextOfHandle().
+ // chppServiceOfHandle(), or chppClientOrServiceStateOfHandle().
+ // Make sure the client is open before it can receive any message:
switch (CHPP_APP_GET_MESSAGE_TYPE(type)) {
- case CHPP_MESSAGE_TYPE_CLIENT_REQUEST: {
- return chppServiceOfHandle(context, handle)->requestDispatchFunctionPtr;
- }
- case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE: {
- struct ChppClientState *clientState =
- (struct ChppClientState *)chppClientServiceContextOfHandle(
- context, handle, type);
+ case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
+ case CHPP_MESSAGE_TYPE_SERVICE_REQUEST:
+ case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
+ struct ChppEndpointState *clientState =
+ chppClientStateOfHandle(context, handle);
if (clientState->openState == CHPP_OPEN_STATE_CLOSED) {
CHPP_LOGE("RX service response but client closed");
- break;
+ return NULL;
}
- return chppClientOfHandle(context, handle)->responseDispatchFunctionPtr;
+ break;
}
- case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
+ default:
+ // no check needed on the service side
+ break;
+ }
+
+ switch (CHPP_APP_GET_MESSAGE_TYPE(type)) {
+ case CHPP_MESSAGE_TYPE_CLIENT_REQUEST:
+ return chppServiceOfHandle(context, handle)->requestDispatchFunctionPtr;
+ case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
+ return chppClientOfHandle(context, handle)->responseDispatchFunctionPtr;
+ case CHPP_MESSAGE_TYPE_SERVICE_REQUEST:
+ return chppClientOfHandle(context, handle)->requestDispatchFunctionPtr;
+ case CHPP_MESSAGE_TYPE_CLIENT_RESPONSE:
+ return chppServiceOfHandle(context, handle)->responseDispatchFunctionPtr;
+ case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION:
return chppServiceOfHandle(context, handle)
->notificationDispatchFunctionPtr;
- }
- case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
- struct ChppClientState *clientState =
- (struct ChppClientState *)chppClientServiceContextOfHandle(
- context, handle, type);
- if (clientState->openState == CHPP_OPEN_STATE_CLOSED) {
- CHPP_LOGE("RX service notification but client closed");
- break;
- }
+ case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION:
return chppClientOfHandle(context, handle)
->notificationDispatchFunctionPtr;
- }
}
return NULL;
}
+#ifdef CHPP_CLIENT_ENABLED_DISCOVERY
/**
* Returns the reset notification function pointer of a particular negotiated
- * client. The function pointer will be set to null by clients that do not need
- * or support a reset notification.
+ * client.
+ *
+ * Returns null for clients that do not need or support a reset notification.
*
- * @param context Maintains status for each app layer instance.
+ * @param context State of the app layer.
* @param index Index of the registered client.
*
* @return Pointer to the reset notification function.
*/
-ChppNotifierFunction *chppGetClientResetNotifierFunction(
+static ChppNotifierFunction *chppGetClientResetNotifierFunction(
struct ChppAppState *context, uint8_t index) {
+ CHPP_DEBUG_NOT_NULL(context);
return context->registeredClients[index]->resetNotifierFunctionPtr;
}
+#endif // CHPP_CLIENT_ENABLED_DISCOVERY
/**
- * Returns the reset function pointer of a particular registered service. The
- * function pointer will be set to null by services that do not need or support
- * a reset notification.
+ * Returns the reset function pointer of a particular registered service.
+ *
+ * Returns null for services that do not need or support a reset notification.
*
- * @param context Maintains status for each app layer instance.
+ * @param context State of the app layer.
* @param index Index of the registered service.
*
* @return Pointer to the reset function.
*/
ChppNotifierFunction *chppGetServiceResetNotifierFunction(
struct ChppAppState *context, uint8_t index) {
+ CHPP_DEBUG_NOT_NULL(context);
return context->registeredServices[index]->resetNotifierFunctionPtr;
}
/**
* Returns a pointer to the ChppService struct of the service matched to a
- * negotiated handle. Returns null if a service doesn't exist for the handle.
+ * negotiated handle.
*
- * @param context Maintains status for each app layer instance.
+ * Returns null if a service doesn't exist for the handle.
+ *
+ * @param context State of the app layer.
* @param handle Handle number.
*
* @return Pointer to the ChppService struct of a particular service handle.
*/
static inline const struct ChppService *chppServiceOfHandle(
struct ChppAppState *context, uint8_t handle) {
+ CHPP_DEBUG_NOT_NULL(context);
uint8_t serviceIndex = CHPP_SERVICE_INDEX_OF_HANDLE(handle);
if (serviceIndex < context->registeredServiceCount) {
return context->registeredServices[serviceIndex];
@@ -404,15 +382,18 @@ static inline const struct ChppService *chppServiceOfHandle(
/**
* Returns a pointer to the ChppClient struct of the client matched to a
- * negotiated handle. Returns null if a client doesn't exist for the handle.
+ * negotiated handle.
+ *
+ * Returns null if a client doesn't exist for the handle.
*
- * @param context Maintains status for each app layer instance.
+ * @param context State of the app layer.
* @param handle Handle number.
*
* @return Pointer to the ChppClient struct matched to a particular handle.
*/
static inline const struct ChppClient *chppClientOfHandle(
struct ChppAppState *context, uint8_t handle) {
+ CHPP_DEBUG_NOT_NULL(context);
uint8_t serviceIndex = CHPP_SERVICE_INDEX_OF_HANDLE(handle);
if (serviceIndex < context->discoveredServiceCount) {
uint8_t clientIndex = context->clientIndexOfServiceIndex[serviceIndex];
@@ -425,71 +406,71 @@ static inline const struct ChppClient *chppClientOfHandle(
}
/**
- * Returns a pointer to the service struct of a particular negotiated service
- * handle.
- * It is up to the caller to ensure the handle number is valid.
+ * Returns the service state for a given handle.
+ *
+ * The caller must pass a valid handle.
*
- * @param context Maintains status for each app layer instance.
+ * @param context State of the app layer.
* @param handle Handle number for the service.
*
- * @return Pointer to the context struct of the service.
+ * @return Pointer to a ChppEndpointState.
*/
-static inline void *chppServiceContextOfHandle(struct ChppAppState *context,
- uint8_t handle) {
+static inline struct ChppEndpointState *chppServiceStateOfHandle(
+ struct ChppAppState *context, uint8_t handle) {
+ CHPP_DEBUG_NOT_NULL(context);
CHPP_DEBUG_ASSERT(CHPP_SERVICE_INDEX_OF_HANDLE(handle) <
context->registeredServiceCount);
- return context
- ->registeredServiceContexts[CHPP_SERVICE_INDEX_OF_HANDLE(handle)];
+
+ const uint8_t serviceIdx = CHPP_SERVICE_INDEX_OF_HANDLE(handle);
+ return context->registeredServiceStates[serviceIdx];
}
/**
- * Returns a pointer to the client struct of a particular negotiated client
- * handle.
- * It is up to the caller to ensure the handle number is valid.
+ * Returns a pointer to the client state for a given handle.
*
- * @param context Maintains status for each app layer instance.
+ * The caller must pass a valid handle.
+ *
+ * @param context State of the app layer.
* @param handle Handle number for the service.
*
- * @return Pointer to the ChppService struct of the client.
+ * @return Pointer to the endpoint state.
*/
-static inline void *chppClientContextOfHandle(struct ChppAppState *context,
- uint8_t handle) {
+static inline struct ChppEndpointState *chppClientStateOfHandle(
+ struct ChppAppState *context, uint8_t handle) {
+ CHPP_DEBUG_NOT_NULL(context);
CHPP_DEBUG_ASSERT(CHPP_SERVICE_INDEX_OF_HANDLE(handle) <
context->registeredClientCount);
- return context
- ->registeredClientContexts[context->clientIndexOfServiceIndex
- [CHPP_SERVICE_INDEX_OF_HANDLE(handle)]];
+ const uint8_t serviceIdx = CHPP_SERVICE_INDEX_OF_HANDLE(handle);
+ const uint8_t clientIdx = context->clientIndexOfServiceIndex[serviceIdx];
+ return context->registeredClientStates[clientIdx]->context;
}
/**
- * Returns a pointer to the client/service struct of a particular negotiated
- * client/service handle.
- * It is up to the caller to ensure the handle number is valid.
+ * Returns a pointer to the client or service state for a given handle.
*
- * @param appContext Maintains status for each app layer instance.
+ * The caller must pass a valid handle.
+ *
+ * @param appContext State of the app layer.
* @param handle Handle number for the service.
* @param type Message type (indicates if this is for a client or service).
*
- * @return Pointer to the client/service struct of the service handle.
+ * @return Pointer to the endpoint state (NULL if wrong type).
*/
-static void *chppClientServiceContextOfHandle(struct ChppAppState *appContext,
- uint8_t handle,
- enum ChppMessageType type) {
+static struct ChppEndpointState *chppClientOrServiceStateOfHandle(
+ struct ChppAppState *appContext, uint8_t handle,
+ enum ChppMessageType type) {
switch (CHPP_APP_GET_MESSAGE_TYPE(type)) {
case CHPP_MESSAGE_TYPE_CLIENT_REQUEST:
- case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
- return chppServiceContextOfHandle(appContext, handle);
- break;
- }
+ case CHPP_MESSAGE_TYPE_CLIENT_RESPONSE:
+ case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION:
+ return chppServiceStateOfHandle(appContext, handle);
+ case CHPP_MESSAGE_TYPE_SERVICE_REQUEST:
case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
- case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
- return chppClientContextOfHandle(appContext, handle);
- break;
- }
- default: {
+ case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION:
+ return chppClientStateOfHandle(appContext, handle);
+ default:
CHPP_LOGE("Unknown type=0x%" PRIx8 " (H#%" PRIu8 ")", type, handle);
return NULL;
- }
}
}
@@ -497,38 +478,38 @@ static void *chppClientServiceContextOfHandle(struct ChppAppState *appContext,
* Processes a received datagram that is determined to be for a predefined CHPP
* service. Responds with an error if unsuccessful.
*
- * @param context Maintains status for each app layer instance.
+ * Predefined requests are only sent by the client side.
+ * Predefined responses are only sent by the service side.
+ *
+ * @param context State of the app layer.
* @param buf Input data. Cannot be null.
* @param len Length of input data in bytes.
*/
static void chppProcessPredefinedHandleDatagram(struct ChppAppState *context,
uint8_t *buf, size_t len) {
+ CHPP_DEBUG_NOT_NULL(context);
+ CHPP_DEBUG_NOT_NULL(buf);
+
struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
- bool success = true;
+ bool success = false;
switch (CHPP_APP_GET_MESSAGE_TYPE(rxHeader->type)) {
case CHPP_MESSAGE_TYPE_CLIENT_REQUEST: {
success = chppProcessPredefinedClientRequest(context, buf, len);
break;
}
- case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
- success = chppProcessPredefinedClientNotification(context, buf, len);
- break;
- }
case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE: {
success = chppProcessPredefinedServiceResponse(context, buf, len);
break;
}
- case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
- success = chppProcessPredefinedServiceNotification(context, buf, len);
+ default:
+ // Predefined client/services do not use
+ // - notifications,
+ // - service requests / client responses
break;
- }
- default: {
- success = false;
- }
}
- if (success == false) {
+ if (!success) {
CHPP_LOGE("H#%" PRIu8 " undefined msg type=0x%" PRIx8 " (len=%" PRIuSIZE
", ID=%" PRIu8 ")",
rxHeader->handle, rxHeader->type, len, rxHeader->transaction);
@@ -539,42 +520,54 @@ static void chppProcessPredefinedHandleDatagram(struct ChppAppState *context,
/**
* Processes a received datagram that is determined to be for a negotiated CHPP
- * client or service. Responds with an error if unsuccessful.
+ * client or service.
+ *
+ * The datagram is processed by the dispatch function matching the datagram
+ * type. @see ChppService and ChppClient.
*
- * @param context Maintains status for each app layer instance.
+ * If a request dispatch function returns an error (anything different from
+ * CHPP_APP_ERROR_NONE) then an error response is automatically sent back to the
+ * remote endpoint.
+ *
+ * @param appContext State of the app layer.
* @param buf Input data. Cannot be null.
* @param len Length of input data in bytes.
*/
-static void chppProcessNegotiatedHandleDatagram(struct ChppAppState *context,
+static void chppProcessNegotiatedHandleDatagram(struct ChppAppState *appContext,
uint8_t *buf, size_t len) {
- struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
+ CHPP_DEBUG_NOT_NULL(appContext);
+ CHPP_DEBUG_NOT_NULL(buf);
+
+ const struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
enum ChppMessageType messageType = CHPP_APP_GET_MESSAGE_TYPE(rxHeader->type);
- void *clientServiceContext =
- chppClientServiceContextOfHandle(context, rxHeader->handle, messageType);
- if (clientServiceContext == NULL) {
+ // Could be either the client or the service state depending on the message
+ // type.
+ struct ChppEndpointState *endpointState = chppClientOrServiceStateOfHandle(
+ appContext, rxHeader->handle, messageType);
+ if (endpointState == NULL) {
CHPP_LOGE("H#%" PRIu8 " missing ctx (msg=0x%" PRIx8 " len=%" PRIuSIZE
", ID=%" PRIu8 ")",
rxHeader->handle, rxHeader->type, len, rxHeader->transaction);
- chppEnqueueTxErrorDatagram(context->transportContext,
+ chppEnqueueTxErrorDatagram(appContext->transportContext,
CHPP_TRANSPORT_ERROR_APPLAYER);
CHPP_DEBUG_ASSERT(false);
return;
}
ChppDispatchFunction *dispatchFunc =
- chppGetDispatchFunction(context, rxHeader->handle, messageType);
+ chppGetDispatchFunction(appContext, rxHeader->handle, messageType);
if (dispatchFunc == NULL) {
CHPP_LOGE("H#%" PRIu8 " unsupported msg=0x%" PRIx8 " (len=%" PRIuSIZE
", ID=%" PRIu8 ")",
rxHeader->handle, rxHeader->type, len, rxHeader->transaction);
- chppEnqueueTxErrorDatagram(context->transportContext,
+ chppEnqueueTxErrorDatagram(appContext->transportContext,
CHPP_TRANSPORT_ERROR_APPLAYER);
return;
}
// All good. Dispatch datagram and possibly notify a waiting client
- enum ChppAppErrorCode error = dispatchFunc(clientServiceContext, buf, len);
+ enum ChppAppErrorCode error = dispatchFunc(endpointState->context, buf, len);
if (error != CHPP_APP_ERROR_NONE) {
CHPP_LOGE("RX dispatch err=0x%" PRIx16 " H#%" PRIu8 " type=0x%" PRIx8
@@ -582,34 +575,30 @@ static void chppProcessNegotiatedHandleDatagram(struct ChppAppState *context,
error, rxHeader->handle, rxHeader->type, rxHeader->transaction,
rxHeader->command, len);
- // Only client requests require a dispatch failure response.
- if (messageType == CHPP_MESSAGE_TYPE_CLIENT_REQUEST) {
+ // Requests require a dispatch failure response.
+ if (messageType == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ||
+ messageType == CHPP_MESSAGE_TYPE_SERVICE_REQUEST) {
struct ChppAppHeader *response =
- chppAllocServiceResponseFixed(rxHeader, struct ChppAppHeader);
- if (response == NULL) {
- CHPP_LOG_OOM();
- } else {
+ chppAllocResponseFixed(rxHeader, struct ChppAppHeader);
+ if (response != NULL) {
response->error = (uint8_t)error;
- chppEnqueueTxDatagramOrFail(context->transportContext, response,
+ chppEnqueueTxDatagramOrFail(appContext->transportContext, response,
sizeof(*response));
}
}
return;
}
- if (messageType == CHPP_MESSAGE_TYPE_SERVICE_RESPONSE) {
- // Datagram is a service response. Check for synchronous operation and
- // notify waiting client if needed.
-
- struct ChppClientState *clientState =
- (struct ChppClientState *)clientServiceContext;
- chppMutexLock(&clientState->responseMutex);
- clientState->responseReady = true;
- CHPP_LOGD(
- "Finished dispatching a service response. Notifying a potential "
- "synchronous client");
- chppConditionVariableSignal(&clientState->responseCondVar);
- chppMutexUnlock(&clientState->responseMutex);
+ // Datagram is a response.
+ // Check for synchronous operation and notify waiting endpoint if needed.
+ if (messageType == CHPP_MESSAGE_TYPE_SERVICE_RESPONSE ||
+ messageType == CHPP_MESSAGE_TYPE_CLIENT_RESPONSE) {
+ struct ChppSyncResponse *syncResponse = &endpointState->syncResponse;
+ chppMutexLock(&syncResponse->mutex);
+ syncResponse->ready = true;
+ CHPP_LOGD("Finished dispatching a response -> synchronous notification");
+ chppConditionVariableSignal(&syncResponse->condVar);
+ chppMutexUnlock(&syncResponse->mutex);
}
}
@@ -631,6 +620,7 @@ void chppAppInitWithClientServiceSet(
struct ChppTransportState *transportContext,
struct ChppClientServiceSet clientServiceSet) {
CHPP_NOT_NULL(appContext);
+ CHPP_DEBUG_NOT_NULL(transportContext);
CHPP_LOGD("App Init");
@@ -638,7 +628,8 @@ void chppAppInitWithClientServiceSet(
appContext->clientServiceSet = clientServiceSet;
appContext->transportContext = transportContext;
- appContext->nextRequestTimeoutNs = CHPP_TIME_MAX;
+ appContext->nextClientRequestTimeoutNs = CHPP_TIME_MAX;
+ appContext->nextServiceRequestTimeoutNs = CHPP_TIME_MAX;
chppPalSystemApiInit(appContext);
@@ -670,7 +661,10 @@ void chppAppDeinit(struct ChppAppState *appContext) {
void chppAppProcessRxDatagram(struct ChppAppState *context, uint8_t *buf,
size_t len) {
- struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
+ CHPP_DEBUG_NOT_NULL(context);
+ CHPP_DEBUG_NOT_NULL(buf);
+
+ const struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
if (len == 0) {
CHPP_DEBUG_ASSERT_LOG(false, "App rx w/ len 0");
@@ -711,6 +705,8 @@ void chppAppProcessRxDatagram(struct ChppAppState *context, uint8_t *buf,
}
void chppAppProcessReset(struct ChppAppState *context) {
+ CHPP_DEBUG_NOT_NULL(context);
+
#ifdef CHPP_CLIENT_ENABLED_DISCOVERY
if (!context->isDiscoveryComplete) {
chppInitiateDiscovery(context);
@@ -729,7 +725,8 @@ void chppAppProcessReset(struct ChppAppState *context) {
(ResetNotifierFunction != NULL));
if (ResetNotifierFunction != NULL) {
- ResetNotifierFunction(context->registeredClientContexts[clientIndex]);
+ ResetNotifierFunction(
+ context->registeredClientStates[clientIndex]->context);
}
}
}
@@ -745,7 +742,7 @@ void chppAppProcessReset(struct ChppAppState *context) {
CHPP_SERVICE_HANDLE_OF_INDEX(i), (ResetNotifierFunction != NULL));
if (ResetNotifierFunction != NULL) {
- ResetNotifierFunction(context->registeredServiceContexts[i]);
+ ResetNotifierFunction(context->registeredServiceStates[i]->context);
}
}
@@ -786,8 +783,11 @@ uint8_t chppAppErrorToChreError(uint8_t chppError) {
uint8_t chppAppShortResponseErrorHandler(uint8_t *buf, size_t len,
const char *responseName) {
+ CHPP_DEBUG_NOT_NULL(buf);
+ CHPP_DEBUG_NOT_NULL(responseName);
+
CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
- struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
+ const struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
if (rxHeader->error == CHPP_APP_ERROR_NONE) {
CHPP_LOGE("%s resp short len=%" PRIuSIZE, responseName, len);
@@ -797,3 +797,422 @@ uint8_t chppAppShortResponseErrorHandler(uint8_t *buf, size_t len,
CHPP_LOGD("%s resp short len=%" PRIuSIZE, responseName, len);
return chppAppErrorToChreError(rxHeader->error);
}
+
+struct ChppAppHeader *chppAllocNotification(uint8_t type, size_t len) {
+ CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
+ CHPP_ASSERT(type == CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION ||
+ type == CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION);
+
+ struct ChppAppHeader *notification = chppMalloc(len);
+ if (notification != NULL) {
+ notification->type = type;
+ notification->handle = CHPP_HANDLE_NONE;
+ notification->transaction = 0;
+ notification->error = CHPP_APP_ERROR_NONE;
+ notification->command = CHPP_APP_COMMAND_NONE;
+ } else {
+ CHPP_LOG_OOM();
+ }
+ return notification;
+}
+
+struct ChppAppHeader *chppAllocRequest(uint8_t type,
+ struct ChppEndpointState *endpointState,
+ size_t len) {
+ CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
+ CHPP_ASSERT(type == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ||
+ type == CHPP_MESSAGE_TYPE_SERVICE_REQUEST);
+ CHPP_DEBUG_NOT_NULL(endpointState);
+
+ struct ChppAppHeader *request = chppMalloc(len);
+ if (request != NULL) {
+ request->handle = endpointState->handle;
+ request->type = type;
+ request->transaction = endpointState->transaction;
+ request->error = CHPP_APP_ERROR_NONE;
+ request->command = CHPP_APP_COMMAND_NONE;
+
+ endpointState->transaction++;
+ } else {
+ CHPP_LOG_OOM();
+ }
+ return request;
+}
+
+struct ChppAppHeader *chppAllocResponse(
+ const struct ChppAppHeader *requestHeader, size_t len) {
+ CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
+ CHPP_DEBUG_NOT_NULL(requestHeader);
+ uint8_t type = requestHeader->type;
+ CHPP_ASSERT(type == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ||
+ type == CHPP_MESSAGE_TYPE_SERVICE_REQUEST);
+
+ struct ChppAppHeader *response = chppMalloc(len);
+ if (response != NULL) {
+ *response = *requestHeader;
+ response->type = type == CHPP_MESSAGE_TYPE_CLIENT_REQUEST
+ ? CHPP_MESSAGE_TYPE_SERVICE_RESPONSE
+ : CHPP_MESSAGE_TYPE_CLIENT_RESPONSE;
+ response->error = CHPP_APP_ERROR_NONE;
+ } else {
+ CHPP_LOG_OOM();
+ }
+ return response;
+}
+
+void chppTimestampIncomingRequest(struct ChppIncomingRequestState *inReqState,
+ const struct ChppAppHeader *requestHeader) {
+ CHPP_DEBUG_NOT_NULL(inReqState);
+ CHPP_DEBUG_NOT_NULL(requestHeader);
+ if (inReqState->responseTimeNs == CHPP_TIME_NONE &&
+ inReqState->requestTimeNs != CHPP_TIME_NONE) {
+ CHPP_LOGE("RX dupe req t=%" PRIu64,
+ inReqState->requestTimeNs / CHPP_NSEC_PER_MSEC);
+ }
+ inReqState->requestTimeNs = chppGetCurrentTimeNs();
+ inReqState->responseTimeNs = CHPP_TIME_NONE;
+ inReqState->transaction = requestHeader->transaction;
+}
+
+void chppTimestampOutgoingRequest(struct ChppAppState *appState,
+ struct ChppOutgoingRequestState *outReqState,
+ const struct ChppAppHeader *requestHeader,
+ uint64_t timeoutNs) {
+ CHPP_DEBUG_NOT_NULL(appState);
+ CHPP_DEBUG_NOT_NULL(outReqState);
+ CHPP_DEBUG_NOT_NULL(requestHeader);
+ enum ChppMessageType msgType = requestHeader->type;
+ enum ChppEndpointType endpointType =
+ msgType == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ? CHPP_ENDPOINT_CLIENT
+ : CHPP_ENDPOINT_SERVICE;
+
+ CHPP_ASSERT(msgType == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ||
+ msgType == CHPP_MESSAGE_TYPE_SERVICE_REQUEST);
+
+ if (outReqState->requestState == CHPP_REQUEST_STATE_REQUEST_SENT) {
+ CHPP_LOGE("Dupe req ID=%" PRIu8 " existing ID=%" PRIu8 " from t=%" PRIu64,
+ requestHeader->transaction, outReqState->transaction,
+ outReqState->requestTimeNs / CHPP_NSEC_PER_MSEC);
+
+ // Clear a possible pending timeout from the previous request
+ outReqState->responseTimeNs = CHPP_TIME_MAX;
+ chppRecalculateNextTimeout(appState, endpointType);
+ }
+
+ outReqState->requestTimeNs = chppGetCurrentTimeNs();
+ outReqState->requestState = CHPP_REQUEST_STATE_REQUEST_SENT;
+ outReqState->transaction = requestHeader->transaction;
+
+ uint64_t *nextRequestTimeoutNs =
+ getNextRequestTimeoutNs(appState, endpointType);
+
+ if (timeoutNs == CHPP_REQUEST_TIMEOUT_INFINITE) {
+ outReqState->responseTimeNs = CHPP_TIME_MAX;
+
+ } else {
+ outReqState->responseTimeNs = timeoutNs + outReqState->requestTimeNs;
+
+ *nextRequestTimeoutNs =
+ MIN(*nextRequestTimeoutNs, outReqState->responseTimeNs);
+ }
+
+ CHPP_LOGD("Timestamp req ID=%" PRIu8 " at t=%" PRIu64 " timeout=%" PRIu64
+ " (requested=%" PRIu64 "), next timeout=%" PRIu64,
+ outReqState->transaction,
+ outReqState->requestTimeNs / CHPP_NSEC_PER_MSEC,
+ outReqState->responseTimeNs / CHPP_NSEC_PER_MSEC,
+ timeoutNs / CHPP_NSEC_PER_MSEC,
+ *nextRequestTimeoutNs / CHPP_NSEC_PER_MSEC);
+}
+
+bool chppTimestampIncomingResponse(struct ChppAppState *appState,
+ struct ChppOutgoingRequestState *outReqState,
+ const struct ChppAppHeader *responseHeader) {
+ CHPP_DEBUG_NOT_NULL(appState);
+ CHPP_DEBUG_NOT_NULL(outReqState);
+ CHPP_DEBUG_NOT_NULL(responseHeader);
+
+ uint8_t type = responseHeader->type;
+
+ CHPP_ASSERT(type == CHPP_MESSAGE_TYPE_CLIENT_RESPONSE ||
+ type == CHPP_MESSAGE_TYPE_SERVICE_RESPONSE);
+
+ bool success = false;
+ uint64_t responseTime = chppGetCurrentTimeNs();
+
+ switch (outReqState->requestState) {
+ case CHPP_REQUEST_STATE_NONE: {
+ CHPP_LOGE("Resp with no req t=%" PRIu64,
+ responseTime / CHPP_NSEC_PER_MSEC);
+ break;
+ }
+
+ case CHPP_REQUEST_STATE_RESPONSE_RCV: {
+ CHPP_LOGE("Extra resp at t=%" PRIu64 " for req t=%" PRIu64,
+ responseTime / CHPP_NSEC_PER_MSEC,
+ outReqState->requestTimeNs / CHPP_NSEC_PER_MSEC);
+ break;
+ }
+
+ case CHPP_REQUEST_STATE_RESPONSE_TIMEOUT: {
+ CHPP_LOGE("Late resp at t=%" PRIu64 " for req t=%" PRIu64,
+ responseTime / CHPP_NSEC_PER_MSEC,
+ outReqState->requestTimeNs / CHPP_NSEC_PER_MSEC);
+ break;
+ }
+
+ case CHPP_REQUEST_STATE_REQUEST_SENT: {
+ if (responseHeader->transaction != outReqState->transaction) {
+ CHPP_LOGE("Invalid resp ID=%" PRIu8 " at t=%" PRIu64
+ " expected=%" PRIu8,
+ responseHeader->transaction,
+ responseTime / CHPP_NSEC_PER_MSEC, outReqState->transaction);
+ } else {
+ outReqState->requestState = (responseTime > outReqState->responseTimeNs)
+ ? CHPP_REQUEST_STATE_RESPONSE_TIMEOUT
+ : CHPP_REQUEST_STATE_RESPONSE_RCV;
+ success = true;
+
+ CHPP_LOGD(
+ "Timestamp resp ID=%" PRIu8 " req t=%" PRIu64 " resp t=%" PRIu64
+ " timeout t=%" PRIu64 " (RTT=%" PRIu64 ", timeout = %s)",
+ outReqState->transaction,
+ outReqState->requestTimeNs / CHPP_NSEC_PER_MSEC,
+ responseTime / CHPP_NSEC_PER_MSEC,
+ outReqState->responseTimeNs / CHPP_NSEC_PER_MSEC,
+ (responseTime - outReqState->requestTimeNs) / CHPP_NSEC_PER_MSEC,
+ (responseTime > outReqState->responseTimeNs) ? "yes" : "no");
+ }
+ break;
+ }
+
+ default: {
+ CHPP_DEBUG_ASSERT_LOG(false, "Invalid req state");
+ }
+ }
+
+ if (success) {
+ // When the received request is the next one that was expected
+ // to timeout we need to recompute the timeout considering the
+ // other pending requests.
+ enum ChppEndpointType endpointType =
+ type == CHPP_MESSAGE_TYPE_SERVICE_RESPONSE ? CHPP_ENDPOINT_CLIENT
+ : CHPP_ENDPOINT_SERVICE;
+ if (outReqState->responseTimeNs ==
+ *getNextRequestTimeoutNs(appState, endpointType)) {
+ chppRecalculateNextTimeout(appState, endpointType);
+ }
+ outReqState->responseTimeNs = responseTime;
+ }
+ return success;
+}
+
+uint64_t chppTimestampOutgoingResponse(
+ struct ChppIncomingRequestState *inReqState) {
+ CHPP_DEBUG_NOT_NULL(inReqState);
+
+ uint64_t previousResponseTime = inReqState->responseTimeNs;
+ inReqState->responseTimeNs = chppGetCurrentTimeNs();
+ return previousResponseTime;
+}
+
+bool chppSendTimestampedResponseOrFail(
+ struct ChppAppState *appState, struct ChppIncomingRequestState *inReqState,
+ void *buf, size_t len) {
+ CHPP_DEBUG_NOT_NULL(appState);
+ CHPP_DEBUG_NOT_NULL(inReqState);
+ CHPP_DEBUG_NOT_NULL(buf);
+ uint64_t previousResponseTime = chppTimestampOutgoingResponse(inReqState);
+
+ if (inReqState->requestTimeNs == CHPP_TIME_NONE) {
+ CHPP_LOGE("TX response w/ no req t=%" PRIu64,
+ inReqState->responseTimeNs / CHPP_NSEC_PER_MSEC);
+
+ } else if (previousResponseTime != CHPP_TIME_NONE) {
+ CHPP_LOGW("TX additional response t=%" PRIu64 " for req t=%" PRIu64,
+ inReqState->responseTimeNs / CHPP_NSEC_PER_MSEC,
+ inReqState->requestTimeNs / CHPP_NSEC_PER_MSEC);
+
+ } else {
+ CHPP_LOGD("Sending initial response at t=%" PRIu64
+ " for request at t=%" PRIu64 " (RTT=%" PRIu64 ")",
+ inReqState->responseTimeNs / CHPP_NSEC_PER_MSEC,
+ inReqState->requestTimeNs / CHPP_NSEC_PER_MSEC,
+ (inReqState->responseTimeNs - inReqState->requestTimeNs) /
+ CHPP_NSEC_PER_MSEC);
+ }
+
+ return chppEnqueueTxDatagramOrFail(appState->transportContext, buf, len);
+}
+
+bool chppSendTimestampedRequestOrFail(
+ struct ChppEndpointState *endpointState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
+ uint64_t timeoutNs) {
+ CHPP_DEBUG_NOT_NULL(outReqState);
+ CHPP_DEBUG_NOT_NULL(buf);
+ CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
+
+ if (timeoutNs < CHPP_TRANSPORT_TX_TIMEOUT_NS) {
+ // The app layer sits above the transport layer.
+ // Request timeout (app layer) should be longer than the transport timeout.
+ CHPP_LOGW("Request timeout (%" PRIu64
+ "ns) should be longer than the transport timeout (%" PRIu64 "ns)",
+ timeoutNs, (uint64_t)CHPP_TRANSPORT_TX_TIMEOUT_NS);
+ }
+
+ chppTimestampOutgoingRequest(endpointState->appContext, outReqState, buf,
+ timeoutNs);
+ endpointState->syncResponse.ready = false;
+
+ bool success = chppEnqueueTxDatagramOrFail(
+ endpointState->appContext->transportContext, buf, len);
+
+ // Failure to enqueue a TX datagram means that a request was known to be not
+ // transmitted. We explicitly set requestState to be in the NONE state, so
+ // that unintended app layer timeouts do not occur.
+ if (!success) {
+ outReqState->requestState = CHPP_REQUEST_STATE_NONE;
+ }
+
+ return success;
+}
+
+bool chppWaitForResponseWithTimeout(
+ struct ChppSyncResponse *syncResponse,
+ struct ChppOutgoingRequestState *outReqState, uint64_t timeoutNs) {
+ CHPP_DEBUG_NOT_NULL(syncResponse);
+ CHPP_DEBUG_NOT_NULL(outReqState);
+
+ bool result = true;
+
+ chppMutexLock(&syncResponse->mutex);
+
+ while (result && !syncResponse->ready) {
+ result = chppConditionVariableTimedWait(&syncResponse->condVar,
+ &syncResponse->mutex, timeoutNs);
+ }
+ if (!syncResponse->ready) {
+ outReqState->requestState = CHPP_REQUEST_STATE_RESPONSE_TIMEOUT;
+ CHPP_LOGE("Response timeout after %" PRIu64 " ms",
+ timeoutNs / CHPP_NSEC_PER_MSEC);
+ result = false;
+ }
+
+ chppMutexUnlock(&syncResponse->mutex);
+
+ return result;
+}
+
+struct ChppEndpointState *getRegisteredEndpointState(
+ struct ChppAppState *appState, uint8_t index, enum ChppEndpointType type) {
+ CHPP_DEBUG_NOT_NULL(appState);
+ CHPP_DEBUG_ASSERT(index < getRegisteredEndpointCount(appState, type));
+
+ return type == CHPP_ENDPOINT_CLIENT
+ ? appState->registeredClientStates[index]
+ : appState->registeredServiceStates[index];
+}
+
+uint16_t getRegisteredEndpointOutReqCount(struct ChppAppState *appState,
+ uint8_t index,
+ enum ChppEndpointType type) {
+ CHPP_DEBUG_NOT_NULL(appState);
+ CHPP_DEBUG_ASSERT(index < getRegisteredEndpointCount(appState, type));
+
+ return type == CHPP_ENDPOINT_CLIENT
+ ? appState->registeredClients[index]->outReqCount
+ : appState->registeredServices[index]->outReqCount;
+}
+
+uint8_t getRegisteredEndpointCount(struct ChppAppState *appState,
+ enum ChppEndpointType type) {
+ return type == CHPP_ENDPOINT_CLIENT ? appState->registeredClientCount
+ : appState->registeredServiceCount;
+}
+
+void chppRecalculateNextTimeout(struct ChppAppState *appState,
+ enum ChppEndpointType type) {
+ CHPP_DEBUG_NOT_NULL(appState);
+
+ uint64_t timeoutNs = CHPP_TIME_MAX;
+
+ const uint8_t endpointCount = getRegisteredEndpointCount(appState, type);
+
+ for (uint8_t endpointIdx = 0; endpointIdx < endpointCount; endpointIdx++) {
+ uint16_t reqCount =
+ getRegisteredEndpointOutReqCount(appState, endpointIdx, type);
+ struct ChppEndpointState *endpointState =
+ getRegisteredEndpointState(appState, endpointIdx, type);
+ struct ChppOutgoingRequestState *reqStates = endpointState->outReqStates;
+ for (uint16_t cmdIdx = 0; cmdIdx < reqCount; cmdIdx++) {
+ struct ChppOutgoingRequestState *reqState = &reqStates[cmdIdx];
+
+ if (reqState->requestState == CHPP_REQUEST_STATE_REQUEST_SENT) {
+ timeoutNs = MIN(timeoutNs, reqState->responseTimeNs);
+ }
+ }
+ }
+
+ CHPP_LOGD("nextReqTimeout=%" PRIu64, timeoutNs / CHPP_NSEC_PER_MSEC);
+
+ if (type == CHPP_ENDPOINT_CLIENT) {
+ appState->nextClientRequestTimeoutNs = timeoutNs;
+ } else {
+ appState->nextServiceRequestTimeoutNs = timeoutNs;
+ }
+}
+
+uint64_t *getNextRequestTimeoutNs(struct ChppAppState *appState,
+ enum ChppEndpointType type) {
+ return type == CHPP_ENDPOINT_CLIENT ? &appState->nextClientRequestTimeoutNs
+ : &appState->nextServiceRequestTimeoutNs;
+}
+
+void chppCloseOpenRequests(struct ChppEndpointState *endpointState,
+ enum ChppEndpointType type, bool clearOnly) {
+ CHPP_DEBUG_NOT_NULL(endpointState);
+
+ bool recalcNeeded = false;
+
+ struct ChppAppState *appState = endpointState->appContext;
+ const uint8_t enpointIdx = endpointState->index;
+ const uint16_t cmdCount =
+ getRegisteredEndpointOutReqCount(appState, enpointIdx, type);
+
+ for (uint16_t cmdIdx = 0; cmdIdx < cmdCount; cmdIdx++) {
+ if (endpointState->outReqStates[cmdIdx].requestState ==
+ CHPP_REQUEST_STATE_REQUEST_SENT) {
+ recalcNeeded = true;
+
+ CHPP_LOGE("Closing open req #%" PRIu16 " clear %d", cmdIdx, clearOnly);
+
+ if (clearOnly) {
+ endpointState->outReqStates[cmdIdx].requestState =
+ CHPP_REQUEST_STATE_RESPONSE_TIMEOUT;
+ } else {
+ struct ChppAppHeader *response =
+ chppMalloc(sizeof(struct ChppAppHeader));
+ if (response == NULL) {
+ CHPP_LOG_OOM();
+ } else {
+ // Simulate receiving a timeout response.
+ response->handle = endpointState->handle;
+ response->type = type == CHPP_ENDPOINT_CLIENT
+ ? CHPP_MESSAGE_TYPE_SERVICE_RESPONSE
+ : CHPP_MESSAGE_TYPE_CLIENT_RESPONSE;
+ response->transaction =
+ endpointState->outReqStates[cmdIdx].transaction;
+ response->error = CHPP_APP_ERROR_TIMEOUT;
+ response->command = cmdIdx;
+
+ chppAppProcessRxDatagram(appState, (uint8_t *)response,
+ sizeof(struct ChppAppHeader));
+ }
+ }
+ }
+ }
+ if (recalcNeeded) {
+ chppRecalculateNextTimeout(appState, type);
+ }
+} \ No newline at end of file
diff --git a/chpp/clients.c b/chpp/clients.c
index 198e32b2..4c3df54e 100644
--- a/chpp/clients.c
+++ b/chpp/clients.c
@@ -50,8 +50,8 @@
* Prototypes
***********************************************/
-static bool chppIsClientApiReady(struct ChppClientState *clientState);
-ChppClientDeinitFunction *chppGetClientDeinitFunction(
+static bool chppIsClientApiReady(struct ChppEndpointState *clientState);
+static ChppClientDeinitFunction *chppGetClientDeinitFunction(
struct ChppAppState *context, uint8_t index);
/************************************************
@@ -65,9 +65,11 @@ ChppClientDeinitFunction *chppGetClientDeinitFunction(
*
* @param clientState State of the client sending the client request.
*
- * @return Indicates whetherthe client is ready.
+ * @return Indicates whether the client is ready.
*/
-static bool chppIsClientApiReady(struct ChppClientState *clientState) {
+static bool chppIsClientApiReady(struct ChppEndpointState *clientState) {
+ CHPP_DEBUG_NOT_NULL(clientState);
+
bool result = false;
if (clientState->initialized) {
@@ -109,8 +111,10 @@ static bool chppIsClientApiReady(struct ChppClientState *clientState) {
*
* @return Pointer to the match notification function.
*/
-ChppClientDeinitFunction *chppGetClientDeinitFunction(
+static ChppClientDeinitFunction *chppGetClientDeinitFunction(
struct ChppAppState *context, uint8_t index) {
+ CHPP_DEBUG_NOT_NULL(context);
+
return context->registeredClients[index]->deinitFunctionPtr;
}
@@ -120,6 +124,8 @@ ChppClientDeinitFunction *chppGetClientDeinitFunction(
void chppRegisterCommonClients(struct ChppAppState *context) {
UNUSED_VAR(context);
+ CHPP_DEBUG_NOT_NULL(context);
+
CHPP_LOGD("Registering Clients");
#ifdef CHPP_CLIENT_ENABLED_WWAN
@@ -143,6 +149,8 @@ void chppRegisterCommonClients(struct ChppAppState *context) {
void chppDeregisterCommonClients(struct ChppAppState *context) {
UNUSED_VAR(context);
+ CHPP_DEBUG_NOT_NULL(context);
+
CHPP_LOGD("Deregistering Clients");
#ifdef CHPP_CLIENT_ENABLED_WWAN
@@ -165,10 +173,14 @@ void chppDeregisterCommonClients(struct ChppAppState *context) {
}
void chppRegisterClient(struct ChppAppState *appContext, void *clientContext,
- struct ChppClientState *clientState,
- struct ChppRequestResponseState *rRStates,
+ struct ChppEndpointState *clientState,
+ struct ChppOutgoingRequestState *outReqStates,
const struct ChppClient *newClient) {
CHPP_NOT_NULL(newClient);
+ CHPP_DEBUG_NOT_NULL(appContext);
+ CHPP_DEBUG_NOT_NULL(clientContext);
+ CHPP_DEBUG_NOT_NULL(clientState);
+ CHPP_DEBUG_NOT_NULL(newClient);
if (appContext->registeredClientCount >= CHPP_MAX_REGISTERED_CLIENTS) {
CHPP_LOGE("Max clients registered: %" PRIu8,
@@ -176,13 +188,12 @@ void chppRegisterClient(struct ChppAppState *appContext, void *clientContext,
return;
}
clientState->appContext = appContext;
- clientState->rRStates = rRStates;
+ clientState->outReqStates = outReqStates;
clientState->index = appContext->registeredClientCount;
-
- appContext->registeredClientContexts[appContext->registeredClientCount] =
- clientContext;
+ clientState->context = clientContext;
appContext->registeredClientStates[appContext->registeredClientCount] =
clientState;
+
appContext->registeredClients[appContext->registeredClientCount] = newClient;
char uuidText[CHPP_SERVICE_UUID_STRING_LEN];
@@ -199,6 +210,8 @@ void chppRegisterClient(struct ChppAppState *appContext, void *clientContext,
void chppInitBasicClients(struct ChppAppState *context) {
UNUSED_VAR(context);
+ CHPP_DEBUG_NOT_NULL(context);
+
CHPP_LOGD("Initializing basic clients");
#ifdef CHPP_CLIENT_ENABLED_LOOPBACK
@@ -216,21 +229,23 @@ void chppInitBasicClients(struct ChppAppState *context) {
#endif
}
-void chppClientInit(struct ChppClientState *clientState, uint8_t handle) {
+void chppClientInit(struct ChppEndpointState *clientState, uint8_t handle) {
+ CHPP_DEBUG_NOT_NULL(clientState);
CHPP_ASSERT_LOG(!clientState->initialized,
"Client H#%" PRIu8 " already initialized", handle);
if (!clientState->everInitialized) {
clientState->handle = handle;
- chppMutexInit(&clientState->responseMutex);
- chppConditionVariableInit(&clientState->responseCondVar);
+ chppMutexInit(&clientState->syncResponse.mutex);
+ chppConditionVariableInit(&clientState->syncResponse.condVar);
clientState->everInitialized = true;
}
clientState->initialized = true;
}
-void chppClientDeinit(struct ChppClientState *clientState) {
+void chppClientDeinit(struct ChppEndpointState *clientState) {
+ CHPP_DEBUG_NOT_NULL(clientState);
CHPP_ASSERT_LOG(clientState->initialized,
"Client H#%" PRIu8 " already deinitialized",
clientState->handle);
@@ -240,6 +255,8 @@ void chppClientDeinit(struct ChppClientState *clientState) {
void chppDeinitBasicClients(struct ChppAppState *context) {
UNUSED_VAR(context);
+ CHPP_DEBUG_NOT_NULL(context);
+
CHPP_LOGD("Deinitializing basic clients");
#ifdef CHPP_CLIENT_ENABLED_LOOPBACK
@@ -258,6 +275,7 @@ void chppDeinitBasicClients(struct ChppAppState *context) {
}
void chppDeinitMatchedClients(struct ChppAppState *context) {
+ CHPP_DEBUG_NOT_NULL(context);
CHPP_LOGD("Deinitializing matched clients");
for (uint8_t i = 0; i < context->discoveredServiceCount; i++) {
@@ -272,211 +290,79 @@ void chppDeinitMatchedClients(struct ChppAppState *context) {
(clientDeinitFunction != NULL));
if (clientDeinitFunction != NULL) {
- clientDeinitFunction(context->registeredClientContexts[clientIndex]);
+ clientDeinitFunction(
+ context->registeredClientStates[clientIndex]->context);
}
}
}
}
struct ChppAppHeader *chppAllocClientRequest(
- struct ChppClientState *clientState, size_t len) {
- CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
-
- struct ChppAppHeader *result = chppMalloc(len);
- if (result != NULL) {
- result->handle = clientState->handle;
- result->type = CHPP_MESSAGE_TYPE_CLIENT_REQUEST;
- result->transaction = clientState->transaction;
- result->error = CHPP_APP_ERROR_NONE;
- result->command = CHPP_APP_COMMAND_NONE;
-
- clientState->transaction++;
- }
- return result;
+ struct ChppEndpointState *clientState, size_t len) {
+ CHPP_DEBUG_NOT_NULL(clientState);
+ return chppAllocRequest(CHPP_MESSAGE_TYPE_CLIENT_REQUEST, clientState, len);
}
struct ChppAppHeader *chppAllocClientRequestCommand(
- struct ChppClientState *clientState, uint16_t command) {
- struct ChppAppHeader *result =
+ struct ChppEndpointState *clientState, uint16_t command) {
+ struct ChppAppHeader *request =
chppAllocClientRequest(clientState, sizeof(struct ChppAppHeader));
- if (result != NULL) {
- result->command = command;
+ if (request != NULL) {
+ request->command = command;
}
- return result;
+ return request;
}
-void chppClientTimestampRequest(struct ChppClientState *clientState,
- struct ChppRequestResponseState *rRState,
- struct ChppAppHeader *requestHeader,
- uint64_t timeoutNs) {
- if (rRState->requestState == CHPP_REQUEST_STATE_REQUEST_SENT) {
- CHPP_LOGE("Dupe req ID=%" PRIu8 " existing ID=%" PRIu8 " from t=%" PRIu64,
- requestHeader->transaction, rRState->transaction,
- rRState->requestTimeNs / CHPP_NSEC_PER_MSEC);
-
- // Clear a possible pending timeout from the previous request
- rRState->responseTimeNs = CHPP_TIME_MAX;
- chppClientRecalculateNextTimeout(clientState->appContext);
- }
-
- rRState->requestTimeNs = chppGetCurrentTimeNs();
- rRState->requestState = CHPP_REQUEST_STATE_REQUEST_SENT;
- rRState->transaction = requestHeader->transaction;
-
- if (timeoutNs == CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE) {
- rRState->responseTimeNs = CHPP_TIME_MAX;
-
- } else {
- rRState->responseTimeNs = timeoutNs + rRState->requestTimeNs;
-
- clientState->appContext->nextRequestTimeoutNs = MIN(
- clientState->appContext->nextRequestTimeoutNs, rRState->responseTimeNs);
- }
-
- CHPP_LOGD("Timestamp req ID=%" PRIu8 " at t=%" PRIu64 " timeout=%" PRIu64
- " (requested=%" PRIu64 "), next timeout=%" PRIu64,
- rRState->transaction, rRState->requestTimeNs / CHPP_NSEC_PER_MSEC,
- rRState->responseTimeNs / CHPP_NSEC_PER_MSEC,
- timeoutNs / CHPP_NSEC_PER_MSEC,
- clientState->appContext->nextRequestTimeoutNs / CHPP_NSEC_PER_MSEC);
-}
-
-bool chppClientTimestampResponse(struct ChppClientState *clientState,
- struct ChppRequestResponseState *rRState,
- const struct ChppAppHeader *responseHeader) {
- bool success = false;
- uint64_t responseTime = chppGetCurrentTimeNs();
-
- switch (rRState->requestState) {
- case CHPP_REQUEST_STATE_NONE: {
- CHPP_LOGE("Resp with no req t=%" PRIu64,
- responseTime / CHPP_NSEC_PER_MSEC);
- break;
- }
-
- case CHPP_REQUEST_STATE_RESPONSE_RCV: {
- CHPP_LOGE("Extra resp at t=%" PRIu64 " for req t=%" PRIu64,
- responseTime / CHPP_NSEC_PER_MSEC,
- rRState->requestTimeNs / CHPP_NSEC_PER_MSEC);
- break;
- }
-
- case CHPP_REQUEST_STATE_RESPONSE_TIMEOUT: {
- CHPP_LOGE("Late resp at t=%" PRIu64 " for req t=%" PRIu64,
- responseTime / CHPP_NSEC_PER_MSEC,
- rRState->requestTimeNs / CHPP_NSEC_PER_MSEC);
- break;
- }
-
- case CHPP_REQUEST_STATE_REQUEST_SENT: {
- if (responseHeader->transaction != rRState->transaction) {
- CHPP_LOGE("Invalid resp ID=%" PRIu8 " at t=%" PRIu64
- " expected=%" PRIu8,
- responseHeader->transaction,
- responseTime / CHPP_NSEC_PER_MSEC, rRState->transaction);
- } else {
- rRState->requestState = (responseTime > rRState->responseTimeNs)
- ? CHPP_REQUEST_STATE_RESPONSE_TIMEOUT
- : CHPP_REQUEST_STATE_RESPONSE_RCV;
- success = true;
-
- CHPP_LOGD(
- "Timestamp resp ID=%" PRIu8 " req t=%" PRIu64 " resp t=%" PRIu64
- " timeout t=%" PRIu64 " (RTT=%" PRIu64 ", timeout = %s)",
- rRState->transaction, rRState->requestTimeNs / CHPP_NSEC_PER_MSEC,
- responseTime / CHPP_NSEC_PER_MSEC,
- rRState->responseTimeNs / CHPP_NSEC_PER_MSEC,
- (responseTime - rRState->requestTimeNs) / CHPP_NSEC_PER_MSEC,
- (responseTime > rRState->responseTimeNs) ? "yes" : "no");
- }
- break;
- }
-
- default: {
- CHPP_DEBUG_ASSERT_LOG(false, "Invalid req state");
- }
- }
-
- if (success) {
- if (rRState->responseTimeNs ==
- clientState->appContext->nextRequestTimeoutNs) {
- // This was the next upcoming timeout
- chppClientRecalculateNextTimeout(clientState->appContext);
- }
- rRState->responseTimeNs = responseTime;
- }
- return success;
-}
+bool chppClientSendTimestampedRequestOrFail(
+ struct ChppEndpointState *clientState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
+ uint64_t timeoutNs) {
+ CHPP_DEBUG_NOT_NULL(clientState);
+ CHPP_DEBUG_NOT_NULL(outReqState);
+ CHPP_DEBUG_NOT_NULL(buf);
-bool chppSendTimestampedRequestOrFail(struct ChppClientState *clientState,
- struct ChppRequestResponseState *rRState,
- void *buf, size_t len,
- uint64_t timeoutNs) {
- CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
if (!chppIsClientApiReady(clientState)) {
CHPP_FREE_AND_NULLIFY(buf);
return false;
}
- chppClientTimestampRequest(clientState, rRState, buf, timeoutNs);
- clientState->responseReady = false;
-
- bool success = chppEnqueueTxDatagramOrFail(
- clientState->appContext->transportContext, buf, len);
-
- // Failure to enqueue a TX datagram means that a request was known to be not
- // transmitted. We explicitly set requestState to be in the NONE state, so
- // that unintended app layer timeouts do not occur.
- if (!success) {
- rRState->requestState = CHPP_REQUEST_STATE_NONE;
- }
-
- return success;
+ return chppSendTimestampedRequestOrFail(clientState, outReqState, buf, len,
+ timeoutNs);
}
-bool chppSendTimestampedRequestAndWait(struct ChppClientState *clientState,
- struct ChppRequestResponseState *rRState,
- void *buf, size_t len) {
- return chppSendTimestampedRequestAndWaitTimeout(
- clientState, rRState, buf, len, CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT);
+bool chppClientSendTimestampedRequestAndWait(
+ struct ChppEndpointState *clientState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len) {
+ return chppClientSendTimestampedRequestAndWaitTimeout(
+ clientState, outReqState, buf, len, CHPP_REQUEST_TIMEOUT_DEFAULT);
}
-bool chppSendTimestampedRequestAndWaitTimeout(
- struct ChppClientState *clientState,
- struct ChppRequestResponseState *rRState, void *buf, size_t len,
+bool chppClientSendTimestampedRequestAndWaitTimeout(
+ struct ChppEndpointState *clientState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
uint64_t timeoutNs) {
- bool result = chppSendTimestampedRequestOrFail(
- clientState, rRState, buf, len, CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE);
-
- if (result) {
- chppMutexLock(&clientState->responseMutex);
-
- while (result && !clientState->responseReady) {
- result = chppConditionVariableTimedWait(&clientState->responseCondVar,
- &clientState->responseMutex,
- timeoutNs);
- }
- if (!clientState->responseReady) {
- rRState->requestState = CHPP_REQUEST_STATE_RESPONSE_TIMEOUT;
- CHPP_LOGE("Response timeout after %" PRIu64 " ms",
- timeoutNs / CHPP_NSEC_PER_MSEC);
- result = false;
- }
+ bool result = chppClientSendTimestampedRequestOrFail(
+ clientState, outReqState, buf, len, CHPP_REQUEST_TIMEOUT_INFINITE);
- chppMutexUnlock(&clientState->responseMutex);
+ if (!result) {
+ return false;
}
- return result;
+ return chppWaitForResponseWithTimeout(&clientState->syncResponse, outReqState,
+ timeoutNs);
}
-void chppClientPseudoOpen(struct ChppClientState *clientState) {
+void chppClientPseudoOpen(struct ChppEndpointState *clientState) {
clientState->pseudoOpen = true;
}
-bool chppClientSendOpenRequest(struct ChppClientState *clientState,
- struct ChppRequestResponseState *openRRState,
+bool chppClientSendOpenRequest(struct ChppEndpointState *clientState,
+ struct ChppOutgoingRequestState *openReqState,
uint16_t openCommand, bool blocking) {
+ CHPP_NOT_NULL(clientState);
+ CHPP_NOT_NULL(openReqState);
+
bool result = false;
uint8_t priorState = clientState->openState;
@@ -488,7 +374,6 @@ bool chppClientSendOpenRequest(struct ChppClientState *clientState,
chppAllocClientRequestCommand(clientState, openCommand);
if (request == NULL) {
- CHPP_LOG_OOM();
return false;
}
@@ -496,13 +381,13 @@ bool chppClientSendOpenRequest(struct ChppClientState *clientState,
if (blocking) {
CHPP_LOGD("Opening service - blocking");
- result = chppSendTimestampedRequestAndWait(clientState, openRRState,
- request, sizeof(*request));
+ result = chppClientSendTimestampedRequestAndWait(clientState, openReqState,
+ request, sizeof(*request));
} else {
CHPP_LOGD("Opening service - non-blocking");
- result = chppSendTimestampedRequestOrFail(
- clientState, openRRState, request, sizeof(*request),
- CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE);
+ result = chppClientSendTimestampedRequestOrFail(
+ clientState, openReqState, request, sizeof(*request),
+ CHPP_REQUEST_TIMEOUT_INFINITE);
}
if (!result) {
@@ -517,8 +402,11 @@ bool chppClientSendOpenRequest(struct ChppClientState *clientState,
return result;
}
-void chppClientProcessOpenResponse(struct ChppClientState *clientState,
+void chppClientProcessOpenResponse(struct ChppEndpointState *clientState,
uint8_t *buf, size_t len) {
+ CHPP_DEBUG_NOT_NULL(clientState);
+ CHPP_DEBUG_NOT_NULL(buf);
+
UNUSED_VAR(len); // Necessary depending on assert macro below
// Assert condition already guaranteed by chppAppProcessRxDatagram() but
// checking again since this is a public function
@@ -534,63 +422,13 @@ void chppClientProcessOpenResponse(struct ChppClientState *clientState,
}
}
-void chppClientRecalculateNextTimeout(struct ChppAppState *context) {
- context->nextRequestTimeoutNs = CHPP_TIME_MAX;
-
- for (uint8_t clientIdx = 0; clientIdx < context->registeredClientCount;
- clientIdx++) {
- const struct ChppClient *client = context->registeredClients[clientIdx];
- for (uint16_t cmdIdx = 0; cmdIdx < client->rRStateCount; cmdIdx++) {
- const struct ChppClientState *state =
- context->registeredClientStates[clientIdx];
- struct ChppRequestResponseState *rRState = &state->rRStates[cmdIdx];
-
- if (rRState->requestState == CHPP_REQUEST_STATE_REQUEST_SENT) {
- context->nextRequestTimeoutNs =
- MIN(context->nextRequestTimeoutNs, rRState->responseTimeNs);
- }
- }
- }
-
- CHPP_LOGD("nextReqTimeout=%" PRIu64,
- context->nextRequestTimeoutNs / CHPP_NSEC_PER_MSEC);
-}
-
-void chppClientCloseOpenRequests(struct ChppClientState *clientState,
+void chppClientCloseOpenRequests(struct ChppEndpointState *clientState,
const struct ChppClient *client,
bool clearOnly) {
- bool recalcNeeded = false;
-
- for (uint16_t cmdIdx = 0; cmdIdx < client->rRStateCount; cmdIdx++) {
- if (clientState->rRStates[cmdIdx].requestState ==
- CHPP_REQUEST_STATE_REQUEST_SENT) {
- recalcNeeded = true;
-
- CHPP_LOGE("Closing open req #%" PRIu16 " clear %d", cmdIdx, clearOnly);
-
- if (clearOnly) {
- clientState->rRStates[cmdIdx].requestState =
- CHPP_REQUEST_STATE_RESPONSE_TIMEOUT;
- } else {
- struct ChppAppHeader *response =
- chppMalloc(sizeof(struct ChppAppHeader));
- if (response == NULL) {
- CHPP_LOG_OOM();
- } else {
- response->handle = clientState->handle;
- response->type = CHPP_MESSAGE_TYPE_SERVICE_RESPONSE;
- response->transaction = clientState->rRStates[cmdIdx].transaction;
- response->error = CHPP_APP_ERROR_TIMEOUT;
- response->command = cmdIdx;
-
- chppAppProcessRxDatagram(clientState->appContext, (uint8_t *)response,
- sizeof(struct ChppAppHeader));
- }
- }
- }
- }
-
- if (recalcNeeded) {
- chppClientRecalculateNextTimeout(clientState->appContext);
- }
+ UNUSED_VAR(client);
+ chppCloseOpenRequests(clientState, CHPP_ENDPOINT_CLIENT, clearOnly);
}
+
+struct ChppAppHeader *chppAllocClientNotification(size_t len) {
+ return chppAllocNotification(CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION, len);
+} \ No newline at end of file
diff --git a/chpp/clients/discovery.c b/chpp/clients/discovery.c
index e6817521..af314e2b 100644
--- a/chpp/clients/discovery.c
+++ b/chpp/clients/discovery.c
@@ -22,6 +22,7 @@
#include <string.h>
#include "chpp/app.h"
+#include "chpp/clients.h"
#include "chpp/common/discovery.h"
#include "chpp/log.h"
#include "chpp/macros.h"
@@ -160,7 +161,7 @@ static void chppProcessDiscoverAllResponse(
// Initialize client
if (!client->initFunctionPtr(
- appState->registeredClientContexts[clientIndex],
+ appState->registeredClientStates[clientIndex]->context,
CHPP_SERVICE_HANDLE_OF_INDEX(i), service->version)) {
CHPP_LOGE("Client v=%" PRIu8 ".%" PRIu8 ".%" PRIu16
" rejected init. Service v=%" PRIu8 ".%" PRIu8 ".%" PRIu16,
@@ -199,7 +200,8 @@ static void chppProcessDiscoverAllResponse(
(matchNotifierFunction != NULL));
if (matchNotifierFunction != NULL) {
- matchNotifierFunction(appState->registeredClientContexts[clientIndex]);
+ matchNotifierFunction(
+ appState->registeredClientStates[clientIndex]->context);
}
}
}
diff --git a/chpp/clients/gnss.c b/chpp/clients/gnss.c
index ca131d7e..f56ce01b 100644
--- a/chpp/clients/gnss.c
+++ b/chpp/clients/gnss.c
@@ -62,10 +62,11 @@ static void chppGnssClientNotifyMatch(void *clientContext);
* (RR) functionality.
*/
struct ChppGnssClientState {
- struct ChppClientState client; // GNSS client state
+ struct ChppEndpointState client; // CHPP client state
const struct chrePalGnssApi *api; // GNSS PAL API
- struct ChppRequestResponseState rRState[CHPP_GNSS_CLIENT_REQUEST_MAX + 1];
+ struct ChppOutgoingRequestState
+ outReqStates[CHPP_GNSS_CLIENT_REQUEST_MAX + 1];
uint32_t capabilities; // Cached GetCapabilities result
bool requestStateResyncPending; // requestStateResync() is waiting to be
@@ -109,8 +110,8 @@ static const struct ChppClient kGnssClientConfig = {
// Service notification dispatch function pointer
.deinitFunctionPtr = &chppGnssClientDeinit,
- // Number of request-response states in the rRStates array.
- .rRStateCount = ARRAY_SIZE(gGnssClientContext.rRState),
+ // Number of request-response states in the outReqStates array.
+ .outReqCount = ARRAY_SIZE(gGnssClientContext.outReqStates),
// Min length is the entire header
.minLength = sizeof(struct ChppAppHeader),
@@ -181,9 +182,10 @@ static enum ChppAppErrorCode chppDispatchGnssResponse(void *clientContext,
if (rxHeader->command > CHPP_GNSS_CLIENT_REQUEST_MAX) {
error = CHPP_APP_ERROR_INVALID_COMMAND;
- } else if (!chppClientTimestampResponse(
- &gnssClientContext->client,
- &gnssClientContext->rRState[rxHeader->command], rxHeader)) {
+ } else if (!chppTimestampIncomingResponse(
+ gnssClientContext->client.appContext,
+ &gnssClientContext->outReqStates[rxHeader->command],
+ rxHeader)) {
error = CHPP_APP_ERROR_UNEXPECTED_RESPONSE;
} else {
@@ -332,7 +334,7 @@ static void chppGnssClientNotifyReset(void *clientContext) {
gnssClientContext->client.openState);
gnssClientContext->requestStateResyncPending = true;
chppClientSendOpenRequest(&gGnssClientContext.client,
- &gGnssClientContext.rRState[CHPP_GNSS_OPEN],
+ &gGnssClientContext.outReqStates[CHPP_GNSS_OPEN],
CHPP_GNSS_OPEN,
/*blocking=*/false);
}
@@ -350,7 +352,7 @@ static void chppGnssClientNotifyMatch(void *clientContext) {
if (gnssClientContext->client.pseudoOpen) {
CHPP_LOGD("Pseudo-open GNSS client opening");
chppClientSendOpenRequest(&gGnssClientContext.client,
- &gGnssClientContext.rRState[CHPP_GNSS_OPEN],
+ &gGnssClientContext.outReqStates[CHPP_GNSS_OPEN],
CHPP_GNSS_OPEN,
/*blocking=*/false);
}
@@ -589,8 +591,8 @@ static void chppGnssMeasurementResultNotification(
*/
static bool chppGnssClientOpen(const struct chrePalSystemApi *systemApi,
const struct chrePalGnssCallbacks *callbacks) {
- CHPP_DEBUG_ASSERT(systemApi != NULL);
- CHPP_DEBUG_ASSERT(callbacks != NULL);
+ CHPP_DEBUG_NOT_NULL(systemApi);
+ CHPP_DEBUG_NOT_NULL(callbacks);
bool result = false;
gSystemApi = systemApi;
@@ -604,7 +606,7 @@ static bool chppGnssClientOpen(const struct chrePalSystemApi *systemApi,
CHPP_GNSS_DISCOVERY_TIMEOUT_MS)) {
result = chppClientSendOpenRequest(
&gGnssClientContext.client,
- &gGnssClientContext.rRState[CHPP_GNSS_OPEN], CHPP_GNSS_OPEN,
+ &gGnssClientContext.outReqStates[CHPP_GNSS_OPEN], CHPP_GNSS_OPEN,
/*blocking=*/true);
}
@@ -627,9 +629,9 @@ static void chppGnssClientClose(void) {
if (request == NULL) {
CHPP_LOG_OOM();
- } else if (chppSendTimestampedRequestAndWait(
+ } else if (chppClientSendTimestampedRequestAndWait(
&gGnssClientContext.client,
- &gGnssClientContext.rRState[CHPP_GNSS_CLOSE], request,
+ &gGnssClientContext.outReqStates[CHPP_GNSS_CLOSE], request,
sizeof(*request))) {
gGnssClientContext.client.openState = CHPP_OPEN_STATE_CLOSED;
gGnssClientContext.capabilities = CHRE_GNSS_CAPABILITIES_NONE;
@@ -659,10 +661,10 @@ static uint32_t chppGnssClientGetCapabilities(void) {
if (request == NULL) {
CHPP_LOG_OOM();
} else {
- if (chppSendTimestampedRequestAndWait(
+ if (chppClientSendTimestampedRequestAndWait(
&gGnssClientContext.client,
- &gGnssClientContext.rRState[CHPP_GNSS_GET_CAPABILITIES], request,
- sizeof(*request))) {
+ &gGnssClientContext.outReqStates[CHPP_GNSS_GET_CAPABILITIES],
+ request, sizeof(*request))) {
// Success. gGnssClientContext.capabilities is now populated
if (gGnssClientContext.capabilitiesValid) {
capabilities = gGnssClientContext.capabilities;
@@ -703,9 +705,9 @@ static bool chppGnssClientControlLocationSession(bool enable,
request->params.minIntervalMs = minIntervalMs;
request->params.minTimeToNextFixMs = minTimeToNextFixMs;
- result = chppSendTimestampedRequestOrFail(
+ result = chppClientSendTimestampedRequestOrFail(
&gGnssClientContext.client,
- &gGnssClientContext.rRState[CHPP_GNSS_CONTROL_LOCATION_SESSION],
+ &gGnssClientContext.outReqStates[CHPP_GNSS_CONTROL_LOCATION_SESSION],
request, sizeof(*request), CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS);
}
@@ -749,9 +751,9 @@ static bool chppGnssClientControlMeasurementSession(bool enable,
request->params.enable = enable;
request->params.minIntervalMs = minIntervalMs;
- result = chppSendTimestampedRequestOrFail(
+ result = chppClientSendTimestampedRequestOrFail(
&gGnssClientContext.client,
- &gGnssClientContext.rRState[CHPP_GNSS_CONTROL_MEASUREMENT_SESSION],
+ &gGnssClientContext.outReqStates[CHPP_GNSS_CONTROL_MEASUREMENT_SESSION],
request, sizeof(*request), CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS);
}
@@ -795,11 +797,11 @@ static bool chppGnssClientConfigurePassiveLocationListener(bool enable) {
request->header.command = CHPP_GNSS_CONFIGURE_PASSIVE_LOCATION_LISTENER;
request->params.enable = enable;
- result = chppSendTimestampedRequestOrFail(
+ result = chppClientSendTimestampedRequestOrFail(
&gGnssClientContext.client,
&gGnssClientContext
- .rRState[CHPP_GNSS_CONFIGURE_PASSIVE_LOCATION_LISTENER],
- request, sizeof(*request), CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT);
+ .outReqStates[CHPP_GNSS_CONFIGURE_PASSIVE_LOCATION_LISTENER],
+ request, sizeof(*request), CHPP_REQUEST_TIMEOUT_DEFAULT);
}
return result;
@@ -812,8 +814,8 @@ static bool chppGnssClientConfigurePassiveLocationListener(bool enable) {
void chppRegisterGnssClient(struct ChppAppState *appContext) {
memset(&gGnssClientContext, 0, sizeof(gGnssClientContext));
chppRegisterClient(appContext, (void *)&gGnssClientContext,
- &gGnssClientContext.client, gGnssClientContext.rRState,
- &kGnssClientConfig);
+ &gGnssClientContext.client,
+ gGnssClientContext.outReqStates, &kGnssClientConfig);
}
void chppDeregisterGnssClient(struct ChppAppState *appContext) {
@@ -822,7 +824,7 @@ void chppDeregisterGnssClient(struct ChppAppState *appContext) {
UNUSED_VAR(appContext);
}
-struct ChppClientState *getChppGnssClientState(void) {
+struct ChppEndpointState *getChppGnssClientState(void) {
return &gGnssClientContext.client;
}
diff --git a/chpp/clients/loopback.c b/chpp/clients/loopback.c
index b8f19e8f..c92ae68a 100644
--- a/chpp/clients/loopback.c
+++ b/chpp/clients/loopback.c
@@ -42,8 +42,8 @@
* (RR) functionality.
*/
struct ChppLoopbackClientState {
- struct ChppClientState client; // Loopback client state
- struct ChppRequestResponseState runLoopbackTest; // Loopback test state
+ struct ChppEndpointState client; // CHPP client state
+ struct ChppOutgoingRequestState runLoopbackTest; // Loopback test state
struct ChppLoopbackTestResult testResult; // Last test result
const uint8_t *loopbackData; // Pointer to loopback data
@@ -88,9 +88,9 @@ bool chppDispatchLoopbackServiceResponse(struct ChppAppState *appState,
CHPP_NOT_NULL(state);
CHPP_NOT_NULL(state->loopbackData);
- CHPP_ASSERT(
- chppClientTimestampResponse(&state->client, &state->runLoopbackTest,
- (const struct ChppAppHeader *)response));
+ CHPP_ASSERT(chppTimestampIncomingResponse(
+ state->client.appContext, &state->runLoopbackTest,
+ (const struct ChppAppHeader *)response));
struct ChppLoopbackTestResult *result = &state->testResult;
@@ -123,10 +123,10 @@ bool chppDispatchLoopbackServiceResponse(struct ChppAppState *appState,
result->firstError, result->byteErrors);
// Notify waiting (synchronous) client
- chppMutexLock(&state->client.responseMutex);
- state->client.responseReady = true;
- chppConditionVariableSignal(&state->client.responseCondVar);
- chppMutexUnlock(&state->client.responseMutex);
+ chppMutexLock(&state->client.syncResponse.mutex);
+ state->client.syncResponse.ready = true;
+ chppConditionVariableSignal(&state->client.syncResponse.condVar);
+ chppMutexUnlock(&state->client.syncResponse.mutex);
return true;
}
@@ -187,7 +187,7 @@ struct ChppLoopbackTestResult chppRunLoopbackTest(struct ChppAppState *appState,
state->loopbackData = buf;
memcpy(&loopbackRequest[CHPP_LOOPBACK_HEADER_LEN], buf, len);
- if (!chppSendTimestampedRequestAndWaitTimeout(
+ if (!chppClientSendTimestampedRequestAndWaitTimeout(
&state->client, &state->runLoopbackTest, loopbackRequest,
result->requestLen, 5 * CHPP_NSEC_PER_SEC)) {
result->error = CHPP_APP_ERROR_UNSPECIFIED;
diff --git a/chpp/clients/timesync.c b/chpp/clients/timesync.c
index de0664b8..3026f216 100644
--- a/chpp/clients/timesync.c
+++ b/chpp/clients/timesync.c
@@ -40,8 +40,8 @@
* (RR) functionality.
*/
struct ChppTimesyncClientState {
- struct ChppClientState client; // Timesync client state
- struct ChppRequestResponseState measureOffset; // Request response state
+ struct ChppEndpointState client; // CHPP client state
+ struct ChppOutgoingRequestState measureOffset; // Request response state
struct ChppTimesyncResult timesyncResult; // Result of measureOffset
};
@@ -104,8 +104,8 @@ bool chppDispatchTimesyncServiceResponse(struct ChppAppState *appState,
const struct ChppTimesyncResponse *response =
(const struct ChppTimesyncResponse *)buf;
- if (chppClientTimestampResponse(&state->client, &state->measureOffset,
- &response->header)) {
+ if (chppTimestampIncomingResponse(state->client.appContext,
+ &state->measureOffset, &response->header)) {
state->timesyncResult.rttNs = state->measureOffset.responseTimeNs -
state->measureOffset.requestTimeNs;
int64_t offsetNs =
@@ -164,9 +164,9 @@ bool chppTimesyncMeasureOffset(struct ChppAppState *appState) {
state->timesyncResult.error = CHPP_APP_ERROR_OOM;
CHPP_LOG_OOM();
- } else if (!chppSendTimestampedRequestOrFail(
+ } else if (!chppClientSendTimestampedRequestOrFail(
&state->client, &state->measureOffset, request, requestLen,
- CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE)) {
+ CHPP_REQUEST_TIMEOUT_INFINITE)) {
state->timesyncResult.error = CHPP_APP_ERROR_UNSPECIFIED;
} else {
diff --git a/chpp/clients/wifi.c b/chpp/clients/wifi.c
index b5446840..9438a845 100644
--- a/chpp/clients/wifi.c
+++ b/chpp/clients/wifi.c
@@ -75,10 +75,11 @@ static void chppWifiClientNotifyMatch(void *clientContext);
* (RR) functionality.
*/
struct ChppWifiClientState {
- struct ChppClientState client; // WiFi client state
+ struct ChppEndpointState client; // CHPP client state
const struct chrePalWifiApi *api; // WiFi PAL API
- struct ChppRequestResponseState rRState[CHPP_WIFI_CLIENT_REQUEST_MAX + 1];
+ struct ChppOutgoingRequestState
+ outReqStates[CHPP_WIFI_CLIENT_REQUEST_MAX + 1];
uint32_t capabilities; // Cached GetCapabilities result
bool scanMonitorEnabled; // Scan monitoring is enabled
@@ -123,8 +124,8 @@ static const struct ChppClient kWifiClientConfig = {
// Service notification dispatch function pointer
.deinitFunctionPtr = &chppWifiClientDeinit,
- // Number of request-response states in the rRStates array.
- .rRStateCount = ARRAY_SIZE(gWifiClientContext.rRState),
+ // Number of request-response states in the outReqStates array.
+ .outReqCount = ARRAY_SIZE(gWifiClientContext.outReqStates),
// Min length is the entire header
.minLength = sizeof(struct ChppAppHeader),
@@ -201,9 +202,10 @@ static enum ChppAppErrorCode chppDispatchWifiResponse(void *clientContext,
if (rxHeader->command > CHPP_WIFI_CLIENT_REQUEST_MAX) {
error = CHPP_APP_ERROR_INVALID_COMMAND;
- } else if (!chppClientTimestampResponse(
- &wifiClientContext->client,
- &wifiClientContext->rRState[rxHeader->command], rxHeader)) {
+ } else if (!chppTimestampIncomingResponse(
+ wifiClientContext->client.appContext,
+ &wifiClientContext->outReqStates[rxHeader->command],
+ rxHeader)) {
error = CHPP_APP_ERROR_UNEXPECTED_RESPONSE;
} else {
@@ -380,7 +382,7 @@ static void chppWifiClientNotifyReset(void *clientContext) {
CHPP_LOGI("WiFi client reopening from state=%" PRIu8,
wifiClientContext->client.openState);
chppClientSendOpenRequest(&wifiClientContext->client,
- &wifiClientContext->rRState[CHPP_WIFI_OPEN],
+ &wifiClientContext->outReqStates[CHPP_WIFI_OPEN],
CHPP_WIFI_OPEN,
/*blocking=*/false);
}
@@ -398,7 +400,7 @@ static void chppWifiClientNotifyMatch(void *clientContext) {
if (wifiClientContext->client.pseudoOpen) {
CHPP_LOGD("Pseudo-open WiFi client opening");
chppClientSendOpenRequest(&wifiClientContext->client,
- &wifiClientContext->rRState[CHPP_WIFI_OPEN],
+ &wifiClientContext->outReqStates[CHPP_WIFI_OPEN],
CHPP_WIFI_OPEN,
/*blocking=*/false);
}
@@ -832,8 +834,8 @@ static void chppWifiNanSubscriptionCanceledNotification(uint8_t *buf,
*/
static bool chppWifiClientOpen(const struct chrePalSystemApi *systemApi,
const struct chrePalWifiCallbacks *callbacks) {
- CHPP_DEBUG_ASSERT(systemApi != NULL);
- CHPP_DEBUG_ASSERT(callbacks != NULL);
+ CHPP_DEBUG_NOT_NULL(systemApi);
+ CHPP_DEBUG_NOT_NULL(callbacks);
bool result = false;
gSystemApi = systemApi;
@@ -847,7 +849,7 @@ static bool chppWifiClientOpen(const struct chrePalSystemApi *systemApi,
CHPP_WIFI_DISCOVERY_TIMEOUT_MS)) {
result = chppClientSendOpenRequest(
&gWifiClientContext.client,
- &gWifiClientContext.rRState[CHPP_WIFI_OPEN], CHPP_WIFI_OPEN,
+ &gWifiClientContext.outReqStates[CHPP_WIFI_OPEN], CHPP_WIFI_OPEN,
/*blocking=*/true);
}
@@ -870,9 +872,9 @@ static void chppWifiClientClose(void) {
if (request == NULL) {
CHPP_LOG_OOM();
- } else if (chppSendTimestampedRequestAndWait(
+ } else if (chppClientSendTimestampedRequestAndWait(
&gWifiClientContext.client,
- &gWifiClientContext.rRState[CHPP_WIFI_CLOSE], request,
+ &gWifiClientContext.outReqStates[CHPP_WIFI_CLOSE], request,
sizeof(*request))) {
gWifiClientContext.client.openState = CHPP_OPEN_STATE_CLOSED;
gWifiClientContext.capabilities = CHRE_WIFI_CAPABILITIES_NONE;
@@ -902,10 +904,10 @@ static uint32_t chppWifiClientGetCapabilities(void) {
if (request == NULL) {
CHPP_LOG_OOM();
} else {
- if (chppSendTimestampedRequestAndWait(
+ if (chppClientSendTimestampedRequestAndWait(
&gWifiClientContext.client,
- &gWifiClientContext.rRState[CHPP_WIFI_GET_CAPABILITIES], request,
- sizeof(*request))) {
+ &gWifiClientContext.outReqStates[CHPP_WIFI_GET_CAPABILITIES],
+ request, sizeof(*request))) {
// Success. gWifiClientContext.capabilities is now populated
if (gWifiClientContext.capabilitiesValid) {
capabilities = gWifiClientContext.capabilities;
@@ -938,12 +940,14 @@ static bool chppWifiClientConfigureScanMonitor(bool enable) {
request->header.command = CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC;
request->params.enable = enable;
request->params.cookie =
- &gWifiClientContext.rRState[CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC];
+ &gWifiClientContext
+ .outReqStates[CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC];
- result = chppSendTimestampedRequestOrFail(
+ result = chppClientSendTimestampedRequestOrFail(
&gWifiClientContext.client,
- &gWifiClientContext.rRState[CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC],
- request, sizeof(*request), CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT);
+ &gWifiClientContext
+ .outReqStates[CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC],
+ request, sizeof(*request), CHPP_REQUEST_TIMEOUT_DEFAULT);
}
return result;
@@ -976,9 +980,9 @@ static bool chppWifiClientRequestScan(const struct chreWifiScanParams *params) {
CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS > CHPP_WIFI_SCAN_RESULT_TIMEOUT_NS,
"Chpp wifi scan timeout needs to be smaller than CHRE wifi scan "
"timeout");
- result = chppSendTimestampedRequestOrFail(
+ result = chppClientSendTimestampedRequestOrFail(
&gWifiClientContext.client,
- &gWifiClientContext.rRState[CHPP_WIFI_REQUEST_SCAN_ASYNC], request,
+ &gWifiClientContext.outReqStates[CHPP_WIFI_REQUEST_SCAN_ASYNC], request,
requestLen, CHPP_WIFI_SCAN_RESULT_TIMEOUT_NS);
}
@@ -1027,10 +1031,10 @@ static bool chppWifiClientRequestRanging(
request->header.error = CHPP_APP_ERROR_NONE;
request->header.command = CHPP_WIFI_REQUEST_RANGING_ASYNC;
- result = chppSendTimestampedRequestOrFail(
+ result = chppClientSendTimestampedRequestOrFail(
&gWifiClientContext.client,
- &gWifiClientContext.rRState[CHPP_WIFI_REQUEST_RANGING_ASYNC], request,
- requestLen, CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS);
+ &gWifiClientContext.outReqStates[CHPP_WIFI_REQUEST_RANGING_ASYNC],
+ request, requestLen, CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS);
}
return result;
@@ -1075,9 +1079,9 @@ static bool chppWifiClientNanSubscribe(
request->header.error = CHPP_APP_ERROR_NONE;
request->header.command = CHPP_WIFI_REQUEST_NAN_SUB;
- result = chppSendTimestampedRequestOrFail(
+ result = chppClientSendTimestampedRequestOrFail(
&gWifiClientContext.client,
- &gWifiClientContext.rRState[CHPP_WIFI_REQUEST_NAN_SUB], request,
+ &gWifiClientContext.outReqStates[CHPP_WIFI_REQUEST_NAN_SUB], request,
requestLen, CHRE_ASYNC_RESULT_TIMEOUT_NS);
}
return result;
@@ -1106,10 +1110,10 @@ static bool chppWifiClientNanSubscribeCancel(uint32_t subscriptionId) {
request->header.error = CHPP_APP_ERROR_NONE;
request->subscriptionId = subscriptionId;
- result = chppSendTimestampedRequestAndWait(
+ result = chppClientSendTimestampedRequestAndWait(
&gWifiClientContext.client,
- &gWifiClientContext.rRState[CHPP_WIFI_REQUEST_NAN_SUB_CANCEL], request,
- sizeof(*request));
+ &gWifiClientContext.outReqStates[CHPP_WIFI_REQUEST_NAN_SUB_CANCEL],
+ request, sizeof(*request));
}
return result;
}
@@ -1152,9 +1156,9 @@ static bool chppWifiClientNanRequestNanRanging(
request->header.transaction = gWifiClientContext.client.transaction++;
request->header.error = CHPP_APP_ERROR_NONE;
- result = chppSendTimestampedRequestOrFail(
+ result = chppClientSendTimestampedRequestOrFail(
&gWifiClientContext.client,
- &gWifiClientContext.rRState[CHPP_WIFI_REQUEST_NAN_RANGING_ASYNC],
+ &gWifiClientContext.outReqStates[CHPP_WIFI_REQUEST_NAN_RANGING_ASYNC],
request, requestLen, CHRE_ASYNC_RESULT_TIMEOUT_NS);
}
return result;
@@ -1174,8 +1178,8 @@ static bool chppWifiGetNanCapabilites(
void chppRegisterWifiClient(struct ChppAppState *appContext) {
memset(&gWifiClientContext, 0, sizeof(gWifiClientContext));
chppRegisterClient(appContext, (void *)&gWifiClientContext,
- &gWifiClientContext.client, gWifiClientContext.rRState,
- &kWifiClientConfig);
+ &gWifiClientContext.client,
+ gWifiClientContext.outReqStates, &kWifiClientConfig);
}
void chppDeregisterWifiClient(struct ChppAppState *appContext) {
@@ -1184,7 +1188,7 @@ void chppDeregisterWifiClient(struct ChppAppState *appContext) {
UNUSED_VAR(appContext);
}
-struct ChppClientState *getChppWifiClientState(void) {
+struct ChppEndpointState *getChppWifiClientState(void) {
return &gWifiClientContext.client;
}
diff --git a/chpp/clients/wwan.c b/chpp/clients/wwan.c
index 98aea88c..1ac8aa3f 100644
--- a/chpp/clients/wwan.c
+++ b/chpp/clients/wwan.c
@@ -64,10 +64,11 @@ static void chppWwanClientNotifyMatch(void *clientContext);
* (RR) functionality.
*/
struct ChppWwanClientState {
- struct ChppClientState client; // WWAN client state
+ struct ChppEndpointState client; // CHPP client state
const struct chrePalWwanApi *api; // WWAN PAL API
- struct ChppRequestResponseState rRState[CHPP_WWAN_CLIENT_REQUEST_MAX + 1];
+ struct ChppOutgoingRequestState
+ outReqStates[CHPP_WWAN_CLIENT_REQUEST_MAX + 1];
uint32_t capabilities; // Cached GetCapabilities result
bool capabilitiesValid; // Flag to indicate if the capabilities result
@@ -109,8 +110,8 @@ static const struct ChppClient kWwanClientConfig = {
// Service notification dispatch function pointer
.deinitFunctionPtr = &chppWwanClientDeinit,
- // Number of request-response states in the rRStates array.
- .rRStateCount = ARRAY_SIZE(gWwanClientContext.rRState),
+ // Number of request-response states in the outReqStates array.
+ .outReqCount = ARRAY_SIZE(gWwanClientContext.outReqStates),
// Min length is the entire header
.minLength = sizeof(struct ChppAppHeader),
@@ -163,9 +164,10 @@ static enum ChppAppErrorCode chppDispatchWwanResponse(void *clientContext,
if (rxHeader->command > CHPP_WWAN_CLIENT_REQUEST_MAX) {
error = CHPP_APP_ERROR_INVALID_COMMAND;
- } else if (!chppClientTimestampResponse(
- &wwanClientContext->client,
- &wwanClientContext->rRState[rxHeader->command], rxHeader)) {
+ } else if (!chppTimestampIncomingResponse(
+ wwanClientContext->client.appContext,
+ &wwanClientContext->outReqStates[rxHeader->command],
+ rxHeader)) {
error = CHPP_APP_ERROR_UNEXPECTED_RESPONSE;
} else {
@@ -252,7 +254,7 @@ static void chppWwanClientNotifyReset(void *clientContext) {
CHPP_LOGI("WWAN client reopening from state=%" PRIu8,
wwanClientContext->client.openState);
chppClientSendOpenRequest(&wwanClientContext->client,
- &wwanClientContext->rRState[CHPP_WWAN_OPEN],
+ &wwanClientContext->outReqStates[CHPP_WWAN_OPEN],
CHPP_WWAN_OPEN,
/*blocking=*/false);
}
@@ -270,7 +272,7 @@ static void chppWwanClientNotifyMatch(void *clientContext) {
if (wwanClientContext->client.pseudoOpen) {
CHPP_LOGD("Pseudo-open WWAN client opening");
chppClientSendOpenRequest(&wwanClientContext->client,
- &wwanClientContext->rRState[CHPP_WWAN_OPEN],
+ &wwanClientContext->outReqStates[CHPP_WWAN_OPEN],
CHPP_WWAN_OPEN,
/*blocking=*/false);
}
@@ -400,8 +402,8 @@ static void chppWwanGetCellInfoAsyncResult(
*/
static bool chppWwanClientOpen(const struct chrePalSystemApi *systemApi,
const struct chrePalWwanCallbacks *callbacks) {
- CHPP_DEBUG_ASSERT(systemApi != NULL);
- CHPP_DEBUG_ASSERT(callbacks != NULL);
+ CHPP_DEBUG_NOT_NULL(systemApi);
+ CHPP_DEBUG_NOT_NULL(callbacks);
bool result = false;
gSystemApi = systemApi;
@@ -416,7 +418,7 @@ static bool chppWwanClientOpen(const struct chrePalSystemApi *systemApi,
CHPP_WWAN_DISCOVERY_TIMEOUT_MS)) {
result = chppClientSendOpenRequest(
&gWwanClientContext.client,
- &gWwanClientContext.rRState[CHPP_WWAN_OPEN], CHPP_WWAN_OPEN,
+ &gWwanClientContext.outReqStates[CHPP_WWAN_OPEN], CHPP_WWAN_OPEN,
/*blocking=*/true);
}
@@ -439,9 +441,9 @@ static void chppWwanClientClose(void) {
if (request == NULL) {
CHPP_LOG_OOM();
- } else if (chppSendTimestampedRequestAndWait(
+ } else if (chppClientSendTimestampedRequestAndWait(
&gWwanClientContext.client,
- &gWwanClientContext.rRState[CHPP_WWAN_CLOSE], request,
+ &gWwanClientContext.outReqStates[CHPP_WWAN_CLOSE], request,
sizeof(*request))) {
gWwanClientContext.client.openState = CHPP_OPEN_STATE_CLOSED;
gWwanClientContext.capabilities = CHRE_WWAN_CAPABILITIES_NONE;
@@ -471,10 +473,10 @@ static uint32_t chppWwanClientGetCapabilities(void) {
if (request == NULL) {
CHPP_LOG_OOM();
} else {
- if (chppSendTimestampedRequestAndWait(
+ if (chppClientSendTimestampedRequestAndWait(
&gWwanClientContext.client,
- &gWwanClientContext.rRState[CHPP_WWAN_GET_CAPABILITIES], request,
- sizeof(*request))) {
+ &gWwanClientContext.outReqStates[CHPP_WWAN_GET_CAPABILITIES],
+ request, sizeof(*request))) {
// Success. gWwanClientContext.capabilities is now populated
if (gWwanClientContext.capabilitiesValid) {
capabilities = gWwanClientContext.capabilities;
@@ -502,10 +504,10 @@ static bool chppWwanClientGetCellInfoAsync(void) {
if (request == NULL) {
CHPP_LOG_OOM();
} else {
- result = chppSendTimestampedRequestOrFail(
+ result = chppClientSendTimestampedRequestOrFail(
&gWwanClientContext.client,
- &gWwanClientContext.rRState[CHPP_WWAN_GET_CELLINFO_ASYNC], request,
- sizeof(*request), CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT);
+ &gWwanClientContext.outReqStates[CHPP_WWAN_GET_CELLINFO_ASYNC], request,
+ sizeof(*request), CHPP_REQUEST_TIMEOUT_DEFAULT);
}
return result;
@@ -531,8 +533,8 @@ static void chppWwanClientReleaseCellInfoResult(
void chppRegisterWwanClient(struct ChppAppState *appContext) {
memset(&gWwanClientContext, 0, sizeof(gWwanClientContext));
chppRegisterClient(appContext, (void *)&gWwanClientContext,
- &gWwanClientContext.client, gWwanClientContext.rRState,
- &kWwanClientConfig);
+ &gWwanClientContext.client,
+ gWwanClientContext.outReqStates, &kWwanClientConfig);
}
void chppDeregisterWwanClient(struct ChppAppState *appContext) {
@@ -541,7 +543,7 @@ void chppDeregisterWwanClient(struct ChppAppState *appContext) {
UNUSED_VAR(appContext);
}
-struct ChppClientState *getChppWwanClientState(void) {
+struct ChppEndpointState *getChppWwanClientState(void) {
return &gWwanClientContext.client;
}
diff --git a/chpp/include/chpp/app.h b/chpp/include/chpp/app.h
index 67bf54da..eda11fa5 100644
--- a/chpp/include/chpp/app.h
+++ b/chpp/include/chpp/app.h
@@ -24,6 +24,7 @@
#include "chpp/condition_variable.h"
#include "chpp/macros.h"
#include "chpp/transport.h"
+#include "chre_api/chre/common.h"
#ifdef __cplusplus
extern "C" {
@@ -34,6 +35,32 @@ extern "C" {
***********************************************/
/**
+ * Allocates a variable-length response message of a specific type.
+ *
+ * @param requestHeader request header, as per chppAllocResponse().
+ * @param type Type of response which includes an arrayed member.
+ * @param count number of items in the array of arrayField.
+ * @param arrayField The arrayed member field.
+ *
+ * @return Pointer to allocated memory.
+ */
+#define chppAllocResponseTypedArray(requestHeader, type, count, arrayField) \
+ (type *)chppAllocResponse( \
+ requestHeader, \
+ sizeof(type) + (count)*sizeof_member(type, arrayField[0]))
+
+/**
+ * Allocates a response message of a specific type and its corresponding length.
+ *
+ * @param requestHeader request header, as per chppAllocResponse().
+ * @param type Type of response.
+ *
+ * @return Pointer to allocated memory.
+ */
+#define chppAllocResponseFixed(requestHeader, type) \
+ (type *)chppAllocResponse(requestHeader, sizeof(type))
+
+/**
* Maximum number of services that can be registered by CHPP (not including
* predefined services), if not defined by the build system.
*/
@@ -58,6 +85,25 @@ extern "C" {
MAX(CHPP_MAX_REGISTERED_SERVICES, CHPP_MAX_REGISTERED_CLIENTS)
#endif
+#define CHPP_REQUEST_TIMEOUT_INFINITE CHPP_TIME_MAX
+
+#if defined(CHPP_REQUEST_TIMEOUT_DEFAULT) && \
+ defined(CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT)
+// Build systems should prefer to only set CHPP_REQUEST_TIMEOUT_DEFAULT
+#error Can not set both CHPP_REQUEST_TIMEOUT_DEFAULT and CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT
+#endif
+
+// For backwards compatibility with vendor build systems
+#ifdef CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT
+#define CHPP_REQUEST_TIMEOUT_DEFAULT CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT
+#undef CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT
+#endif
+
+// If not customized in the build, we default to CHRE expectations
+#ifndef CHPP_REQUEST_TIMEOUT_DEFAULT
+#define CHPP_REQUEST_TIMEOUT_DEFAULT CHRE_ASYNC_RESULT_TIMEOUT_NS
+#endif
+
/**
* Default value for reserved fields.
*/
@@ -74,6 +120,14 @@ extern "C" {
#define CHPP_APP_COMMAND_NONE 0
/**
+ * Type of endpoint (either client or service)
+ */
+enum ChppEndpointType {
+ CHPP_ENDPOINT_CLIENT = 0,
+ CHPP_ENDPOINT_SERVICE = 1,
+};
+
+/**
* Handle Numbers in ChppAppHeader
*/
enum ChppHandleNumber {
@@ -114,6 +168,13 @@ enum ChppMessageType {
//! Notification from service. Client shall not respond.
CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION = 3,
+
+ //! Request from service. Needs response from client.
+ CHPP_MESSAGE_TYPE_SERVICE_REQUEST = 4,
+
+ //! Response from client (with the same Command and Transaction ID as the
+ //! service request).
+ CHPP_MESSAGE_TYPE_CLIENT_RESPONSE = 5,
};
/**
@@ -189,7 +250,10 @@ struct ChppAppHeader {
CHPP_PACKED_END
/**
- * Function type that dispatches incoming datagrams for any client or service
+ * Function type that dispatches incoming datagrams for any client or service.
+ *
+ * The buffer is freed shortly after the function returns.
+ * User code must make a copy for later processing if needed.
*/
typedef enum ChppAppErrorCode(ChppDispatchFunction)(void *context, uint8_t *buf,
size_t len);
@@ -229,6 +293,17 @@ typedef void(ChppNotifierFunction)(void *context);
#define CHPP_SERVICE_NAME_MAX_LEN (15 + 1)
/**
+ * Support for sync response.
+ *
+ * @see chppClientSendTimestampedRequestAndWaitTimeout.
+ */
+struct ChppSyncResponse {
+ struct ChppMutex mutex;
+ struct ChppConditionVariable condVar;
+ bool ready;
+};
+
+/**
* CHPP definition of a service descriptor as sent over the wire.
*/
CHPP_PACKED_START
@@ -252,19 +327,31 @@ struct ChppService {
//! Service Descriptor as sent over the wire.
struct ChppServiceDescriptor descriptor;
- //! Pointer to the function that is used to notify the service if CHPP is
- //! reset.
+ //! Notifies the service if CHPP is reset.
ChppNotifierFunction *resetNotifierFunctionPtr;
- //! Pointer to the function that dispatches incoming client requests for the
- //! service.
+ //! Dispatches incoming client requests.
+ //! When an error is returned by the dispatch function it is logged and an
+ //! error response is automatically sent to the remote endpoint.
ChppDispatchFunction *requestDispatchFunctionPtr;
- //! Pointer to the function that dispatches incoming client notifications for
- //! the service.
+ //! Dispatches incoming client notifications.
+ //! Errors returned by the dispatch function are logged.
ChppDispatchFunction *notificationDispatchFunctionPtr;
- //! Minimum valid length of datagrams for the service.
+ //! Dispatches incoming client responses.
+ //! Errors returned by the dispatch function are logged.
+ ChppDispatchFunction *responseDispatchFunctionPtr;
+
+ //! Number of outgoing requests supported by this service.
+ //! ChppAppHeader.command must be in the range [0, outReqCount - 1]
+ //! ChppEndpointState.outReqStates must contains that many elements.
+ uint16_t outReqCount;
+
+ //! Minimum valid length of datagrams for the service:
+ //! - client requests
+ //! - client notifications
+ //! - client responses
size_t minLength;
};
@@ -287,38 +374,45 @@ struct ChppClient {
//! Client descriptor.
struct ChppClientDescriptor descriptor;
- //! Pointer to the function that is used to notify the client if CHPP is
- //! reset.
+ //! Notifies the client if CHPP is reset.
ChppNotifierFunction *resetNotifierFunctionPtr;
- //! Pointer to the function that is used to notify the client if CHPP is
- //! matched to a service.
+ //! Notifies the client if CHPP is matched to a service.
ChppNotifierFunction *matchNotifierFunctionPtr;
- //! Pointer to the function that dispatches incoming service responses for the
- //! client.
+ //! Dispatches incoming service responses.
//! Service responses are only dispatched to clients that have been opened or
- //! are in the process of being (re)opened. @see ChppOpenState
+ //! are in the process of being (re)opened. @see ChppOpenState.
+ //! Errors returned by the dispatch function are logged.
ChppDispatchFunction *responseDispatchFunctionPtr;
- //! Pointer to the function that dispatches incoming service notifications for
- //! the client.
+ //! Dispatches incoming service notifications.
//! Service notifications are only dispatched to clients that have been
//! opened. @see ChppOpenState
+ //! Errors returned by the dispatch function are logged.
ChppDispatchFunction *notificationDispatchFunctionPtr;
- //! Pointer to the function that initializes the client (after it is matched
- //! with a service at discovery) and assigns it its handle number.
+ //! Dispatches incoming service requests.
+ //! When an error is returned by the dispatch function it is logged and an
+ //! error response is automatically sent to the remote endpoint.
+ ChppDispatchFunction *requestDispatchFunctionPtr;
+
+ //! Initializes the client (after it is matched with a service at discovery)
+ //! and assigns it its handle number.
ChppClientInitFunction *initFunctionPtr;
- //! Pointer to the function that deinitializes the client.
+ //! Deinitializes the client.
ChppClientDeinitFunction *deinitFunctionPtr;
- //! Number of request-response states in the rRStates array. This is a
- //! uint16_t to match the uint16_t command in struct ChppAppHeader.
- uint16_t rRStateCount;
+ //! Number of outgoing requests supported by this client.
+ //! ChppAppHeader.command must be in the range [0, outReqCount - 1]
+ //! ChppEndpointState.outReqStates must contains that many elements.
+ uint16_t outReqCount;
- //! Minimum valid length of datagrams for the service.
+ //! Minimum valid length of datagrams for the service:
+ //! - service responses
+ //! - service notifications
+ //! - service requests
size_t minLength;
};
@@ -326,31 +420,54 @@ struct ChppClient {
* Request status for clients.
*/
enum ChppRequestState {
- CHPP_REQUEST_STATE_NONE = 0, // No request sent ever
- CHPP_REQUEST_STATE_REQUEST_SENT = 1, // Sent but no response yet
- CHPP_REQUEST_STATE_RESPONSE_RCV = 2, // Sent and response received
- CHPP_REQUEST_STATE_RESPONSE_TIMEOUT = 3, // Timeout. Responded as need be
+ CHPP_REQUEST_STATE_NONE = 0, //!< No request sent ever
+ CHPP_REQUEST_STATE_REQUEST_SENT = 1, //!< Sent, waiting for a response
+ CHPP_REQUEST_STATE_RESPONSE_RCV = 2, //!< Sent and response received
+ CHPP_REQUEST_STATE_RESPONSE_TIMEOUT = 3, //!< Timeout. Responded as need be
};
/**
- * Maintains the basic state for each request/response functionality of a
- * client or service.
- * Any number of these may be included in the (context) status variable of a
- * client or service (one per every every request/response functionality).
+ * State of each outgoing request and their response.
+ *
+ * There must be as many ChppOutgoingRequestState in the client or service state
+ * (ChppEndpointState) as the number of commands they support.
*/
-struct ChppRequestResponseState {
+struct ChppOutgoingRequestState {
uint64_t requestTimeNs; // Time of the last request
- uint64_t
- responseTimeNs; // If requestState is CHPP_REQUEST_STATE_REQUEST_SENT,
- // indicates the timeout time for the request
- // If requestState is CHPP_REQUEST_STATE_RESPONSE_RCV,
- // indicates when the response was received
-
+ // When requestState is CHPP_REQUEST_STATE_REQUEST_SENT,
+ // indicates the timeout time for the request.
+ // When requestState is CHPP_REQUEST_STATE_RESPONSE_RCV,
+ // indicates when the response was received.
+ uint64_t responseTimeNs;
uint8_t requestState; // From enum ChppRequestState
uint8_t transaction; // Transaction ID for the last request/response
};
/**
+ * State of each incoming request and their response.
+ *
+ * There must be as many ChppIncomingRequestState in the client or service state
+ * as the number of commands supported by the other side (corresponding service
+ * for a client and corresponding client for a service).
+ *
+ * Contrary to ChppOutgoingRequestState those are not part of
+ * CChppEndpointState. They must be stored to and retrieved from the context
+ * passed to chppRegisterClient / chppRegisterService.
+ *
+ * Note: while ChppIncomingRequestState and ChppOutgoingRequestState have the
+ * same layout, we want the types to be distinct to be enforced at compile time.
+ * Using a typedef would make both types equivalent.
+ *
+ * @see ChppOutgoingRequestState for field details.
+ */
+struct ChppIncomingRequestState {
+ uint64_t requestTimeNs;
+ uint64_t responseTimeNs;
+ uint8_t requestState;
+ uint8_t transaction;
+};
+
+/**
* Enabled clients and services.
*/
struct ChppClientServiceSet {
@@ -366,6 +483,36 @@ struct ChppClientServiceSet {
struct ChppLoopbackClientState;
struct ChppTimesyncClientState;
+/**
+ * CHPP state of a client or a service.
+ *
+ * This is the CHPP internal client/service state.
+ * Their private state is store in the context field.
+ */
+struct ChppEndpointState {
+ struct ChppAppState *appContext; // Pointer to app layer context
+
+ // State for the outgoing requests.
+ // It must accommodate Chpp{Client,Service}.outReqCount elements.
+ // It also tracks corresponding incoming responses.
+ // NULL when outReqCount = 0.
+ struct ChppOutgoingRequestState *outReqStates;
+
+ void *context; //!< Private state of the endpoint.
+
+ struct ChppSyncResponse syncResponse;
+
+ uint8_t index; //!< Index (in ChppAppState lists).
+ uint8_t handle; //!< Handle used to match client and service.
+ uint8_t transaction; //!< Next Transaction ID to be used.
+
+ uint8_t openState; //!< see enum ChppOpenState
+
+ bool pseudoOpen : 1; //!< Client to be opened upon a reset
+ bool initialized : 1; //!< Client is initialized
+ bool everInitialized : 1; //!< Client sync primitives initialized
+};
+
struct ChppAppState {
struct ChppTransportState *transportContext; // Pointing to transport context
@@ -375,18 +522,19 @@ struct ChppAppState {
const struct ChppService *registeredServices[CHPP_MAX_REGISTERED_SERVICES];
- void *registeredServiceContexts[CHPP_MAX_REGISTERED_SERVICES];
+ struct ChppEndpointState
+ *registeredServiceStates[CHPP_MAX_REGISTERED_SERVICES];
uint8_t registeredClientCount; // Number of clients currently registered
const struct ChppClient *registeredClients[CHPP_MAX_REGISTERED_CLIENTS];
- const struct ChppClientState
- *registeredClientStates[CHPP_MAX_REGISTERED_CLIENTS];
-
- void *registeredClientContexts[CHPP_MAX_REGISTERED_CLIENTS];
+ struct ChppEndpointState *registeredClientStates[CHPP_MAX_REGISTERED_CLIENTS];
- uint64_t nextRequestTimeoutNs;
+ // When the first outstanding request sent from the client timeouts.
+ uint64_t nextClientRequestTimeoutNs;
+ // When the first outstanding request sent from the service timeouts.
+ uint64_t nextServiceRequestTimeoutNs;
uint8_t
clientIndexOfServiceIndex[CHPP_MAX_DISCOVERED_SERVICES]; // Lookup table
@@ -509,6 +657,256 @@ uint8_t chppAppErrorToChreError(uint8_t error);
uint8_t chppAppShortResponseErrorHandler(uint8_t *buf, size_t len,
const char *responseName);
+/**
+ * Allocates a notification of a specified length.
+ *
+ * This function is internal. Instead use either
+ * - chppAllocClientNotification
+ * - or chppAllocServiceNotification
+ *
+ * The caller must initialize at least the handle and command fields of the
+ * ChppAppHeader.
+ *
+ * @param type CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION or
+ * CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION.
+ * @param len Length of the notification (including header) in bytes. Note
+ * that the specified length must be at least equal to the length of the
+ * app layer header.
+ *
+ * @return Pointer to allocated memory.
+ */
+struct ChppAppHeader *chppAllocNotification(uint8_t type, size_t len);
+
+/**
+ * Allocates a request message.
+ *
+ * This function is internal. Instead use either:
+ * - chppAllocClientRequest
+ * - or chppAllocServiceRequest
+ *
+ * @param type CHPP_MESSAGE_TYPE_CLIENT_REQUEST or
+ * CHPP_MESSAGE_TYPE_SERVICE_REQUEST.
+ * @param endpointState State of the endpoint.
+ * @param len Length of the response message (including header) in bytes. Note
+ * that the specified length must be at least equal to the length of the
+ * app layer header.
+ *
+ * @return Pointer to allocated memory.
+ */
+struct ChppAppHeader *chppAllocRequest(uint8_t type,
+ struct ChppEndpointState *endpointState,
+ size_t len);
+
+/**
+ * Allocates a response message of a specified length, populating the (app
+ * layer) response header according to the provided request (app layer) header.
+ *
+ * This function can be used to allocate either client or service response.
+ *
+ * @param requestHeader request header.
+ * @param len Length of the response message (including header) in bytes. Note
+ * that the specified length must be at least equal to the length of the
+ * app layer header.
+ *
+ * @return Pointer to allocated memory.
+ */
+struct ChppAppHeader *chppAllocResponse(
+ const struct ChppAppHeader *requestHeader, size_t len);
+
+/**
+ * This function shall be called for all incoming requests in order to
+ * A) Timestamp them, and
+ * B) Save their Transaction ID
+ *
+ * This function prints an error message if a duplicate request is received
+ * while outstanding request is still pending without a response.
+ *
+ * @param inReqState State of the request/response.
+ * @param requestHeader Request header.
+ */
+void chppTimestampIncomingRequest(struct ChppIncomingRequestState *inReqState,
+ const struct ChppAppHeader *requestHeader);
+
+/**
+ * This function shall be called for all outgoing requests in order to
+ * A) Timestamp them, and
+ * B) Save their Transaction ID
+ *
+ * This function prints an error message if a duplicate request is sent
+ * while outstanding request is still pending without a response.
+ *
+ * @param appState App layer state.
+ * @param outReqState state of the request/response.
+ * @param requestHeader Client request header.
+ * @param timeoutNs The timeout.
+ */
+void chppTimestampOutgoingRequest(struct ChppAppState *appState,
+ struct ChppOutgoingRequestState *outReqState,
+ const struct ChppAppHeader *requestHeader,
+ uint64_t timeoutNs);
+
+/**
+ * This function shall be called for incoming responses to a request in
+ * order to
+ * A) Verify the correct transaction ID
+ * B) Timestamp them, and
+ * C) Mark them as fulfilled
+ *
+ * This function prints an error message if a response is received without an
+ * outstanding request.
+ *
+ * @param appState App layer state.
+ * @param outReqState state of the request/response.
+ * @param requestHeader Request header.
+ *
+ * @return false if there is an error. true otherwise.
+ */
+bool chppTimestampIncomingResponse(struct ChppAppState *appState,
+ struct ChppOutgoingRequestState *outReqState,
+ const struct ChppAppHeader *responseHeader);
+
+/**
+ * This function shall be called for the outgoing response to a request in order
+ * to:
+ * A) Timestamp them, and
+ * B) Mark them as fulfilled part of the request/response's
+ * ChppOutgoingRequestState struct.
+ *
+ * For most responses, it is expected that chppSendTimestampedResponseOrFail()
+ * shall be used to both timestamp and send the response in one shot.
+ *
+ * @param inReqState State of the request/response.
+ * @return The last response time (CHPP_TIME_NONE for the first response).
+ */
+uint64_t chppTimestampOutgoingResponse(
+ struct ChppIncomingRequestState *inReqState);
+
+/**
+ * Timestamps a response using chppTimestampOutgoingResponse() and enqueues it
+ * using chppEnqueueTxDatagramOrFail().
+ *
+ * Refer to their respective documentation for details.
+ *
+ * This function logs an error message if a response is attempted without an
+ * outstanding request.
+ *
+ * @param appState App layer state.
+ * @param inReqState State of the request/response.
+ * @param buf Datagram payload allocated through chppMalloc. Cannot be null.
+ * @param len Datagram length in bytes.
+ *
+ * @return whether the datagram was successfully enqueued. false means that the
+ * queue was full and the payload discarded.
+ */
+bool chppSendTimestampedResponseOrFail(
+ struct ChppAppState *appState, struct ChppIncomingRequestState *inReqState,
+ void *buf, size_t len);
+
+/**
+ * Timestamps and enqueues a request.
+ *
+ * This function is internal. User either:
+ * - chppClientSendTimestampedRequestOrFail
+ * - or chppServiceSendTimestampedRequestOrFail
+ *
+ * Note that the ownership of buf is taken from the caller when this method is
+ * invoked.
+ *
+ * @param endpointState state of the endpoint.
+ * @param outReqState state of the request/response.
+ * @param buf Datagram payload allocated through chppMalloc. Cannot be null.
+ * @param len Datagram length in bytes.
+ * @param timeoutNs Time in nanoseconds before a timeout response is generated.
+ * Zero means no timeout response.
+ *
+ * @return True informs the sender that the datagram was successfully enqueued.
+ * False informs the sender that the queue was full and the payload
+ * discarded.
+ */
+bool chppSendTimestampedRequestOrFail(
+ struct ChppEndpointState *endpointState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
+ uint64_t timeoutNs);
+
+/**
+ * Wait for a response to be received.
+ *
+ * @param syncResponse sync primitives.
+ * @param outReqState state of the request/response.
+ * @param timeoutNs Time in nanoseconds before a timeout response is generated.
+ */
+bool chppWaitForResponseWithTimeout(
+ struct ChppSyncResponse *syncResponse,
+ struct ChppOutgoingRequestState *outReqState, uint64_t timeoutNs);
+
+/**
+ * Returns the state of a registered endpoint.
+ *
+ * @param appState State of the app layer.
+ * @param index Index of the client or service.
+ * @param type Type of the endpoint to return.
+ * @return state of the client or service.
+ */
+struct ChppEndpointState *getRegisteredEndpointState(
+ struct ChppAppState *appState, uint8_t index, enum ChppEndpointType type);
+
+/**
+ * Returns the number of possible outgoing requests.
+ *
+ * @param appState State of the app layer.
+ * @param index Index of the client or service.
+ * @param type Type of the endpoint to return.
+ * @return The number of possible outgoing requests.
+ */
+uint16_t getRegisteredEndpointOutReqCount(struct ChppAppState *appState,
+ uint8_t index,
+ enum ChppEndpointType type);
+
+/**
+ * Returns the number of registered endpoints of the given type.
+ *
+ * @param appState State of the app layer.
+ * @param type Type of the endpoint to return.
+ * @return The number of endpoints.
+ */
+uint8_t getRegisteredEndpointCount(struct ChppAppState *appState,
+ enum ChppEndpointType type);
+
+/**
+ * Recalculates the next upcoming request timeout.
+ *
+ * The timeout is updated in the app layer state.
+ *
+ * @param appState State of the app layer.
+ * @param type Type of the endpoint.
+ */
+void chppRecalculateNextTimeout(struct ChppAppState *appState,
+ enum ChppEndpointType type);
+
+/**
+ * Returns a pointer to the next request timeout for the given endpoint type.
+ *
+ * @param appState State of the app layer.
+ * @param type Type of the endpoint.
+ * @return Pointer to the timeout in nanoseconds.
+ */
+uint64_t *getNextRequestTimeoutNs(struct ChppAppState *appState,
+ enum ChppEndpointType type);
+
+/**
+ * Closes any remaining open requests by simulating a timeout.
+ *
+ * This function is used when an endpoint is reset.
+ *
+ * @param endpointState State of the endpoint.
+ * @param type The type of the endpoint.
+ * @param clearOnly If true, indicates that a timeout response shouldn't be
+ * sent. This must only be set if the requests are being cleared as
+ * part of the closing.
+ */
+void chppCloseOpenRequests(struct ChppEndpointState *endpointState,
+ enum ChppEndpointType type, bool clearOnly);
+
#ifdef __cplusplus
}
#endif
diff --git a/chpp/include/chpp/clients.h b/chpp/include/chpp/clients.h
index f48686f8..fe2dfe72 100644
--- a/chpp/include/chpp/clients.h
+++ b/chpp/include/chpp/clients.h
@@ -25,7 +25,6 @@
#include "chpp/condition_variable.h"
#include "chpp/macros.h"
#include "chpp/mutex.h"
-#include "chre_api/chre/common.h"
#ifdef __cplusplus
extern "C" {
@@ -36,10 +35,10 @@ extern "C" {
***********************************************/
/**
- * Uses chppAllocClientRequest() to allocate a client request message of a
- * specific type and its corresponding length.
+ * Allocates a client request message of a specific type and its corresponding
+ * length.
*
- * @param clientState State variable of the client.
+ * @param clientState State of the client.
* @param type Type of response.
*
* @return Pointer to allocated memory
@@ -48,10 +47,9 @@ extern "C" {
(type *)chppAllocClientRequest(clientState, sizeof(type))
/**
- * Uses chppAllocClientRequest() to allocate a variable-length client request
- * message of a specific type.
+ * Allocates a variable-length client request message of a specific type.
*
- * @param clientState State variable of the client.
+ * @param clientState State of the client.
* @param type Type of response which includes an arrayed member.
* @param count number of items in the array of arrayField.
* @param arrayField The arrayed member field.
@@ -63,27 +61,27 @@ extern "C" {
clientState, sizeof(type) + (count)*sizeof_member(type, arrayField[0]))
/**
- * Maintains the basic state of a client.
- * This is expected to be included once in the (context) status variable of
- * each client.
+ * Allocates a variable-length notification of a specific type.
+ *
+ * @param type Type of notification which includes an arrayed member.
+ * @param count number of items in the array of arrayField.
+ * @param arrayField The arrayed member field.
+ *
+ * @return Pointer to allocated memory
+ */
+#define chppAllocClientNotificationTypedArray(type, count, arrayField) \
+ (type *)chppAllocClientNotification( \
+ sizeof(type) + (count)*sizeof_member(type, arrayField[0]))
+
+/**
+ * Allocates a notification of a specific type and its corresponding length.
+ *
+ * @param type Type of notification.
+ *
+ * @return Pointer to allocated memory
*/
-struct ChppClientState {
- struct ChppAppState *appContext; // Pointer to app layer context
- struct ChppRequestResponseState
- *rRStates; // Pointer to array of request-response states, if any
- uint8_t index; // Index of this client
- uint8_t handle; // Handle number for this client
- uint8_t transaction; // Next Transaction ID to be used
-
- uint8_t openState; // As defined in enum ChppOpenState
- bool pseudoOpen : 1; // Client to be opened upon a reset
- bool initialized : 1; // Is initialized
- bool everInitialized : 1; // Synchronization primitives initialized
-
- bool responseReady : 1; // For sync. request/responses
- struct ChppMutex responseMutex;
- struct ChppConditionVariable responseCondVar;
-};
+#define chppAllocClientNotificationFixed(type) \
+ (type *)chppAllocClientNotification(sizeof(type))
#ifdef CHPP_CLIENT_ENABLED_CHRE_WWAN
#define CHPP_CLIENT_ENABLED_WWAN
@@ -105,12 +103,6 @@ struct ChppClientState {
#define CHPP_CLIENT_ENABLED
#endif
-#define CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE CHPP_TIME_MAX
-
-#ifndef CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT
-#define CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT CHRE_ASYNC_RESULT_TIMEOUT_NS
-#endif
-
// Default timeout for discovery completion.
#ifndef CHPP_DISCOVERY_DEFAULT_TIMEOUT_MS
#define CHPP_DISCOVERY_DEFAULT_TIMEOUT_MS UINT64_C(10000) // 10s
@@ -149,19 +141,27 @@ void chppDeregisterCommonClients(struct ChppAppState *context);
* When a match succeeds, the client's initialization function (pointer) is
* called, assigning them their handle number.
*
+ * outReqStates must point to an array of ChppOutgoingRequestState with
+ * ChppEndpointState.outReqCount elements. It must be NULL when the client
+ * does not send requests (ChppEndpointState.outReqCount = 0).
+ *
+ * inReqStates must point to an array of ChppIncomingRequestState with
+ * as many elements as the corresponding service can send. It must be NULL when
+ * the service does not send requests (ChppEndpointState.outReqCount = 0).
+ *
* Note that the maximum number of clients that can be registered on a platform
* can specified as CHPP_MAX_REGISTERED_CLIENTS by the initialization code.
* Otherwise, a default value will be used.
*
* @param appContext State of the app layer.
* @param clientContext State of the client instance.
- * @param clientState State variable of the client.
- * @param rRStates Pointer to array of request-response states, if any.
+ * @param clientState State of the client.
+ * @param outReqStates List of outgoing request states.
* @param newClient The client to be registered on this platform.
*/
void chppRegisterClient(struct ChppAppState *appContext, void *clientContext,
- struct ChppClientState *clientState,
- struct ChppRequestResponseState *rRStates,
+ struct ChppEndpointState *clientState,
+ struct ChppOutgoingRequestState *outReqStates,
const struct ChppClient *newClient);
/**
@@ -175,17 +175,17 @@ void chppInitBasicClients(struct ChppAppState *context);
* Initializes a client. This function must be called when a client is matched
* with a service during discovery to provides its handle number.
*
- * @param clientState State variable of the client.
+ * @param clientState State of the client.
* @param handle Handle number for this client.
*/
-void chppClientInit(struct ChppClientState *clientState, uint8_t handle);
+void chppClientInit(struct ChppEndpointState *clientState, uint8_t handle);
/**
* Deinitializes a client.
*
- * @param clientState State variable of the client.
+ * @param clientState State of the client.
*/
-void chppClientDeinit(struct ChppClientState *clientState);
+void chppClientDeinit(struct ChppEndpointState *clientState);
/**
* Deinitializes basic clients.
@@ -202,140 +202,102 @@ void chppDeinitBasicClients(struct ChppAppState *context);
void chppDeinitMatchedClients(struct ChppAppState *context);
/**
- * Allocates a client request message of a specified length, populating the
- * (app layer) client request header, including the sequence ID. The
- * next-sequence ID stored in the client state variable is subsequently
- * incremented.
+ * Allocates a client request message of a specified length.
*
- * It is expected that for most use cases, the chppAllocClientRequestFixed()
- * or chppAllocClientRequestTypedArray() macros shall be used rather than
- * calling this function directly.
+ * It populates the request header, including the transaction number which is
+ * then incremented.
*
- * @param clientState State variable of the client.
+ * For most use cases, the chppAllocClientRequestFixed() or
+ * chppAllocClientRequestTypedArray() macros shall be preferred.
+ *
+ * @param clientState State of the client.
* @param len Length of the response message (including header) in bytes. Note
- * that the specified length must be at least equal to the lendth of the app
- * layer header.
+ * that the specified length must be at least equal to the length of the
+ * app layer header.
*
* @return Pointer to allocated memory
*/
struct ChppAppHeader *chppAllocClientRequest(
- struct ChppClientState *clientState, size_t len);
+ struct ChppEndpointState *clientState, size_t len);
/**
- * Uses chppAllocClientRequest() to allocate a specific client request command
- * without any additional payload.
+ * Allocates a specific client request command without any additional payload.
*
- * @param clientState State variable of the client.
+ * @param clientState State of the client.
* @param command Type of response.
*
* @return Pointer to allocated memory
*/
struct ChppAppHeader *chppAllocClientRequestCommand(
- struct ChppClientState *clientState, uint16_t command);
+ struct ChppEndpointState *clientState, uint16_t command);
/**
- * This function shall be called for all outgoing client requests in order to
- * A) Timestamp them, and
- * B) Save their Transaction ID
- * as part of the request/response's ChppRequestResponseState struct.
- *
- * This function prints an error message if a duplicate request is sent
- * while outstanding request is still pending without a response.
- *
- * @param clientState State of the client sending the client request.
- * @param transactionId The transaction ID to use when loading the app.
- * @param rRState Maintains the basic state for each request/response
- * functionality of a client.
- * @param requestHeader Client request header.
- */
-void chppClientTimestampRequest(struct ChppClientState *clientState,
- struct ChppRequestResponseState *rRState,
- struct ChppAppHeader *requestHeader,
- uint64_t timeoutNs);
-
-/**
- * This function shall be called for incoming responses to a client request in
- * order to
- * A) Verify the correct transaction ID
- * B) Timestamp them, and
- * C) Mark them as fulfilled
- * D) TODO: check for timeout
- *
- * This function prints an error message if a response is received without an
- * outstanding request.
- *
- * @param clientState State of the client sending the client request.
- * @param rRState Maintains the basic state for each request/response
- * functionality of a client.
- * @param requestHeader Client request header.
- *
- * @return false if there is an error. True otherwise.
- */
-bool chppClientTimestampResponse(struct ChppClientState *clientState,
- struct ChppRequestResponseState *rRState,
- const struct ChppAppHeader *responseHeader);
-
-/**
- * Timestamps a client request using chppClientTimestampResponse() and enqueues
- * it using chppEnqueueTxDatagramOrFail().
- *
- * Refer to their respective documentation for details.
+ * Timestamps and enqueues a request.
*
* Note that the ownership of buf is taken from the caller when this method is
* invoked.
*
- * @param clientState State of the client sending the client request.
- * @param rRState Maintains the basic state for each request/response
- * functionality of a client.
+ * @param clientState State of the client sending the request.
+ * @param outReqState State of the request/response
* @param buf Datagram payload allocated through chppMalloc. Cannot be null.
* @param len Datagram length in bytes.
* @param timeoutNs Time in nanoseconds before a timeout response is generated.
- * Zero means no timeout response.
+ * Zero means no timeout response.
*
* @return True informs the sender that the datagram was successfully enqueued.
- * False informs the sender that the queue was full and the payload discarded.
+ * False informs the sender that the queue was full and the payload
+ * discarded.
*/
-bool chppSendTimestampedRequestOrFail(struct ChppClientState *clientState,
- struct ChppRequestResponseState *rRState,
- void *buf, size_t len,
- uint64_t timeoutNs);
+bool chppClientSendTimestampedRequestOrFail(
+ struct ChppEndpointState *clientState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
+ uint64_t timeoutNs);
/**
- * Similar to chppSendTimestampedRequestOrFail() but blocks execution until a
- * response is received. Used for synchronous requests.
+ * Similar to chppClientSendTimestampedRequestOrFail() but blocks execution
+ * until a response is received. Used for synchronous requests.
*
* In order to use this function, clientState->responseNotifier must have been
* initialized using chppNotifierInit() upon initialization of the client.
*
- * @param clientState State of the client sending the client request.
- * @param rRState Maintains the basic state for each request/response
- * functionality of a client.
+ * @param clientState State of the client sending the request.
+ * @param outReqState State of the request/response.
* @param buf Datagram payload allocated through chppMalloc. Cannot be null.
* @param len Datagram length in bytes.
*
* @return True informs the sender that the datagram was successfully enqueued.
- * False informs the sender that the payload was discarded because either the
- * queue was full, or the request timed out.
+ * False informs the sender that the payload was discarded because
+ * either the queue was full, or the request timed out.
*/
-bool chppSendTimestampedRequestAndWait(struct ChppClientState *clientState,
- struct ChppRequestResponseState *rRState,
- void *buf, size_t len);
+bool chppClientSendTimestampedRequestAndWait(
+ struct ChppEndpointState *clientState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len);
/**
- * Same as chppSendTimestampedRequestAndWait() but with a specified timeout.
+ * Same as chppClientSendTimestampedRequestAndWait() but with a specified
+ * timeout.
+ *
+ * @param clientState State of the client sending the request.
+ * @param outReqState State of the request/response.
+ * @param buf Datagram payload allocated through chppMalloc. Cannot be null.
+ * @param len Datagram length in bytes.
+ *
+ * @return True informs the sender that the datagram was successfully enqueued.
+ * False informs the sender that the payload was discarded because
+ * either the queue was full, or the request timed out.
*/
-bool chppSendTimestampedRequestAndWaitTimeout(
- struct ChppClientState *clientState,
- struct ChppRequestResponseState *rRState, void *buf, size_t len,
+bool chppClientSendTimestampedRequestAndWaitTimeout(
+ struct ChppEndpointState *clientState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
uint64_t timeoutNs);
/**
* Marks a closed client as pseudo-open, so that it would be opened upon a
* reset.
*
- * @param clientState State variable of the client.
+ * @param clientState State of the client.
*/
-void chppClientPseudoOpen(struct ChppClientState *clientState);
+void chppClientPseudoOpen(struct ChppEndpointState *clientState);
/**
* Sends a client request for the open command in a blocking or non-blocking
@@ -343,46 +305,59 @@ void chppClientPseudoOpen(struct ChppClientState *clientState);
* A non-blocking open is used to for reopening a service after a reset or for
* opening a pseudo-open service.
*
- * @param clientState State variable of the client.
- * @param openRRState Request/response state for the open command.
+ * @param clientState State of the client.
+ * @param openReqState State of the request/response for the open command.
* @param openCommand Open command to be sent.
* @param blocking Indicates a blocking (vs. non-blocking) open request.
*
* @return Indicates success or failure.
*/
-bool chppClientSendOpenRequest(struct ChppClientState *clientState,
- struct ChppRequestResponseState *openRRState,
+bool chppClientSendOpenRequest(struct ChppEndpointState *clientState,
+ struct ChppOutgoingRequestState *openReqState,
uint16_t openCommand, bool blocking);
/**
* Processes a service response for the open command.
*
- * @param clientState State variable of the client.
+ * @param clientState State of the client.
*/
-void chppClientProcessOpenResponse(struct ChppClientState *clientState,
+void chppClientProcessOpenResponse(struct ChppEndpointState *clientState,
uint8_t *buf, size_t len);
/**
- * Recalculates the next upcoming client request timeout time.
- *
- * @param context State of the app layer.
- */
-void chppClientRecalculateNextTimeout(struct ChppAppState *context);
+ * Closes any remaining open requests by simulating a timeout.
-/**
- * Closes any remaining open requests for a given client by sending a timeout.
* This function is used when a client is reset.
*
- * @param clientState State variable of the client.
- * @param client The client for whech to clear out open requests.
+ * @param clientState State of the client.
+ * @param client The client for which to clear out open requests.
* @param clearOnly If true, indicates that a timeout response shouldn't be
- * sent to the client. This must only be set if the requests are being
- * cleared as part of the client closing.
+ * sent. This must only be set if the requests are being cleared as part
+ * of the client closing.
*/
-void chppClientCloseOpenRequests(struct ChppClientState *clientState,
+void chppClientCloseOpenRequests(struct ChppEndpointState *clientState,
const struct ChppClient *client,
bool clearOnly);
+/**
+ * Allocates a client notification of a specified length.
+ *
+ * It is expected that for most use cases, the
+ * chppAllocClientNotificationFixed() or
+ * chppAllocClientNotificationTypedArray() macros shall be used rather than
+ * calling this function directly.
+ *
+ * The caller must initialize at least the handle and command fields of the
+ * ChppAppHeader.
+ *
+ * @param len Length of the notification (including header) in bytes. Note
+ * that the specified length must be at least equal to the length of the
+ * app layer header.
+ *
+ * @return Pointer to allocated memory.
+ */
+struct ChppAppHeader *chppAllocClientNotification(size_t len);
+
#ifdef __cplusplus
}
#endif
diff --git a/chpp/include/chpp/clients/gnss.h b/chpp/include/chpp/clients/gnss.h
index 74f5022d..a26dcbeb 100644
--- a/chpp/include/chpp/clients/gnss.h
+++ b/chpp/include/chpp/clients/gnss.h
@@ -50,9 +50,9 @@ void chppRegisterGnssClient(struct ChppAppState *appContext);
void chppDeregisterGnssClient(struct ChppAppState *appContext);
/**
- * @return The ChppClientState pointer to the GNSS client.
+ * @return The ChppEndpointState pointer to the GNSS client.
*/
-struct ChppClientState *getChppGnssClientState(void);
+struct ChppEndpointState *getChppGnssClientState(void);
#ifndef CHPP_CLIENT_ENABLED_CHRE_GNSS
/**
diff --git a/chpp/include/chpp/clients/wifi.h b/chpp/include/chpp/clients/wifi.h
index e0384cd0..f750c761 100644
--- a/chpp/include/chpp/clients/wifi.h
+++ b/chpp/include/chpp/clients/wifi.h
@@ -50,9 +50,9 @@ void chppRegisterWifiClient(struct ChppAppState *appContext);
void chppDeregisterWifiClient(struct ChppAppState *appContext);
/**
- * @return The ChppClientState pointer to the WiFi client.
+ * @return The ChppEndpointState pointer to the WiFi client.
*/
-struct ChppClientState *getChppWifiClientState(void);
+struct ChppEndpointState *getChppWifiClientState(void);
#ifndef CHPP_CLIENT_ENABLED_CHRE_WIFI
/**
diff --git a/chpp/include/chpp/clients/wwan.h b/chpp/include/chpp/clients/wwan.h
index 3b10f2a4..41a680c6 100644
--- a/chpp/include/chpp/clients/wwan.h
+++ b/chpp/include/chpp/clients/wwan.h
@@ -50,9 +50,9 @@ void chppRegisterWwanClient(struct ChppAppState *appContext);
void chppDeregisterWwanClient(struct ChppAppState *appContext);
/**
- * @return The ChppClientState pointer to the WWAN client.
+ * @return The ChppEndpointState pointer to the WWAN client.
*/
-struct ChppClientState *getChppWwanClientState(void);
+struct ChppEndpointState *getChppWwanClientState(void);
#ifndef CHPP_CLIENT_ENABLED_CHRE_WWAN
/**
diff --git a/chpp/include/chpp/notifier.h b/chpp/include/chpp/notifier.h
index 2624b476..de0e6bd5 100644
--- a/chpp/include/chpp/notifier.h
+++ b/chpp/include/chpp/notifier.h
@@ -96,6 +96,8 @@ static uint32_t chppNotifierTimedWait(struct ChppNotifier *notifier,
* multiple events to be handled simultaneously in chppNotifierTimedWait().
*
* @param notifier Points to the ChppNotifier being used.
+ * @param signal The value where each bit represents a different event.
+ * As such the value 0 will not notify any event.
*/
static void chppNotifierSignal(struct ChppNotifier *notifier, uint32_t signal);
diff --git a/chpp/include/chpp/services.h b/chpp/include/chpp/services.h
index ddd5a93f..a89af3cb 100644
--- a/chpp/include/chpp/services.h
+++ b/chpp/include/chpp/services.h
@@ -38,71 +38,55 @@ extern "C" {
#endif
/**
- * Uses chppAllocServiceNotification() to allocate a variable-length response
- * message of a specific type.
+ * Allocates a service request message of a specific type and its corresponding
+ * length.
*
- * @param type Type of notification which includes an arrayed member.
- * @param count number of items in the array of arrayField.
- * @param arrayField The arrayed member field.
+ * @param serviceState State of the service.
+ * @param type Type of response.
*
- * @return Pointer to allocated memory
+ * @return Pointer to allocated memory.
*/
-#define chppAllocServiceNotificationTypedArray(type, count, arrayField) \
- (type *)chppAllocServiceNotification( \
- sizeof(type) + (count)*sizeof_member(type, arrayField[0]))
+#define chppAllocServiceRequestFixed(serviceState, type) \
+ (type *)chppAllocServiceRequest(serviceState, sizeof(type))
/**
- * Uses chppAllocServiceNotification() to allocate a response message of a
- * specific type and its corresponding length.
+ * Allocate a variable-length service request message of a specific type.
*
- * @param type Type of notification.
+ * @param serviceState State of the service.
+ * @param type Type of response which includes an arrayed member.
+ * @param count number of items in the array of arrayField.
+ * @param arrayField The arrayed member field.
*
- * @return Pointer to allocated memory
+ * @return Pointer to allocated memory.
*/
-#define chppAllocServiceNotificationFixed(type) \
- (type *)chppAllocServiceNotification(sizeof(type))
+#define chppAllocServiceRequestTypedArray(serviceState, type, count, \
+ arrayField) \
+ (type *)chppAllocServiceRequest( \
+ serviceState, sizeof(type) + (count)*sizeof_member(type, arrayField[0]))
/**
- * Uses chppAllocServiceResponse() to allocate a variable-length response
- * message of a specific type.
+ * Allocates a variable-length notification of a specific type.
*
- * @param requestHeader client request header, as per
- * chppAllocServiceResponse().
- * @param type Type of response which includes an arrayed member.
+ * @param type Type of notification which includes an arrayed member.
* @param count number of items in the array of arrayField.
* @param arrayField The arrayed member field.
*
- * @return Pointer to allocated memory
+ * @return Pointer to allocated memory.
*/
-#define chppAllocServiceResponseTypedArray(requestHeader, type, count, \
- arrayField) \
- (type *)chppAllocServiceResponse( \
- requestHeader, \
+#define chppAllocServiceNotificationTypedArray(type, count, arrayField) \
+ (type *)chppAllocServiceNotification( \
sizeof(type) + (count)*sizeof_member(type, arrayField[0]))
/**
- * Uses chppAllocServiceResponse() to allocate a response message of a specific
- * type and its corresponding length.
+ * Uses chppAllocServiceNotification() to allocate a response notification of a
+ * specific type and its corresponding length.
*
- * @param requestHeader client request header, as per
- * chppAllocServiceResponse().
- * @param type Type of response.
+ * @param type Type of notification.
*
* @return Pointer to allocated memory
*/
-#define chppAllocServiceResponseFixed(requestHeader, type) \
- (type *)chppAllocServiceResponse(requestHeader, sizeof(type))
-
-/**
- * Maintains the basic state of a service.
- * This is expected to be included in the state of each service.
- */
-struct ChppServiceState {
- struct ChppAppState *appContext; // Pointer to app layer context
- uint8_t handle; // Handle number for this service
-
- uint8_t openState; // As defined in enum ChppOpenState
-};
+#define chppAllocServiceNotificationFixed(type) \
+ (type *)chppAllocServiceNotification(sizeof(type))
/************************************************
* Public functions
@@ -132,17 +116,27 @@ void chppDeregisterCommonServices(struct ChppAppState *context);
* server (if any), i.e. except those that are registered through
* chppRegisterCommonServices().
*
+ * outReqStates must point to an array of ChppOutgoingRequestState with
+ * ChppEndpointState.outReqCount elements. It must be NULL when the service
+ * does not send requests (ChppEndpointState.outReqCount = 0).
+ *
+ * inReqStates must point to an array of ChppIncomingRequestState with
+ * as many elements as the corresponding client can send. It must be NULL when
+ * the client does not send requests (ChppEndpointState.outReqCount = 0).
+ *
* Note that the maximum number of services that can be registered on a platform
* can specified as CHPP_MAX_REGISTERED_SERVICES by the initialization code.
* Otherwise, a default value will be used.
*
* @param appContext State of the app layer.
* @param serviceContext State of the service instance.
- * @param serviceState State variable of the client.
+ * @param serviceState State of the client.
+ * @param outReqStates List of outgoing request states.
* @param newService The service to be registered on this platform.
*/
void chppRegisterService(struct ChppAppState *appContext, void *serviceContext,
- struct ChppServiceState *serviceState,
+ struct ChppEndpointState *serviceState,
+ struct ChppOutgoingRequestState *outReqStates,
const struct ChppService *newService);
/**
@@ -153,83 +147,118 @@ void chppRegisterService(struct ChppAppState *appContext, void *serviceContext,
* chppAllocServiceNotificationTypedArray() macros shall be used rather than
* calling this function directly.
*
+ * The caller must initialize at least the handle and command fields of the
+ * ChppAppHeader.
+ *
* @param len Length of the notification (including header) in bytes. Note
- * that the specified length must be at least equal to the length of the app
- * layer header.
+ * that the specified length must be at least equal to the length of the
+ * app layer header.
*
* @return Pointer to allocated memory
*/
struct ChppAppHeader *chppAllocServiceNotification(size_t len);
/**
- * Allocates a service response message of a specified length, populating the
- * (app layer) service response header according to the provided client request
- * (app layer) header.
+ * Allocates a service request message of a specified length.
*
- * It is expected that for most use cases, the chppAllocServiceResponseFixed()
- * or chppAllocServiceResponseTypedArray() macros shall be used rather than
- * calling this function directly.
+ * It populates the request header, including the transaction number which is
+ * then incremented.
+ *
+ * For most use cases, the chppAllocServiceRequestFixed() or
+ * chppAllocServiceRequestTypedArray() macros shall be preferred.
*
- * @param requestHeader Client request header.
+ * @param serviceState State of the service.
* @param len Length of the response message (including header) in bytes. Note
- * that the specified length must be at least equal to the length of the app
- * layer header.
+ * that the specified length must be at least equal to the length of the
+ * app layer header.
*
* @return Pointer to allocated memory
*/
-struct ChppAppHeader *chppAllocServiceResponse(
- const struct ChppAppHeader *requestHeader, size_t len);
+struct ChppAppHeader *chppAllocServiceRequest(
+ struct ChppEndpointState *serviceState, size_t len);
/**
- * This function shall be called for all incoming client requests in order to
- * A) Timestamp them, and
- * B) Save their Transaction ID
- * as part of the request/response's ChppRequestResponseState struct.
+ * Allocates a specific service request command without any additional payload.
*
- * This function prints an error message if a duplicate request is received
- * while outstanding request is still pending without a response.
+ * @param serviceState State of the service.
+ * @param command Type of response.
*
- * @param rRStateState State of the current request/response.
- * @param requestHeader Client request header.
+ * @return Pointer to allocated memory
*/
-void chppServiceTimestampRequest(struct ChppRequestResponseState *rRState,
- struct ChppAppHeader *requestHeader);
+struct ChppAppHeader *chppAllocServiceRequestCommand(
+ struct ChppEndpointState *serviceState, uint16_t command);
/**
- * This function shall be called for the final service response to a client
- * request in order to
- * A) Timestamp them, and
- * B) Mark them as fulfilled
- * part of the request/response's ChppRequestResponseState struct.
+ * Timestamps and enqueues a request.
*
- * For most responses, it is expected that chppSendTimestampedResponseOrFail()
- * shall be used to both timestamp and send the response in one shot.
+ * Note that the ownership of buf is taken from the caller when this method is
+ * invoked.
+ *
+ * @param serviceState State of the service sending the request.
+ * @param outReqState State of the request/response.
+ * @param buf Datagram payload allocated through chppMalloc. Cannot be null.
+ * @param len Datagram length in bytes.
+ * @param timeoutNs Time in nanoseconds before a timeout response is generated.
+ * Zero means no timeout response.
*
- * @param rRState State of the current request/response.
- * @return The last response time (CHPP_TIME_NONE for the first response).
+ * @return True informs the sender that the datagram was successfully enqueued.
+ * False informs the sender that the queue was full and the payload
+ * discarded.
*/
-uint64_t chppServiceTimestampResponse(struct ChppRequestResponseState *rRState);
+bool chppServiceSendTimestampedRequestOrFail(
+ struct ChppEndpointState *serviceState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
+ uint64_t timeoutNs);
/**
- * Timestamps a service response using chppServiceTimestampResponse() and
- * enqueues it using chppEnqueueTxDatagramOrFail().
+ * Similar to chppServiceSendTimestampedRequestOrFail() but blocks execution
+ * until a response is received. Used for synchronous requests.
*
- * Refer to their respective documentation for details.
+ * @param serviceState State of the service sending the request.
+ * @param outReqState State of the request/response.
+ * @param buf Datagram payload allocated through chppMalloc. Cannot be null.
+ * @param len Datagram length in bytes.
*
- * This function logs an error message if a response is attempted without an
- * outstanding request.
+ * @return True informs the sender that the datagram was successfully enqueued.
+ * False informs the sender that the payload was discarded because
+ * either the queue was full, or the request timed out.
+ */
+bool chppServiceSendTimestampedRequestAndWait(
+ struct ChppEndpointState *serviceState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len);
+
+/**
+ * Same as chppClientSendTimestampedRequestAndWait() but with a specified
+ * timeout.
*
- * @param serviceState State of the service sending the response service.
- * @param rRState State of the current request/response.
+ * @param serviceState State of the service sending the request.
+ * @param outReqState State of the request/response.
* @param buf Datagram payload allocated through chppMalloc. Cannot be null.
* @param len Datagram length in bytes.
*
* @return True informs the sender that the datagram was successfully enqueued.
- * False informs the sender that the queue was full and the payload discarded.
+ * False informs the sender that the payload was discarded because
+ * either the queue was full, or the request timed out.
+ */
+bool chppServiceSendTimestampedRequestAndWaitTimeout(
+ struct ChppEndpointState *serviceState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
+ uint64_t timeoutNs);
+
+/**
+ * Closes any remaining open requests by simulating a timeout.
+ *
+ * This function is used when a service is reset.
+ *
+ * @param serviceState State of the service.
+ * @param service The service for which to clear out open requests.
+ * @param clearOnly If true, indicates that a timeout response shouldn't be
+ * sent. This must only be set if the requests are being cleared as
+ * part of the closing.
*/
-bool chppSendTimestampedResponseOrFail(struct ChppServiceState *serviceState,
- struct ChppRequestResponseState *rRState,
- void *buf, size_t len);
+void chppServiceCloseOpenRequests(struct ChppEndpointState *serviceState,
+ const struct ChppService *service,
+ bool clearOnly);
#ifdef __cplusplus
}
diff --git a/chpp/include/chpp/transport.h b/chpp/include/chpp/transport.h
index 19c701ce..f25b321c 100644
--- a/chpp/include/chpp/transport.h
+++ b/chpp/include/chpp/transport.h
@@ -295,7 +295,7 @@ struct ChppTransportConfiguration {
uint16_t reserved3;
} CHPP_PACKED_ATTR;
CHPP_PACKED_END
-// LINT.ThenChange(chpp/test/packet_util.cpp)
+// LINT.ThenChange(../../../chpp/test/packet_util.cpp)
struct ChppRxStatus {
//! Current receiving state, as described in ChppRxState.
diff --git a/chpp/services.c b/chpp/services.c
index 3445524a..0420bfe6 100644
--- a/chpp/services.c
+++ b/chpp/services.c
@@ -23,7 +23,9 @@
#include "chpp/app.h"
#include "chpp/log.h"
+#include "chpp/macros.h"
#include "chpp/memory.h"
+#include "chpp/mutex.h"
#ifdef CHPP_SERVICE_ENABLED_GNSS
#include "chpp/services/gnss.h"
#endif
@@ -33,7 +35,6 @@
#ifdef CHPP_SERVICE_ENABLED_WWAN
#include "chpp/services/wwan.h"
#endif
-#include "chpp/time.h"
#include "chpp/transport.h"
/************************************************
@@ -41,6 +42,7 @@
***********************************************/
void chppRegisterCommonServices(struct ChppAppState *context) {
+ CHPP_DEBUG_NOT_NULL(context);
UNUSED_VAR(context);
#ifdef CHPP_SERVICE_ENABLED_WWAN
@@ -63,6 +65,7 @@ void chppRegisterCommonServices(struct ChppAppState *context) {
}
void chppDeregisterCommonServices(struct ChppAppState *context) {
+ CHPP_DEBUG_NOT_NULL(context);
UNUSED_VAR(context);
#ifdef CHPP_SERVICE_ENABLED_WWAN
@@ -85,7 +88,8 @@ void chppDeregisterCommonServices(struct ChppAppState *context) {
}
void chppRegisterService(struct ChppAppState *appContext, void *serviceContext,
- struct ChppServiceState *serviceState,
+ struct ChppEndpointState *serviceState,
+ struct ChppOutgoingRequestState *outReqStates,
const struct ChppService *newService) {
CHPP_DEBUG_NOT_NULL(appContext);
CHPP_DEBUG_NOT_NULL(serviceContext);
@@ -96,6 +100,8 @@ void chppRegisterService(struct ChppAppState *appContext, void *serviceContext,
serviceState->openState = CHPP_OPEN_STATE_CLOSED;
serviceState->appContext = appContext;
+ serviceState->outReqStates = outReqStates;
+ serviceState->context = serviceContext;
if (numServices >= CHPP_MAX_REGISTERED_SERVICES) {
CHPP_LOGE("Max services registered: # %" PRIu8, numServices);
@@ -103,12 +109,16 @@ void chppRegisterService(struct ChppAppState *appContext, void *serviceContext,
return;
}
+ serviceState->index = numServices;
serviceState->handle = CHPP_SERVICE_HANDLE_OF_INDEX(numServices);
appContext->registeredServices[numServices] = newService;
- appContext->registeredServiceContexts[numServices] = serviceContext;
+ appContext->registeredServiceStates[numServices] = serviceState;
appContext->registeredServiceCount++;
+ chppMutexInit(&serviceState->syncResponse.mutex);
+ chppConditionVariableInit(&serviceState->syncResponse.condVar);
+
char uuidText[CHPP_SERVICE_UUID_STRING_LEN];
chppUuidToStr(newService->descriptor.uuid, uuidText);
CHPP_LOGD("Registered service # %" PRIu8
@@ -119,79 +129,64 @@ void chppRegisterService(struct ChppAppState *appContext, void *serviceContext,
uuidText, newService->descriptor.version.major,
newService->descriptor.version.minor,
newService->descriptor.version.patch, newService->minLength);
-
- return;
}
struct ChppAppHeader *chppAllocServiceNotification(size_t len) {
- CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
-
- struct ChppAppHeader *result = chppMalloc(len);
- if (result) {
- result->handle = CHPP_HANDLE_NONE;
- result->type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION;
- result->transaction = 0;
- result->error = CHPP_APP_ERROR_NONE;
- result->command = CHPP_APP_COMMAND_NONE;
- }
- return result;
+ return chppAllocNotification(CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION, len);
+}
+
+struct ChppAppHeader *chppAllocServiceRequest(
+ struct ChppEndpointState *serviceState, size_t len) {
+ CHPP_DEBUG_NOT_NULL(serviceState);
+ return chppAllocRequest(CHPP_MESSAGE_TYPE_SERVICE_REQUEST, serviceState, len);
}
-struct ChppAppHeader *chppAllocServiceResponse(
- const struct ChppAppHeader *requestHeader, size_t len) {
- CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
+struct ChppAppHeader *chppAllocServiceRequestCommand(
+ struct ChppEndpointState *serviceState, uint16_t command) {
+ struct ChppAppHeader *request =
+ chppAllocServiceRequest(serviceState, sizeof(struct ChppAppHeader));
- struct ChppAppHeader *result = chppMalloc(len);
- if (result) {
- *result = *requestHeader;
- result->type = CHPP_MESSAGE_TYPE_SERVICE_RESPONSE;
- result->error = CHPP_APP_ERROR_NONE;
+ if (request != NULL) {
+ request->command = command;
}
- return result;
+ return request;
}
-void chppServiceTimestampRequest(struct ChppRequestResponseState *rRState,
- struct ChppAppHeader *requestHeader) {
- if (rRState->responseTimeNs == CHPP_TIME_NONE &&
- rRState->requestTimeNs != CHPP_TIME_NONE) {
- CHPP_LOGE("RX dupe req t=%" PRIu64,
- rRState->requestTimeNs / CHPP_NSEC_PER_MSEC);
- }
- rRState->requestTimeNs = chppGetCurrentTimeNs();
- rRState->responseTimeNs = CHPP_TIME_NONE;
- rRState->transaction = requestHeader->transaction;
+bool chppServiceSendTimestampedRequestOrFail(
+ struct ChppEndpointState *serviceState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
+ uint64_t timeoutNs) {
+ return chppSendTimestampedRequestOrFail(serviceState, outReqState, buf, len,
+ timeoutNs);
}
-uint64_t chppServiceTimestampResponse(
- struct ChppRequestResponseState *rRState) {
- uint64_t previousResponseTime = rRState->responseTimeNs;
- rRState->responseTimeNs = chppGetCurrentTimeNs();
- return previousResponseTime;
+bool chppServiceSendTimestampedRequestAndWait(
+ struct ChppEndpointState *serviceState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len) {
+ return chppServiceSendTimestampedRequestAndWaitTimeout(
+ serviceState, outReqState, buf, len, CHPP_REQUEST_TIMEOUT_DEFAULT);
}
-bool chppSendTimestampedResponseOrFail(struct ChppServiceState *serviceState,
- struct ChppRequestResponseState *rRState,
- void *buf, size_t len) {
- uint64_t previousResponseTime = chppServiceTimestampResponse(rRState);
-
- if (rRState->requestTimeNs == CHPP_TIME_NONE) {
- CHPP_LOGE("TX response w/ no req t=%" PRIu64,
- rRState->responseTimeNs / CHPP_NSEC_PER_MSEC);
-
- } else if (previousResponseTime != CHPP_TIME_NONE) {
- CHPP_LOGW("TX additional response t=%" PRIu64 " for req t=%" PRIu64,
- rRState->responseTimeNs / CHPP_NSEC_PER_MSEC,
- rRState->requestTimeNs / CHPP_NSEC_PER_MSEC);
-
- } else {
- CHPP_LOGD("Sending initial response at t=%" PRIu64
- " for request at t=%" PRIu64 " (RTT=%" PRIu64 ")",
- rRState->responseTimeNs / CHPP_NSEC_PER_MSEC,
- rRState->requestTimeNs / CHPP_NSEC_PER_MSEC,
- (rRState->responseTimeNs - rRState->requestTimeNs) /
- CHPP_NSEC_PER_MSEC);
+bool chppServiceSendTimestampedRequestAndWaitTimeout(
+ struct ChppEndpointState *serviceState,
+ struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
+ uint64_t timeoutNs) {
+ CHPP_DEBUG_NOT_NULL(serviceState);
+
+ bool result = chppServiceSendTimestampedRequestOrFail(
+ serviceState, outReqState, buf, len, CHPP_REQUEST_TIMEOUT_INFINITE);
+
+ if (!result) {
+ return false;
}
- return chppEnqueueTxDatagramOrFail(serviceState->appContext->transportContext,
- buf, len);
+ return chppWaitForResponseWithTimeout(&serviceState->syncResponse,
+ outReqState, timeoutNs);
}
+
+void chppServiceCloseOpenRequests(struct ChppEndpointState *serviceState,
+ const struct ChppService *service,
+ bool clearOnly) {
+ UNUSED_VAR(service);
+ chppCloseOpenRequests(serviceState, CHPP_ENDPOINT_SERVICE, clearOnly);
+} \ No newline at end of file
diff --git a/chpp/services/discovery.c b/chpp/services/discovery.c
index 4ed54913..2712a648 100644
--- a/chpp/services/discovery.c
+++ b/chpp/services/discovery.c
@@ -51,9 +51,9 @@ static void chppDiscoveryDiscoverAll(
sizeof(struct ChppAppHeader) +
context->registeredServiceCount * sizeof(struct ChppServiceDescriptor);
- struct ChppDiscoveryResponse *response = chppAllocServiceResponseTypedArray(
- requestHeader, struct ChppDiscoveryResponse,
- context->registeredServiceCount, services);
+ struct ChppDiscoveryResponse *response =
+ chppAllocResponseTypedArray(requestHeader, struct ChppDiscoveryResponse,
+ context->registeredServiceCount, services);
if (response == NULL) {
CHPP_LOG_OOM();
diff --git a/chpp/services/gnss.c b/chpp/services/gnss.c
index 33f2ca4e..57bdf246 100644
--- a/chpp/services/gnss.c
+++ b/chpp/services/gnss.c
@@ -72,18 +72,18 @@ static const struct ChppService kGnssServiceConfig = {
* (RR) functionality.
*/
struct ChppGnssServiceState {
- struct ChppServiceState service; // GNSS service state
+ struct ChppEndpointState service; // CHPP service state
const struct chrePalGnssApi *api; // GNSS PAL API
// Based on chre/pal/gnss.h and chrePalGnssApi
- struct ChppRequestResponseState open; // Service init state
- struct ChppRequestResponseState close; // Service deinit state
- struct ChppRequestResponseState getCapabilities; // Get Capabilities state
- struct ChppRequestResponseState
+ struct ChppIncomingRequestState open; // Service init state
+ struct ChppIncomingRequestState close; // Service deinit state
+ struct ChppIncomingRequestState getCapabilities; // Get Capabilities state
+ struct ChppIncomingRequestState
controlLocationSession; // Control Location measurement state
- struct ChppRequestResponseState
+ struct ChppIncomingRequestState
controlMeasurementSession; // Control Raw GNSS measurement state
- struct ChppRequestResponseState
+ struct ChppIncomingRequestState
configurePassiveLocationListener; // Configure Passive location receiving
// state
};
@@ -153,51 +153,51 @@ static enum ChppAppErrorCode chppDispatchGnssRequest(void *serviceContext,
struct ChppGnssServiceState *gnssServiceContext =
(struct ChppGnssServiceState *)serviceContext;
- struct ChppRequestResponseState *rRState = NULL;
+ struct ChppIncomingRequestState *inReqState = NULL;
enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
bool dispatched = true;
switch (rxHeader->command) {
case CHPP_GNSS_OPEN: {
- rRState = &gnssServiceContext->open;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &gnssServiceContext->open;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppGnssServiceOpen(gnssServiceContext, rxHeader);
break;
}
case CHPP_GNSS_CLOSE: {
- rRState = &gnssServiceContext->close;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &gnssServiceContext->close;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppGnssServiceClose(gnssServiceContext, rxHeader);
break;
}
case CHPP_GNSS_GET_CAPABILITIES: {
- rRState = &gnssServiceContext->getCapabilities;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &gnssServiceContext->getCapabilities;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppGnssServiceGetCapabilities(gnssServiceContext, rxHeader);
break;
}
case CHPP_GNSS_CONTROL_LOCATION_SESSION: {
- rRState = &gnssServiceContext->controlLocationSession;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &gnssServiceContext->controlLocationSession;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppGnssServiceControlLocationSession(gnssServiceContext,
rxHeader, buf, len);
break;
}
case CHPP_GNSS_CONTROL_MEASUREMENT_SESSION: {
- rRState = &gnssServiceContext->controlMeasurementSession;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &gnssServiceContext->controlMeasurementSession;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppGnssServiceControlMeasurementSession(gnssServiceContext,
rxHeader, buf, len);
break;
}
case CHPP_GNSS_CONFIGURE_PASSIVE_LOCATION_LISTENER: {
- rRState = &gnssServiceContext->configurePassiveLocationListener;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &gnssServiceContext->configurePassiveLocationListener;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppGnssServiceConfigurePassiveLocationListener(
gnssServiceContext, rxHeader, buf, len);
break;
@@ -212,8 +212,8 @@ static enum ChppAppErrorCode chppDispatchGnssRequest(void *serviceContext,
if (dispatched == true && error != CHPP_APP_ERROR_NONE) {
// Request was dispatched but an error was returned. Close out
- // chppServiceTimestampRequest()
- chppServiceTimestampResponse(rRState);
+ // chppTimestampIncomingRequest()
+ chppTimestampOutgoingResponse(inReqState);
}
return error;
@@ -258,14 +258,14 @@ static enum ChppAppErrorCode chppGnssServiceOpen(
gnssServiceContext->service.openState = CHPP_OPEN_STATE_OPENED;
struct ChppAppHeader *response =
- chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
+ chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
size_t responseLen = sizeof(*response);
if (response == NULL) {
CHPP_LOG_OOM();
error = CHPP_APP_ERROR_OOM;
} else {
- chppSendTimestampedResponseOrFail(&gnssServiceContext->service,
+ chppSendTimestampedResponseOrFail(gnssServiceContext->service.appContext,
&gnssServiceContext->open, response,
responseLen);
}
@@ -293,14 +293,14 @@ static enum ChppAppErrorCode chppGnssServiceClose(
CHPP_LOGD("GNSS service closed");
struct ChppAppHeader *response =
- chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
+ chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
size_t responseLen = sizeof(*response);
if (response == NULL) {
CHPP_LOG_OOM();
error = CHPP_APP_ERROR_OOM;
} else {
- chppSendTimestampedResponseOrFail(&gnssServiceContext->service,
+ chppSendTimestampedResponseOrFail(gnssServiceContext->service.appContext,
&gnssServiceContext->close, response,
responseLen);
}
@@ -340,9 +340,8 @@ static enum ChppAppErrorCode chppGnssServiceGetCapabilities(
struct ChppAppHeader *requestHeader) {
enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
- struct ChppGnssGetCapabilitiesResponse *response =
- chppAllocServiceResponseFixed(requestHeader,
- struct ChppGnssGetCapabilitiesResponse);
+ struct ChppGnssGetCapabilitiesResponse *response = chppAllocResponseFixed(
+ requestHeader, struct ChppGnssGetCapabilitiesResponse);
size_t responseLen = sizeof(*response);
if (response == NULL) {
@@ -354,7 +353,7 @@ static enum ChppAppErrorCode chppGnssServiceGetCapabilities(
CHPP_LOGD("chppGnssServiceGetCapabilities returning 0x%" PRIx32
", %" PRIuSIZE " bytes",
response->params.capabilities, responseLen);
- chppSendTimestampedResponseOrFail(&gnssServiceContext->service,
+ chppSendTimestampedResponseOrFail(gnssServiceContext->service.appContext,
&gnssServiceContext->getCapabilities,
response, responseLen);
}
@@ -472,7 +471,7 @@ static enum ChppAppErrorCode chppGnssServiceConfigurePassiveLocationListener(
} else {
struct ChppAppHeader *response =
- chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
+ chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
size_t responseLen = sizeof(*response);
if (response == NULL) {
@@ -480,7 +479,7 @@ static enum ChppAppErrorCode chppGnssServiceConfigurePassiveLocationListener(
error = CHPP_APP_ERROR_OOM;
} else {
chppSendTimestampedResponseOrFail(
- &gnssServiceContext->service,
+ gnssServiceContext->service.appContext,
&gnssServiceContext->configurePassiveLocationListener, response,
responseLen);
}
@@ -527,8 +526,8 @@ static void chppGnssServiceLocationStatusChangeCallback(bool enabled,
};
struct ChppGnssControlLocationSessionResponse *response =
- chppAllocServiceResponseFixed(
- &requestHeader, struct ChppGnssControlLocationSessionResponse);
+ chppAllocResponseFixed(&requestHeader,
+ struct ChppGnssControlLocationSessionResponse);
size_t responseLen = sizeof(*response);
if (response == NULL) {
@@ -540,7 +539,7 @@ static void chppGnssServiceLocationStatusChangeCallback(bool enabled,
response->errorCode = errorCode;
chppSendTimestampedResponseOrFail(
- &gGnssServiceContext.service,
+ gGnssServiceContext.service.appContext,
&gGnssServiceContext.controlLocationSession, response, responseLen);
}
}
@@ -599,8 +598,8 @@ static void chppGnssServiceMeasurementStatusChangeCallback(bool enabled,
};
struct ChppGnssControlMeasurementSessionResponse *response =
- chppAllocServiceResponseFixed(
- &requestHeader, struct ChppGnssControlMeasurementSessionResponse);
+ chppAllocResponseFixed(&requestHeader,
+ struct ChppGnssControlMeasurementSessionResponse);
size_t responseLen = sizeof(*response);
if (response == NULL) {
@@ -612,7 +611,7 @@ static void chppGnssServiceMeasurementStatusChangeCallback(bool enabled,
response->errorCode = errorCode;
chppSendTimestampedResponseOrFail(
- &gGnssServiceContext.service,
+ gGnssServiceContext.service.appContext,
&gGnssServiceContext.controlMeasurementSession, response, responseLen);
}
}
@@ -670,7 +669,8 @@ void chppRegisterGnssService(struct ChppAppState *appContext) {
} else {
chppRegisterService(appContext, (void *)&gGnssServiceContext,
- &gGnssServiceContext.service, &kGnssServiceConfig);
+ &gGnssServiceContext.service, NULL /*outReqState*/,
+ &kGnssServiceConfig);
CHPP_DEBUG_ASSERT(gGnssServiceContext.service.handle);
}
}
diff --git a/chpp/services/timesync.c b/chpp/services/timesync.c
index c81187ab..b7ad6259 100644
--- a/chpp/services/timesync.c
+++ b/chpp/services/timesync.c
@@ -39,7 +39,7 @@
static void chppTimesyncGetTime(struct ChppAppState *context,
const struct ChppAppHeader *requestHeader) {
struct ChppTimesyncResponse *response =
- chppAllocServiceResponseFixed(requestHeader, struct ChppTimesyncResponse);
+ chppAllocResponseFixed(requestHeader, struct ChppTimesyncResponse);
size_t responseLen = sizeof(*response);
if (response == NULL) {
diff --git a/chpp/services/wifi.c b/chpp/services/wifi.c
index 966e77f9..090e599d 100644
--- a/chpp/services/wifi.c
+++ b/chpp/services/wifi.c
@@ -73,22 +73,22 @@ static const struct ChppService kWifiServiceConfig = {
* (RR) functionality.
*/
struct ChppWifiServiceState {
- struct ChppServiceState service; // WiFi service state
+ struct ChppEndpointState service; // CHPP service state
const struct chrePalWifiApi *api; // WiFi PAL API
// Based on chre/pal/wifi.h and chrePalWifiApi
- struct ChppRequestResponseState open; // Service init state
- struct ChppRequestResponseState close; // Service deinit state
- struct ChppRequestResponseState getCapabilities; // Get Capabilities state
- struct ChppRequestResponseState
+ struct ChppIncomingRequestState open; // Service init state
+ struct ChppIncomingRequestState close; // Service deinit state
+ struct ChppIncomingRequestState getCapabilities; // Get Capabilities state
+ struct ChppIncomingRequestState
configureScanMonitorAsync; // Configure scan monitor state
- struct ChppRequestResponseState requestScanAsync; // Request scan state
- struct ChppRequestResponseState requestRangingAsync; // Request ranging state
- struct ChppRequestResponseState
+ struct ChppIncomingRequestState requestScanAsync; // Request scan state
+ struct ChppIncomingRequestState requestRangingAsync; // Request ranging state
+ struct ChppIncomingRequestState
requestNanSubscribe; // Request Nan Subscription state
- struct ChppRequestResponseState
+ struct ChppIncomingRequestState
requestNanSubscribeCancel; // Request Nan Subscription cancelation state
- struct ChppRequestResponseState
+ struct ChppIncomingRequestState
requestNanRangingAsync; // Request NAN ranging state
};
@@ -174,75 +174,75 @@ static enum ChppAppErrorCode chppDispatchWifiRequest(void *serviceContext,
struct ChppWifiServiceState *wifiServiceContext =
(struct ChppWifiServiceState *)serviceContext;
- struct ChppRequestResponseState *rRState = NULL;
+ struct ChppIncomingRequestState *inReqState = NULL;
enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
bool dispatched = true;
switch (rxHeader->command) {
case CHPP_WIFI_OPEN: {
- rRState = &wifiServiceContext->open;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wifiServiceContext->open;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWifiServiceOpen(wifiServiceContext, rxHeader);
break;
}
case CHPP_WIFI_CLOSE: {
- rRState = &wifiServiceContext->close;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wifiServiceContext->close;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWifiServiceClose(wifiServiceContext, rxHeader);
break;
}
case CHPP_WIFI_GET_CAPABILITIES: {
- rRState = &wifiServiceContext->getCapabilities;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wifiServiceContext->getCapabilities;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWifiServiceGetCapabilities(wifiServiceContext, rxHeader);
break;
}
case CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC: {
- rRState = &wifiServiceContext->configureScanMonitorAsync;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wifiServiceContext->configureScanMonitorAsync;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWifiServiceConfigureScanMonitorAsync(wifiServiceContext,
rxHeader, buf, len);
break;
}
case CHPP_WIFI_REQUEST_SCAN_ASYNC: {
- rRState = &wifiServiceContext->requestScanAsync;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wifiServiceContext->requestScanAsync;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWifiServiceRequestScanAsync(wifiServiceContext, rxHeader, buf,
len);
break;
}
case CHPP_WIFI_REQUEST_RANGING_ASYNC: {
- rRState = &wifiServiceContext->requestRangingAsync;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wifiServiceContext->requestRangingAsync;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWifiServiceRequestRangingAsync(wifiServiceContext, rxHeader,
buf, len);
break;
}
case CHPP_WIFI_REQUEST_NAN_SUB: {
- rRState = &wifiServiceContext->requestNanSubscribe;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wifiServiceContext->requestNanSubscribe;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWifiServiceRequestNanSubscribe(wifiServiceContext, rxHeader,
buf, len);
break;
}
case CHPP_WIFI_REQUEST_NAN_SUB_CANCEL: {
- rRState = &wifiServiceContext->requestNanSubscribeCancel;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wifiServiceContext->requestNanSubscribeCancel;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWifiServiceRequestNanSubscribeCancel(wifiServiceContext,
rxHeader, buf, len);
break;
};
case CHPP_WIFI_REQUEST_NAN_RANGING_ASYNC: {
- rRState = &wifiServiceContext->requestNanRangingAsync;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wifiServiceContext->requestNanRangingAsync;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWifiServiceRequestNanRanging(wifiServiceContext, rxHeader,
buf, len);
break;
@@ -257,8 +257,8 @@ static enum ChppAppErrorCode chppDispatchWifiRequest(void *serviceContext,
if (dispatched == true && error != CHPP_APP_ERROR_NONE) {
// Request was dispatched but an error was returned. Close out
- // chppServiceTimestampRequest()
- chppServiceTimestampResponse(rRState);
+ // chppTimestampIncomingRequest()
+ chppTimestampOutgoingResponse(inReqState);
}
return error;
@@ -307,14 +307,14 @@ static enum ChppAppErrorCode chppWifiServiceOpen(
wifiServiceContext->service.openState = CHPP_OPEN_STATE_OPENED;
struct ChppAppHeader *response =
- chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
+ chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
size_t responseLen = sizeof(*response);
if (response == NULL) {
CHPP_LOG_OOM();
error = CHPP_APP_ERROR_OOM;
} else {
- chppSendTimestampedResponseOrFail(&wifiServiceContext->service,
+ chppSendTimestampedResponseOrFail(wifiServiceContext->service.appContext,
&wifiServiceContext->open, response,
responseLen);
}
@@ -342,14 +342,14 @@ static enum ChppAppErrorCode chppWifiServiceClose(
CHPP_LOGD("WiFi service closed");
struct ChppAppHeader *response =
- chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
+ chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
size_t responseLen = sizeof(*response);
if (response == NULL) {
CHPP_LOG_OOM();
error = CHPP_APP_ERROR_OOM;
} else {
- chppSendTimestampedResponseOrFail(&wifiServiceContext->service,
+ chppSendTimestampedResponseOrFail(wifiServiceContext->service.appContext,
&wifiServiceContext->close, response,
responseLen);
}
@@ -388,9 +388,8 @@ static enum ChppAppErrorCode chppWifiServiceGetCapabilities(
struct ChppAppHeader *requestHeader) {
enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
- struct ChppWifiGetCapabilitiesResponse *response =
- chppAllocServiceResponseFixed(requestHeader,
- struct ChppWifiGetCapabilitiesResponse);
+ struct ChppWifiGetCapabilitiesResponse *response = chppAllocResponseFixed(
+ requestHeader, struct ChppWifiGetCapabilitiesResponse);
size_t responseLen = sizeof(*response);
if (response == NULL) {
@@ -402,7 +401,7 @@ static enum ChppAppErrorCode chppWifiServiceGetCapabilities(
CHPP_LOGD("chppWifiServiceGetCapabilities returning 0x%" PRIx32
", %" PRIuSIZE " bytes",
response->params.capabilities, responseLen);
- chppSendTimestampedResponseOrFail(&wifiServiceContext->service,
+ chppSendTimestampedResponseOrFail(wifiServiceContext->service.appContext,
&wifiServiceContext->getCapabilities,
response, responseLen);
}
@@ -532,7 +531,7 @@ static enum ChppAppErrorCode chppWifiServiceRequestRangingAsync(
} else {
struct ChppAppHeader *response =
- chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
+ chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
size_t responseLen = sizeof(*response);
if (response == NULL) {
@@ -540,7 +539,7 @@ static enum ChppAppErrorCode chppWifiServiceRequestRangingAsync(
error = CHPP_APP_ERROR_OOM;
} else {
chppSendTimestampedResponseOrFail(
- &wifiServiceContext->service,
+ wifiServiceContext->service.appContext,
&wifiServiceContext->requestRangingAsync, response, responseLen);
}
}
@@ -575,7 +574,7 @@ static enum ChppAppErrorCode chppWifiServiceRequestNanSubscribe(
} else {
struct ChppAppHeader *response =
- chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
+ chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
size_t responseLen = sizeof(*response);
if (response == NULL) {
@@ -583,7 +582,7 @@ static enum ChppAppErrorCode chppWifiServiceRequestNanSubscribe(
error = CHPP_APP_ERROR_OOM;
} else {
chppSendTimestampedResponseOrFail(
- &wifiServiceContext->service,
+ wifiServiceContext->service.appContext,
&wifiServiceContext->requestNanSubscribe, response, responseLen);
}
}
@@ -610,7 +609,7 @@ static enum ChppAppErrorCode chppWifiServiceRequestNanSubscribeCancel(
} else {
struct ChppAppHeader *response =
- chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
+ chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
size_t responseLen = sizeof(*response);
if (response == NULL) {
@@ -618,7 +617,7 @@ static enum ChppAppErrorCode chppWifiServiceRequestNanSubscribeCancel(
error = CHPP_APP_ERROR_OOM;
} else {
chppSendTimestampedResponseOrFail(
- &wifiServiceContext->service,
+ wifiServiceContext->service.appContext,
&wifiServiceContext->requestNanSubscribeCancel, response,
responseLen);
}
@@ -647,7 +646,7 @@ static bool chppWifiServiceRequestNanRanging(
} else {
struct ChppAppHeader *response =
- chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
+ chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
size_t responseLen = sizeof(*response);
if (response == NULL) {
@@ -655,7 +654,7 @@ static bool chppWifiServiceRequestNanRanging(
error = CHPP_APP_ERROR_OOM;
} else {
chppSendTimestampedResponseOrFail(
- &wifiServiceContext->service,
+ wifiServiceContext->service.appContext,
&wifiServiceContext->requestNanRangingAsync, response, responseLen);
}
}
@@ -680,8 +679,8 @@ static void chppWifiServiceScanMonitorStatusChangeCallback(bool enabled,
};
struct ChppWifiConfigureScanMonitorAsyncResponse *response =
- chppAllocServiceResponseFixed(
- &requestHeader, struct ChppWifiConfigureScanMonitorAsyncResponse);
+ chppAllocResponseFixed(&requestHeader,
+ struct ChppWifiConfigureScanMonitorAsyncResponse);
size_t responseLen = sizeof(*response);
if (response == NULL) {
@@ -693,7 +692,7 @@ static void chppWifiServiceScanMonitorStatusChangeCallback(bool enabled,
response->params.errorCode = errorCode;
chppSendTimestampedResponseOrFail(
- &gWifiServiceContext.service,
+ gWifiServiceContext.service.appContext,
&gWifiServiceContext.configureScanMonitorAsync, response, responseLen);
}
}
@@ -713,7 +712,7 @@ static void chppWifiServiceScanResponseCallback(bool pending,
.command = CHPP_WIFI_REQUEST_SCAN_ASYNC,
};
- struct ChppWifiRequestScanResponse *response = chppAllocServiceResponseFixed(
+ struct ChppWifiRequestScanResponse *response = chppAllocResponseFixed(
&requestHeader, struct ChppWifiRequestScanResponse);
size_t responseLen = sizeof(*response);
@@ -725,7 +724,7 @@ static void chppWifiServiceScanResponseCallback(bool pending,
response->params.pending = pending;
response->params.errorCode = errorCode;
- chppSendTimestampedResponseOrFail(&gWifiServiceContext.service,
+ chppSendTimestampedResponseOrFail(gWifiServiceContext.service.appContext,
&gWifiServiceContext.requestScanAsync,
response, responseLen);
}
@@ -1020,7 +1019,8 @@ void chppRegisterWifiService(struct ChppAppState *appContext) {
} else {
chppRegisterService(appContext, (void *)&gWifiServiceContext,
- &gWifiServiceContext.service, &kWifiServiceConfig);
+ &gWifiServiceContext.service, NULL /*outReqStates*/,
+ &kWifiServiceConfig);
CHPP_DEBUG_ASSERT(gWifiServiceContext.service.handle);
}
}
diff --git a/chpp/services/wwan.c b/chpp/services/wwan.c
index bd284039..7f173c82 100644
--- a/chpp/services/wwan.c
+++ b/chpp/services/wwan.c
@@ -74,13 +74,13 @@ static const struct ChppService kWwanServiceConfig = {
* (RR) functionality.
*/
struct ChppWwanServiceState {
- struct ChppServiceState service; // WWAN service state
+ struct ChppEndpointState service; // CHPP service state
const struct chrePalWwanApi *api; // WWAN PAL API
- struct ChppRequestResponseState open; // Service init state
- struct ChppRequestResponseState close; // Service deinit state
- struct ChppRequestResponseState getCapabilities; // Get Capabilities state
- struct ChppRequestResponseState getCellInfoAsync; // Get CellInfo Async state
+ struct ChppIncomingRequestState open; // Service init state
+ struct ChppIncomingRequestState close; // Service deinit state
+ struct ChppIncomingRequestState getCapabilities; // Get Capabilities state
+ struct ChppIncomingRequestState getCellInfoAsync; // Get CellInfo Async state
};
// Note: This global definition of gWwanServiceContext supports only one
@@ -138,7 +138,7 @@ static enum ChppAppErrorCode chppDispatchWwanRequest(void *serviceContext,
struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
struct ChppWwanServiceState *wwanServiceContext =
(struct ChppWwanServiceState *)serviceContext;
- struct ChppRequestResponseState *rRState = NULL;
+ struct ChppIncomingRequestState *inReqState = NULL;
enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
bool dispatched = true;
@@ -146,29 +146,29 @@ static enum ChppAppErrorCode chppDispatchWwanRequest(void *serviceContext,
switch (rxHeader->command) {
case CHPP_WWAN_OPEN: {
- rRState = &wwanServiceContext->open;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wwanServiceContext->open;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWwanServiceOpen(wwanServiceContext, rxHeader);
break;
}
case CHPP_WWAN_CLOSE: {
- rRState = &wwanServiceContext->close;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wwanServiceContext->close;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWwanServiceClose(wwanServiceContext, rxHeader);
break;
}
case CHPP_WWAN_GET_CAPABILITIES: {
- rRState = &wwanServiceContext->getCapabilities;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wwanServiceContext->getCapabilities;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWwanServiceGetCapabilities(wwanServiceContext, rxHeader);
break;
}
case CHPP_WWAN_GET_CELLINFO_ASYNC: {
- rRState = &wwanServiceContext->getCellInfoAsync;
- chppServiceTimestampRequest(rRState, rxHeader);
+ inReqState = &wwanServiceContext->getCellInfoAsync;
+ chppTimestampIncomingRequest(inReqState, rxHeader);
error = chppWwanServiceGetCellInfoAsync(wwanServiceContext, rxHeader);
break;
}
@@ -182,8 +182,8 @@ static enum ChppAppErrorCode chppDispatchWwanRequest(void *serviceContext,
if (dispatched == true && error != CHPP_APP_ERROR_NONE) {
// Request was dispatched but an error was returned. Close out
- // chppServiceTimestampRequest()
- chppServiceTimestampResponse(rRState);
+ // chppTimestampIncomingRequest()
+ chppTimestampOutgoingResponse(inReqState);
}
return error;
@@ -222,14 +222,14 @@ static enum ChppAppErrorCode chppWwanServiceOpen(
wwanServiceContext->service.openState = CHPP_OPEN_STATE_OPENED;
struct ChppAppHeader *response =
- chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
+ chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
size_t responseLen = sizeof(*response);
if (response == NULL) {
CHPP_LOG_OOM();
error = CHPP_APP_ERROR_OOM;
} else {
- chppSendTimestampedResponseOrFail(&wwanServiceContext->service,
+ chppSendTimestampedResponseOrFail(wwanServiceContext->service.appContext,
&wwanServiceContext->open, response,
responseLen);
}
@@ -257,14 +257,14 @@ static enum ChppAppErrorCode chppWwanServiceClose(
CHPP_LOGD("WWAN service closed");
struct ChppAppHeader *response =
- chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader);
+ chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
size_t responseLen = sizeof(*response);
if (response == NULL) {
CHPP_LOG_OOM();
error = CHPP_APP_ERROR_OOM;
} else {
- chppSendTimestampedResponseOrFail(&wwanServiceContext->service,
+ chppSendTimestampedResponseOrFail(wwanServiceContext->service.appContext,
&wwanServiceContext->close, response,
responseLen);
}
@@ -304,9 +304,8 @@ static enum ChppAppErrorCode chppWwanServiceGetCapabilities(
struct ChppAppHeader *requestHeader) {
enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
- struct ChppWwanGetCapabilitiesResponse *response =
- chppAllocServiceResponseFixed(requestHeader,
- struct ChppWwanGetCapabilitiesResponse);
+ struct ChppWwanGetCapabilitiesResponse *response = chppAllocResponseFixed(
+ requestHeader, struct ChppWwanGetCapabilitiesResponse);
size_t responseLen = sizeof(*response);
if (response == NULL) {
@@ -318,7 +317,7 @@ static enum ChppAppErrorCode chppWwanServiceGetCapabilities(
CHPP_LOGD("chppWwanServiceGetCapabilities returning 0x%" PRIx32
", %" PRIuSIZE " bytes",
response->params.capabilities, responseLen);
- chppSendTimestampedResponseOrFail(&wwanServiceContext->service,
+ chppSendTimestampedResponseOrFail(wwanServiceContext->service.appContext,
&wwanServiceContext->getCapabilities,
response, responseLen);
}
@@ -366,17 +365,17 @@ static enum ChppAppErrorCode chppWwanServiceGetCellInfoAsync(
static void chppWwanServiceCellInfoResultCallback(
struct chreWwanCellInfoResult *result) {
// Recover state
- struct ChppRequestResponseState *rRState =
+ struct ChppIncomingRequestState *inReqState =
&gWwanServiceContext.getCellInfoAsync;
struct ChppWwanServiceState *wwanServiceContext =
- container_of(rRState, struct ChppWwanServiceState, getCellInfoAsync);
+ container_of(inReqState, struct ChppWwanServiceState, getCellInfoAsync);
// Craft response per parser script
struct ChppWwanCellInfoResultWithHeader *response = NULL;
size_t responseLen = 0;
if (!chppWwanCellInfoResultFromChre(result, &response, &responseLen)) {
CHPP_LOGE("CellInfo conversion failed (OOM?) ID=%" PRIu8,
- rRState->transaction);
+ inReqState->transaction);
response = chppMalloc(sizeof(struct ChppAppHeader));
if (response == NULL) {
@@ -389,14 +388,14 @@ static void chppWwanServiceCellInfoResultCallback(
if (response != NULL) {
response->header.handle = wwanServiceContext->service.handle;
response->header.type = CHPP_MESSAGE_TYPE_SERVICE_RESPONSE;
- response->header.transaction = rRState->transaction;
+ response->header.transaction = inReqState->transaction;
response->header.error = (responseLen > sizeof(struct ChppAppHeader))
? CHPP_APP_ERROR_NONE
: CHPP_APP_ERROR_CONVERSION_FAILED;
response->header.command = CHPP_WWAN_GET_CELLINFO_ASYNC;
- chppSendTimestampedResponseOrFail(&wwanServiceContext->service, rRState,
- response, responseLen);
+ chppSendTimestampedResponseOrFail(wwanServiceContext->service.appContext,
+ inReqState, response, responseLen);
}
gWwanServiceContext.api->releaseCellInfoResult(result);
@@ -415,7 +414,8 @@ void chppRegisterWwanService(struct ChppAppState *appContext) {
} else {
chppRegisterService(appContext, (void *)&gWwanServiceContext,
- &gWwanServiceContext.service, &kWwanServiceConfig);
+ &gWwanServiceContext.service, NULL /*outReqStates*/,
+ &kWwanServiceConfig);
CHPP_DEBUG_ASSERT(gWwanServiceContext.service.handle);
}
}
diff --git a/chpp/test/app_discovery_test.cpp b/chpp/test/app_discovery_test.cpp
new file mode 100644
index 00000000..51ab800c
--- /dev/null
+++ b/chpp/test/app_discovery_test.cpp
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <cstring>
+#include <thread>
+
+#include "chpp/app.h"
+#include "chpp/clients.h"
+#include "chpp/clients/discovery.h"
+#include "chpp/macros.h"
+#include "chpp/platform/platform_link.h"
+#include "chpp/platform/utils.h"
+#include "chpp/services.h"
+#include "chpp/transport.h"
+
+namespace chre {
+
+namespace {
+
+constexpr uint64_t kResetWaitTimeMs = 5000;
+constexpr uint64_t kDiscoveryWaitTimeMs = 5000;
+
+void *workThread(void *transportState) {
+ ChppTransportState *state = static_cast<ChppTransportState *>(transportState);
+
+ auto linkContext =
+ static_cast<struct ChppLinuxLinkState *>(state->linkContext);
+
+ pthread_setname_np(pthread_self(), linkContext->workThreadName);
+
+ chppWorkThreadStart(state);
+
+ return nullptr;
+}
+
+#define TEST_UUID \
+ { \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x12 \
+ }
+
+constexpr uint16_t kNumCommands = 1;
+
+struct ClientState {
+ struct ChppEndpointState chppClientState;
+ struct ChppOutgoingRequestState outReqStates[kNumCommands];
+ bool resetNotified;
+ bool matchNotified;
+};
+
+void clientNotifyReset(void *clientState);
+void clientNotifyMatch(void *clientState);
+bool clientInit(void *clientState, uint8_t handle,
+ struct ChppVersion serviceVersion);
+void clientDeinit(void *clientState);
+
+constexpr struct ChppClient kClient = {
+ .descriptor.uuid = TEST_UUID,
+ .descriptor.version.major = 1,
+ .descriptor.version.minor = 0,
+ .descriptor.version.patch = 0,
+ .resetNotifierFunctionPtr = &clientNotifyReset,
+ .matchNotifierFunctionPtr = &clientNotifyMatch,
+ .responseDispatchFunctionPtr = nullptr,
+ .notificationDispatchFunctionPtr = nullptr,
+ .initFunctionPtr = &clientInit,
+ .deinitFunctionPtr = &clientDeinit,
+ .outReqCount = kNumCommands,
+ .minLength = sizeof(struct ChppAppHeader),
+};
+
+void clientNotifyReset(void *clientState) {
+ auto state = static_cast<struct ClientState *>(clientState);
+ state->resetNotified = true;
+}
+
+void clientNotifyMatch(void *clientState) {
+ auto state = static_cast<struct ClientState *>(clientState);
+ state->matchNotified = true;
+}
+
+bool clientInit(void *clientState, uint8_t handle,
+ struct ChppVersion serviceVersion) {
+ UNUSED_VAR(serviceVersion);
+ auto state = static_cast<struct ClientState *>(clientState);
+ state->chppClientState.openState = CHPP_OPEN_STATE_OPENED;
+ chppClientInit(&state->chppClientState, handle);
+ return true;
+}
+
+void clientDeinit(void *clientState) {
+ auto state = static_cast<struct ClientState *>(clientState);
+ chppClientDeinit(&state->chppClientState);
+ state->chppClientState.openState = CHPP_OPEN_STATE_CLOSED;
+}
+
+// Service
+struct ServiceState {
+ struct ChppEndpointState chppServiceState;
+ struct ChppIncomingRequestState inReqStates[kNumCommands];
+ bool resetNotified;
+};
+
+void serviceNotifyReset(void *serviceState) {
+ auto state = static_cast<struct ServiceState *>(serviceState);
+ state->resetNotified = true;
+}
+
+const struct ChppService kService = {
+ .descriptor.uuid = TEST_UUID,
+ .descriptor.name = "Test",
+ .descriptor.version.major = 1,
+ .descriptor.version.minor = 0,
+ .descriptor.version.patch = 0,
+ .resetNotifierFunctionPtr = &serviceNotifyReset,
+ .requestDispatchFunctionPtr = nullptr,
+ .notificationDispatchFunctionPtr = nullptr,
+ .minLength = sizeof(struct ChppAppHeader),
+};
+
+// Test Clients/Services discovery and matching.
+class AppDiscoveryTest : public testing::Test {
+ protected:
+ void SetUp() {
+ chppClearTotalAllocBytes();
+ memset(&mClientLinkContext, 0, sizeof(mClientLinkContext));
+ memset(&mServiceLinkContext, 0, sizeof(mServiceLinkContext));
+
+ mServiceLinkContext.linkThreadName = "Host Link";
+ mServiceLinkContext.workThreadName = "Host worker";
+ mServiceLinkContext.isLinkActive = true;
+ mServiceLinkContext.remoteLinkState = &mClientLinkContext;
+ mServiceLinkContext.rxInRemoteEndpointWorker = false;
+
+ mClientLinkContext.linkThreadName = "CHRE Link";
+ mClientLinkContext.workThreadName = "CHRE worker";
+ mClientLinkContext.isLinkActive = true;
+ mClientLinkContext.remoteLinkState = &mServiceLinkContext;
+ mClientLinkContext.rxInRemoteEndpointWorker = false;
+
+ // No default clients/services.
+ struct ChppClientServiceSet set;
+ memset(&set, 0, sizeof(set));
+
+ const struct ChppLinkApi *linkApi = getLinuxLinkApi();
+
+ // Init client side.
+ chppTransportInit(&mClientTransportContext, &mClientAppContext,
+ &mClientLinkContext, linkApi);
+ chppAppInitWithClientServiceSet(&mClientAppContext,
+ &mClientTransportContext, set);
+
+ // Init service side.
+ chppTransportInit(&mServiceTransportContext, &mServiceAppContext,
+ &mServiceLinkContext, linkApi);
+ chppAppInitWithClientServiceSet(&mServiceAppContext,
+ &mServiceTransportContext, set);
+ }
+
+ void TearDown() {
+ chppWorkThreadStop(&mClientTransportContext);
+ chppWorkThreadStop(&mServiceTransportContext);
+ pthread_join(mClientWorkThread, NULL);
+ pthread_join(mServiceWorkThread, NULL);
+
+ // Deinit client side.
+ chppAppDeinit(&mClientAppContext);
+ chppTransportDeinit(&mClientTransportContext);
+
+ // Deinit service side.
+ chppAppDeinit(&mServiceAppContext);
+ chppTransportDeinit(&mServiceTransportContext);
+
+ EXPECT_EQ(chppGetTotalAllocBytes(), 0);
+ }
+
+ // Client side.
+ ChppLinuxLinkState mClientLinkContext = {};
+ ChppTransportState mClientTransportContext = {};
+ ChppAppState mClientAppContext = {};
+ pthread_t mClientWorkThread;
+ ClientState mClientState;
+
+ // Service side
+ ChppLinuxLinkState mServiceLinkContext = {};
+ ChppTransportState mServiceTransportContext = {};
+ ChppAppState mServiceAppContext = {};
+ pthread_t mServiceWorkThread;
+ ServiceState mServiceState;
+};
+
+TEST_F(AppDiscoveryTest, workWhenThereIsNoService) {
+ // Register the client
+ memset(&mClientState, 0, sizeof(mClientState));
+ chppRegisterClient(&mClientAppContext, &mClientState,
+ &mClientState.chppClientState,
+ &mClientState.outReqStates[0], &kClient);
+
+ pthread_create(&mClientWorkThread, NULL, workThread,
+ &mClientTransportContext);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(450));
+
+ // Start the service thread (no service registered).
+ pthread_create(&mServiceWorkThread, NULL, workThread,
+ &mServiceTransportContext);
+
+ mClientLinkContext.linkEstablished = true;
+ mServiceLinkContext.linkEstablished = true;
+
+ EXPECT_TRUE(chppTransportWaitForResetComplete(&mClientTransportContext,
+ kResetWaitTimeMs));
+ EXPECT_TRUE(chppTransportWaitForResetComplete(&mServiceTransportContext,
+ kResetWaitTimeMs));
+
+ EXPECT_TRUE(
+ chppWaitForDiscoveryComplete(&mClientAppContext, kDiscoveryWaitTimeMs));
+ EXPECT_TRUE(
+ chppWaitForDiscoveryComplete(&mServiceAppContext, kDiscoveryWaitTimeMs));
+
+ EXPECT_FALSE(mClientState.resetNotified);
+ EXPECT_FALSE(mClientState.matchNotified);
+ EXPECT_EQ(mClientAppContext.discoveredServiceCount, 0);
+ EXPECT_EQ(mClientAppContext.matchedClientCount, 0);
+ EXPECT_EQ(mServiceAppContext.discoveredServiceCount, 0);
+ EXPECT_EQ(mServiceAppContext.matchedClientCount, 0);
+}
+
+TEST_F(AppDiscoveryTest, servicesShouldBeDiscovered) {
+ // Start the client thread (no client registered).
+ pthread_create(&mClientWorkThread, NULL, workThread,
+ &mClientTransportContext);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(450));
+
+ // Register the service
+ memset(&mServiceState, 0, sizeof(mServiceState));
+ chppRegisterService(&mServiceAppContext, &mServiceState,
+ &mServiceState.chppServiceState, NULL /*outReqStates*/,
+ &kService);
+
+ pthread_create(&mServiceWorkThread, NULL, workThread,
+ &mServiceTransportContext);
+
+ mClientLinkContext.linkEstablished = true;
+ mServiceLinkContext.linkEstablished = true;
+
+ EXPECT_TRUE(chppTransportWaitForResetComplete(&mClientTransportContext,
+ kResetWaitTimeMs));
+ EXPECT_TRUE(chppTransportWaitForResetComplete(&mServiceTransportContext,
+ kResetWaitTimeMs));
+
+ EXPECT_TRUE(
+ chppWaitForDiscoveryComplete(&mClientAppContext, kDiscoveryWaitTimeMs));
+ EXPECT_TRUE(
+ chppWaitForDiscoveryComplete(&mServiceAppContext, kDiscoveryWaitTimeMs));
+
+ EXPECT_FALSE(mClientState.resetNotified);
+ EXPECT_TRUE(mServiceState.resetNotified);
+ EXPECT_FALSE(mClientState.matchNotified);
+ EXPECT_EQ(mClientAppContext.discoveredServiceCount, 1);
+ EXPECT_EQ(mClientAppContext.matchedClientCount, 0);
+ EXPECT_EQ(mServiceAppContext.discoveredServiceCount, 0);
+ EXPECT_EQ(mServiceAppContext.matchedClientCount, 0);
+}
+
+TEST_F(AppDiscoveryTest, discoveredServiceShouldBeMatchedWithClients) {
+ // Register the client
+ memset(&mClientState, 0, sizeof(mClientState));
+ chppRegisterClient(&mClientAppContext, &mClientState,
+ &mClientState.chppClientState,
+ &mClientState.outReqStates[0], &kClient);
+
+ pthread_create(&mClientWorkThread, NULL, workThread,
+ &mClientTransportContext);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(450));
+
+ // Register the service
+ memset(&mServiceState, 0, sizeof(mServiceState));
+ chppRegisterService(&mServiceAppContext, &mServiceState,
+ &mServiceState.chppServiceState, NULL /*outReqStates*/,
+ &kService);
+
+ pthread_create(&mServiceWorkThread, NULL, workThread,
+ &mServiceTransportContext);
+
+ mClientLinkContext.linkEstablished = true;
+ mServiceLinkContext.linkEstablished = true;
+
+ EXPECT_TRUE(chppTransportWaitForResetComplete(&mClientTransportContext,
+ kResetWaitTimeMs));
+ EXPECT_TRUE(chppTransportWaitForResetComplete(&mServiceTransportContext,
+ kResetWaitTimeMs));
+
+ EXPECT_TRUE(
+ chppWaitForDiscoveryComplete(&mClientAppContext, kDiscoveryWaitTimeMs));
+ EXPECT_TRUE(
+ chppWaitForDiscoveryComplete(&mServiceAppContext, kDiscoveryWaitTimeMs));
+
+ EXPECT_FALSE(mClientState.resetNotified);
+ EXPECT_TRUE(mServiceState.resetNotified);
+ EXPECT_TRUE(mClientState.matchNotified);
+ EXPECT_EQ(mClientAppContext.discoveredServiceCount, 1);
+ EXPECT_EQ(mClientAppContext.matchedClientCount, 1);
+ EXPECT_TRUE(mClientState.chppClientState.initialized);
+ EXPECT_EQ(mServiceAppContext.discoveredServiceCount, 0);
+ EXPECT_EQ(mServiceAppContext.matchedClientCount, 0);
+}
+
+} // namespace
+
+} // namespace chre \ No newline at end of file
diff --git a/chpp/test/app_notification_test.cpp b/chpp/test/app_notification_test.cpp
new file mode 100644
index 00000000..6f1f557d
--- /dev/null
+++ b/chpp/test/app_notification_test.cpp
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <cstring>
+#include <thread>
+
+#include "chpp/app.h"
+#include "chpp/clients.h"
+#include "chpp/clients/discovery.h"
+#include "chpp/macros.h"
+#include "chpp/notifier.h"
+#include "chpp/platform/platform_link.h"
+#include "chpp/platform/utils.h"
+#include "chpp/services.h"
+#include "chpp/transport.h"
+#include "chre/util/enum.h"
+#include "chre/util/time.h"
+
+namespace chre {
+
+namespace {
+
+constexpr uint64_t kResetWaitTimeMs = 5000;
+constexpr uint64_t kDiscoveryWaitTimeMs = 5000;
+
+void *workThread(void *transportState) {
+ ChppTransportState *state = static_cast<ChppTransportState *>(transportState);
+
+ auto linkContext =
+ static_cast<struct ChppLinuxLinkState *>(state->linkContext);
+
+ pthread_setname_np(pthread_self(), linkContext->workThreadName);
+
+ chppWorkThreadStart(state);
+
+ return nullptr;
+}
+
+#define TEST_UUID \
+ { \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x12 \
+ }
+
+enum class Commands : uint16_t {
+ kServiceNotification,
+ kClientNotification,
+};
+
+constexpr uint16_t kNumCommands = 1;
+
+struct ClientState {
+ struct ChppEndpointState chppClientState;
+ struct ChppOutgoingRequestState outReqStates[kNumCommands];
+ bool serviceNotificationStatus;
+ struct ChppNotifier notifier;
+};
+
+bool clientInit(void *clientState, uint8_t handle,
+ struct ChppVersion serviceVersion);
+void clientDeinit(void *clientState);
+enum ChppAppErrorCode clientDispatchNotification(void *clientState,
+ uint8_t *buf, size_t len);
+constexpr struct ChppClient kClient = {
+ .descriptor.uuid = TEST_UUID,
+ .descriptor.version.major = 1,
+ .descriptor.version.minor = 0,
+ .descriptor.version.patch = 0,
+ .resetNotifierFunctionPtr = nullptr,
+ .matchNotifierFunctionPtr = nullptr,
+ .responseDispatchFunctionPtr = nullptr,
+ .notificationDispatchFunctionPtr = &clientDispatchNotification,
+ .initFunctionPtr = &clientInit,
+ .deinitFunctionPtr = &clientDeinit,
+ .outReqCount = kNumCommands,
+ .minLength = sizeof(struct ChppAppHeader),
+};
+
+// Called when a notification from a service is received.
+enum ChppAppErrorCode clientDispatchNotification(void *clientState,
+ uint8_t *buf, size_t len) {
+ auto state = static_cast<struct ClientState *>(clientState);
+
+ // The response is composed of the app header only.
+ if (len != sizeof(ChppAppHeader)) {
+ return CHPP_APP_ERROR_NONE;
+ }
+
+ auto notification = reinterpret_cast<struct ChppAppHeader *>(buf);
+
+ switch (notification->command) {
+ case asBaseType(Commands::kServiceNotification):
+ state->serviceNotificationStatus =
+ notification->error == CHPP_APP_ERROR_NONE;
+ chppNotifierSignal(&state->notifier, 1 /*signal*/);
+ return CHPP_APP_ERROR_NONE;
+
+ default:
+ return CHPP_APP_ERROR_NONE;
+ }
+}
+
+bool clientInit(void *clientState, uint8_t handle,
+ struct ChppVersion serviceVersion) {
+ UNUSED_VAR(serviceVersion);
+ auto state = static_cast<struct ClientState *>(clientState);
+ state->chppClientState.openState = CHPP_OPEN_STATE_OPENED;
+ chppClientInit(&state->chppClientState, handle);
+ return true;
+}
+
+void clientDeinit(void *clientState) {
+ auto state = static_cast<struct ClientState *>(clientState);
+ chppClientDeinit(&state->chppClientState);
+ state->chppClientState.openState = CHPP_OPEN_STATE_CLOSED;
+}
+
+// Service
+struct ServiceState {
+ struct ChppEndpointState chppServiceState;
+ struct ChppIncomingRequestState inReqStates[kNumCommands];
+ bool clientNotificationStatus;
+ struct ChppNotifier notifier;
+};
+
+// Called when a notification from a client is received.
+enum ChppAppErrorCode serviceDispatchNotification(void *serviceState,
+ uint8_t *buf, size_t len) {
+ auto state = static_cast<struct ServiceState *>(serviceState);
+
+ // The response is composed of the app header only.
+ if (len != sizeof(ChppAppHeader)) {
+ return CHPP_APP_ERROR_NONE;
+ }
+
+ auto notification = reinterpret_cast<struct ChppAppHeader *>(buf);
+
+ switch (notification->command) {
+ case asBaseType(Commands::kClientNotification):
+ state->clientNotificationStatus =
+ notification->error == CHPP_APP_ERROR_NONE;
+ chppNotifierSignal(&state->notifier, 1 /*signal*/);
+ return CHPP_APP_ERROR_NONE;
+
+ default:
+ return CHPP_APP_ERROR_NONE;
+ }
+}
+
+const struct ChppService kService = {
+ .descriptor.uuid = TEST_UUID,
+ .descriptor.name = "Test",
+ .descriptor.version.major = 1,
+ .descriptor.version.minor = 0,
+ .descriptor.version.patch = 0,
+ .resetNotifierFunctionPtr = nullptr,
+ .requestDispatchFunctionPtr = nullptr,
+ .notificationDispatchFunctionPtr = &serviceDispatchNotification,
+ .minLength = sizeof(struct ChppAppHeader),
+};
+
+// Test notifications.
+class AppNotificationTest : public testing::Test {
+ protected:
+ void SetUp() {
+ chppClearTotalAllocBytes();
+ chppNotifierInit(&mClientState.notifier);
+ chppNotifierInit(&mServiceState.notifier);
+ memset(&mClientLinkContext, 0, sizeof(mClientLinkContext));
+ memset(&mServiceLinkContext, 0, sizeof(mServiceLinkContext));
+
+ mServiceLinkContext.linkThreadName = "Host Link";
+ mServiceLinkContext.workThreadName = "Host worker";
+ mServiceLinkContext.isLinkActive = true;
+ mServiceLinkContext.remoteLinkState = &mClientLinkContext;
+ mServiceLinkContext.rxInRemoteEndpointWorker = false;
+
+ mClientLinkContext.linkThreadName = "CHRE Link";
+ mClientLinkContext.workThreadName = "CHRE worker";
+ mClientLinkContext.isLinkActive = true;
+ mClientLinkContext.remoteLinkState = &mServiceLinkContext;
+ mClientLinkContext.rxInRemoteEndpointWorker = false;
+
+ // No default clients/services.
+ struct ChppClientServiceSet set;
+ memset(&set, 0, sizeof(set));
+
+ const struct ChppLinkApi *linkApi = getLinuxLinkApi();
+
+ // Init client side.
+ chppTransportInit(&mClientTransportContext, &mClientAppContext,
+ &mClientLinkContext, linkApi);
+ chppAppInitWithClientServiceSet(&mClientAppContext,
+ &mClientTransportContext, set);
+
+ // Init service side.
+ chppTransportInit(&mServiceTransportContext, &mServiceAppContext,
+ &mServiceLinkContext, linkApi);
+ chppAppInitWithClientServiceSet(&mServiceAppContext,
+ &mServiceTransportContext, set);
+
+ BringUpClient();
+ std::this_thread::sleep_for(std::chrono::milliseconds(450));
+ BringUpService();
+ mClientLinkContext.linkEstablished = true;
+ mServiceLinkContext.linkEstablished = true;
+
+ EXPECT_TRUE(chppTransportWaitForResetComplete(&mClientTransportContext,
+ kResetWaitTimeMs));
+ EXPECT_TRUE(chppTransportWaitForResetComplete(&mServiceTransportContext,
+ kResetWaitTimeMs));
+ EXPECT_TRUE(
+ chppWaitForDiscoveryComplete(&mClientAppContext, kDiscoveryWaitTimeMs));
+ EXPECT_TRUE(chppWaitForDiscoveryComplete(&mServiceAppContext,
+ kDiscoveryWaitTimeMs));
+ }
+
+ void BringUpClient() {
+ memset(&mClientState, 0, sizeof(mClientState));
+ chppRegisterClient(&mClientAppContext, &mClientState,
+ &mClientState.chppClientState,
+ &mClientState.outReqStates[0], &kClient);
+
+ pthread_create(&mClientWorkThread, NULL, workThread,
+ &mClientTransportContext);
+ }
+
+ void BringUpService() {
+ memset(&mServiceState, 0, sizeof(mServiceState));
+ chppRegisterService(&mServiceAppContext, &mServiceState,
+ &mServiceState.chppServiceState, NULL /*outReqStates*/,
+ &kService);
+
+ pthread_create(&mServiceWorkThread, NULL, workThread,
+ &mServiceTransportContext);
+ }
+
+ void TearDown() {
+ chppNotifierDeinit(&mClientState.notifier);
+ chppNotifierDeinit(&mServiceState.notifier);
+ chppWorkThreadStop(&mClientTransportContext);
+ chppWorkThreadStop(&mServiceTransportContext);
+ pthread_join(mClientWorkThread, NULL);
+ pthread_join(mServiceWorkThread, NULL);
+
+ // Deinit client side.
+ chppAppDeinit(&mClientAppContext);
+ chppTransportDeinit(&mClientTransportContext);
+
+ // Deinit service side.
+ chppAppDeinit(&mServiceAppContext);
+ chppTransportDeinit(&mServiceTransportContext);
+
+ EXPECT_EQ(chppGetTotalAllocBytes(), 0);
+ }
+
+ // Client side.
+ ChppLinuxLinkState mClientLinkContext = {};
+ ChppTransportState mClientTransportContext = {};
+ ChppAppState mClientAppContext = {};
+ pthread_t mClientWorkThread;
+ ClientState mClientState;
+
+ // Service side
+ ChppLinuxLinkState mServiceLinkContext = {};
+ ChppTransportState mServiceTransportContext = {};
+ ChppAppState mServiceAppContext = {};
+ pthread_t mServiceWorkThread;
+ ServiceState mServiceState;
+};
+
+TEST_F(AppNotificationTest, serviceSendANotificationToClient) {
+ // Send a notification.
+ constexpr size_t notificationLen = sizeof(struct ChppAppHeader);
+
+ struct ChppAppHeader *notification =
+ chppAllocServiceNotification(notificationLen);
+ ASSERT_NE(notification, nullptr);
+ notification->command = asBaseType(Commands::kServiceNotification);
+ notification->handle = mServiceState.chppServiceState.handle;
+
+ mClientState.serviceNotificationStatus = false;
+
+ EXPECT_TRUE(chppEnqueueTxDatagramOrFail(&mServiceTransportContext,
+ notification, notificationLen));
+
+ chppNotifierWait(&mClientState.notifier);
+
+ EXPECT_TRUE(mClientState.serviceNotificationStatus);
+}
+
+TEST_F(AppNotificationTest, clientSendANotificationToService) {
+ // Send a notification.
+ constexpr size_t notificationLen = sizeof(struct ChppAppHeader);
+
+ struct ChppAppHeader *notification =
+ chppAllocClientNotification(notificationLen);
+ ASSERT_NE(notification, nullptr);
+ notification->command = asBaseType(Commands::kClientNotification);
+ notification->handle = mClientState.chppClientState.handle;
+
+ mServiceState.clientNotificationStatus = false;
+
+ EXPECT_TRUE(chppEnqueueTxDatagramOrFail(&mClientTransportContext,
+ notification, notificationLen));
+
+ chppNotifierWait(&mServiceState.notifier);
+
+ EXPECT_TRUE(mServiceState.clientNotificationStatus);
+}
+
+} // namespace
+
+} // namespace chre \ No newline at end of file
diff --git a/chpp/test/app_req_resp_test.cpp b/chpp/test/app_req_resp_test.cpp
new file mode 100644
index 00000000..0bcf0578
--- /dev/null
+++ b/chpp/test/app_req_resp_test.cpp
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <cstring>
+#include <thread>
+
+#include "chpp/app.h"
+#include "chpp/clients.h"
+#include "chpp/clients/discovery.h"
+#include "chpp/macros.h"
+#include "chpp/notifier.h"
+#include "chpp/platform/platform_link.h"
+#include "chpp/platform/utils.h"
+#include "chpp/services.h"
+#include "chpp/transport.h"
+#include "chre/util/enum.h"
+#include "chre/util/time.h"
+
+namespace chre {
+namespace {
+
+constexpr uint64_t kResetWaitTimeMs = 5000;
+constexpr uint64_t kDiscoveryWaitTimeMs = 5000;
+
+void *workThread(void *transportState) {
+ ChppTransportState *state = static_cast<ChppTransportState *>(transportState);
+
+ auto linkContext =
+ static_cast<struct ChppLinuxLinkState *>(state->linkContext);
+
+ pthread_setname_np(pthread_self(), linkContext->workThreadName);
+
+ chppWorkThreadStart(state);
+
+ return nullptr;
+}
+
+#define TEST_UUID \
+ { \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x12 \
+ }
+
+enum class Commands : uint16_t {
+ kOk,
+ kError,
+ kTimeout,
+ // Number of request, must stay last
+ kNumCommands,
+};
+
+constexpr uint16_t kNumCommands = asBaseType(Commands::kNumCommands);
+
+// Common code for the client and the service.
+
+struct CommonState {
+ bool okResponseStatus;
+ bool errorResponseStatus;
+ bool timeoutResponseStatus;
+ struct ChppNotifier notifier;
+};
+
+enum ChppAppErrorCode dispatchResponse(
+ struct ChppAppState *appState,
+ struct ChppOutgoingRequestState *outReqStates, struct CommonState *common,
+ struct ChppAppHeader *response, size_t len) {
+ // The response is composed of the app header only.
+ if (len != sizeof(ChppAppHeader)) {
+ return CHPP_APP_ERROR_NONE;
+ }
+
+ switch (response->command) {
+ case asBaseType(Commands::kOk):
+ // The response for the kOk command should have a CHPP_APP_ERROR_NONE
+ // error.
+ common->okResponseStatus = chppTimestampIncomingResponse(
+ appState, &outReqStates[asBaseType(Commands::kOk)], response);
+
+ common->okResponseStatus &= response->error == CHPP_APP_ERROR_NONE;
+ return CHPP_APP_ERROR_NONE;
+
+ case asBaseType(Commands::kError):
+ // The response for the kError command should have a
+ // CHPP_APP_ERROR_UNSPECIFIED error.
+ common->errorResponseStatus = chppTimestampIncomingResponse(
+ appState, &outReqStates[asBaseType(Commands::kError)], response);
+
+ common->errorResponseStatus &=
+ response->error == CHPP_APP_ERROR_UNSPECIFIED;
+ return CHPP_APP_ERROR_NONE;
+
+ case asBaseType(Commands::kTimeout):
+ // The response for the kTimeout command should have a
+ // CHPP_APP_ERROR_TIMEOUT error. That response is generated by the app
+ // layer.
+ common->timeoutResponseStatus = chppTimestampIncomingResponse(
+ appState, &outReqStates[asBaseType(Commands::kTimeout)], response);
+
+ common->timeoutResponseStatus &=
+ response->error == CHPP_APP_ERROR_TIMEOUT;
+ chppNotifierSignal(&common->notifier, 1 /*signal*/);
+ return CHPP_APP_ERROR_NONE;
+
+ default:
+ return CHPP_APP_ERROR_NONE;
+ }
+}
+
+enum ChppAppErrorCode dispatchRequest(
+ struct ChppAppState *appState, struct ChppIncomingRequestState *inReqStates,
+ struct ChppAppHeader *request, size_t len) {
+ // The request is composed of the app header only.
+ if (len != sizeof(ChppAppHeader)) {
+ return CHPP_APP_ERROR_NONE;
+ }
+
+ switch (request->command) {
+ case asBaseType(Commands::kOk): {
+ // Return a response for the kOk command.
+ chppTimestampIncomingRequest(&inReqStates[asBaseType(Commands::kOk)],
+ request);
+
+ struct ChppAppHeader *response =
+ chppAllocResponse(request, sizeof(ChppAppHeader));
+
+ chppSendTimestampedResponseOrFail(appState,
+ &inReqStates[asBaseType(Commands::kOk)],
+ response, sizeof(ChppAppHeader));
+ return CHPP_APP_ERROR_NONE;
+ }
+ case asBaseType(Commands::kError): {
+ // Return a response with a CHPP_APP_ERROR_UNSPECIFIED error on kError
+ // command.
+ return CHPP_APP_ERROR_UNSPECIFIED;
+ }
+
+ case asBaseType(Commands::kTimeout): {
+ // Do not send a response on kTimeout for the remote endpoint to timeout.
+ chppTimestampIncomingRequest(&inReqStates[asBaseType(Commands::kError)],
+ request);
+
+ return CHPP_APP_ERROR_NONE;
+ }
+
+ default:
+ return CHPP_APP_ERROR_NONE;
+ }
+}
+
+// Client specific code.
+struct ClientState {
+ struct ChppEndpointState chppClientState;
+ struct ChppOutgoingRequestState outReqStates[kNumCommands];
+ struct ChppIncomingRequestState inReqStates[kNumCommands];
+ struct CommonState common;
+};
+
+bool clientInit(void *clientState, uint8_t handle,
+ struct ChppVersion serviceVersion);
+void clientDeinit(void *clientState);
+enum ChppAppErrorCode clientDispatchResponse(void *clientState, uint8_t *buf,
+ size_t len);
+enum ChppAppErrorCode clientDispatchRequest(void *clientState, uint8_t *buf,
+ size_t len);
+
+constexpr struct ChppClient kClient = {
+ .descriptor.uuid = TEST_UUID,
+ .descriptor.version.major = 1,
+ .descriptor.version.minor = 0,
+ .descriptor.version.patch = 0,
+ .resetNotifierFunctionPtr = nullptr,
+ .matchNotifierFunctionPtr = nullptr,
+ .responseDispatchFunctionPtr = &clientDispatchResponse,
+ .notificationDispatchFunctionPtr = nullptr,
+ .requestDispatchFunctionPtr = &clientDispatchRequest,
+ .initFunctionPtr = &clientInit,
+ .deinitFunctionPtr = &clientDeinit,
+ .outReqCount = kNumCommands,
+ .minLength = sizeof(struct ChppAppHeader),
+};
+
+// Called when a response is received from the service.
+enum ChppAppErrorCode clientDispatchResponse(void *clientState, uint8_t *buf,
+ size_t len) {
+ CHPP_NOT_NULL(clientState);
+
+ auto state = static_cast<struct ClientState *>(clientState);
+
+ return dispatchResponse(state->chppClientState.appContext,
+ state->outReqStates, &state->common,
+ reinterpret_cast<struct ChppAppHeader *>(buf), len);
+}
+
+// Called when a request is received from the service.
+enum ChppAppErrorCode clientDispatchRequest(void *clientState, uint8_t *buf,
+ size_t len) {
+ auto request = reinterpret_cast<struct ChppAppHeader *>(buf);
+ auto state = static_cast<struct ClientState *>(clientState);
+
+ return dispatchRequest(state->chppClientState.appContext, state->inReqStates,
+ request, len);
+}
+
+bool clientInit(void *clientState, uint8_t handle,
+ struct ChppVersion serviceVersion) {
+ UNUSED_VAR(serviceVersion);
+ auto state = static_cast<struct ClientState *>(clientState);
+ state->chppClientState.openState = CHPP_OPEN_STATE_OPENED;
+ chppClientInit(&state->chppClientState, handle);
+ return true;
+}
+
+void clientDeinit(void *clientState) {
+ auto state = static_cast<struct ClientState *>(clientState);
+ chppClientDeinit(&state->chppClientState);
+ state->chppClientState.openState = CHPP_OPEN_STATE_CLOSED;
+}
+
+// Service specific code.
+
+struct ServiceState {
+ struct ChppEndpointState chppServiceState;
+ struct ChppOutgoingRequestState outReqStates[kNumCommands];
+ struct ChppIncomingRequestState inReqStates[kNumCommands];
+ struct CommonState common;
+};
+
+// Called when a request is received from the client.
+enum ChppAppErrorCode serviceDispatchRequest(void *serviceState, uint8_t *buf,
+ size_t len) {
+ auto request = reinterpret_cast<struct ChppAppHeader *>(buf);
+ auto state = static_cast<struct ServiceState *>(serviceState);
+
+ return dispatchRequest(state->chppServiceState.appContext, state->inReqStates,
+ request, len);
+}
+
+// Called when a response is received from the client.
+enum ChppAppErrorCode serviceDispatchResponse(void *serviceState, uint8_t *buf,
+ size_t len) {
+ CHPP_NOT_NULL(serviceState);
+
+ auto state = static_cast<struct ServiceState *>(serviceState);
+
+ return dispatchResponse(state->chppServiceState.appContext,
+ state->outReqStates, &state->common,
+ reinterpret_cast<struct ChppAppHeader *>(buf), len);
+}
+
+const struct ChppService kService = {
+ .descriptor.uuid = TEST_UUID,
+ .descriptor.name = "Test",
+ .descriptor.version.major = 1,
+ .descriptor.version.minor = 0,
+ .descriptor.version.patch = 0,
+ .resetNotifierFunctionPtr = nullptr,
+ .requestDispatchFunctionPtr = &serviceDispatchRequest,
+ .notificationDispatchFunctionPtr = nullptr,
+ .responseDispatchFunctionPtr = &serviceDispatchResponse,
+ .outReqCount = kNumCommands,
+ .minLength = sizeof(struct ChppAppHeader),
+};
+
+/**
+ * Test requests and responses.
+ *
+ * The test parameter is:
+ * - CHPP_MESSAGE_TYPE_CLIENT_REQUEST for client side requests
+ * - CHPP_MESSAGE_TYPE_SERVICE_REQUEST for service side requests
+ */
+class AppReqRespParamTest : public testing::TestWithParam<ChppMessageType> {
+ protected:
+ void SetUp() {
+ chppClearTotalAllocBytes();
+ chppNotifierInit(&mClientState.common.notifier);
+ chppNotifierInit(&mServiceState.common.notifier);
+ memset(&mClientLinkState, 0, sizeof(mClientLinkState));
+ memset(&mServiceLinkState, 0, sizeof(mServiceLinkState));
+
+ mServiceLinkState.linkThreadName = "Service Link";
+ mServiceLinkState.workThreadName = "Service worker";
+ mServiceLinkState.isLinkActive = true;
+ mServiceLinkState.remoteLinkState = &mClientLinkState;
+ mServiceLinkState.rxInRemoteEndpointWorker = false;
+
+ mClientLinkState.linkThreadName = "Client Link";
+ mClientLinkState.workThreadName = "Client worker";
+ mClientLinkState.isLinkActive = true;
+ mClientLinkState.remoteLinkState = &mServiceLinkState;
+ mClientLinkState.rxInRemoteEndpointWorker = false;
+
+ // No default clients/services.
+ struct ChppClientServiceSet set;
+ memset(&set, 0, sizeof(set));
+
+ const struct ChppLinkApi *linkApi = getLinuxLinkApi();
+
+ // Init client side.
+ chppTransportInit(&mClientTransportState, &mClientAppState,
+ &mClientLinkState, linkApi);
+ chppAppInitWithClientServiceSet(&mClientAppState, &mClientTransportState,
+ set);
+
+ // Init service side.
+ chppTransportInit(&mServiceTransportState, &mServiceAppState,
+ &mServiceLinkState, linkApi);
+ chppAppInitWithClientServiceSet(&mServiceAppState, &mServiceTransportState,
+ set);
+
+ BringUpClient();
+ std::this_thread::sleep_for(std::chrono::milliseconds(450));
+ BringUpService();
+ mClientLinkState.linkEstablished = true;
+ mServiceLinkState.linkEstablished = true;
+
+ EXPECT_TRUE(chppTransportWaitForResetComplete(&mClientTransportState,
+ kResetWaitTimeMs));
+ EXPECT_TRUE(chppTransportWaitForResetComplete(&mServiceTransportState,
+ kResetWaitTimeMs));
+
+ EXPECT_TRUE(
+ chppWaitForDiscoveryComplete(&mClientAppState, kDiscoveryWaitTimeMs));
+ EXPECT_TRUE(
+ chppWaitForDiscoveryComplete(&mServiceAppState, kDiscoveryWaitTimeMs));
+ }
+
+ void BringUpClient() {
+ memset(&mClientState, 0, sizeof(mClientState));
+ chppRegisterClient(&mClientAppState, &mClientState,
+ &mClientState.chppClientState,
+ &mClientState.outReqStates[0], &kClient);
+
+ pthread_create(&mClientWorkThread, NULL, workThread,
+ &mClientTransportState);
+ }
+
+ void BringUpService() {
+ memset(&mServiceState, 0, sizeof(mServiceState));
+ chppRegisterService(&mServiceAppState, &mServiceState,
+ &mServiceState.chppServiceState,
+ &mServiceState.outReqStates[0], &kService);
+
+ pthread_create(&mServiceWorkThread, NULL, workThread,
+ &mServiceTransportState);
+ }
+
+ void TearDown() {
+ chppNotifierDeinit(&mClientState.common.notifier);
+ chppNotifierDeinit(&mServiceState.common.notifier);
+ chppWorkThreadStop(&mClientTransportState);
+ chppWorkThreadStop(&mServiceTransportState);
+ pthread_join(mClientWorkThread, NULL);
+ pthread_join(mServiceWorkThread, NULL);
+
+ // Deinit client side.
+ chppAppDeinit(&mClientAppState);
+ chppTransportDeinit(&mClientTransportState);
+
+ // Deinit service side.
+ chppAppDeinit(&mServiceAppState);
+ chppTransportDeinit(&mServiceTransportState);
+
+ EXPECT_EQ(chppGetTotalAllocBytes(), 0);
+ }
+
+ struct ChppAppHeader *AllocRequestCommand(Commands command) {
+ return GetParam() == CHPP_MESSAGE_TYPE_CLIENT_REQUEST
+ ? chppAllocClientRequestCommand(&mClientState.chppClientState,
+ asBaseType(command))
+ : chppAllocServiceRequestCommand(&mServiceState.chppServiceState,
+ asBaseType(command));
+ }
+
+ struct CommonState *GetCommonState() {
+ return GetParam() == CHPP_MESSAGE_TYPE_CLIENT_REQUEST
+ ? &mClientState.common
+ : &mServiceState.common;
+ }
+
+ bool SendTimestampedRequestAndWait(struct ChppAppHeader *request) {
+ constexpr size_t len = sizeof(struct ChppAppHeader);
+ if (request->type == CHPP_MESSAGE_TYPE_CLIENT_REQUEST) {
+ return chppClientSendTimestampedRequestAndWait(
+ &mClientState.chppClientState,
+ &mClientState.outReqStates[request->command], request, len);
+ }
+
+ return chppServiceSendTimestampedRequestAndWait(
+ &mServiceState.chppServiceState,
+ &mServiceState.outReqStates[request->command], request, len);
+ }
+
+ bool SendTimestampedRequestOrFail(struct ChppAppHeader *request,
+ uint64_t timeoutNs) {
+ constexpr size_t len = sizeof(struct ChppAppHeader);
+ if (request->type == CHPP_MESSAGE_TYPE_CLIENT_REQUEST) {
+ return chppClientSendTimestampedRequestOrFail(
+ &mClientState.chppClientState,
+ &mClientState.outReqStates[request->command], request, len,
+ timeoutNs);
+ }
+
+ return chppServiceSendTimestampedRequestOrFail(
+ &mServiceState.chppServiceState,
+ &mServiceState.outReqStates[request->command], request, len, timeoutNs);
+ }
+
+ // Client side.
+ ChppLinuxLinkState mClientLinkState = {};
+ ChppTransportState mClientTransportState = {};
+ ChppAppState mClientAppState = {};
+ ClientState mClientState;
+ pthread_t mClientWorkThread;
+
+ // Service side
+ ChppLinuxLinkState mServiceLinkState = {};
+ ChppTransportState mServiceTransportState = {};
+ ChppAppState mServiceAppState = {};
+ ServiceState mServiceState = {};
+ pthread_t mServiceWorkThread;
+};
+
+TEST_P(AppReqRespParamTest, sendsRequestAndReceiveResponse) {
+ struct ChppAppHeader *request = AllocRequestCommand(Commands::kOk);
+ ASSERT_NE(request, nullptr);
+
+ GetCommonState()->okResponseStatus = false;
+
+ EXPECT_TRUE(SendTimestampedRequestAndWait(request));
+
+ EXPECT_TRUE(GetCommonState()->okResponseStatus);
+}
+
+TEST_P(AppReqRespParamTest, sendsRequestAndReceiveErrorResponse) {
+ struct ChppAppHeader *request = AllocRequestCommand(Commands::kError);
+ ASSERT_NE(request, nullptr);
+
+ GetCommonState()->errorResponseStatus = false;
+
+ EXPECT_TRUE(SendTimestampedRequestAndWait(request));
+
+ EXPECT_TRUE(GetCommonState()->errorResponseStatus);
+}
+
+TEST_P(AppReqRespParamTest, sendsRequestAndReceiveTimeoutResponse) {
+ struct ChppAppHeader *request = AllocRequestCommand(Commands::kTimeout);
+ ASSERT_NE(request, nullptr);
+
+ GetCommonState()->timeoutResponseStatus = false;
+
+ EXPECT_TRUE(
+ SendTimestampedRequestOrFail(request, 10 * kOneMicrosecondInNanoseconds));
+
+ chppNotifierWait(&GetCommonState()->notifier);
+
+ EXPECT_TRUE(GetCommonState()->timeoutResponseStatus);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AppReqRespTest, AppReqRespParamTest,
+ testing::Values(CHPP_MESSAGE_TYPE_CLIENT_REQUEST,
+ CHPP_MESSAGE_TYPE_SERVICE_REQUEST),
+ [](const testing::TestParamInfo<AppReqRespParamTest::ParamType> &info) {
+ return info.param == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ? "ClientRequests"
+ : "ServiceRequests";
+ });
+
+} // namespace
+} // namespace chre \ No newline at end of file
diff --git a/chpp/test/app_test.cpp b/chpp/test/app_test.cpp
index 84d826c3..fdc2f4bf 100644
--- a/chpp/test/app_test.cpp
+++ b/chpp/test/app_test.cpp
@@ -142,8 +142,12 @@ TEST_F(ChppAppTest, FragmentedLoopback) {
}
TEST_F(ChppAppTest, Timesync) {
- constexpr uint64_t kMaxRtt = 2 * CHPP_NSEC_PER_MSEC; // in ms
- constexpr int64_t kMaxOffset = 1 * CHPP_NSEC_PER_MSEC; // in ms
+ // Upper bound for the RTT (response received - request sent).
+ constexpr uint64_t kMaxRttNs = 20 * CHPP_NSEC_PER_MSEC;
+ // The offset is defined as (Time when the service sent the response) - (Time
+ // when the client got the response).
+ // We use half the RTT as the upper bound.
+ constexpr int64_t kMaxOffsetNs = kMaxRttNs / 2;
CHPP_LOGI("Starting timesync test...");
@@ -154,11 +158,11 @@ TEST_F(ChppAppTest, Timesync) {
EXPECT_EQ(chppTimesyncGetResult(&mClientAppContext)->error,
CHPP_APP_ERROR_NONE);
- EXPECT_LT(chppTimesyncGetResult(&mClientAppContext)->rttNs, kMaxRtt);
+ EXPECT_LT(chppTimesyncGetResult(&mClientAppContext)->rttNs, kMaxRttNs);
EXPECT_NE(chppTimesyncGetResult(&mClientAppContext)->rttNs, 0);
- EXPECT_LT(chppTimesyncGetResult(&mClientAppContext)->offsetNs, kMaxOffset);
- EXPECT_GT(chppTimesyncGetResult(&mClientAppContext)->offsetNs, -kMaxOffset);
+ EXPECT_LT(chppTimesyncGetResult(&mClientAppContext)->offsetNs, kMaxOffsetNs);
+ EXPECT_GT(chppTimesyncGetResult(&mClientAppContext)->offsetNs, -kMaxOffsetNs);
EXPECT_NE(chppTimesyncGetResult(&mClientAppContext)->offsetNs, 0);
}
diff --git a/chpp/test/app_test_base.cpp b/chpp/test/app_test_base.cpp
index 907b15e4..1a9e3fc9 100644
--- a/chpp/test/app_test_base.cpp
+++ b/chpp/test/app_test_base.cpp
@@ -97,11 +97,17 @@ void AppTestBase::SetUp() {
mClientLinkContext.linkEstablished = true;
mServiceLinkContext.linkEstablished = true;
- constexpr uint64_t kResetWaitTimeMs = 1500;
- chppTransportWaitForResetComplete(&mClientTransportContext, kResetWaitTimeMs);
+ constexpr uint64_t kResetWaitTimeMs = 5000;
+ EXPECT_TRUE(chppTransportWaitForResetComplete(&mClientTransportContext,
+ kResetWaitTimeMs));
+ EXPECT_TRUE(chppTransportWaitForResetComplete(&mServiceTransportContext,
+ kResetWaitTimeMs));
constexpr uint64_t kDiscoveryWaitTimeMs = 5000;
- chppWaitForDiscoveryComplete(&mClientAppContext, kDiscoveryWaitTimeMs);
+ EXPECT_TRUE(
+ chppWaitForDiscoveryComplete(&mClientAppContext, kDiscoveryWaitTimeMs));
+ EXPECT_TRUE(
+ chppWaitForDiscoveryComplete(&mServiceAppContext, kDiscoveryWaitTimeMs));
}
void AppTestBase::TearDown() {
diff --git a/chpp/test/app_timeout_test.cpp b/chpp/test/app_timeout_test.cpp
new file mode 100644
index 00000000..8f155f22
--- /dev/null
+++ b/chpp/test/app_timeout_test.cpp
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_timeout_test.h"
+
+#include <gtest/gtest.h>
+#include <string.h>
+#include <cstdint>
+#include <thread>
+
+#include "chpp/app.h"
+#include "chpp/clients.h"
+#include "chpp/clients/gnss.h"
+#include "chpp/clients/wifi.h"
+#include "chpp/clients/wwan.h"
+#include "chpp/macros.h"
+#include "chpp/memory.h"
+#include "chpp/platform/platform_link.h"
+#include "chpp/platform/utils.h"
+#include "chpp/services.h"
+#include "chpp/time.h"
+#include "chpp/transport.h"
+#include "chre/pal/wwan.h"
+
+namespace chre {
+namespace {
+
+#define TEST_UUID \
+ { \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x12 \
+ }
+
+// Number of requests supported by the client and the service.
+constexpr uint16_t kNumCommands = 3;
+
+struct ClientState {
+ struct ChppEndpointState chppClientState;
+ struct ChppOutgoingRequestState outReqStates[kNumCommands];
+};
+
+constexpr struct ChppClient kClient = {
+ .descriptor.uuid = TEST_UUID,
+ .descriptor.version.major = 1,
+ .descriptor.version.minor = 0,
+ .descriptor.version.patch = 0,
+ .outReqCount = kNumCommands,
+ .minLength = sizeof(struct ChppAppHeader),
+};
+
+struct ServiceState {
+ struct ChppEndpointState chppServiceState;
+ struct ChppOutgoingRequestState outReqStates[kNumCommands];
+};
+
+const struct ChppService kService = {
+ .descriptor.uuid = TEST_UUID,
+ .descriptor.name = "Test",
+ .descriptor.version.major = 1,
+ .descriptor.version.minor = 0,
+ .descriptor.version.patch = 0,
+ .outReqCount = kNumCommands,
+ .minLength = sizeof(struct ChppAppHeader),
+};
+
+void ValidateClientStateAndReqState(struct ChppEndpointState *clientState,
+ const struct ChppAppHeader *request) {
+ ASSERT_NE(clientState, nullptr);
+ const uint8_t clientIdx = clientState->index;
+
+ ASSERT_NE(clientState->appContext, nullptr);
+ ASSERT_NE(clientState->appContext->registeredClients, nullptr);
+ ASSERT_NE(clientState->appContext->registeredClients[clientIdx], nullptr);
+ ASSERT_LT(request->command,
+ clientState->appContext->registeredClients[clientIdx]->outReqCount);
+ ASSERT_NE(clientState->appContext->registeredClientStates[clientIdx],
+ nullptr);
+ ASSERT_NE(
+ clientState->appContext->registeredClientStates[clientIdx]->outReqStates,
+ nullptr);
+ ASSERT_NE(clientState->appContext->registeredClientStates[clientIdx]->context,
+ nullptr);
+}
+
+void ValidateServiceStateAndReqState(struct ChppEndpointState *serviceState,
+ const struct ChppAppHeader *request) {
+ ASSERT_NE(serviceState, nullptr);
+ const uint8_t serviceIdx = serviceState->index;
+
+ ASSERT_NE(serviceState->appContext, nullptr);
+ ASSERT_NE(serviceState->appContext->registeredServices, nullptr);
+ ASSERT_NE(serviceState->appContext->registeredServices[serviceIdx], nullptr);
+ ASSERT_LT(
+ request->command,
+ serviceState->appContext->registeredServices[serviceIdx]->outReqCount);
+ ASSERT_NE(serviceState->appContext->registeredServiceStates[serviceIdx],
+ nullptr);
+ ASSERT_NE(serviceState->appContext->registeredServiceStates[serviceIdx]
+ ->outReqStates,
+ nullptr);
+ ASSERT_NE(
+ serviceState->appContext->registeredServiceStates[serviceIdx]->context,
+ nullptr);
+}
+
+void validateTimeout(uint64_t timeoutTimeNs, uint64_t expectedTimeNs) {
+ constexpr uint64_t kJitterNs = 10 * CHPP_NSEC_PER_MSEC;
+
+ if (expectedTimeNs == CHPP_TIME_MAX) {
+ EXPECT_EQ(timeoutTimeNs, expectedTimeNs);
+ } else {
+ EXPECT_GE(timeoutTimeNs, expectedTimeNs);
+ EXPECT_LE(timeoutTimeNs, expectedTimeNs + kJitterNs);
+ }
+}
+
+void validateTimeoutResponse(const struct ChppAppHeader *request,
+ const struct ChppAppHeader *response) {
+ ASSERT_NE(request, nullptr);
+ ASSERT_NE(response, nullptr);
+
+ EXPECT_EQ(response->handle, request->handle);
+
+ EXPECT_EQ(response->type, request->type == CHPP_MESSAGE_TYPE_CLIENT_REQUEST
+ ? CHPP_MESSAGE_TYPE_SERVICE_RESPONSE
+ : CHPP_MESSAGE_TYPE_CLIENT_RESPONSE);
+ EXPECT_EQ(response->transaction, request->transaction);
+ EXPECT_EQ(response->error, CHPP_APP_ERROR_TIMEOUT);
+ EXPECT_EQ(response->command, request->command);
+}
+
+/**
+ * Test timeout for client and service side requests.
+ *
+ * The test parameter is:
+ * - CHPP_MESSAGE_TYPE_CLIENT_REQUEST for client side requests
+ * - CHPP_MESSAGE_TYPE_SERVICE_REQUEST for service side requests
+ */
+class TimeoutParamTest : public testing::TestWithParam<ChppMessageType> {
+ protected:
+ void SetUp() override {
+ chppClearTotalAllocBytes();
+
+ memset(&mClientLinkContext, 0, sizeof(mClientLinkContext));
+ memset(&mServiceLinkContext, 0, sizeof(mServiceLinkContext));
+
+ mServiceLinkContext.isLinkActive = true;
+ mServiceLinkContext.remoteLinkState = &mClientLinkContext;
+ mServiceLinkContext.rxInRemoteEndpointWorker = false;
+
+ mClientLinkContext.isLinkActive = true;
+ mClientLinkContext.remoteLinkState = &mServiceLinkContext;
+ mClientLinkContext.rxInRemoteEndpointWorker = false;
+
+ // No default clients/services.
+ struct ChppClientServiceSet set;
+ memset(&set, 0, sizeof(set));
+
+ const struct ChppLinkApi *linkApi = getLinuxLinkApi();
+
+ // Init client side.
+ chppTransportInit(&mClientTransportContext, &mClientAppContext,
+ &mClientLinkContext, linkApi);
+ mClientTransportContext.resetState = CHPP_RESET_STATE_NONE;
+ chppAppInitWithClientServiceSet(&mClientAppContext,
+ &mClientTransportContext, set);
+
+ // Init service side.
+ chppTransportInit(&mServiceTransportContext, &mServiceAppContext,
+ &mServiceLinkContext, linkApi);
+ mServiceTransportContext.resetState = CHPP_RESET_STATE_NONE;
+ chppAppInitWithClientServiceSet(&mServiceAppContext,
+ &mServiceTransportContext, set);
+
+ // Bring up the client
+ memset(&mClientState, 0, sizeof(mClientState));
+ chppRegisterClient(&mClientAppContext, &mClientState,
+ &mClientState.chppClientState,
+ &mClientState.outReqStates[0], &kClient);
+
+ // Bring up the service
+ memset(&mServiceState, 0, sizeof(mServiceState));
+ chppRegisterService(&mServiceAppContext, &mServiceState,
+ &mServiceState.chppServiceState,
+ &mServiceState.outReqStates[0], &kService);
+
+ mClientLinkContext.linkEstablished = true;
+ mServiceLinkContext.linkEstablished = true;
+
+ chppClientInit(&mClientState.chppClientState,
+ CHPP_HANDLE_NEGOTIATED_RANGE_START);
+ }
+
+ void TearDown() override {
+ chppAppDeinit(&mClientAppContext);
+ chppTransportDeinit(&mClientTransportContext);
+ chppClientDeinit(&mClientState.chppClientState);
+
+ chppAppDeinit(&mServiceAppContext);
+ chppTransportDeinit(&mServiceTransportContext);
+
+ EXPECT_EQ(chppGetTotalAllocBytes(), 0);
+ }
+
+ struct ChppAppHeader *AllocRequestCommand(uint16_t command) {
+ return GetParam() == CHPP_MESSAGE_TYPE_CLIENT_REQUEST
+ ? chppAllocClientRequestCommand(&mClientState.chppClientState,
+ command)
+ : chppAllocServiceRequestCommand(&mServiceState.chppServiceState,
+ command);
+ }
+
+ void TimestampOutgoingRequest(struct ChppAppHeader *request,
+ uint64_t timeoutNs) {
+ CHPP_NOT_NULL(request);
+
+ const uint16_t command = request->command;
+
+ if (GetParam() == CHPP_MESSAGE_TYPE_CLIENT_REQUEST) {
+ chppTimestampOutgoingRequest(&mClientAppContext,
+ &mClientState.outReqStates[command], request,
+ timeoutNs);
+ } else {
+ chppTimestampOutgoingRequest(&mServiceAppContext,
+ &mServiceState.outReqStates[command],
+ request, timeoutNs);
+ }
+ }
+
+ bool TimestampIncomingResponse(struct ChppAppHeader *response) {
+ CHPP_NOT_NULL(response);
+
+ const uint16_t command = response->command;
+
+ if (GetParam() == CHPP_MESSAGE_TYPE_CLIENT_REQUEST) {
+ return chppTimestampIncomingResponse(
+ &mClientAppContext, &mClientState.outReqStates[command], response);
+ }
+ return chppTimestampIncomingResponse(
+ &mServiceAppContext, &mServiceState.outReqStates[command], response);
+ }
+
+ uint64_t GetNextRequestTimeoutNs(void) {
+ return GetParam() == CHPP_MESSAGE_TYPE_CLIENT_REQUEST
+ ? mClientAppContext.nextClientRequestTimeoutNs
+ : mServiceAppContext.nextServiceRequestTimeoutNs;
+ }
+
+ struct ChppAppHeader *GetTimeoutResponse(void) {
+ return GetParam() == CHPP_MESSAGE_TYPE_CLIENT_REQUEST
+ ? chppTransportGetRequestTimeoutResponse(
+ &mClientTransportContext, CHPP_ENDPOINT_CLIENT)
+ : chppTransportGetRequestTimeoutResponse(
+ &mServiceTransportContext, CHPP_ENDPOINT_SERVICE);
+ }
+
+ void ValidateRequestState(struct ChppAppHeader *request) {
+ CHPP_NOT_NULL(request);
+ if (GetParam() == CHPP_MESSAGE_TYPE_CLIENT_REQUEST) {
+ ValidateClientStateAndReqState(&mClientState.chppClientState, request);
+ } else {
+ ValidateServiceStateAndReqState(&mServiceState.chppServiceState, request);
+ }
+ }
+
+ void RegisterAndValidateRequestForTimeout(struct ChppAppHeader *request,
+ uint64_t kTimeoutNs,
+ uint64_t expectedTimeNs) {
+ CHPP_NOT_NULL(request);
+ ValidateRequestState(request);
+ TimestampOutgoingRequest(request, kTimeoutNs);
+
+ validateTimeout(GetNextRequestTimeoutNs(), expectedTimeNs);
+ }
+
+ void RegisterAndValidateResponseForTimeout(struct ChppAppHeader *request,
+ uint64_t expectedTimeNs) {
+ CHPP_NOT_NULL(request);
+
+ struct ChppAppHeader *response =
+ chppAllocResponse(request, sizeof(*request));
+
+ ValidateRequestState(request);
+ TimestampIncomingResponse(response);
+
+ validateTimeout(GetNextRequestTimeoutNs(), expectedTimeNs);
+
+ chppFree(response);
+ }
+
+ // Client side.
+ ChppLinuxLinkState mClientLinkContext = {};
+ ChppTransportState mClientTransportContext = {};
+ ChppAppState mClientAppContext = {};
+ ClientState mClientState;
+
+ // Service side
+ ChppLinuxLinkState mServiceLinkContext = {};
+ ChppTransportState mServiceTransportContext = {};
+ ChppAppState mServiceAppContext = {};
+ ServiceState mServiceState;
+};
+
+// Simulates a request and a response.
+// There should be no error as the timeout is infinite.
+TEST_P(TimeoutParamTest, RequestResponseTimestampValid) {
+ struct ChppAppHeader *request = AllocRequestCommand(0 /* command */);
+ ASSERT_NE(request, nullptr);
+ TimestampOutgoingRequest(request, CHPP_REQUEST_TIMEOUT_INFINITE);
+
+ struct ChppAppHeader *response = chppAllocResponse(request, sizeof(*request));
+ EXPECT_TRUE(TimestampIncomingResponse(response));
+
+ chppFree(request);
+ chppFree(response);
+}
+
+// Simulates a single request with 2 responses.
+TEST_P(TimeoutParamTest, RequestResponseTimestampDuplicate) {
+ struct ChppAppHeader *request = AllocRequestCommand(0 /* command */);
+ ASSERT_NE(request, nullptr);
+ TimestampOutgoingRequest(request, CHPP_REQUEST_TIMEOUT_INFINITE);
+
+ struct ChppAppHeader *response = chppAllocResponse(request, sizeof(*request));
+
+ // The first response has no error.
+ EXPECT_TRUE(TimestampIncomingResponse(response));
+
+ // The second response errors as one response has already been received.
+ EXPECT_FALSE(TimestampIncomingResponse(response));
+
+ chppFree(request);
+ chppFree(response);
+}
+
+// Simulates a response to a request that has not been timestamped.
+TEST_P(TimeoutParamTest, RequestResponseTimestampInvalidId) {
+ constexpr uint16_t command = 0;
+
+ struct ChppAppHeader *request1 = AllocRequestCommand(command);
+ ASSERT_NE(request1, nullptr);
+ TimestampOutgoingRequest(request1, CHPP_REQUEST_TIMEOUT_INFINITE);
+
+ struct ChppAppHeader *request2 = AllocRequestCommand(command);
+ ASSERT_NE(request2, nullptr);
+
+ // We expect a response for req but get a response for newReq.
+ // That is an error (the transaction does not match).
+ struct ChppAppHeader *response =
+ chppAllocResponse(request2, sizeof(*request1));
+ EXPECT_FALSE(TimestampIncomingResponse(response));
+
+ chppFree(request1);
+ chppFree(request2);
+ chppFree(response);
+}
+
+// Make sure the request does not timeout right away.
+TEST_P(TimeoutParamTest, RequestTimeoutAddRemoveSingle) {
+ EXPECT_EQ(GetNextRequestTimeoutNs(), CHPP_TIME_MAX);
+
+ struct ChppAppHeader *request = AllocRequestCommand(1 /* command */);
+ ASSERT_NE(request, nullptr);
+
+ const uint64_t timeNs = chppGetCurrentTimeNs();
+ constexpr uint64_t kTimeoutNs = 1000 * CHPP_NSEC_PER_MSEC;
+ RegisterAndValidateRequestForTimeout(request, kTimeoutNs,
+ timeNs + kTimeoutNs);
+
+ // Timeout is not expired yet.
+ EXPECT_EQ(GetTimeoutResponse(), nullptr);
+
+ RegisterAndValidateResponseForTimeout(request, CHPP_TIME_MAX);
+
+ chppFree(request);
+}
+
+TEST_P(TimeoutParamTest, RequestTimeoutAddRemoveMultiple) {
+ EXPECT_EQ(GetNextRequestTimeoutNs(), CHPP_TIME_MAX);
+
+ struct ChppAppHeader *request1 = AllocRequestCommand(0 /* command */);
+ struct ChppAppHeader *request2 = AllocRequestCommand(1 /* command */);
+ struct ChppAppHeader *request3 = AllocRequestCommand(2 /* command */);
+ ASSERT_NE(request1, nullptr);
+ ASSERT_NE(request2, nullptr);
+ ASSERT_NE(request3, nullptr);
+
+ // kTimeout1Ns is the smallest so it will be the first timeout to expire
+ // for all the requests.
+ const uint64_t time1Ns = chppGetCurrentTimeNs();
+ constexpr uint64_t kTimeout1Ns = 2000 * CHPP_NSEC_PER_MSEC;
+ RegisterAndValidateRequestForTimeout(request1, kTimeout1Ns,
+ time1Ns + kTimeout1Ns);
+
+ const uint64_t time2Ns = chppGetCurrentTimeNs();
+ constexpr uint64_t kTimeout2Ns = 4000 * CHPP_NSEC_PER_MSEC;
+ RegisterAndValidateRequestForTimeout(request2, kTimeout2Ns,
+ time1Ns + kTimeout1Ns);
+
+ const uint64_t time3Ns = chppGetCurrentTimeNs();
+ constexpr uint64_t kTimeout3Ns = 3000 * CHPP_NSEC_PER_MSEC;
+ RegisterAndValidateRequestForTimeout(request3, kTimeout3Ns,
+ time1Ns + kTimeout1Ns);
+
+ RegisterAndValidateResponseForTimeout(request1, time3Ns + kTimeout3Ns);
+
+ // Timeout is not expired yet.
+ EXPECT_EQ(GetTimeoutResponse(), nullptr);
+
+ // kTimeout4Ns is now the smallest timeout.
+ const uint64_t time4Ns = chppGetCurrentTimeNs();
+ constexpr uint64_t kTimeout4Ns = 1000 * CHPP_NSEC_PER_MSEC;
+ RegisterAndValidateRequestForTimeout(request1, kTimeout4Ns,
+ time4Ns + kTimeout4Ns);
+
+ RegisterAndValidateResponseForTimeout(request1, time3Ns + kTimeout3Ns);
+
+ RegisterAndValidateResponseForTimeout(request3, time2Ns + kTimeout2Ns);
+
+ RegisterAndValidateResponseForTimeout(request2, CHPP_TIME_MAX);
+
+ EXPECT_EQ(GetTimeoutResponse(), nullptr);
+
+ chppFree(request1);
+ chppFree(request2);
+ chppFree(request3);
+}
+
+TEST_P(TimeoutParamTest, DuplicateRequestTimeoutResponse) {
+ // Sleep padding to make sure we timeout.
+ constexpr auto kTimeoutPadding = std::chrono::milliseconds(50);
+
+ EXPECT_EQ(GetNextRequestTimeoutNs(), CHPP_TIME_MAX);
+
+ struct ChppAppHeader *request = AllocRequestCommand(1 /* command */);
+ ASSERT_NE(request, nullptr);
+
+ // Send the first request.
+ constexpr uint64_t kTimeout1Ns = 20 * CHPP_NSEC_PER_MSEC;
+ const uint64_t kShouldTimeout1AtNs = chppGetCurrentTimeNs() + kTimeout1Ns;
+ RegisterAndValidateRequestForTimeout(request, kTimeout1Ns,
+ kShouldTimeout1AtNs);
+
+ // Override with a new request.
+ constexpr uint64_t kTimeout2Ns = 400 * CHPP_NSEC_PER_MSEC;
+ const uint64_t kShouldTimeout2AtNs = chppGetCurrentTimeNs() + kTimeout2Ns;
+ RegisterAndValidateRequestForTimeout(request, kTimeout2Ns,
+ kShouldTimeout2AtNs);
+
+ std::this_thread::sleep_for(
+ std::chrono::nanoseconds(kShouldTimeout1AtNs - chppGetCurrentTimeNs()) +
+ kTimeoutPadding);
+ // First request would have timed out but superseded by second request.
+ EXPECT_GT(GetNextRequestTimeoutNs(), chppGetCurrentTimeNs());
+
+ std::this_thread::sleep_for(
+ std::chrono::nanoseconds(kShouldTimeout2AtNs - chppGetCurrentTimeNs()) +
+ kTimeoutPadding);
+ // Second request should have timed out - so we get a response.
+ EXPECT_LT(GetNextRequestTimeoutNs(), chppGetCurrentTimeNs());
+
+ struct ChppAppHeader *response = GetTimeoutResponse();
+ ASSERT_NE(response, nullptr);
+ validateTimeoutResponse(request, response);
+ chppFree(response);
+
+ RegisterAndValidateResponseForTimeout(request, CHPP_TIME_MAX);
+ EXPECT_EQ(GetTimeoutResponse(), nullptr);
+
+ chppFree(request);
+}
+
+TEST_P(TimeoutParamTest, RequestTimeoutResponse) {
+ EXPECT_EQ(GetNextRequestTimeoutNs(), CHPP_TIME_MAX);
+
+ struct ChppAppHeader *request1 = AllocRequestCommand(1 /* command */);
+ struct ChppAppHeader *request2 = AllocRequestCommand(2 /* command */);
+ ASSERT_NE(request1, nullptr);
+ ASSERT_NE(request2, nullptr);
+
+ const uint64_t time1Ns = chppGetCurrentTimeNs();
+ constexpr uint64_t kTimeout1Ns = 200 * CHPP_NSEC_PER_MSEC;
+ RegisterAndValidateRequestForTimeout(request1, kTimeout1Ns,
+ time1Ns + kTimeout1Ns);
+
+ std::this_thread::sleep_for(std::chrono::nanoseconds(kTimeout1Ns));
+ ASSERT_LT(GetNextRequestTimeoutNs(), chppGetCurrentTimeNs());
+
+ // No response in time, we then get a timeout response.
+ struct ChppAppHeader *response = GetTimeoutResponse();
+ validateTimeoutResponse(request1, response);
+ chppFree(response);
+
+ RegisterAndValidateResponseForTimeout(request1, CHPP_TIME_MAX);
+ // No other request in timeout.
+ EXPECT_EQ(GetTimeoutResponse(), nullptr);
+
+ // Simulate a new timeout and make sure we have a timeout response.
+ const uint64_t time2Ns = chppGetCurrentTimeNs();
+ constexpr uint64_t kTimeout2Ns = 200 * CHPP_NSEC_PER_MSEC;
+ RegisterAndValidateRequestForTimeout(request2, kTimeout2Ns,
+ time2Ns + kTimeout2Ns);
+
+ std::this_thread::sleep_for(std::chrono::nanoseconds(kTimeout2Ns));
+ ASSERT_LT(GetNextRequestTimeoutNs(), chppGetCurrentTimeNs());
+
+ response = GetTimeoutResponse();
+ validateTimeoutResponse(request2, response);
+ chppFree(response);
+
+ chppFree(request1);
+ chppFree(request2);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ TimeoutTest, TimeoutParamTest,
+ testing::Values(CHPP_MESSAGE_TYPE_CLIENT_REQUEST,
+ CHPP_MESSAGE_TYPE_SERVICE_REQUEST),
+ [](const testing::TestParamInfo<TimeoutParamTest::ParamType> &info) {
+ return info.param == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ? "ClientRequests"
+ : "ServiceRequests";
+ });
+
+} // namespace
+} // namespace chre \ No newline at end of file
diff --git a/chpp/test/clients_test.h b/chpp/test/app_timeout_test.h
index d7caa321..2b41d1ef 100644
--- a/chpp/test/clients_test.h
+++ b/chpp/test/app_timeout_test.h
@@ -28,8 +28,8 @@ extern "C" {
* Functions necessary for unit testing
***********************************************/
-struct ChppAppHeader *chppTransportGetClientRequestTimeoutResponse(
- struct ChppTransportState *context);
+struct ChppAppHeader *chppTransportGetRequestTimeoutResponse(
+ struct ChppTransportState *context, enum ChppEndpointType type);
#ifdef __cplusplus
}
diff --git a/chpp/test/clients_test.cpp b/chpp/test/clients_test.cpp
deleted file mode 100644
index 5f69ec82..00000000
--- a/chpp/test/clients_test.cpp
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "clients_test.h"
-
-#include <gtest/gtest.h>
-
-#include <string.h>
-#include <thread>
-
-#include "chpp/app.h"
-#include "chpp/clients.h"
-#include "chpp/clients/gnss.h"
-#include "chpp/clients/wifi.h"
-#include "chpp/clients/wwan.h"
-#include "chpp/macros.h"
-#include "chpp/memory.h"
-#include "chpp/platform/platform_link.h"
-#include "chpp/platform/utils.h"
-#include "chpp/services.h"
-#include "chpp/time.h"
-#include "chpp/transport.h"
-#include "chre/pal/wwan.h"
-
-class ClientsTest : public testing::Test {
- protected:
- void SetUp() override {
- chppClearTotalAllocBytes();
-
- memset(&mAppContext, 0, sizeof(mAppContext));
- memset(&mTransportContext, 0, sizeof(mTransportContext));
- memset(&mLinkContext, 0, sizeof(mLinkContext));
- mLinkContext.linkEstablished = true;
-
- chppTransportInit(&mTransportContext, &mAppContext, &mLinkContext,
- getLinuxLinkApi());
- chppAppInit(&mAppContext, &mTransportContext);
- mClientState =
- (struct ChppClientState *)mAppContext.registeredClientContexts[0];
- chppClientInit(mClientState, CHPP_HANDLE_NEGOTIATED_RANGE_START);
-
- mTransportContext.resetState = CHPP_RESET_STATE_NONE;
- }
-
- void TearDown() override {
- chppAppDeinit(&mAppContext);
- chppTransportDeinit(&mTransportContext);
-
- EXPECT_EQ(chppGetTotalAllocBytes(), 0);
- }
-
- struct ChppTransportState mTransportContext;
- struct ChppAppState mAppContext;
- struct ChppLinuxLinkState mLinkContext;
- struct ChppClientState *mClientState;
- struct ChppRequestResponseState mRRState;
-};
-
-void getClientRRStateInputCheck(struct ChppClientState *clientState,
- struct ChppAppHeader *header) {
- ASSERT_TRUE(clientState != NULL);
- uint8_t clientIdx = clientState->index;
-
- ASSERT_TRUE(clientState->appContext != NULL);
- ASSERT_TRUE(clientState->appContext->registeredClients != NULL);
- ASSERT_TRUE(clientState->appContext->registeredClients[clientIdx] != NULL);
- ASSERT_TRUE(
- clientState->appContext->registeredClientStates[clientIdx]->rRStates !=
- NULL);
- ASSERT_LT(
- header->command,
- clientState->appContext->registeredClients[clientIdx]->rRStateCount);
-}
-
-struct ChppRequestResponseState *getClientRRState(
- struct ChppClientState *clientState, struct ChppAppHeader *header) {
- getClientRRStateInputCheck(clientState, header);
-
- uint8_t clientIdx = clientState->index;
- return &(clientState->appContext->registeredClientStates[clientIdx]
- ->rRStates[header->command]);
-}
-
-void isTimeoutAsExpected(uint64_t timeoutTimeNs, uint64_t expectedTimeNs) {
- uint64_t kJitterNs = 10 * CHPP_NSEC_PER_MSEC;
-
- if (expectedTimeNs == CHPP_TIME_MAX) {
- EXPECT_EQ(timeoutTimeNs, expectedTimeNs);
- } else {
- EXPECT_GE(timeoutTimeNs, expectedTimeNs);
- EXPECT_LE(timeoutTimeNs, expectedTimeNs + kJitterNs);
- }
-}
-
-void registerAndValidateRequestForTimeout(struct ChppClientState *clientState,
- struct ChppAppHeader *header,
- uint64_t timeoutNs,
- uint64_t expectedTimeNs) {
- struct ChppRequestResponseState *rRState =
- getClientRRState(clientState, header);
- chppClientTimestampRequest(clientState, rRState, header, timeoutNs);
-
- isTimeoutAsExpected(clientState->appContext->nextRequestTimeoutNs,
- expectedTimeNs);
-}
-
-void registerAndValidateResponseForTimeout(struct ChppClientState *clientState,
- const struct ChppAppHeader *header,
- uint64_t expectedTimeNs) {
- ASSERT_FALSE(clientState == NULL);
- uint8_t clientIdx = clientState->index;
-
- ASSERT_FALSE(clientState->appContext == NULL);
- ASSERT_FALSE(clientState->appContext->registeredClients == NULL);
- ASSERT_FALSE(clientState->appContext->registeredClients[clientIdx] == NULL);
- ASSERT_FALSE(
- clientState->appContext->registeredClientStates[clientIdx]->rRStates ==
- NULL);
- ASSERT_LT(
- header->command,
- clientState->appContext->registeredClients[clientIdx]->rRStateCount);
-
- struct ChppRequestResponseState *rRState =
- &(clientState->appContext->registeredClientStates[clientIdx]
- ->rRStates[header->command]);
- chppClientTimestampResponse(clientState, rRState, header);
-
- isTimeoutAsExpected(clientState->appContext->nextRequestTimeoutNs,
- expectedTimeNs);
-}
-
-void validateTimeoutResponse(const struct ChppAppHeader *request,
- const struct ChppAppHeader *response) {
- ASSERT_TRUE(request != NULL);
- ASSERT_TRUE(response != NULL);
-
- EXPECT_EQ(response->handle, request->handle);
- EXPECT_EQ(response->type, CHPP_MESSAGE_TYPE_SERVICE_RESPONSE);
- EXPECT_EQ(response->transaction, request->transaction);
- EXPECT_EQ(response->error, CHPP_APP_ERROR_TIMEOUT);
- EXPECT_EQ(response->command, request->command);
-}
-
-TEST_F(ClientsTest, RequestResponseTimestampValid) {
- struct ChppAppHeader *reqHeader =
- chppAllocClientRequestCommand(mClientState, 0 /* command */);
- chppClientTimestampRequest(mClientState, &mRRState, reqHeader,
- CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE);
-
- struct ChppAppHeader *respHeader =
- chppAllocServiceResponse(reqHeader, sizeof(*reqHeader));
- ASSERT_TRUE(chppClientTimestampResponse(mClientState, &mRRState, respHeader));
-
- chppFree(reqHeader);
- chppFree(respHeader);
-}
-
-TEST_F(ClientsTest, RequestResponseTimestampDuplicate) {
- struct ChppAppHeader *reqHeader =
- chppAllocClientRequestCommand(mClientState, 0 /* command */);
- chppClientTimestampRequest(mClientState, &mRRState, reqHeader,
- CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE);
-
- struct ChppAppHeader *respHeader =
- chppAllocServiceResponse(reqHeader, sizeof(*reqHeader));
- ASSERT_TRUE(chppClientTimestampResponse(mClientState, &mRRState, respHeader));
- ASSERT_FALSE(
- chppClientTimestampResponse(mClientState, &mRRState, respHeader));
-
- chppFree(reqHeader);
- chppFree(respHeader);
-}
-
-TEST_F(ClientsTest, RequestResponseTimestampInvalidId) {
- struct ChppAppHeader *reqHeader =
- chppAllocClientRequestCommand(mClientState, 0 /* command */);
- chppClientTimestampRequest(mClientState, &mRRState, reqHeader,
- CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE);
-
- struct ChppAppHeader *newReqHeader =
- chppAllocClientRequestCommand(mClientState, 0 /* command */);
- struct ChppAppHeader *respHeader =
- chppAllocServiceResponse(newReqHeader, sizeof(*reqHeader));
- ASSERT_FALSE(
- chppClientTimestampResponse(mClientState, &mRRState, respHeader));
-
- chppFree(reqHeader);
- chppFree(newReqHeader);
- chppFree(respHeader);
-}
-
-TEST_F(ClientsTest, RequestTimeoutAddRemoveSingle) {
- EXPECT_EQ(mAppContext.nextRequestTimeoutNs, CHPP_TIME_MAX);
-
- struct ChppAppHeader *reqHeader =
- chppAllocClientRequestCommand(mClientState, 1 /* command */);
-
- uint64_t time = chppGetCurrentTimeNs();
- uint64_t timeout = 1000 * CHPP_NSEC_PER_MSEC;
- registerAndValidateRequestForTimeout(mClientState, reqHeader, timeout,
- time + timeout);
-
- EXPECT_TRUE(
- chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
-
- registerAndValidateResponseForTimeout(mClientState, reqHeader, CHPP_TIME_MAX);
-
- chppFree(reqHeader);
-}
-
-TEST_F(ClientsTest, RequestTimeoutAddRemoveMultiple) {
- struct ChppAppHeader *reqHeader1 =
- chppAllocClientRequestCommand(mClientState, 0 /* command */);
- struct ChppAppHeader *reqHeader2 =
- chppAllocClientRequestCommand(mClientState, 1 /* command */);
- struct ChppAppHeader *reqHeader3 =
- chppAllocClientRequestCommand(mClientState, 2 /* command */);
-
- EXPECT_EQ(mAppContext.nextRequestTimeoutNs, CHPP_TIME_MAX);
-
- uint64_t time1 = chppGetCurrentTimeNs();
- uint64_t timeout1 = 2000 * CHPP_NSEC_PER_MSEC;
- registerAndValidateRequestForTimeout(mClientState, reqHeader1, timeout1,
- time1 + timeout1);
-
- uint64_t time2 = chppGetCurrentTimeNs();
- uint64_t timeout2 = 4000 * CHPP_NSEC_PER_MSEC;
- registerAndValidateRequestForTimeout(mClientState, reqHeader2, timeout2,
- time1 + timeout1);
-
- uint64_t time3 = chppGetCurrentTimeNs();
- uint64_t timeout3 = 3000 * CHPP_NSEC_PER_MSEC;
- registerAndValidateRequestForTimeout(mClientState, reqHeader3, timeout3,
- time1 + timeout1);
-
- registerAndValidateResponseForTimeout(mClientState, reqHeader1,
- time3 + timeout3);
-
- EXPECT_TRUE(
- chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
-
- uint64_t time4 = chppGetCurrentTimeNs();
- uint64_t timeout4 = 1000 * CHPP_NSEC_PER_MSEC;
- registerAndValidateRequestForTimeout(mClientState, reqHeader1, timeout4,
- time4 + timeout4);
-
- registerAndValidateResponseForTimeout(mClientState, reqHeader1,
- time3 + timeout3);
-
- registerAndValidateResponseForTimeout(mClientState, reqHeader3,
- time2 + timeout2);
-
- registerAndValidateResponseForTimeout(mClientState, reqHeader2,
- CHPP_TIME_MAX);
-
- EXPECT_TRUE(
- chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
-
- chppFree(reqHeader1);
- chppFree(reqHeader2);
- chppFree(reqHeader3);
-}
-
-TEST_F(ClientsTest, DuplicateRequestTimeoutResponse) {
- EXPECT_EQ(mAppContext.nextRequestTimeoutNs, CHPP_TIME_MAX);
-
- struct ChppAppHeader *reqHeader =
- chppAllocClientRequestCommand(mClientState, 1 /* command */);
-
- uint64_t time1 = chppGetCurrentTimeNs();
- uint64_t timeout1 = 200 * CHPP_NSEC_PER_MSEC;
- registerAndValidateRequestForTimeout(mClientState, reqHeader, timeout1,
- time1 + timeout1);
-
- std::this_thread::sleep_for(std::chrono::nanoseconds(timeout1 / 2));
-
- uint64_t time2 = chppGetCurrentTimeNs();
- uint64_t timeout2 = 200 * CHPP_NSEC_PER_MSEC;
- registerAndValidateRequestForTimeout(mClientState, reqHeader, timeout2,
- time2 + timeout2);
-
- std::this_thread::sleep_for(
- std::chrono::nanoseconds(timeout1 + time1 - chppGetCurrentTimeNs()));
- // First request would have timed out but superseded by second request
- ASSERT_GT(mAppContext.nextRequestTimeoutNs, chppGetCurrentTimeNs());
-
- std::this_thread::sleep_for(
- std::chrono::nanoseconds(timeout2 + time2 - chppGetCurrentTimeNs()));
- // Second request should have timed out
- ASSERT_LT(mAppContext.nextRequestTimeoutNs, chppGetCurrentTimeNs());
-
- struct ChppAppHeader *response =
- chppTransportGetClientRequestTimeoutResponse(&mTransportContext);
- validateTimeoutResponse(reqHeader, response);
- if (response != NULL) {
- chppFree(response);
- }
-
- registerAndValidateResponseForTimeout(mClientState, reqHeader, CHPP_TIME_MAX);
- EXPECT_TRUE(
- chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
-
- chppFree(reqHeader);
-}
-
-TEST_F(ClientsTest, RequestTimeoutResponse) {
- EXPECT_EQ(mAppContext.nextRequestTimeoutNs, CHPP_TIME_MAX);
-
- struct ChppAppHeader *reqHeader1 =
- chppAllocClientRequestCommand(mClientState, 1 /* command */);
- struct ChppAppHeader *reqHeader2 =
- chppAllocClientRequestCommand(mClientState, 2 /* command */);
-
- uint64_t time1 = chppGetCurrentTimeNs();
- uint64_t timeout1 = 200 * CHPP_NSEC_PER_MSEC;
- registerAndValidateRequestForTimeout(mClientState, reqHeader1, timeout1,
- time1 + timeout1);
-
- std::this_thread::sleep_for(std::chrono::nanoseconds(timeout1));
- ASSERT_LT(mAppContext.nextRequestTimeoutNs, chppGetCurrentTimeNs());
-
- struct ChppAppHeader *response =
- chppTransportGetClientRequestTimeoutResponse(&mTransportContext);
- validateTimeoutResponse(reqHeader1, response);
- if (response != NULL) {
- chppFree(response);
- }
-
- registerAndValidateResponseForTimeout(mClientState, reqHeader1,
- CHPP_TIME_MAX);
- EXPECT_TRUE(
- chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
-
- uint64_t time2 = chppGetCurrentTimeNs();
- uint64_t timeout2 = 200 * CHPP_NSEC_PER_MSEC;
- registerAndValidateRequestForTimeout(mClientState, reqHeader2, timeout2,
- time2 + timeout2);
-
- std::this_thread::sleep_for(std::chrono::nanoseconds(timeout2));
- ASSERT_LT(mAppContext.nextRequestTimeoutNs, chppGetCurrentTimeNs());
-
- response = chppTransportGetClientRequestTimeoutResponse(&mTransportContext);
- validateTimeoutResponse(reqHeader2, response);
- if (response != NULL) {
- chppFree(response);
- }
-
- chppFree(reqHeader1);
- chppFree(reqHeader2);
-} \ No newline at end of file
diff --git a/chpp/test/fake_link_sync_test.cpp b/chpp/test/fake_link_sync_test.cpp
index c4ec2a1a..f926dd6b 100644
--- a/chpp/test/fake_link_sync_test.cpp
+++ b/chpp/test/fake_link_sync_test.cpp
@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
+#include <string.h>
#include <cstdint>
#include <iostream>
#include <thread>
@@ -87,6 +88,7 @@ namespace chpp::test {
class FakeLinkSyncTests : public testing::Test {
protected:
void SetUp() override {
+ memset(&mLinkContext, 0, sizeof(mLinkContext));
chppTransportInit(&mTransportContext, &mAppContext, &mLinkContext,
&gLinkApi);
chppAppInitWithClientServiceSet(&mAppContext, &mTransportContext,
@@ -96,19 +98,24 @@ class FakeLinkSyncTests : public testing::Test {
mWorkThread = std::thread(chppWorkThreadStart, &mTransportContext);
// Proceed to the initialized state by performing the CHPP 3-way handshake
+ CHPP_LOGI("Send a RESET packet");
ASSERT_TRUE(mFakeLink->waitForTxPacket());
std::vector<uint8_t> resetPkt = mFakeLink->popTxPacket();
ASSERT_TRUE(comparePacket(resetPkt, generateResetPacket()))
<< "Full packet: " << asResetPacket(resetPkt);
+ CHPP_LOGI("Receive a RESET ACK packet");
ChppResetPacket resetAck = generateResetAckPacket();
chppRxDataCb(&mTransportContext, reinterpret_cast<uint8_t *>(&resetAck),
sizeof(resetAck));
+ // chppProcessResetAck() results in sending a no error packet.
+ CHPP_LOGI("Send CHPP_TRANSPORT_ERROR_NONE packet");
ASSERT_TRUE(mFakeLink->waitForTxPacket());
std::vector<uint8_t> ackPkt = mFakeLink->popTxPacket();
ASSERT_TRUE(comparePacket(ackPkt, generateEmptyPacket()))
<< "Full packet: " << asChpp(ackPkt);
+ CHPP_LOGI("CHPP handshake complete");
}
void TearDown() override {
@@ -127,7 +134,7 @@ class FakeLinkSyncTests : public testing::Test {
ChppTransportState mTransportContext = {};
ChppAppState mAppContext = {};
- ChppTestLinkState mLinkContext = {};
+ ChppTestLinkState mLinkContext;
FakeLink *mFakeLink;
std::thread mWorkThread;
};
@@ -139,6 +146,7 @@ TEST_F(FakeLinkSyncTests, CheckRetryOnTimeout) {
std::vector<uint8_t> pkt1 = mFakeLink->popTxPacket();
+ // Not calling chppRxDataCb() will result in a timeout.
// Ideally, to speed up the test, we'd have a mechanism to trigger
// chppNotifierWait() to return immediately, to simulate timeout
ASSERT_TRUE(mFakeLink->waitForTxPacket());
diff --git a/chpp/test/transport_test.cpp b/chpp/test/transport_test.cpp
index 2ef0bed0..f1defb39 100644
--- a/chpp/test/transport_test.cpp
+++ b/chpp/test/transport_test.cpp
@@ -83,7 +83,7 @@ class TransportTests : public testing::TestWithParam<int> {
mTransportContext.resetState = CHPP_RESET_STATE_NONE;
// Make sure CHPP has a correct count of the number of registered services
- // on this platform, (in this case, 1,) as registered in the function
+ // on this platform as registered in the function
// chppRegisterCommonServices().
ASSERT_EQ(mAppContext.registeredServiceCount, kServiceCount);
}
@@ -108,7 +108,7 @@ void WaitForTransport(struct ChppTransportState *transportContext) {
// Start sending data out.
cycleSendThread();
// Wait for data to be received and processed.
- std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
// Should have reset loc and length for next packet / datagram
EXPECT_EQ(transportContext->rxStatus.locInDatagram, 0);
diff --git a/chpp/transport.c b/chpp/transport.c
index 14001cfe..53687c03 100644
--- a/chpp/transport.c
+++ b/chpp/transport.c
@@ -31,6 +31,7 @@
#include "chpp/macros.h"
#include "chpp/memory.h"
#include "chpp/platform/platform_link.h"
+#include "chpp/services.h"
#include "chpp/time.h"
/************************************************
@@ -73,6 +74,7 @@ static struct ChppTransportHeader *chppAddHeader(
struct ChppTransportState *context);
static void chppAddPayload(struct ChppTransportState *context);
static void chppAddFooter(struct ChppTransportState *context);
+// Can not be static (used in tests).
size_t chppDequeueTxDatagram(struct ChppTransportState *context);
static void chppClearTxDatagramQueue(struct ChppTransportState *context);
static void chppTransportDoWork(struct ChppTransportState *context);
@@ -81,35 +83,53 @@ static void chppAppendToPendingTxPacket(struct ChppTransportState *context,
static const char *chppGetPacketAttrStr(uint8_t packetCode);
static bool chppEnqueueTxDatagram(struct ChppTransportState *context,
uint8_t packetCode, void *buf, size_t len);
-enum ChppLinkErrorCode chppSendPendingPacket(
+static enum ChppLinkErrorCode chppSendPendingPacket(
struct ChppTransportState *context);
static void chppResetTransportContext(struct ChppTransportState *context);
static void chppReset(struct ChppTransportState *context,
enum ChppTransportPacketAttributes resetType,
enum ChppTransportErrorCode error);
-#ifdef CHPP_CLIENT_ENABLED
-struct ChppAppHeader *chppTransportGetClientRequestTimeoutResponse(
- struct ChppTransportState *context);
-#endif
+struct ChppAppHeader *chppTransportGetRequestTimeoutResponse(
+ struct ChppTransportState *context, enum ChppEndpointType type);
+static const char *chppGetRxStatusLabel(enum ChppRxState state);
+static void chppWorkHandleTimeout(struct ChppTransportState *context);
/************************************************
* Private Functions
***********************************************/
+/** Returns a string representation of the passed ChppRxState */
+static const char *chppGetRxStatusLabel(enum ChppRxState state) {
+ switch (state) {
+ case CHPP_STATE_PREAMBLE:
+ return "PREAMBLE (0)";
+ case CHPP_STATE_HEADER:
+ return "HEADER (1)";
+ case CHPP_STATE_PAYLOAD:
+ return "PAYLOAD (2)";
+ case CHPP_STATE_FOOTER:
+ return "FOOTER (3)";
+ }
+
+ return "invalid";
+}
+
/**
* Called any time the Rx state needs to be changed. Ensures that the location
* counter among that state (rxStatus.locInState) is also reset at the same
* time.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
* @param newState Next Rx state.
*/
static void chppSetRxState(struct ChppTransportState *context,
enum ChppRxState newState) {
- CHPP_LOGD("Changing RX transport state from %" PRIu8 " to %" PRIu8
- " after %" PRIuSIZE " bytes",
- context->rxStatus.state, newState, context->rxStatus.locInState);
+ CHPP_LOGD(
+ "Changing RX transport state from %s to %s"
+ " after %" PRIuSIZE " bytes",
+ chppGetRxStatusLabel(context->rxStatus.state),
+ chppGetRxStatusLabel(newState), context->rxStatus.locInState);
context->rxStatus.locInState = 0;
context->rxStatus.state = newState;
}
@@ -122,7 +142,7 @@ static void chppSetRxState(struct ChppTransportState *context,
* Any future backwards-incompatible versions of CHPP Transport will use a
* different preamble.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
* @param buf Input data.
* @param len Length of input data in bytes.
*
@@ -169,7 +189,7 @@ static size_t chppConsumePreamble(struct ChppTransportState *context,
* stream.
* Moves the Rx state to CHPP_STATE_PAYLOAD afterwards.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
* @param buf Input data.
* @param len Length of input data in bytes.
*
@@ -235,7 +255,7 @@ static size_t chppConsumeHeader(struct ChppTransportState *context,
* by the header, from the incoming data stream.
* Moves the Rx state to CHPP_STATE_FOOTER afterwards.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
* @param buf Input data
* @param len Length of input data in bytes
*
@@ -264,7 +284,7 @@ static size_t chppConsumePayload(struct ChppTransportState *context,
* stream. Checks checksum, triggering the correct response (ACK / NACK).
* Moves the Rx state to CHPP_STATE_PREAMBLE afterwards.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
* @param buf Input data.
* @param len Length of input data in bytes.
*
@@ -361,7 +381,7 @@ static size_t chppConsumeFooter(struct ChppTransportState *context,
* Discards of an incomplete Rx packet during receive (e.g. due to a timeout or
* bad checksum).
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
static void chppAbortRxPacket(struct ChppTransportState *context) {
size_t undoLen = 0;
@@ -422,7 +442,7 @@ static void chppAbortRxPacket(struct ChppTransportState *context) {
/**
* Processes a request that is determined to be for a transport-layer loopback.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
#ifdef CHPP_SERVICE_ENABLED_TRANSPORT_LOOPBACK
static void chppProcessTransportLoopbackRequest(
@@ -467,7 +487,7 @@ static void chppProcessTransportLoopbackRequest(
/**
* Processes a response that is determined to be for a transport-layer loopback.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
#ifdef CHPP_CLIENT_ENABLED_TRANSPORT_LOOPBACK
static void chppProcessTransportLoopbackResponse(
@@ -504,7 +524,7 @@ static void chppProcessTransportLoopbackResponse(
/**
* Method to invoke when the reset sequence is completed.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
static void chppSetResetComplete(struct ChppTransportState *context) {
context->resetState = CHPP_RESET_STATE_NONE;
@@ -516,7 +536,7 @@ static void chppSetResetComplete(struct ChppTransportState *context) {
* An incoming reset-ack packet indicates that a reset is complete at the other
* end of the CHPP link.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
static void chppProcessResetAck(struct ChppTransportState *context) {
if (context->resetState == CHPP_RESET_STATE_NONE) {
@@ -564,7 +584,7 @@ static void chppProcessResetAck(struct ChppTransportState *context) {
/**
* Process a received, checksum-validated packet.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
static void chppProcessRxPacket(struct ChppTransportState *context) {
uint64_t now = chppGetCurrentTimeNs();
@@ -611,7 +631,7 @@ static void chppProcessRxPacket(struct ChppTransportState *context) {
* Process the payload of a validated payload-bearing packet and send out the
* ACK.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
static void chppProcessRxPayload(struct ChppTransportState *context) {
context->rxStatus.expectedSeq++; // chppProcessRxPacket() already confirms
@@ -657,7 +677,7 @@ static void chppProcessRxPayload(struct ChppTransportState *context) {
* layer to inform the transport layer using chppDatagramProcessDoneCb() once it
* is done with the buffer so it is freed.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
static void chppClearRxDatagram(struct ChppTransportState *context) {
context->rxStatus.locInDatagram = 0;
@@ -668,7 +688,7 @@ static void chppClearRxDatagram(struct ChppTransportState *context) {
/**
* Validates the checksum of an incoming packet.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*
* @return True if and only if the checksum is correct.
*/
@@ -696,7 +716,7 @@ static bool chppRxChecksumIsOk(const struct ChppTransportState *context) {
* Performs consistency checks on received packet header to determine if it is
* obviously corrupt / invalid / duplicate / out-of-order.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*
* @return True if and only if header passes checks
*/
@@ -722,7 +742,7 @@ static enum ChppTransportErrorCode chppRxHeaderCheck(
* Registers a received ACK. If an outgoing datagram is fully ACKed, it is
* popped from the TX queue.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
static void chppRegisterRxAck(struct ChppTransportState *context) {
uint8_t rxAckSeq = context->rxHeader.ackSeq;
@@ -789,7 +809,7 @@ static void chppRegisterRxAck(struct ChppTransportState *context) {
* would only need to send an ACK for the last (correct) packet, hence we only
* need a queue length of one here.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
* @param packetCode Error code and packet attributes to be sent.
*/
static void chppEnqueueTxPacket(struct ChppTransportState *context,
@@ -820,7 +840,7 @@ static size_t chppAddPreamble(uint8_t *buf) {
/**
* Adds the packet header to link tx buffer.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*
* @return Pointer to the added packet header.
*/
@@ -844,7 +864,7 @@ static struct ChppTransportHeader *chppAddHeader(
/**
* Adds the packet payload to link tx buffer.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
static void chppAddPayload(struct ChppTransportState *context) {
uint8_t *linkTxBuffer = context->linkApi->getTxBuffer(context->linkContext);
@@ -884,7 +904,7 @@ static void chppAddPayload(struct ChppTransportState *context) {
/**
* Adds a footer (containing the checksum) to a packet.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
static void chppAddFooter(struct ChppTransportState *context) {
struct ChppTransportFooter footer;
@@ -906,7 +926,7 @@ static void chppAddFooter(struct ChppTransportState *context) {
* Dequeues the datagram at the front of the datagram tx queue, if any, and
* frees the payload. Returns the number of remaining datagrams in the queue.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
* @return Number of remaining datagrams in queue.
*/
size_t chppDequeueTxDatagram(struct ChppTransportState *context) {
@@ -939,7 +959,7 @@ size_t chppDequeueTxDatagram(struct ChppTransportState *context) {
/**
* Flushes the Tx datagram queue of any pending packets.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
static void chppClearTxDatagramQueue(struct ChppTransportState *context) {
while (context->txDatagramQueue.pending > 0) {
@@ -959,7 +979,7 @@ static void chppClearTxDatagramQueue(struct ChppTransportState *context) {
* Repeat payload: If we haven't received an ACK yet for our previous payload,
* i.e. we have registered an explicit or implicit NACK.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
static void chppTransportDoWork(struct ChppTransportState *context) {
bool havePacketForLinkLayer = false;
@@ -1021,10 +1041,11 @@ static void chppTransportDoWork(struct ChppTransportState *context) {
} else {
CHPP_LOGW(
"DoWork nothing to send. hasPackets=%d, linkBusy=%d, pending=%" PRIu8
- ", RX ACK=%" PRIu8 ", TX seq=%" PRIu8 ", RX state=%" PRIu8,
+ ", RX ACK=%" PRIu8 ", TX seq=%" PRIu8 ", RX state=%s",
context->txStatus.hasPacketsToSend, context->txStatus.linkBusy,
context->txDatagramQueue.pending, context->rxStatus.receivedAckSeq,
- context->txStatus.sentSeq, context->rxStatus.state);
+ context->txStatus.sentSeq,
+ chppGetRxStatusLabel(context->rxStatus.state));
}
chppMutexUnlock(&context->mutex);
@@ -1049,7 +1070,7 @@ static void chppTransportDoWork(struct ChppTransportState *context) {
#ifdef CHPP_CLIENT_ENABLED
{ // create a scope to declare timeoutResponse (C89).
struct ChppAppHeader *timeoutResponse =
- chppTransportGetClientRequestTimeoutResponse(context);
+ chppTransportGetRequestTimeoutResponse(context, CHPP_ENDPOINT_CLIENT);
if (timeoutResponse != NULL) {
CHPP_LOGE("Response timeout H#%" PRIu8 " cmd=%" PRIu16 " ID=%" PRIu8,
@@ -1060,13 +1081,27 @@ static void chppTransportDoWork(struct ChppTransportState *context) {
}
}
#endif // CHPP_CLIENT_ENABLED
+#ifdef CHPP_SERVICE_ENABLED
+ { // create a scope to declare timeoutResponse (C89).
+ struct ChppAppHeader *timeoutResponse =
+ chppTransportGetRequestTimeoutResponse(context, CHPP_ENDPOINT_SERVICE);
+
+ if (timeoutResponse != NULL) {
+ CHPP_LOGE("Response timeout H#%" PRIu8 " cmd=%" PRIu16 " ID=%" PRIu8,
+ timeoutResponse->handle, timeoutResponse->command,
+ timeoutResponse->transaction);
+ chppAppProcessRxDatagram(context->appContext, (uint8_t *)timeoutResponse,
+ sizeof(struct ChppAppHeader));
+ }
+ }
+#endif // CHPP_SERVICE_ENABLED
}
/**
* Appends data from a buffer of length len to a link tx buffer, updating its
* length.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
* @param buf Input data to be copied from.
* @param len Length of input data in bytes.
*/
@@ -1109,7 +1144,7 @@ static const char *chppGetPacketAttrStr(uint8_t packetCode) {
* If enqueueing is unsuccessful, it is up to the caller to decide when or if
* to free the payload and/or resend it later.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
* @param packetCode Error code and packet attributes to be sent.
* @param buf Datagram payload allocated through chppMalloc. Cannot be null.
* @param len Datagram length in bytes.
@@ -1171,11 +1206,11 @@ static bool chppEnqueueTxDatagram(struct ChppTransportState *context,
* Sends the pending outgoing packet over to the link
* layer using Send() and updates the last Tx packet time.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*
* @return Result of Send().
*/
-enum ChppLinkErrorCode chppSendPendingPacket(
+static enum ChppLinkErrorCode chppSendPendingPacket(
struct ChppTransportState *context) {
enum ChppLinkErrorCode error =
context->linkApi->send(context->linkContext, context->linkBufferSize);
@@ -1188,7 +1223,7 @@ enum ChppLinkErrorCode chppSendPendingPacket(
/**
* Resets the transport state, maintaining the link layer parameters.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
*/
static void chppResetTransportContext(struct ChppTransportState *context) {
memset(&context->rxStatus, 0, sizeof(struct ChppRxStatus));
@@ -1212,7 +1247,7 @@ static void chppResetTransportContext(struct ChppTransportState *context) {
* This function retains and restores the platform-specific values of
* transportContext.linkContext.
*
- * @param transportContext Maintains state for each transport layer instance.
+ * @param transportContext State of the transport layer.
* @param resetType Type of reset to send after resetting CHPP (reset vs.
* reset-ack), as defined in the ChppTransportPacketAttributes struct.
* @param error Provides the error that led to the reset.
@@ -1266,68 +1301,74 @@ static void chppReset(struct ChppTransportState *transportContext,
}
/**
- * Checks for a timed out client request and generates a timeout response if a
- * client request timeout has occurred.
+ * Checks for a timed out request and generates a timeout response if a timeout
+ * has occurred.
*
- * @param context Maintains state for each transport layer instance.
+ * @param context State of the transport layer.
+ * @param type The type of the endpoint.
* @return App layer response header if a timeout has occurred. Null otherwise.
*/
-#ifdef CHPP_CLIENT_ENABLED
-struct ChppAppHeader *chppTransportGetClientRequestTimeoutResponse(
- struct ChppTransportState *context) {
+struct ChppAppHeader *chppTransportGetRequestTimeoutResponse(
+ struct ChppTransportState *context, enum ChppEndpointType type) {
+ CHPP_DEBUG_NOT_NULL(context);
+
+ struct ChppAppState *appState = context->appContext;
struct ChppAppHeader *response = NULL;
- bool timeoutClientFound = false;
- uint8_t timedOutClient;
+ bool timeoutEndpointFound = false;
+ uint8_t timedOutEndpointIdx;
uint16_t timedOutCmd;
chppMutexLock(&context->mutex);
- if (context->appContext->nextRequestTimeoutNs <= chppGetCurrentTimeNs()) {
+ if (*getNextRequestTimeoutNs(appState, type) <= chppGetCurrentTimeNs()) {
// Determine which request has timed out
-
- uint64_t lowestTimeout = CHPP_TIME_MAX;
- for (uint8_t clientIdx = 0;
- clientIdx < context->appContext->registeredClientCount; clientIdx++) {
- for (uint16_t cmdIdx = 0;
- cmdIdx <
- context->appContext->registeredClients[clientIdx]->rRStateCount;
- cmdIdx++) {
- struct ChppRequestResponseState *rRState =
- &context->appContext->registeredClientStates[clientIdx]
- ->rRStates[cmdIdx];
-
- if (rRState->requestState == CHPP_REQUEST_STATE_REQUEST_SENT &&
- rRState->responseTimeNs != CHPP_TIME_NONE &&
- rRState->responseTimeNs < lowestTimeout) {
- lowestTimeout = rRState->responseTimeNs;
- timedOutClient = clientIdx;
+ const uint8_t endpointCount = getRegisteredEndpointCount(appState, type);
+ uint64_t firstTimeout = CHPP_TIME_MAX;
+
+ for (uint8_t endpointIdx = 0; endpointIdx < endpointCount; endpointIdx++) {
+ const uint16_t cmdCount =
+ getRegisteredEndpointOutReqCount(appState, endpointIdx, type);
+ const struct ChppEndpointState *endpointState =
+ getRegisteredEndpointState(appState, endpointIdx, type);
+ const struct ChppOutgoingRequestState *reqStates =
+ &endpointState->outReqStates[0];
+ for (uint16_t cmdIdx = 0; cmdIdx < cmdCount; cmdIdx++) {
+ const struct ChppOutgoingRequestState *reqState = &reqStates[cmdIdx];
+
+ if (reqState->requestState == CHPP_REQUEST_STATE_REQUEST_SENT &&
+ reqState->responseTimeNs != CHPP_TIME_NONE &&
+ reqState->responseTimeNs < firstTimeout) {
+ firstTimeout = reqState->responseTimeNs;
+ timedOutEndpointIdx = endpointIdx;
timedOutCmd = cmdIdx;
- timeoutClientFound = true;
+ timeoutEndpointFound = true;
}
}
}
- if (!timeoutClientFound) {
- CHPP_LOGE("Timeout at %" PRIu64 " but no client",
- context->appContext->nextRequestTimeoutNs / CHPP_NSEC_PER_MSEC);
- chppClientRecalculateNextTimeout(context->appContext);
+ if (!timeoutEndpointFound) {
+ CHPP_LOGE("Timeout at %" PRIu64 " but no endpoint",
+ *getNextRequestTimeoutNs(appState, type) / CHPP_NSEC_PER_MSEC);
+ chppRecalculateNextTimeout(appState, CHPP_ENDPOINT_CLIENT);
}
}
- if (timeoutClientFound) {
- CHPP_LOGE("Client=%" PRIu8 " cmd=%" PRIu16 " timed out", timedOutClient,
- timedOutCmd);
+ if (timeoutEndpointFound) {
+ CHPP_LOGE("Endpoint=%" PRIu8 " cmd=%" PRIu16 " timed out",
+ timedOutEndpointIdx, timedOutCmd);
response = chppMalloc(sizeof(struct ChppAppHeader));
if (response == NULL) {
CHPP_LOG_OOM();
} else {
- response->handle = CHPP_SERVICE_HANDLE_OF_INDEX(timedOutClient);
- response->type = CHPP_MESSAGE_TYPE_SERVICE_RESPONSE;
+ const struct ChppEndpointState *endpointState =
+ getRegisteredEndpointState(appState, timedOutEndpointIdx, type);
+ response->handle = endpointState->handle;
+ response->type = type == CHPP_ENDPOINT_CLIENT
+ ? CHPP_MESSAGE_TYPE_SERVICE_RESPONSE
+ : CHPP_MESSAGE_TYPE_CLIENT_RESPONSE;
response->transaction =
- context->appContext->registeredClientStates[timedOutClient]
- ->rRStates[timedOutCmd]
- .transaction;
+ endpointState->outReqStates[timedOutCmd].transaction;
response->error = CHPP_APP_ERROR_TIMEOUT;
response->command = timedOutCmd;
}
@@ -1337,7 +1378,6 @@ struct ChppAppHeader *chppTransportGetClientRequestTimeoutResponse(
return response;
}
-#endif
/************************************************
* Public Functions
@@ -1437,8 +1477,8 @@ bool chppRxDataCb(struct ChppTransportState *context, const uint8_t *buf,
}
chppMutexUnlock(&context->mutex);
- CHPP_LOGD("RX %" PRIuSIZE " bytes: state=%" PRIu8, len,
- context->rxStatus.state);
+ CHPP_LOGD("RX %" PRIuSIZE " bytes: state=%s", len,
+ chppGetRxStatusLabel(context->rxStatus.state));
uint64_t now = chppGetCurrentTimeNs();
context->rxStatus.lastDataTimeMs = (uint32_t)(now / CHPP_NSEC_PER_MSEC);
context->rxStatus.numTotalDataBytes += len;
@@ -1485,10 +1525,9 @@ bool chppRxDataCb(struct ChppTransportState *context, const uint8_t *buf,
void chppRxPacketCompleteCb(struct ChppTransportState *context) {
chppMutexLock(&context->mutex);
if (context->rxStatus.state != CHPP_STATE_PREAMBLE) {
- CHPP_LOGE("RX pkt ended early: state=%" PRIu8 " seq=%" PRIu8
- " len=%" PRIu16,
- context->rxStatus.state, context->rxHeader.seq,
- context->rxHeader.length);
+ CHPP_LOGE("RX pkt ended early: state=%s seq=%" PRIu8 " len=%" PRIu16,
+ chppGetRxStatusLabel(context->rxStatus.state),
+ context->rxHeader.seq, context->rxHeader.length);
chppAbortRxPacket(context);
chppEnqueueTxPacket(context, CHPP_TRANSPORT_ERROR_HEADER); // NACK
}
@@ -1548,7 +1587,12 @@ void chppEnqueueTxErrorDatagram(struct ChppTransportState *context,
uint64_t chppTransportGetTimeUntilNextDoWorkNs(
struct ChppTransportState *context) {
uint64_t currentTime = chppGetCurrentTimeNs();
- uint64_t nextDoWorkTime = context->appContext->nextRequestTimeoutNs;
+ // This function is called in the context of the transport worker thread.
+ // As we do not know if the transport is used in the context of a service
+ // or a client, we use the min of both timeouts.
+ uint64_t nextDoWorkTime =
+ MIN(context->appContext->nextClientRequestTimeoutNs,
+ context->appContext->nextServiceRequestTimeoutNs);
if (context->txStatus.hasPacketsToSend ||
context->resetState == CHPP_RESET_STATE_RESETTING) {
@@ -1606,40 +1650,18 @@ bool chppWorkThreadHandleSignal(struct ChppTransportState *context,
CHPP_LOGD("CHPP Work Thread terminated");
} else {
continueProcessing = true;
- if (signals & CHPP_TRANSPORT_SIGNAL_EVENT) {
- chppTransportDoWork(context);
- }
-
if (signals == 0) {
- // Triggered by timeout
-
- if (chppGetCurrentTimeNs() - context->txStatus.lastTxTimeNs >=
- CHPP_TRANSPORT_TX_TIMEOUT_NS) {
- CHPP_LOGE("ACK timeout. Tx t=%" PRIu64,
- context->txStatus.lastTxTimeNs / CHPP_NSEC_PER_MSEC);
+ // Triggered by timeout.
+ chppWorkHandleTimeout(context);
+ } else {
+ if (signals & CHPP_TRANSPORT_SIGNAL_EVENT) {
chppTransportDoWork(context);
}
-
- if ((context->resetState == CHPP_RESET_STATE_RESETTING) &&
- (chppGetCurrentTimeNs() - context->resetTimeNs >=
- CHPP_TRANSPORT_RESET_TIMEOUT_NS)) {
- if (context->resetCount + 1 < CHPP_TRANSPORT_MAX_RESET) {
- CHPP_LOGE("RESET-ACK timeout; retrying");
- context->resetCount++;
- chppReset(context, CHPP_TRANSPORT_ATTR_RESET,
- CHPP_TRANSPORT_ERROR_TIMEOUT);
- } else {
- CHPP_LOGE("RESET-ACK timeout; giving up");
- context->resetState = CHPP_RESET_STATE_PERMANENT_FAILURE;
- chppClearTxDatagramQueue(context);
- }
+ if (signals & CHPP_TRANSPORT_SIGNAL_PLATFORM_MASK) {
+ context->linkApi->doWork(context->linkContext,
+ signals & CHPP_TRANSPORT_SIGNAL_PLATFORM_MASK);
}
}
-
- if (signals & CHPP_TRANSPORT_SIGNAL_PLATFORM_MASK) {
- context->linkApi->doWork(context->linkContext,
- signals & CHPP_TRANSPORT_SIGNAL_PLATFORM_MASK);
- }
}
#ifdef CHPP_ENABLE_WORK_MONITOR
@@ -1649,6 +1671,55 @@ bool chppWorkThreadHandleSignal(struct ChppTransportState *context,
return continueProcessing;
}
+/**
+ * Handle timeouts in the worker thread.
+ *
+ * Timeouts occurs when either:
+ * 1. There are packets to send and last packet send was more than
+ * CHPP_TRANSPORT_TX_TIMEOUT_NS ago
+ * 2. We haven't received a response to a request in time
+ * 3. We haven't received the reset ACK
+ *
+ * For 1 and 2, chppTransportDoWork should be called to respectively
+ * - Transmit the packet
+ * - Send a timeout response
+ */
+static void chppWorkHandleTimeout(struct ChppTransportState *context) {
+ const uint64_t currentTimeNs = chppGetCurrentTimeNs();
+ const bool isTxTimeout = currentTimeNs - context->txStatus.lastTxTimeNs >=
+ CHPP_TRANSPORT_TX_TIMEOUT_NS;
+
+ // Call chppTransportDoWork for both TX and request timeouts.
+ if (isTxTimeout) {
+ CHPP_LOGE("ACK timeout. Tx t=%" PRIu64,
+ context->txStatus.lastTxTimeNs / CHPP_NSEC_PER_MSEC);
+ chppTransportDoWork(context);
+ } else {
+ const uint64_t requestTimeoutNs =
+ MIN(context->appContext->nextClientRequestTimeoutNs,
+ context->appContext->nextServiceRequestTimeoutNs);
+ const bool isRequestTimeout = requestTimeoutNs <= currentTimeNs;
+ if (isRequestTimeout) {
+ chppTransportDoWork(context);
+ }
+ }
+
+ if ((context->resetState == CHPP_RESET_STATE_RESETTING) &&
+ (currentTimeNs - context->resetTimeNs >=
+ CHPP_TRANSPORT_RESET_TIMEOUT_NS)) {
+ if (context->resetCount + 1 < CHPP_TRANSPORT_MAX_RESET) {
+ CHPP_LOGE("RESET-ACK timeout; retrying");
+ context->resetCount++;
+ chppReset(context, CHPP_TRANSPORT_ATTR_RESET,
+ CHPP_TRANSPORT_ERROR_TIMEOUT);
+ } else {
+ CHPP_LOGE("RESET-ACK timeout; giving up");
+ context->resetState = CHPP_RESET_STATE_PERMANENT_FAILURE;
+ chppClearTxDatagramQueue(context);
+ }
+ }
+}
+
void chppWorkThreadStop(struct ChppTransportState *context) {
chppNotifierSignal(&context->notifier, CHPP_TRANSPORT_SIGNAL_EXIT);
}
diff --git a/chre_api/archive_chre_api.sh b/chre_api/archive_chre_api.sh
index b6c36a50..2d23107e 100755
--- a/chre_api/archive_chre_api.sh
+++ b/chre_api/archive_chre_api.sh
@@ -3,18 +3,28 @@
# Quit if any command produces an error.
set -e
-# Parse variables
-MAJOR_VERSION=$1
-: ${MAJOR_VERSION:?
- "You must specify the major version of the API to be archived."
- "Usage ./archive_chre_api.sh <major_version> <minor_version>"}
+VERSION_FILE=include/chre_api/chre/version.h
-MINOR_VERSION=$2
-: ${MINOR_VERSION:?
- "You must specify the minor version of the API to be archived."
- "Usage ./archive_chre_api.sh <major_version> <minor_version>"}
+# Get the latest API version
+CURRENT_VERSION=$(grep -E "^\#define CHRE_API_VERSION CHRE_API_VERSION_[0-9]+" $VERSION_FILE)
+MAJOR_VERSION=$(echo $CURRENT_VERSION | cut -d "_" -f 6)
+MINOR_VERSION=$(echo $CURRENT_VERSION | cut -d "_" -f 7)
+ARCHIVE_DIRECTORY=v${MAJOR_VERSION}_${MINOR_VERSION}
+mkdir legacy/$ARCHIVE_DIRECTORY
+cp -r include/chre_api/* legacy/$ARCHIVE_DIRECTORY
-DIRECTORY=v${MAJOR_VERSION}_${MINOR_VERSION}
+ARCHIVED_VERSION=$(grep -n "^\#define CHRE_API_VERSION_${MAJOR_VERSION}_${MINOR_VERSION}" $VERSION_FILE)
+LINE_NUMBER=$(($(echo $ARCHIVED_VERSION | cut -d ":" -f 1) + 2))
+ARCHIVED_VERSION=$(echo $ARCHIVED_VERSION | cut -d ":" -f 2)
-mkdir legacy/$DIRECTORY
-cp -r include/chre_api/* legacy/$DIRECTORY
+HEX_VERSION=$(echo $(echo $(echo $ARCHIVED_VERSION | cut -d "(" -f 2) | cut -d ")" -f 1) | cut -d "x" -f 2)
+HEX_VERSION=$((16#$HEX_VERSION))
+BITSHIFT=$(($MINOR_VERSION << 16))
+HEX_VERSION=$(($HEX_VERSION - $BITSHIFT))
+MINOR_VERSION=$(($MINOR_VERSION + 1))
+BITSHIFT=$(($MINOR_VERSION<< 16));
+HEX_VERSION=$(($HEX_VERSION + $BITSHIFT))
+HEX_VERSION=$(printf "%x" $HEX_VERSION)
+
+sed -i "${LINE_NUMBER}i#define CHRE_API_VERSION_${MAJOR_VERSION}_${MINOR_VERSION} UINT32_C(0x0${HEX_VERSION})\n" $VERSION_FILE
+sed -i "s/${CURRENT_VERSION}/\#define CHRE_API_VERSION CHRE_API_VERSION_${MAJOR_VERSION}_${MINOR_VERSION}/g" $VERSION_FILE
diff --git a/chre_api/include/chre_api/chre/audio.h b/chre_api/include/chre_api/chre/audio.h
index e8ec9607..085329ec 100644
--- a/chre_api/include/chre_api/chre/audio.h
+++ b/chre_api/include/chre_api/chre/audio.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef _CHRE_AUDIO_H_
#define _CHRE_AUDIO_H_
diff --git a/chre_api/include/chre_api/chre/ble.h b/chre_api/include/chre_api/chre/ble.h
index 9f049647..701fbc23 100644
--- a/chre_api/include/chre_api/chre/ble.h
+++ b/chre_api/include/chre_api/chre/ble.h
@@ -13,6 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef CHRE_BLE_H_
#define CHRE_BLE_H_
@@ -89,6 +93,11 @@ extern "C" {
//! CHRE BLE supports RSSI filters
#define CHRE_BLE_FILTER_CAPABILITIES_RSSI UINT32_C(1 << 1)
+//! CHRE BLE supports Broadcaster Address filters (Corresponding HCI OCF:
+//! 0x0157, Sub-command: 0x02)
+//! @since v1.9
+#define CHRE_BLE_FILTER_CAPABILITIES_BROADCASTER_ADDRESS UINT32_C(1 << 2)
+
//! CHRE BLE supports Manufacturer Data filters (Corresponding HCI OCF: 0x0157,
//! Sub-command: 0x06)
//! @since v1.8
@@ -306,11 +315,6 @@ enum chreBleScanMode {
*/
enum chreBleAdType {
//! Service Data with 16-bit UUID
- //! @deprecated as of v1.8
- //! TODO(b/285207430): Remove this enum once CHRE has been updated.
- CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16 = 0x16,
-
- //! Service Data with 16-bit UUID
//! @since v1.8 CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16 was renamed
//! CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE to reflect that nanoapps
//! compiled against v1.8+ should use OTA format for service data filters.
@@ -322,42 +326,34 @@ enum chreBleAdType {
};
/**
- * Generic scan filters definition based on AD Type, mask, and values. The
- * maximum data length is limited to the maximum possible legacy advertisement
- * payload data length (29 bytes).
- *
- * The filter is matched when
- * data & dataMask == advData & dataMask
- * where advData is the advertisement packet data for the specified AD type.
+ * Generic filters are used to filter for the presence of AD structures in the
+ * data field of LE Extended Advertising Report events (ref: BT Core Spec v5.3,
+ * Vol 3, Part E, Section 11).
*
* The CHRE generic filter structure represents a generic filter on an AD Type
* as defined in the Bluetooth spec Assigned Numbers, Generic Access Profile
* (ref: https://www.bluetooth.com/specifications/assigned-numbers/). This
- * generic structure is used by the Advertising Packet Content Filter
- * (APCF) HCI generic AD type sub-command 0x09 (ref:
- * https://source.android.com/devices/bluetooth/hci_requirements#le_apcf_command).
+ * generic structure is used by the Android HCI Advertising Packet Content
+ * Filter (APCF) AD Type sub-command 0x09 (ref:
+ * https://source.android.com/docs/core/connect/bluetooth/hci_requirements#le_apcf_command-ad_type_sub_cmd).
+ *
+ * The filter is matched when an advertisement event contains an AD structure in
+ * its data field that matches the following criteria:
+ * AdStructure.type == type
+ * AdStructure.data & dataMask == data & dataMask
+ *
+ * The maximum data length is limited to the maximum possible legacy
+ * advertisement payload data length (29 bytes). The data and dataMask must be
+ * in OTA format. For each zero bit of the dataMask, the corresponding
+ * data bit must also be zero.
*
* Note that the CHRE implementation may not support every kind of filter that
* can be represented by this structure. Use chreBleGetFilterCapabilities() to
* discover supported filtering capabilities at runtime.
*
- * @since v1.8 The data and dataMask must be in OTA format. The nanoapp support
- * library will handle converting the data and dataMask values to the correct
- * format if a pre v1.8 version of CHRE is running.
- *
- * NOTE: CHRE versions 1.6 and 1.7 expect the 2-byte UUID prefix in
- * CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16 to be given as big-endian. This
- * was corrected in v1.8 to match the OTA format and Bluetooth specification,
- * which uses little-endian. This enum has been removed and replaced with
- * CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE to ensure that nanoapps
- * compiled against v1.8 and later specify their UUID filter using
- * little-endian. Nanoapps compiled against v1.7 or earlier should continue to
- * use big-endian, as CHRE must provide cross-version compatibility for all
- * possible version combinations.
- *
* Example 1: To filter on a 16 bit service data UUID of 0xFE2C, the following
* settings would be used:
- * type = CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16
+ * type = CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE
* len = 2
* data = {0x2C, 0xFE}
* dataMask = {0xFF, 0xFF}
@@ -390,25 +386,43 @@ struct chreBleGenericFilter {
};
/**
- * CHRE Bluetooth LE scan filters are based on a combination of an RSSI
- * threshold and generic scan filters as defined by AD Type, mask, and values.
+ * Broadcaster address filters are used to filter by the address field of the LE
+ * Extended Advertising Report event which is defined in the BT Core Spec v5.3,
+ * Vol 4, Part E, Section 7.7.65.13.
*
- * CHRE-provided filters are implemented in a best-effort manner, depending on
- * HW capabilities of the system and available resources. Therefore, provided
- * scan results may be a superset of the specified filters. Nanoapps should try
- * to take advantage of CHRE scan filters as much as possible, but must design
- * their logic as to not depend on CHRE filtering.
+ * The CHRE broadcaster address filter structure is modeled after the
+ * Advertising Packet Content Filter (APCF) HCI broadcaster address sub-command
+ * 0x02 (ref:
+ * https://source.android.com/docs/core/connect/bluetooth/hci_requirements#le_apcf_command-broadcast_address_sub_cmd).
*
- * The syntax of CHRE scan filter definitions are based on the Android
- * Advertising Packet Content Filter (APCF) HCI requirement subtype 0x08
- * ref:
- * https://source.android.com/devices/bluetooth/hci_requirements#le_apcf_command-set_filtering_parameters_sub_cmd
- * and AD Types as defined in the Bluetooth spec Assigned Numbers, Generic
- * Access Profile
- * ref: https://www.bluetooth.com/specifications/assigned-numbers/
+ * The CHRE broadcaster address filter does not filter by address type at this
+ * time. If a nanoapp wants to filter for a particular address type, it must
+ * check the addressType field of the chreBleAdvertisingReport.
+ *
+ * NOTE: The broadcasterAddress (6-byte) must be in OTA format.
*
- * Even though the scan filters are defined in a generic manner, CHRE Bluetooth
- * is expected to initially support only a limited set of AD Types.
+ * The filter is matched when an advertisement even meets the following criteria:
+ * broadcasterAddress == chreBleAdvertisingReport.address.
+ *
+ * Example: To filter on the address (01:02:03:AB:CD:EF), the following
+ * settings would be used:
+ * broadcasterAddress = {0xEF, 0xCD, 0xAB, 0x03, 0x02, 0x01}
+ *
+ * @since v1.9
+ */
+struct chreBleBroadcasterAddressFilter {
+ //! 6-byte Broadcaster address
+ uint8_t broadcasterAddress[CHRE_BLE_ADDRESS_LEN];
+};
+
+/**
+ * CHRE Bluetooth LE scan filters.
+ *
+ * @see chreBleScanFilterV1_9 for further details.
+ *
+ * @deprecated as of v1.9 due to the addition of the
+ * chreBleBroadcasterAddressFilter. New code should use chreBleScanFilterV1_9
+ * instead of this struct. This struct will be removed in a future version.
*/
struct chreBleScanFilter {
//! RSSI threshold filter (Corresponding HCI OCF: 0x0157, Sub: 0x01), where
@@ -428,6 +442,60 @@ struct chreBleScanFilter {
};
/**
+ * CHRE Bluetooth LE scan filters are based on a combination of an RSSI
+ * threshold, generic filters, and broadcaster address filters.
+ *
+ * When multiple filters are specified, rssiThreshold is combined with the other
+ * filters via functional AND, and the other filters are all combined as
+ * functional OR. In other words, an advertisement matches the filter if:
+ * rssi >= rssiThreshold
+ * AND (matchAny(genericFilters) OR matchAny(broadcasterAddressFilters))
+ *
+ * CHRE-provided filters are implemented in a best-effort manner, depending on
+ * HW capabilities of the system and available resources. Therefore, provided
+ * scan results may be a superset of the specified filters. Nanoapps should try
+ * to take advantage of CHRE scan filters as much as possible, but must design
+ * their logic as to not depend on CHRE filtering.
+ *
+ * The syntax of CHRE scan filter definition is modeled after a combination of
+ * multiple Android HCI Advertising Packet Content Filter (APCF) sub commands
+ * including the RSSI threshold from the set filtering parameters sub command
+ * (ref:
+ * https://source.android.com/docs/core/connect/bluetooth/hci_requirements#le_apcf_command-set_filtering_parameters_sub_cmd).
+ * @see chreBleGenericFilter and chreBleBroadcasterAddressFilter for details
+ * about other APCF sub commands referenced.
+ *
+ * @since v1.9
+ */
+struct chreBleScanFilterV1_9 {
+ //! RSSI threshold filter (Corresponding HCI OCF: 0x0157, Sub: 0x01), where
+ //! advertisements with RSSI values below this threshold may be disregarded.
+ //! An rssiThreshold value of CHRE_BLE_RSSI_THRESHOLD_NONE indicates no RSSI
+ //! filtering.
+ int8_t rssiThreshold;
+
+ //! Number of generic filters provided in the scanFilters array. A
+ //! genericFilterCount value of 0 indicates no generic filters.
+ uint8_t genericFilterCount;
+
+ //! Pointer to an array of generic filters. If the array contains more than
+ //! one entry, advertisements matching any of the entries will be returned
+ //! (functional OR). This is expected to be null if genericFilterCount is 0.
+ const struct chreBleGenericFilter *genericFilters;
+
+ //! Number of broadcaster address filters provided in the
+ //! broadcasterAddressFilters array. A broadcasterAddressFilterCount value
+ //! of 0 indicates no broadcaster address filters.
+ uint8_t broadcasterAddressFilterCount;
+
+ //! Pointer to an array of broadcaster address filters. If the array contains
+ //! more than one entry, advertisements matching any of the entries will be
+ //! returned (functional OR). This is expected to be null if
+ //! broadcasterAddressFilterCount is 0.
+ const struct chreBleBroadcasterAddressFilter *broadcasterAddressFilters;
+};
+
+/**
* CHRE BLE advertising address type is based on the BT Core Spec v5.2, Vol 4,
* Part E, Section 7.7.65.13, LE Extended Advertising Report event,
* Address_Type.
@@ -685,6 +753,19 @@ static inline uint8_t chreBleGetEventTypeAndDataStatus(uint8_t eventType,
/**
* Start Bluetooth LE (BLE) scanning on CHRE.
*
+ * @see chreBleStartScanAsyncV1_9 for further details.
+ *
+ * @deprecated as of v1.9 due to the addition of the chreBleScanFilterV1_9
+ * struct and a cookie parameter. New code should use
+ * chreBleStartScanAsyncV1_9() instead of this function. This function will be
+ * removed in a future version.
+ */
+bool chreBleStartScanAsync(enum chreBleScanMode mode, uint32_t reportDelayMs,
+ const struct chreBleScanFilter *filter);
+
+/**
+ * Start Bluetooth LE (BLE) scanning on CHRE.
+ *
* The result of the operation will be delivered asynchronously via the CHRE
* event CHRE_EVENT_BLE_ASYNC_RESULT.
*
@@ -716,8 +797,8 @@ static inline uint8_t chreBleGetEventTypeAndDataStatus(uint8_t eventType,
* Legacy-only: false
* PHY type: PHY_LE_ALL_SUPPORTED
*
- * For v1.8 and greater, a CHRE_EVENT_BLE_SCAN_STATUS_CHANGE will be generated
- * if the values in chreBleScanStatus changes as a result of this call.
+ * A CHRE_EVENT_BLE_SCAN_STATUS_CHANGE will be generated if the values in
+ * chreBleScanStatus changes as a result of this call.
*
* @param mode Scanning mode selected among enum chreBleScanMode
* @param reportDelayMs Maximum requested batching delay in ms. 0 indicates no
@@ -727,24 +808,43 @@ static inline uint8_t chreBleGetEventTypeAndDataStatus(uint8_t eventType,
* defined by struct chreBleScanFilter. The ownership of filter
* and its nested elements remains with the caller, and the caller
* may release it as soon as chreBleStartScanAsync() returns.
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent as a response to this request.
*
* @return True to indicate that the request was accepted. False otherwise.
*
- * @since v1.6
+ * @since v1.9
*/
-bool chreBleStartScanAsync(enum chreBleScanMode mode, uint32_t reportDelayMs,
- const struct chreBleScanFilter *filter);
+bool chreBleStartScanAsyncV1_9(enum chreBleScanMode mode,
+ uint32_t reportDelayMs,
+ const struct chreBleScanFilterV1_9 *filter,
+ const void *cookie);
+
+/**
+ * Stops a CHRE BLE scan.
+ *
+ * @see chreBleStopScanAsyncV1_9 for further details.
+ *
+ * @deprecated as of v1.9 due to the addition of the cookie parameter. New code
+ * should use chreBleStopScanAsyncV1_9() instead of this function. This function
+ * will be removed in a future version.
+ */
+bool chreBleStopScanAsync(void);
+
/**
* Stops a CHRE BLE scan.
*
* The result of the operation will be delivered asynchronously via the CHRE
* event CHRE_EVENT_BLE_ASYNC_RESULT.
*
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent as a response to this request.
+ *
* @return True to indicate that the request was accepted. False otherwise.
*
- * @since v1.6
+ * @since v1.9
*/
-bool chreBleStopScanAsync(void);
+bool chreBleStopScanAsyncV1_9(const void *cookie);
/**
* Requests to immediately deliver batched scan results. The nanoapp must
diff --git a/chre_api/include/chre_api/chre/common.h b/chre_api/include/chre_api/chre/common.h
index 9e3378e0..3b270af5 100644
--- a/chre_api/include/chre_api/chre/common.h
+++ b/chre_api/include/chre_api/chre/common.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef _CHRE_COMMON_H_
#define _CHRE_COMMON_H_
@@ -121,7 +124,7 @@ enum chreError {
//!< Do not exceed this value when adding new error codes
CHRE_ERROR_LAST = UINT8_MAX,
};
-// LINT.ThenChange(core/include/chre/core/api_manager_common.h)
+// LINT.ThenChange(../../../../core/include/chre/core/api_manager_common.h)
/**
* Generic data structure to indicate the result of an asynchronous operation.
@@ -178,7 +181,8 @@ struct chreAsyncResult {
* @since v1.8
*/
struct chreBatchCompleteEvent {
- //! Indicates the type of event (of type CHRE_EVENT_TYPE_*) that was batched.
+ //! Indicates the type of event (of type CHRE_EVENT_TYPE_*) that was
+ //! batched.
uint16_t eventType;
//! Reserved for future use, set to 0
diff --git a/chre_api/include/chre_api/chre/event.h b/chre_api/include/chre_api/chre/event.h
index 04b2d0d8..f91ef062 100644
--- a/chre_api/include/chre_api/chre/event.h
+++ b/chre_api/include/chre_api/chre/event.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef _CHRE_EVENT_H_
#define _CHRE_EVENT_H_
@@ -508,19 +511,19 @@ struct chreHostEndpointNotification {
*/
//! The host endpoint is part of the Android system framework.
-#define CHRE_HOST_ENDPOINT_TYPE_FRAMEWORK UINT8_C(0)
+#define CHRE_HOST_ENDPOINT_TYPE_FRAMEWORK UINT8_C(0x00)
//! The host endpoint is an Android app.
-#define CHRE_HOST_ENDPOINT_TYPE_APP UINT8_C(1)
+#define CHRE_HOST_ENDPOINT_TYPE_APP UINT8_C(0x01)
//! The host endpoint is an Android native program.
-#define CHRE_HOST_ENDPOINT_TYPE_NATIVE UINT8_C(2)
+#define CHRE_HOST_ENDPOINT_TYPE_NATIVE UINT8_C(0x02)
//! Values in the range [CHRE_HOST_ENDPOINT_TYPE_VENDOR_START,
//! CHRE_HOST_ENDPOINT_TYPE_VENDOR_END] can be a custom defined host endpoint
//! type for platform-specific vendor use.
-#define CHRE_HOST_ENDPOINT_TYPE_VENDOR_START UINT8_C(128)
-#define CHRE_HOST_ENDPOINT_TYPE_VENDOR_END UINT8_C(255)
+#define CHRE_HOST_ENDPOINT_TYPE_VENDOR_START UINT8_C(0x80)
+#define CHRE_HOST_ENDPOINT_TYPE_VENDOR_END UINT8_C(0xFF)
/** @} */
diff --git a/chre_api/include/chre_api/chre/gnss.h b/chre_api/include/chre_api/chre/gnss.h
index 79a8f46b..a326e85b 100644
--- a/chre_api/include/chre_api/chre/gnss.h
+++ b/chre_api/include/chre_api/chre/gnss.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef _CHRE_GNSS_H_
#define _CHRE_GNSS_H_
diff --git a/chre_api/include/chre_api/chre/nanoapp.h b/chre_api/include/chre_api/chre/nanoapp.h
index da199ee0..3a1c3628 100644
--- a/chre_api/include/chre_api/chre/nanoapp.h
+++ b/chre_api/include/chre_api/chre/nanoapp.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef _CHRE_NANOAPP_H_
#define _CHRE_NANOAPP_H_
diff --git a/chre_api/include/chre_api/chre/re.h b/chre_api/include/chre_api/chre/re.h
index 20a69b66..1efa5d30 100644
--- a/chre_api/include/chre_api/chre/re.h
+++ b/chre_api/include/chre_api/chre/re.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef _CHRE_RE_H_
#define _CHRE_RE_H_
@@ -363,7 +366,7 @@ bool chreTimerCancel(uint32_t timerId);
* @return Never. This method does not return, as the CHRE stops nanoapp
* execution immediately.
*/
-void chreAbort(uint32_t abortCode);
+void chreAbort(uint32_t abortCode) CHRE_NO_RETURN;
/**
* Allocate a given number of bytes from the system heap.
diff --git a/chre_api/include/chre_api/chre/sensor.h b/chre_api/include/chre_api/chre/sensor.h
index 41663741..67d07f8a 100644
--- a/chre_api/include/chre_api/chre/sensor.h
+++ b/chre_api/include/chre_api/chre/sensor.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef _CHRE_SENSOR_H_
#define _CHRE_SENSOR_H_
diff --git a/chre_api/include/chre_api/chre/sensor_types.h b/chre_api/include/chre_api/chre/sensor_types.h
index 63b495bb..0f55efce 100644
--- a/chre_api/include/chre_api/chre/sensor_types.h
+++ b/chre_api/include/chre_api/chre/sensor_types.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef _CHRE_SENSOR_TYPES_H_
#define _CHRE_SENSOR_TYPES_H_
@@ -52,7 +55,7 @@ extern "C" {
*
* @since v1.2
*/
-#define CHRE_SENSOR_TYPE_VENDOR_START UINT8_C(192)
+#define CHRE_SENSOR_TYPE_VENDOR_START UINT8_C(0xC0)
/**
* Accelerometer.
@@ -65,7 +68,7 @@ extern "C" {
*
* @see chreConfigureSensorBiasEvents
*/
-#define CHRE_SENSOR_TYPE_ACCELEROMETER UINT8_C(1)
+#define CHRE_SENSOR_TYPE_ACCELEROMETER UINT8_C(0x01)
/**
* Instantaneous motion detection.
@@ -78,7 +81,7 @@ extern "C" {
* to SENSOR_TYPE_MOTION_DETECT, but this triggers instantly upon any
* motion, instead of waiting for a period of continuous motion.
*/
-#define CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT UINT8_C(2)
+#define CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT UINT8_C(0x02)
/**
* Stationary detection.
@@ -87,7 +90,7 @@ extern "C" {
*
* This is a one-shot sensor.
*/
-#define CHRE_SENSOR_TYPE_STATIONARY_DETECT UINT8_C(3)
+#define CHRE_SENSOR_TYPE_STATIONARY_DETECT UINT8_C(0x03)
/**
* Gyroscope.
@@ -100,7 +103,7 @@ extern "C" {
*
* @see chreConfigureSensorBiasEvents
*/
-#define CHRE_SENSOR_TYPE_GYROSCOPE UINT8_C(6)
+#define CHRE_SENSOR_TYPE_GYROSCOPE UINT8_C(0x06)
/**
* Uncalibrated gyroscope.
@@ -110,7 +113,7 @@ extern "C" {
* Note that the UNCALIBRATED_GYROSCOPE_DATA must be factory calibrated data,
* but not runtime calibrated.
*/
-#define CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE UINT8_C(7)
+#define CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE UINT8_C(0x07)
/**
* Magnetometer.
@@ -123,7 +126,7 @@ extern "C" {
*
* @see chreConfigureSensorBiasEvents
*/
-#define CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD UINT8_C(8)
+#define CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD UINT8_C(0x08)
/**
* Uncalibrated magnetometer.
@@ -133,14 +136,14 @@ extern "C" {
* Note that the UNCALIBRATED_GEOMAGNETIC_FIELD_DATA must be factory calibrated
* data, but not runtime calibrated.
*/
-#define CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD UINT8_C(9)
+#define CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD UINT8_C(0x09)
/**
* Barometric pressure sensor.
*
* Generates: CHRE_EVENT_SENSOR_PRESSURE_DATA
*/
-#define CHRE_SENSOR_TYPE_PRESSURE UINT8_C(10)
+#define CHRE_SENSOR_TYPE_PRESSURE UINT8_C(0x0A)
/**
* Ambient light sensor.
@@ -149,7 +152,7 @@ extern "C" {
*
* This is an on-change sensor.
*/
-#define CHRE_SENSOR_TYPE_LIGHT UINT8_C(12)
+#define CHRE_SENSOR_TYPE_LIGHT UINT8_C(0x0C)
/**
* Proximity detection.
@@ -158,7 +161,7 @@ extern "C" {
*
* This is an on-change sensor.
*/
-#define CHRE_SENSOR_TYPE_PROXIMITY UINT8_C(13)
+#define CHRE_SENSOR_TYPE_PROXIMITY UINT8_C(0x0D)
/**
* Step detection.
@@ -167,7 +170,7 @@ extern "C" {
*
* @since v1.3
*/
-#define CHRE_SENSOR_TYPE_STEP_DETECT UINT8_C(23)
+#define CHRE_SENSOR_TYPE_STEP_DETECT UINT8_C(0x17)
/**
* Step counter.
@@ -181,7 +184,7 @@ extern "C" {
*
* @since v1.5
*/
-#define CHRE_SENSOR_TYPE_STEP_COUNTER UINT8_C(24)
+#define CHRE_SENSOR_TYPE_STEP_COUNTER UINT8_C(0x18)
/**
* Hinge angle sensor.
@@ -197,7 +200,7 @@ extern "C" {
*
* @since v1.5
*/
-#define CHRE_SENSOR_TYPE_HINGE_ANGLE UINT8_C(36)
+#define CHRE_SENSOR_TYPE_HINGE_ANGLE UINT8_C(0x24)
/**
* Uncalibrated accelerometer.
@@ -207,28 +210,28 @@ extern "C" {
* Note that the UNCALIBRATED_ACCELEROMETER_DATA must be factory calibrated
* data, but not runtime calibrated.
*/
-#define CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER UINT8_C(55)
+#define CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER UINT8_C(0x37)
/**
* Accelerometer temperature.
*
* Generates: CHRE_EVENT_SENSOR_ACCELEROMETER_TEMPERATURE_DATA
*/
-#define CHRE_SENSOR_TYPE_ACCELEROMETER_TEMPERATURE UINT8_C(56)
+#define CHRE_SENSOR_TYPE_ACCELEROMETER_TEMPERATURE UINT8_C(0x38)
/**
* Gyroscope temperature.
*
* Generates: CHRE_EVENT_SENSOR_GYROSCOPE_TEMPERATURE_DATA
*/
-#define CHRE_SENSOR_TYPE_GYROSCOPE_TEMPERATURE UINT8_C(57)
+#define CHRE_SENSOR_TYPE_GYROSCOPE_TEMPERATURE UINT8_C(0x39)
/**
* Magnetometer temperature.
*
* Generates: CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_TEMPERATURE_DATA
*/
-#define CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD_TEMPERATURE UINT8_C(58)
+#define CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD_TEMPERATURE UINT8_C(0x3A)
#if CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD_TEMPERATURE >= CHRE_SENSOR_TYPE_VENDOR_START
#error Too many sensor types
@@ -252,12 +255,12 @@ extern "C" {
* @{
*/
-#define CHRE_SENSOR_ACCURACY_UNKNOWN UINT8_C(0)
-#define CHRE_SENSOR_ACCURACY_UNRELIABLE UINT8_C(1)
-#define CHRE_SENSOR_ACCURACY_LOW UINT8_C(2)
-#define CHRE_SENSOR_ACCURACY_MEDIUM UINT8_C(3)
-#define CHRE_SENSOR_ACCURACY_HIGH UINT8_C(4)
-#define CHRE_SENSOR_ACCURACY_VENDOR_START UINT8_C(192)
+#define CHRE_SENSOR_ACCURACY_UNKNOWN UINT8_C(0x00)
+#define CHRE_SENSOR_ACCURACY_UNRELIABLE UINT8_C(0x01)
+#define CHRE_SENSOR_ACCURACY_LOW UINT8_C(0x02)
+#define CHRE_SENSOR_ACCURACY_MEDIUM UINT8_C(0x03)
+#define CHRE_SENSOR_ACCURACY_HIGH UINT8_C(0x04)
+#define CHRE_SENSOR_ACCURACY_VENDOR_START UINT8_C(0xC0)
#define CHRE_SENSOR_ACCURACY_VENDOR_END UINT8_MAX
/** @} */
diff --git a/chre_api/include/chre_api/chre/toolchain.h b/chre_api/include/chre_api/chre/toolchain.h
index c2b87222..05b6fb93 100644
--- a/chre_api/include/chre_api/chre/toolchain.h
+++ b/chre_api/include/chre_api/chre/toolchain.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef CHRE_TOOLCHAIN_H_
#define CHRE_TOOLCHAIN_H_
@@ -28,6 +31,9 @@
#define CHRE_DEPRECATED(message) \
__attribute__((deprecated(message)))
+// Indicates that the function does not return (i.e. abort).
+#define CHRE_NO_RETURN __attribute__((noreturn))
+
// Enable printf-style compiler warnings for mismatched format string and args
#define CHRE_PRINTF_ATTR(formatPos, argStart) \
__attribute__((format(printf, formatPos, argStart)))
diff --git a/chre_api/include/chre_api/chre/user_settings.h b/chre_api/include/chre_api/chre/user_settings.h
index c40be90e..a13290d8 100644
--- a/chre_api/include/chre_api/chre/user_settings.h
+++ b/chre_api/include/chre_api/chre/user_settings.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef _CHRE_USER_SETTINGS_H_
#define _CHRE_USER_SETTINGS_H_
diff --git a/chre_api/include/chre_api/chre/version.h b/chre_api/include/chre_api/chre/version.h
index 6872fdde..30087ed5 100644
--- a/chre_api/include/chre_api/chre/version.h
+++ b/chre_api/include/chre_api/chre/version.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef _CHRE_VERSION_H_
#define _CHRE_VERSION_H_
@@ -135,14 +138,28 @@ extern "C" {
/**
* Value for version 1.8 of the Context Hub Runtime Environment API interface.
*
- * This version of the CHRE API is shipped with the Android U release.
+ * This version of the CHRE API is shipped with the Android U release. It adds
+ * support for filtering by manufacturer data in BLE scans, reading the RSSI
+ * value of a BLE connection, allowing the nanoapp to check BLE scan status,
+ * allowing the nanoapp to specify which RPC services it supports, and
+ * delivering batch complete events for batched BLE scans.
+ *
+ * @see CHRE_API_VERSION
+ */
+#define CHRE_API_VERSION_1_8 UINT32_C(0x01080000)
+
+/**
+ * Value for version 1.9 of the Context Hub Runtime Environment API interface.
+ *
+ * This version of the CHRE API is shipped with a post-launch update to the
+ * Android U release. It adds the BLE Broadcaster Address filter.
*
* @note This version of the CHRE API has not been finalized yet, and is
* currently considered a preview that is subject to change.
*
* @see CHRE_API_VERSION
*/
-#define CHRE_API_VERSION_1_8 UINT32_C(0x01080000)
+#define CHRE_API_VERSION_1_9 UINT32_C(0x01090000)
/**
* Major and Minor Version of this Context Hub Runtime Environment API.
@@ -161,7 +178,7 @@ extern "C" {
* Note that version numbers can always be numerically compared with
* expected results, so 1.0.0 < 1.0.4 < 1.1.0 < 2.0.300 < 3.5.0.
*/
-#define CHRE_API_VERSION CHRE_API_VERSION_1_8
+#define CHRE_API_VERSION CHRE_API_VERSION_1_9
/**
* Utility macro to extract only the API major version of a composite CHRE
diff --git a/chre_api/include/chre_api/chre/wifi.h b/chre_api/include/chre_api/chre/wifi.h
index b4bda9c0..048e7ae4 100644
--- a/chre_api/include/chre_api/chre/wifi.h
+++ b/chre_api/include/chre_api/chre/wifi.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef _CHRE_WIFI_H_
#define _CHRE_WIFI_H_
diff --git a/chre_api/include/chre_api/chre/wwan.h b/chre_api/include/chre_api/chre/wwan.h
index 51cf5f9d..ac55f4dd 100644
--- a/chre_api/include/chre_api/chre/wwan.h
+++ b/chre_api/include/chre_api/chre/wwan.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// IWYU pragma: private, include "chre_api/chre.h"
+// IWYU pragma: friend chre/.*\.h
+
#ifndef _CHRE_WWAN_H_
#define _CHRE_WWAN_H_
diff --git a/chre_api/legacy/v1_8/chre.h b/chre_api/legacy/v1_8/chre.h
new file mode 100644
index 00000000..9b87d08b
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_H_
+#define _CHRE_H_
+
+/**
+ * @file
+ * This header file includes all the headers which combine to fully define the
+ * interface for the Context Hub Runtime Environment (CHRE). This interface is
+ * of interest to both implementers of CHREs and authors of nanoapps. The API
+ * documentation attempts to address concerns of both.
+ *
+ * See individual header files for API details, and general comments below
+ * for overall platform information.
+ */
+
+#include <chre/audio.h>
+#include <chre/ble.h>
+#include <chre/common.h>
+#include <chre/event.h>
+#include <chre/gnss.h>
+#include <chre/nanoapp.h>
+#include <chre/re.h>
+#include <chre/sensor.h>
+#include <chre/toolchain.h>
+#include <chre/user_settings.h>
+#include <chre/version.h>
+#include <chre/wifi.h>
+#include <chre/wwan.h>
+
+/**
+ * @mainpage
+ * CHRE is the Context Hub Runtime Environment. CHRE is used in Android to run
+ * contextual applications, called nanoapps, in a low-power processing domain
+ * other than the applications processor that runs Android itself. The CHRE
+ * API, documented herein, is the common interface exposed to nanoapps for any
+ * compatible CHRE implementation. The CHRE API provides the ability for
+ * creating nanoapps that are code-compatible across different CHRE
+ * implementations and underlying platforms. Refer to the following sections for
+ * a discussion on some important details of CHRE that aren't explicitly exposed
+ * in the API itself.
+ *
+ * @section entry_points Entry points
+ *
+ * The following entry points are used to bind a nanoapp to the CHRE system, and
+ * all three must be implemented by any nanoapp (see chre/nanoapp.h):
+ * - nanoappStart: initialization
+ * - nanoappHandleEvent: hook for event-driven processing
+ * - nanoappEnd: graceful teardown
+ *
+ * The CHRE implementation must also ensure that it performs these functions
+ * prior to invoking nanoappStart, or after nanoappEnd returns:
+ * - bss section zeroed out (prior to nanoappStart)
+ * - static variables initialized (prior to nanoappStart)
+ * - global C++ constructors called (prior to nanoappStart)
+ * - global C++ destructors called (after nanoappEnd)
+ *
+ * @section threading Threading model
+ *
+ * A CHRE implementation is free to choose among many different
+ * threading models, including a single-threaded system or a multi-threaded
+ * system with preemption. The current platform definition is agnostic to this
+ * underlying choice. However, the CHRE implementation must ensure that time
+ * spent executing within a nanoapp does not significantly degrade or otherwise
+ * interfere with other functions of the system in which CHRE is implemented,
+ * especially latency-sensitive tasks such as sensor event delivery to the AP.
+ * In other words, it must ensure that these functions can either occur in
+ * parallel or preempt a nanoapp's execution. The current version of the API
+ * does not specify whether the implementation allows for CPU sharing between
+ * nanoapps on a more granular level than the handling of individual events [1].
+ * In any case, event ordering from the perspective of an individual nanoapp
+ * must be FIFO, but the CHRE implementation may choose to violate total
+ * ordering of events across all nanoapps to achieve more fair resource sharing,
+ * but this is not required.
+ *
+ * This version of the CHRE API does require that all nanoapps are treated as
+ * non-reentrant, meaning that only one instance of program flow can be inside
+ * an individual nanoapp at any given time. That is, any of the functions of
+ * the nanoapp, including the entry points and all other callbacks, cannot be
+ * invoked if a previous invocation to the same or any other function in the
+ * nanoapp has not completed yet.
+ *
+ * For example, if a nanoapp is currently in nanoappHandleEvent(), the CHRE is
+ * not allowed to call nanoappHandleEvent() again, or to call a memory freeing
+ * callback. Similarly, if a nanoapp is currently in a memory freeing
+ * callback, the CHRE is not allowed to call nanoappHandleEvent(), or invoke
+ * another memory freeing callback.
+ *
+ * There are two exceptions to this rule: If an invocation of chreSendEvent()
+ * fails (returns 'false'), it is allowed to immediately invoke the memory
+ * freeing callback passed into that function. This is a rare case, and one
+ * where otherwise a CHRE implementation is likely to leak memory. Similarly,
+ * chreSendMessageToHost() is allowed to invoke the memory freeing callback
+ * directly, whether it returns 'true' or 'false'. This is because the CHRE
+ * implementation may copy the message data to its own buffer, and therefore
+ * wouldn't need the nanoapp-supplied buffer after chreSendMessageToHost()
+ * returns.
+ *
+ * For a nanoapp author, this means no thought needs to be given to
+ * synchronization issues with global objects, as they will, by definition,
+ * only be accessed by a single thread at once.
+ *
+ * [1]: Note to CHRE implementers: A future version of the CHRE platform may
+ * require multi-threading with preemption. This is mentioned as a heads up,
+ * and to allow implementors deciding between implementation approaches to
+ * make the most informed choice.
+ *
+ * @section timing Timing
+ *
+ * Nanoapps should expect to be running on a highly constrained system, with
+ * little memory and little CPU. Any single nanoapp should expect to
+ * be one of several nanoapps on the system, which also share the CPU with the
+ * CHRE and possibly other services as well.
+ *
+ * Thus, a nanoapp needs to be efficient in its memory and CPU usage.
+ * Also, as noted in the Threading Model section, a CHRE implementation may
+ * be single threaded. As a result, all methods invoked in a nanoapp
+ * (like nanoappStart, nanoappHandleEvent, memory free callbacks, etc.)
+ * must run "quickly". "Quickly" is difficult to define, as there is a
+ * diversity of Context Hub hardware. Nanoapp authors are strongly recommended
+ * to limit their application to consuming no more than 1 second of CPU time
+ * prior to returning control to the CHRE implementation. A CHRE implementation
+ * may consider a nanoapp as unresponsive if it spends more time than this to
+ * process a single event, and take corrective action.
+ *
+ * A nanoapp may have the need to occasionally perform a large block of
+ * calculations that exceeds the 1 second guidance. The recommended approach in
+ * this case is to split up the large block of calculations into smaller
+ * batches. In one call into the nanoapp, the nanoapp can perform the first
+ * batch, and then set a timer or send an event (chreSendEvent()) to itself
+ * indicating which batch should be done next. This will allow the nanoapp to
+ * perform the entire calculation over time, without monopolizing system
+ * resources.
+ *
+ * @section floats Floating point support
+ *
+ * The C type 'float' is used in this API, and thus a CHRE implementation
+ * is required to support 'float's.
+ *
+ * Support of the C types 'double' and 'long double' is optional for a
+ * CHRE implementation. Note that if a CHRE decides to support them, unlike
+ * 'float' support, there is no requirement that this support is particularly
+ * efficient. So nanoapp authors should be aware this may be inefficient.
+ *
+ * If a CHRE implementation chooses not to support 'double' or
+ * 'long double', then the build toolchain setup provided needs to set
+ * the preprocessor define CHRE_NO_DOUBLE_SUPPORT.
+ *
+ * @section compat CHRE and Nanoapp compatibility
+ *
+ * CHRE implementations must make affordances to maintain binary compatibility
+ * across minor revisions of the API version (e.g. v1.1 to v1.2). This applies
+ * to both running a nanoapp compiled for a newer version of the API on a CHRE
+ * implementation built against an older version (backwards compatibility), and
+ * vice versa (forwards compatibility). API changes that are acceptable in
+ * minor version changes that may require special measures to ensure binary
+ * compatibility include: addition of new functions; addition of arguments to
+ * existing functions when the default value used for nanoapps compiled against
+ * the old version is well-defined and does not affect existing functionality;
+ * and addition of fields to existing structures, even when this induces a
+ * binary layout change (this should be made rare via judicious use of reserved
+ * fields). API changes that must only occur alongside a major version change
+ * and are therefore not compatible include: removal of any function, argument,
+ * field in a data structure, or mandatory functional behavior that a nanoapp
+ * may depend on; any change in the interpretation of an existing data structure
+ * field that alters the way it was defined previously (changing the units of a
+ * field would fall under this, but appropriating a previously reserved field
+ * for some new functionality would not); and any change in functionality or
+ * expected behavior that conflicts with the previous definition.
+ *
+ * Note that the CHRE API only specifies the software interface between a
+ * nanoapp and the CHRE system - the binary interface (ABI) between nanoapp and
+ * CHRE is necessarily implementation-dependent. Therefore, the recommended
+ * approach to accomplish binary compatibility is to build a Nanoapp Support
+ * Library (NSL) that is specific to the CHRE implementation into the nanoapp
+ * binary, and use it to handle ABI details in a way that ensures compatibility.
+ * In addition, to accomplish forwards compatibility, the CHRE implementation is
+ * expected to recognize the CHRE API version that a nanoapp is targeting and
+ * engage compatibility behaviors where necessary.
+ *
+ * By definition, major API version changes (e.g. v1.1 to v2.0) break
+ * compatibility. Therefore, a CHRE implementation must not attempt to load a
+ * nanoapp that is targeting a newer major API version.
+ */
+
+#endif /* _CHRE_H_ */
+
diff --git a/chre_api/legacy/v1_8/chre/audio.h b/chre_api/legacy/v1_8/chre/audio.h
new file mode 100644
index 00000000..e8ec9607
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/audio.h
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_AUDIO_H_
+#define _CHRE_AUDIO_H_
+
+/**
+ * @file
+ * The API for requesting audio in the Context Hub Runtime Environment.
+ *
+ * This includes the definition of audio data structures and the ability to
+ * request audio streams.
+ */
+
+#include <chre/event.h>
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The current compatibility version of the chreAudioDataEvent structure.
+ */
+#define CHRE_AUDIO_DATA_EVENT_VERSION UINT8_C(1)
+
+/**
+ * Produce an event ID in the block of IDs reserved for audio
+ * @param offset Index into audio event ID block; valid range [0,15]
+ */
+#define CHRE_AUDIO_EVENT_ID(offset) (CHRE_EVENT_AUDIO_FIRST_EVENT + (offset))
+
+/**
+ * nanoappHandleEvent argument: struct chreAudioSourceStatusEvent
+ *
+ * Indicates a change in the format and/or rate of audio data provided to a
+ * nanoapp.
+ */
+#define CHRE_EVENT_AUDIO_SAMPLING_CHANGE CHRE_AUDIO_EVENT_ID(0)
+
+/**
+ * nanoappHandleEvent argument: struct chreAudioDataEvent
+ *
+ * Provides a buffer of audio data to a nanoapp.
+ */
+#define CHRE_EVENT_AUDIO_DATA CHRE_AUDIO_EVENT_ID(1)
+
+/**
+ * The maximum size of the name of an audio source including the
+ * null-terminator.
+ */
+#define CHRE_AUDIO_SOURCE_NAME_MAX_SIZE (40)
+
+/**
+ * Helper values for sample rates.
+ *
+ * @defgroup CHRE_AUDIO_SAMPLE_RATES
+ * @{
+ */
+
+//! 16kHz Audio Sample Data
+#define CHRE_AUDIO_SAMPLE_RATE_16KHZ (16000)
+
+/** @} */
+
+/**
+ * Formats for audio that can be provided to a nanoapp.
+ */
+enum chreAudioDataFormat {
+ /**
+ * Unsigned, 8-bit u-Law encoded data as specified by ITU-T G.711.
+ */
+ CHRE_AUDIO_DATA_FORMAT_8_BIT_U_LAW = 0,
+
+ /**
+ * Signed, 16-bit linear PCM data. Endianness must be native to the local
+ * processor.
+ */
+ CHRE_AUDIO_DATA_FORMAT_16_BIT_SIGNED_PCM = 1,
+};
+
+/**
+ * A description of an audio source available to a nanoapp.
+ *
+ * This provides a description of an audio source with a name and a
+ * description of the format of the provided audio data.
+ */
+struct chreAudioSource {
+ /**
+ * A human readable name for this audio source. This is a C-style,
+ * null-terminated string. The length must be less than or equal to
+ * CHRE_AUDIO_SOURCE_NAME_MAX_SIZE bytes (including the null-terminator) and
+ * is expected to describe the source of the audio in US English. All
+ * characters must be printable (i.e.: isprint would return true for all
+ * characters in the name for the EN-US locale). The typical use of this field
+ * is for a nanoapp to log the name of the audio source that it is using.
+ *
+ * Example: "Camcorder Microphone"
+ */
+ const char *name;
+
+ /**
+ * The sampling rate in hertz of this mode. This value is rounded to the
+ * nearest integer. Typical values might include 16000, 44100 and 44800.
+ *
+ * If the requested audio source is preempted by another feature of the system
+ * (e.g. hotword), a gap may occur in received audio data. This is indicated
+ * to the client by posting a CHRE_EVENT_AUDIO_SAMPLING_CHANGE event. The
+ * nanoapp will then receive another CHRE_EVENT_AUDIO_SAMPLING_CHANGE event
+ * once the audio source is available again.
+ */
+ uint32_t sampleRate;
+
+ /**
+ * The minimum amount of time that this audio source can be buffered, in
+ * nanoseconds. Audio data is delivered to nanoapps in buffers. This specifies
+ * the minimum amount of data that can be delivered to a nanoapp without
+ * losing data. A request for a buffer that is smaller than this will fail.
+ */
+ uint64_t minBufferDuration;
+
+ /**
+ * The maximum amount of time that this audio source can be buffered, in
+ * nanoseconds. Audio data is delivered to nanoapps in buffers. This specifies
+ * the maximum amount of data that can be stored by the system in one event
+ * without losing data. A request for a buffer that is larger than this will
+ * fail.
+ */
+ uint64_t maxBufferDuration;
+
+ /**
+ * The format for data provided to the nanoapp. This will be assigned to one
+ * of the enum chreAudioDataFormat values.
+ */
+ uint8_t format;
+};
+
+/**
+ * The current status of an audio source.
+ */
+struct chreAudioSourceStatus {
+ /**
+ * Set to true if the audio source is currently enabled by this nanoapp. If
+ * this struct is provided by a CHRE_EVENT_AUDIO_SAMPLING_CHANGE event, it
+ * must necessarily be set to true because sampling change events are only
+ * sent for sources which this nanoapp has actively subscribed to. If this
+ * struct is obtained from the chreAudioGetStatus API, it may be set to true
+ * or false depending on if audio is currently enabled.
+ */
+ bool enabled;
+
+ /**
+ * Set to true if the audio source is currently suspended and no audio data
+ * will be received from this source.
+ */
+ bool suspended;
+};
+
+/**
+ * The nanoappHandleEvent argument for CHRE_EVENT_AUDIO_SAMPLING_CHANGE.
+ */
+struct chreAudioSourceStatusEvent {
+ /**
+ * The audio source which has completed a status change.
+ */
+ uint32_t handle;
+
+ /**
+ * The status of this audio source.
+ */
+ struct chreAudioSourceStatus status;
+};
+
+/**
+ * The nanoappHandleEvent argument for CHRE_EVENT_AUDIO_DATA.
+ *
+ * One example of the sequence of events for a nanoapp to receive audio data is:
+ *
+ * 1. CHRE_EVENT_AUDIO_SAMPLING_CHANGE - Indicates that audio data is not
+ * suspended.
+ * 2. CHRE_EVENT_AUDIO_DATA - One buffer of audio samples. Potentially repeated.
+ * 3. CHRE_EVENT_AUDIO_SAMPLING_CHANGE - Indicates that audio data has suspended
+ * which indicates a gap in the audio.
+ * 4. CHRE_EVENT_AUDIO_SAMPLING_CHANGE - Indicates that audio data has resumed
+ * and that audio data may be delivered
+ * again if enough samples are buffered.
+ * 5. CHRE_EVENT_AUDIO_DATA - One buffer of audio samples. Potentially repeated.
+ * The nanoapp must tolerate a gap in the timestamps.
+ *
+ * This process repeats for as long as an active request is made for an audio
+ * source. A CHRE_EVENT_AUDIO_SAMPLING_CHANGE does not guarantee that the next
+ * event will be a CHRE_EVENT_AUDIO_DATA event when suspended is set to false.
+ * It may happen that the audio source is suspended before a complete buffer can
+ * be captured. This will cause another CHRE_EVENT_AUDIO_SAMPLING_CHANGE event
+ * to be dispatched with suspended set to true before a buffer is delivered.
+ *
+ * Audio events must be delivered to a nanoapp in order.
+ */
+struct chreAudioDataEvent {
+ /**
+ * Indicates the version of the structure, for compatibility purposes. Clients
+ * do not normally need to worry about this field; the CHRE implementation
+ * guarantees that the client only receives the structure version it expects.
+ */
+ uint8_t version;
+
+ /**
+ * Additional bytes reserved for future use; must be set to 0.
+ */
+ uint8_t reserved[3];
+
+ /**
+ * The handle for which this audio data originated from.
+ */
+ uint32_t handle;
+
+ /**
+ * The base timestamp for this buffer of audio data, from the same time base
+ * as chreGetTime() (in nanoseconds). The audio API does not provide
+ * timestamps for each audio sample. This timestamp corresponds to the first
+ * sample of the buffer. Even though the value is expressed in nanoseconds,
+ * there is an expectation that the sample clock may drift and nanosecond
+ * level accuracy may not be possible. The goal is to be as accurate as
+ * possible within reasonable limitations of a given system.
+ */
+ uint64_t timestamp;
+
+ /**
+ * The sample rate for this buffer of data in hertz, rounded to the nearest
+ * integer. Fractional sampling rates are not supported. Typical values might
+ * include 16000, 44100 and 48000.
+ */
+ uint32_t sampleRate;
+
+ /**
+ * The number of samples provided with this buffer.
+ */
+ uint32_t sampleCount;
+
+ /**
+ * The format of this audio data. This enumeration and union of pointers below
+ * form a tagged struct. The consumer of this API must use this enum to
+ * determine which samples pointer below to dereference. This will be assigned
+ * to one of the enum chreAudioDataFormat values.
+ */
+ uint8_t format;
+
+ /**
+ * A union of pointers to various formats of sample data. These correspond to
+ * the valid chreAudioDataFormat values.
+ */
+ union {
+ const uint8_t *samplesULaw8;
+ const int16_t *samplesS16;
+ };
+};
+
+/**
+ * Retrieves information about an audio source supported by the current CHRE
+ * implementation. The source returned by the runtime must not change for the
+ * entire lifecycle of the Nanoapp and hot-pluggable audio sources are not
+ * supported.
+ *
+ * A simple example of iterating all available audio sources is provided here:
+ *
+ * struct chreAudioSource audioSource;
+ * for (uint32_t i = 0; chreAudioGetSource(i, &audioSource); i++) {
+ * chreLog(CHRE_LOG_INFO, "Found audio source: %s", audioSource.name);
+ * }
+ *
+ * Handles provided to this API must be a stable value for the entire duration
+ * of a nanoapp. Handles for all audio sources must be zero-indexed and
+ * contiguous. The following are examples of handles that could be provided to
+ * this API:
+ *
+ * Valid: 0
+ * Valid: 0, 1, 2, 3
+ * Invalid: 1, 2, 3
+ * Invalid: 0, 2
+ *
+ * @param handle The handle for an audio source to obtain details for. The
+ * range of acceptable handles must be zero-indexed and contiguous.
+ * @param audioSource A struct to populate with details of the audio source.
+ * @return true if the query was successful, false if the provided handle is
+ * invalid or the supplied audioSource is NULL.
+ *
+ * @since v1.2
+ */
+bool chreAudioGetSource(uint32_t handle, struct chreAudioSource *audioSource);
+
+/**
+ * Nanoapps must define CHRE_NANOAPP_USES_AUDIO somewhere in their build
+ * system (e.g. Makefile) if the nanoapp needs to use the following audio APIs.
+ * In addition to allowing access to these APIs, defining this macro will also
+ * ensure CHRE enforces that all host clients this nanoapp talks to have the
+ * required Android permissions needed to listen to audio data by adding
+ * metadata to the nanoapp.
+ */
+#if defined(CHRE_NANOAPP_USES_AUDIO) || !defined(CHRE_IS_NANOAPP_BUILD)
+
+/**
+ * Configures delivery of audio data to the current nanoapp. Note that this may
+ * not fully disable the audio source if it is used by other clients in the
+ * system but it will halt data delivery to the nanoapp.
+ *
+ * The bufferDuration and deliveryInterval parameters as described below are
+ * used together to determine both how much and how often to deliver data to a
+ * nanoapp, respectively. A nanoapp will always be provided the requested
+ * amount of data at the requested interval, even if another nanoapp in CHRE
+ * requests larger/more frequent buffers or smaller/less frequent buffers.
+ * These two buffering parameters allow describing the duty cycle of captured
+ * audio data. If a nanoapp wishes to receive all available audio data, it will
+ * specify a bufferDuration and deliveryInterval that are equal. A 50% duty
+ * cycle would be achieved by specifying a deliveryInterval that is double the
+ * value of the bufferDuration provided. These parameters allow the audio
+ * subsystem to operate at less than 100% duty cycle and permits use of
+ * incomplete audio data without periodic reconfiguration of the source.
+ *
+ * Two examples are illustrated below:
+ *
+ * Target duty cycle: 50%
+ * bufferDuration: 2
+ * deliveryInterval: 4
+ *
+ * Time 0 1 2 3 4 5 6 7
+ * Batch A B
+ * Sample -- -- a1 a2 -- -- b1 b2
+ * Duration [ ] [ ]
+ * Interval [ ] [ ]
+ *
+ *
+ * Target duty cycle: 100%
+ * bufferDuration: 4
+ * deliveryInterval: 4
+ *
+ * Time 0 1 2 3 4 5 6 7
+ * Batch A B
+ * Sample a1 a2 a3 a4 b1 b2 b3 b4
+ * Duration [ ] [ ]
+ * Interval [ ] [ ]
+ *
+ *
+ * This is expected to reduce power overall.
+ *
+ * The first audio buffer supplied to the nanoapp may contain data captured
+ * prior to the request. This could happen if the microphone was already enabled
+ * and reading into a buffer prior to the nanoapp requesting audio data for
+ * itself. The nanoapp must tolerate this.
+ *
+ * It is important to note that multiple logical audio sources (e.g. different
+ * sample rate, format, etc.) may map to one physical audio source. It is
+ * possible for a nanoapp to request audio data from more than one logical
+ * source at a time. Audio data may be suspended for either the current or other
+ * requests. The CHRE_EVENT_AUDIO_SAMPLING_CHANGE will be posted to all clients
+ * if such a change occurs. It is also possible for the request to succeed and
+ * all audio sources are serviced simultaneously. This is implementation defined
+ * but at least one audio source must function correctly if it is advertised,
+ * under normal conditions (e.g. not required for some other system function,
+ * such as hotword).
+ *
+ * @param handle The handle for this audio source. The handle for the desired
+ * audio source can be determined using chreAudioGetSource().
+ * @param enable true if enabling the source, false otherwise. When passed as
+ * false, the bufferDuration and deliveryInterval parameters are ignored.
+ * @param bufferDuration The amount of time to capture audio samples from this
+ * audio source, in nanoseconds per delivery interval. This value must be
+ * in the range of minBufferDuration/maxBufferDuration for this source or
+ * the request will fail. The number of samples captured per buffer will be
+ * derived from the sample rate of the source and the requested duration and
+ * rounded down to the nearest sample boundary.
+ * @param deliveryInterval Desired time between each CHRE_EVENT_AUDIO_DATA
+ * event. This allows specifying the complete duty cycle of a request
+ * for audio data, in nanoseconds. This value must be greater than or equal
+ * to bufferDuration or the request will fail due to an invalid
+ * configuration.
+ * @return true if the configuration was successful, false if invalid parameters
+ * were provided (non-existent handle, invalid buffering configuration).
+ *
+ * @since v1.2
+ * @note Requires audio permission
+ */
+bool chreAudioConfigureSource(uint32_t handle, bool enable,
+ uint64_t bufferDuration,
+ uint64_t deliveryInterval);
+
+/**
+ * Gets the current chreAudioSourceStatus struct for a given audio handle.
+ *
+ * @param handle The handle for the audio source to query. The provided handle
+ * is obtained from a chreAudioSource which is requested from the
+ * chreAudioGetSource API.
+ * @param status The current status of the supplied audio source.
+ * @return true if the provided handle is valid and the status was obtained
+ * successfully, false if the handle was invalid or status is NULL.
+ *
+ * @since v1.2
+ * @note Requires audio permission
+ */
+bool chreAudioGetStatus(uint32_t handle, struct chreAudioSourceStatus *status);
+
+#else /* defined(CHRE_NANOAPP_USES_AUDIO) || !defined(CHRE_IS_NANOAPP_BUILD) */
+#define CHRE_AUDIO_PERM_ERROR_STRING \
+ "CHRE_NANOAPP_USES_AUDIO must be defined when building this nanoapp in " \
+ "order to refer to "
+#define chreAudioConfigureSource(...) \
+ CHRE_BUILD_ERROR(CHRE_AUDIO_PERM_ERROR_STRING "chreAudioConfigureSource")
+#define chreAudioGetStatus(...) \
+ CHRE_BUILD_ERROR(CHRE_AUDIO_PERM_ERROR_STRING "chreAudioGetStatus")
+#endif /* defined(CHRE_NANOAPP_USES_AUDIO) || !defined(CHRE_IS_NANOAPP_BUILD) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHRE_AUDIO_H_ */
diff --git a/chre_api/legacy/v1_8/chre/ble.h b/chre_api/legacy/v1_8/chre/ble.h
new file mode 100644
index 00000000..9f049647
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/ble.h
@@ -0,0 +1,851 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CHRE_BLE_H_
+#define CHRE_BLE_H_
+
+/**
+ * @file
+ * CHRE BLE (Bluetooth Low Energy, Bluetooth LE) API.
+ * The CHRE BLE API currently supports BLE scanning features.
+ *
+ * The features in the CHRE BLE API are a subset and adaptation of Android
+ * capabilities as described in the Android BLE API and HCI requirements.
+ * ref:
+ * https://developer.android.com/guide/topics/connectivity/bluetooth/ble-overview
+ * ref: https://source.android.com/devices/bluetooth/hci_requirements
+ */
+
+#include <chre/common.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The set of flags returned by chreBleGetCapabilities().
+ *
+ * @defgroup CHRE_BLE_CAPABILITIES
+ * @{
+ */
+//! No BLE APIs are supported
+#define CHRE_BLE_CAPABILITIES_NONE UINT32_C(0)
+
+//! CHRE supports BLE scanning
+#define CHRE_BLE_CAPABILITIES_SCAN UINT32_C(1 << 0)
+
+//! CHRE BLE supports batching of scan results, either through Android-specific
+//! HCI (OCF: 0x156), or by the CHRE framework, internally.
+//! @since v1.7 Platforms with this capability must also support flushing scan
+//! results during a batched scan.
+#define CHRE_BLE_CAPABILITIES_SCAN_RESULT_BATCHING UINT32_C(1 << 1)
+
+//! CHRE BLE scan supports best-effort hardware filtering. If filtering is
+//! available, chreBleGetFilterCapabilities() returns a bitmap indicating the
+//! specific filtering capabilities that are supported.
+//! To differentiate best-effort vs. no filtering, the following requirement
+//! must be met for this flag:
+//! If only one nanoapp is requesting BLE scans and there are no BLE scans from
+//! the AP, only filtered results will be provided to the nanoapp.
+#define CHRE_BLE_CAPABILITIES_SCAN_FILTER_BEST_EFFORT UINT32_C(1 << 2)
+
+//! CHRE BLE supports reading the RSSI of a specified LE-ACL connection handle.
+#define CHRE_BLE_CAPABILITIES_READ_RSSI UINT32_C(1 << 3)
+/** @} */
+
+/**
+ * The set of flags returned by chreBleGetFilterCapabilities().
+ *
+ * The representative bit for each filtering capability is based on the sub-OCF
+ * of the Android filtering HCI vendor-specific command (LE_APCF_Command, OCF:
+ * 0x0157) for that particular filtering capability, as found in
+ * https://source.android.com/devices/bluetooth/hci_requirements
+ *
+ * For example, the Service Data filter has a sub-command of 0x7; hence
+ * the filtering capability is indicated by (1 << 0x7).
+ *
+ * @defgroup CHRE_BLE_FILTER_CAPABILITIES
+ * @{
+ */
+//! No CHRE BLE filters are supported
+#define CHRE_BLE_FILTER_CAPABILITIES_NONE UINT32_C(0)
+
+//! CHRE BLE supports RSSI filters
+#define CHRE_BLE_FILTER_CAPABILITIES_RSSI UINT32_C(1 << 1)
+
+//! CHRE BLE supports Manufacturer Data filters (Corresponding HCI OCF: 0x0157,
+//! Sub-command: 0x06)
+//! @since v1.8
+#define CHRE_BLE_FILTER_CAPABILITIES_MANUFACTURER_DATA UINT32_C(1 << 6)
+
+//! CHRE BLE supports Service Data filters (Corresponding HCI OCF: 0x0157,
+//! Sub-command: 0x07)
+#define CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA UINT32_C(1 << 7)
+/** @} */
+
+/**
+ * Produce an event ID in the block of IDs reserved for BLE.
+ *
+ * Valid input range is [0, 15]. Do not add new events with ID > 15
+ * (see chre/event.h)
+ *
+ * @param offset Index into BLE event ID block; valid range is [0, 15].
+ *
+ * @defgroup CHRE_BLE_EVENT_ID
+ * @{
+ */
+#define CHRE_BLE_EVENT_ID(offset) (CHRE_EVENT_BLE_FIRST_EVENT + (offset))
+
+/**
+ * nanoappHandleEvent argument: struct chreAsyncResult
+ *
+ * Communicates the asynchronous result of a request to the BLE API. The
+ * requestType field in {@link #chreAsyncResult} is set to a value from enum
+ * chreBleRequestType.
+ *
+ * This is used for results of async config operations which need to
+ * interop with lower level code (potentially in a different thread) or send an
+ * HCI command to the FW and wait on the response.
+ */
+#define CHRE_EVENT_BLE_ASYNC_RESULT CHRE_BLE_EVENT_ID(0)
+
+/**
+ * nanoappHandleEvent argument: struct chreBleAdvertisementEvent
+ *
+ * Provides results of a BLE scan.
+ */
+#define CHRE_EVENT_BLE_ADVERTISEMENT CHRE_BLE_EVENT_ID(1)
+
+/**
+ * nanoappHandleEvent argument: struct chreAsyncResult
+ *
+ * Indicates that a flush request made via chreBleFlushAsync() is complete, and
+ * all batched advertisements resulting from the flush have been delivered via
+ * preceding CHRE_EVENT_BLE_ADVERTISEMENT events.
+ *
+ * @since v1.7
+ */
+#define CHRE_EVENT_BLE_FLUSH_COMPLETE CHRE_BLE_EVENT_ID(2)
+
+/**
+ * nanoappHandleEvent argument: struct chreBleReadRssiEvent
+ *
+ * Provides the RSSI of an LE ACL connection following a call to
+ * chreBleReadRssiAsync().
+ *
+ * @since v1.8
+ */
+#define CHRE_EVENT_BLE_RSSI_READ CHRE_BLE_EVENT_ID(3)
+
+/**
+ * nanoappHandleEvent argument: struct chreBatchCompleteEvent
+ *
+ * This event is generated if the platform enabled batching, and when all
+ * events in a single batch has been delivered (for example, batching
+ * CHRE_EVENT_BLE_ADVERTISEMENT events if the platform has
+ * CHRE_BLE_CAPABILITIES_SCAN_RESULT_BATCHING enabled, and a non-zero
+ * reportDelayMs in chreBleStartScanAsync() was accepted).
+ *
+ * If the nanoapp receives a CHRE_EVENT_BLE_SCAN_STATUS_CHANGE with a non-zero
+ * reportDelayMs and enabled set to true, then this event must be generated.
+ *
+ * @since v1.8
+ */
+#define CHRE_EVENT_BLE_BATCH_COMPLETE CHRE_BLE_EVENT_ID(4)
+
+/**
+ * nanoappHandleEvent argument: struct chreBleScanStatus
+ *
+ * This event is generated when the values in chreBleScanStatus changes.
+ *
+ * @since v1.8
+ */
+#define CHRE_EVENT_BLE_SCAN_STATUS_CHANGE CHRE_BLE_EVENT_ID(5)
+
+// NOTE: Do not add new events with ID > 15
+/** @} */
+
+/**
+ * Maximum BLE (legacy) advertisement payload data length, in bytes
+ * This is calculated by subtracting 2 (type + len) from 31 (max payload).
+ */
+#define CHRE_BLE_DATA_LEN_MAX (29)
+
+/**
+ * BLE device address length, in bytes.
+ */
+#define CHRE_BLE_ADDRESS_LEN (6)
+
+/**
+ * RSSI value (int8_t) indicating no RSSI threshold.
+ */
+#define CHRE_BLE_RSSI_THRESHOLD_NONE (-128)
+
+/**
+ * RSSI value (int8_t) indicating no RSSI value available.
+ */
+#define CHRE_BLE_RSSI_NONE (127)
+
+/**
+ * Tx power value (int8_t) indicating no Tx power value available.
+ */
+#define CHRE_BLE_TX_POWER_NONE (127)
+
+/**
+ * Indicates ADI field was not provided in advertisement.
+ */
+#define CHRE_BLE_ADI_NONE (0xFF)
+
+/**
+ * The CHRE BLE advertising event type is based on the BT Core Spec v5.2,
+ * Vol 4, Part E, Section 7.7.65.13, LE Extended Advertising Report event,
+ * Event_Type.
+ *
+ * Note: helper functions are provided to avoid bugs, e.g. a nanoapp doing
+ * (eventTypeAndDataStatus == ADV_IND) instead of properly masking off reserved
+ * and irrelevant bits.
+ *
+ * @defgroup CHRE_BLE_EVENT
+ * @{
+ */
+// Extended event types
+#define CHRE_BLE_EVENT_MASK_TYPE (0x1f)
+#define CHRE_BLE_EVENT_TYPE_FLAG_CONNECTABLE (1 << 0)
+#define CHRE_BLE_EVENT_TYPE_FLAG_SCANNABLE (1 << 1)
+#define CHRE_BLE_EVENT_TYPE_FLAG_DIRECTED (1 << 2)
+#define CHRE_BLE_EVENT_TYPE_FLAG_SCAN_RSP (1 << 3)
+#define CHRE_BLE_EVENT_TYPE_FLAG_LEGACY (1 << 4)
+
+// Data status
+#define CHRE_BLE_EVENT_MASK_DATA_STATUS (0x3 << 5)
+#define CHRE_BLE_EVENT_DATA_STATUS_COMPLETE (0x0 << 5)
+#define CHRE_BLE_EVENT_DATA_STATUS_MORE_DATA_PENDING (0x1 << 5)
+#define CHRE_BLE_EVENT_DATA_STATUS_DATA_TRUNCATED (0x2 << 5)
+
+// Legacy event types
+#define CHRE_BLE_EVENT_TYPE_LEGACY_ADV_IND \
+ (CHRE_BLE_EVENT_TYPE_FLAG_LEGACY | CHRE_BLE_EVENT_TYPE_FLAG_CONNECTABLE | \
+ CHRE_BLE_EVENT_TYPE_FLAG_SCANNABLE)
+#define CHRE_BLE_EVENT_TYPE_LEGACY_DIRECT_IND \
+ (CHRE_BLE_EVENT_TYPE_FLAG_LEGACY | CHRE_BLE_EVENT_TYPE_FLAG_CONNECTABLE)
+#define CHRE_BLE_EVENT_TYPE_LEGACY_ADV_SCAN_IND \
+ (CHRE_BLE_EVENT_TYPE_FLAG_LEGACY | CHRE_BLE_EVENT_TYPE_FLAG_SCANNABLE)
+#define CHRE_BLE_EVENT_TYPE_LEGACY_ADV_NONCONN_IND \
+ (CHRE_BLE_EVENT_TYPE_FLAG_LEGACY)
+#define CHRE_BLE_EVENT_TYPE_LEGACY_SCAN_RESP_ADV_IND \
+ (CHRE_BLE_EVENT_TYPE_FLAG_SCAN_RSP | CHRE_BLE_EVENT_TYPE_LEGACY_ADV_IND)
+#define CHRE_BLE_EVENT_TYPE_LEGACY_SCAN_RESP_ADV_SCAN_IND \
+ (CHRE_BLE_EVENT_TYPE_FLAG_SCAN_RSP | CHRE_BLE_EVENT_TYPE_LEGACY_ADV_SCAN_IND)
+/** @} */
+
+/**
+ * The maximum amount of time allowed to elapse between the call to
+ * chreBleFlushAsync() and when CHRE_EVENT_BLE_FLUSH_COMPLETE is delivered to
+ * the nanoapp on a successful flush.
+ */
+#define CHRE_BLE_FLUSH_COMPLETE_TIMEOUT_NS (5 * CHRE_NSEC_PER_SEC)
+
+/**
+ * Indicates a type of request made in this API. Used to populate the resultType
+ * field of struct chreAsyncResult sent with CHRE_EVENT_BLE_ASYNC_RESULT.
+ */
+enum chreBleRequestType {
+ CHRE_BLE_REQUEST_TYPE_START_SCAN = 1,
+ CHRE_BLE_REQUEST_TYPE_STOP_SCAN = 2,
+ CHRE_BLE_REQUEST_TYPE_FLUSH = 3, //!< @since v1.7
+ CHRE_BLE_REQUEST_TYPE_READ_RSSI = 4, //!< @since v1.8
+};
+
+/**
+ * CHRE BLE scan modes identify functional scan levels without specifying or
+ * guaranteeing particular scan parameters (e.g. duty cycle, interval, radio
+ * chain).
+ *
+ * The actual scan parameters may be platform dependent and may change without
+ * notice in real time based on contextual cues, etc.
+ *
+ * Scan modes should be selected based on use cases as described.
+ */
+enum chreBleScanMode {
+ //! A background scan level for always-running ambient applications.
+ //! A representative duty cycle may be between 3 - 10 % (tentative, and
+ //! with no guarantees).
+ CHRE_BLE_SCAN_MODE_BACKGROUND = 1,
+
+ //! A foreground scan level to be used for short periods.
+ //! A representative duty cycle may be between 10 - 20 % (tentative, and
+ //! with no guarantees).
+ CHRE_BLE_SCAN_MODE_FOREGROUND = 2,
+
+ //! A very high duty cycle scan level to be used for very short durations.
+ //! A representative duty cycle may be between 50 - 100 % (tentative, and
+ //! with no guarantees).
+ CHRE_BLE_SCAN_MODE_AGGRESSIVE = 3,
+};
+
+/**
+ * Selected AD Types are available among those defined in the Bluetooth spec.
+ * Assigned Numbers, Generic Access Profile.
+ * ref: https://www.bluetooth.com/specifications/assigned-numbers/
+ */
+enum chreBleAdType {
+ //! Service Data with 16-bit UUID
+ //! @deprecated as of v1.8
+ //! TODO(b/285207430): Remove this enum once CHRE has been updated.
+ CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16 = 0x16,
+
+ //! Service Data with 16-bit UUID
+ //! @since v1.8 CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16 was renamed
+ //! CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE to reflect that nanoapps
+ //! compiled against v1.8+ should use OTA format for service data filters.
+ CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE = 0x16,
+
+ //! Manufacturer Specific Data
+ //! @since v1.8
+ CHRE_BLE_AD_TYPE_MANUFACTURER_DATA = 0xff,
+};
+
+/**
+ * Generic scan filters definition based on AD Type, mask, and values. The
+ * maximum data length is limited to the maximum possible legacy advertisement
+ * payload data length (29 bytes).
+ *
+ * The filter is matched when
+ * data & dataMask == advData & dataMask
+ * where advData is the advertisement packet data for the specified AD type.
+ *
+ * The CHRE generic filter structure represents a generic filter on an AD Type
+ * as defined in the Bluetooth spec Assigned Numbers, Generic Access Profile
+ * (ref: https://www.bluetooth.com/specifications/assigned-numbers/). This
+ * generic structure is used by the Advertising Packet Content Filter
+ * (APCF) HCI generic AD type sub-command 0x09 (ref:
+ * https://source.android.com/devices/bluetooth/hci_requirements#le_apcf_command).
+ *
+ * Note that the CHRE implementation may not support every kind of filter that
+ * can be represented by this structure. Use chreBleGetFilterCapabilities() to
+ * discover supported filtering capabilities at runtime.
+ *
+ * @since v1.8 The data and dataMask must be in OTA format. The nanoapp support
+ * library will handle converting the data and dataMask values to the correct
+ * format if a pre v1.8 version of CHRE is running.
+ *
+ * NOTE: CHRE versions 1.6 and 1.7 expect the 2-byte UUID prefix in
+ * CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16 to be given as big-endian. This
+ * was corrected in v1.8 to match the OTA format and Bluetooth specification,
+ * which uses little-endian. This enum has been removed and replaced with
+ * CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE to ensure that nanoapps
+ * compiled against v1.8 and later specify their UUID filter using
+ * little-endian. Nanoapps compiled against v1.7 or earlier should continue to
+ * use big-endian, as CHRE must provide cross-version compatibility for all
+ * possible version combinations.
+ *
+ * Example 1: To filter on a 16 bit service data UUID of 0xFE2C, the following
+ * settings would be used:
+ * type = CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16
+ * len = 2
+ * data = {0x2C, 0xFE}
+ * dataMask = {0xFF, 0xFF}
+ *
+ * Example 2: To filter for manufacturer data of 0x12, 0x34 from Google (0x00E0),
+ * the following settings would be used:
+ * type = CHRE_BLE_AD_TYPE_MANUFACTURER_DATA
+ * len = 4
+ * data = {0xE0, 0x00, 0x12, 0x34}
+ * dataMask = {0xFF, 0xFF, 0xFF, 0xFF}
+ *
+ * Refer to "Supplement to the Bluetooth Core Specification for details (v9,
+ * Part A, Section 1.4)" for details regarding the manufacturer data format.
+ */
+struct chreBleGenericFilter {
+ //! Acceptable values among enum chreBleAdType
+ uint8_t type;
+
+ /**
+ * Length of data and dataMask. AD payloads shorter than this length will not
+ * be matched by the filter. Length must be greater than 0.
+ */
+ uint8_t len;
+
+ //! Used in combination with dataMask to filter an advertisement
+ uint8_t data[CHRE_BLE_DATA_LEN_MAX];
+
+ //! Used in combination with data to filter an advertisement
+ uint8_t dataMask[CHRE_BLE_DATA_LEN_MAX];
+};
+
+/**
+ * CHRE Bluetooth LE scan filters are based on a combination of an RSSI
+ * threshold and generic scan filters as defined by AD Type, mask, and values.
+ *
+ * CHRE-provided filters are implemented in a best-effort manner, depending on
+ * HW capabilities of the system and available resources. Therefore, provided
+ * scan results may be a superset of the specified filters. Nanoapps should try
+ * to take advantage of CHRE scan filters as much as possible, but must design
+ * their logic as to not depend on CHRE filtering.
+ *
+ * The syntax of CHRE scan filter definitions are based on the Android
+ * Advertising Packet Content Filter (APCF) HCI requirement subtype 0x08
+ * ref:
+ * https://source.android.com/devices/bluetooth/hci_requirements#le_apcf_command-set_filtering_parameters_sub_cmd
+ * and AD Types as defined in the Bluetooth spec Assigned Numbers, Generic
+ * Access Profile
+ * ref: https://www.bluetooth.com/specifications/assigned-numbers/
+ *
+ * Even though the scan filters are defined in a generic manner, CHRE Bluetooth
+ * is expected to initially support only a limited set of AD Types.
+ */
+struct chreBleScanFilter {
+ //! RSSI threshold filter (Corresponding HCI OCF: 0x0157, Sub: 0x01), where
+ //! advertisements with RSSI values below this threshold may be disregarded.
+ //! An rssiThreshold value of CHRE_BLE_RSSI_THRESHOLD_NONE indicates no RSSI
+ //! filtering.
+ int8_t rssiThreshold;
+
+ //! Number of generic scan filters provided in the scanFilters array.
+ //! A scanFilterCount value of 0 indicates no generic scan filters.
+ uint8_t scanFilterCount;
+
+ //! Pointer to an array of scan filters. If the array contains more than one
+ //! entry, advertisements matching any of the entries will be returned
+ //! (functional OR).
+ const struct chreBleGenericFilter *scanFilters;
+};
+
+/**
+ * CHRE BLE advertising address type is based on the BT Core Spec v5.2, Vol 4,
+ * Part E, Section 7.7.65.13, LE Extended Advertising Report event,
+ * Address_Type.
+ */
+enum chreBleAddressType {
+ //! Public device address.
+ CHRE_BLE_ADDRESS_TYPE_PUBLIC = 0x00,
+
+ //! Random device address.
+ CHRE_BLE_ADDRESS_TYPE_RANDOM = 0x01,
+
+ //! Public identity address (corresponds to resolved private address).
+ CHRE_BLE_ADDRESS_TYPE_PUBLIC_IDENTITY = 0x02,
+
+ //! Random (static) Identity Address (corresponds to resolved private
+ //! address)
+ CHRE_BLE_ADDRESS_TYPE_RANDOM_IDENTITY = 0x03,
+
+ //! No address provided (anonymous advertisement).
+ CHRE_BLE_ADDRESS_TYPE_NONE = 0xff,
+};
+
+/**
+ * CHRE BLE physical (PHY) channel encoding type, if supported, is based on the
+ * BT Core Spec v5.2, Vol 4, Part E, Section 7.7.65.13, LE Extended Advertising
+ * Report event, entries Primary_PHY and Secondary_PHY.
+ */
+enum chreBlePhyType {
+ //! No packets on this PHY (only on the secondary channel), or feature not
+ //! supported.
+ CHRE_BLE_PHY_NONE = 0x00,
+
+ //! LE 1 MBPS PHY encoding.
+ CHRE_BLE_PHY_1M = 0x01,
+
+ //! LE 2 MBPS PHY encoding (only on the secondary channel).
+ CHRE_BLE_PHY_2M = 0x02,
+
+ //! LE long-range coded PHY encoding.
+ CHRE_BLE_PHY_CODED = 0x03,
+};
+
+/**
+ * The CHRE BLE Advertising Report event is based on the BT Core Spec v5.2,
+ * Vol 4, Part E, Section 7.7.65.13, LE Extended Advertising Report event, with
+ * the following differences:
+ *
+ * 1) A CHRE timestamp field, which can be useful if CHRE is batching results.
+ * 2) Reordering of the rssi and periodicAdvertisingInterval fields for memory
+ * alignment (prevent padding).
+ * 3) Addition of four reserved bytes to reclaim padding.
+ */
+struct chreBleAdvertisingReport {
+ //! The base timestamp, in nanoseconds, in the same time base as chreGetTime()
+ uint64_t timestamp;
+
+ //! @see CHRE_BLE_EVENT
+ uint8_t eventTypeAndDataStatus;
+
+ //! Advertising address type as defined in enum chreBleAddressType
+ uint8_t addressType;
+
+ //! Advertising device address
+ uint8_t address[CHRE_BLE_ADDRESS_LEN];
+
+ //! Advertiser PHY on primary advertising physical channel, if supported, as
+ //! defined in enum chreBlePhyType.
+ uint8_t primaryPhy;
+
+ //! Advertiser PHY on secondary advertising physical channel, if supported, as
+ //! defined in enum chreBlePhyType.
+ uint8_t secondaryPhy;
+
+ //! Value of the Advertising SID subfield in the ADI field of the PDU among
+ //! the range of [0, 0x0f].
+ //! CHRE_BLE_ADI_NONE indicates no ADI field was provided.
+ //! Other values are reserved.
+ uint8_t advertisingSid;
+
+ //! Transmit (Tx) power in dBm. Typical values are [-127, 20].
+ //! CHRE_BLE_TX_POWER_NONE indicates Tx power not available.
+ int8_t txPower;
+
+ //! Interval of the periodic advertising in 1.25 ms intervals, i.e.
+ //! time = periodicAdvertisingInterval * 1.25 ms
+ //! 0 means no periodic advertising. Minimum value is otherwise 6 (7.5 ms).
+ uint16_t periodicAdvertisingInterval;
+
+ //! RSSI in dBm. Typical values are [-127, 20].
+ //! CHRE_BLE_RSSI_NONE indicates RSSI is not available.
+ int8_t rssi;
+
+ //! Direct address type (i.e. only accept connection requests from a known
+ //! peer device) as defined in enum chreBleAddressType.
+ uint8_t directAddressType;
+
+ //! Direct address (i.e. only accept connection requests from a known peer
+ //! device).
+ uint8_t directAddress[CHRE_BLE_ADDRESS_LEN];
+
+ //! Length of data field. Acceptable range is [0, 62] for legacy and
+ //! [0, 255] for extended advertisements.
+ uint16_t dataLength;
+
+ //! dataLength bytes of data, or null if dataLength is 0. This represents
+ //! the ADV_IND payload, optionally concatenated with SCAN_RSP, as indicated
+ //! by eventTypeAndDataStatus.
+ const uint8_t *data;
+
+ //! Reserved for future use; set to 0
+ uint32_t reserved;
+};
+
+/**
+ * A CHRE BLE Advertising Event can contain any number of CHRE BLE Advertising
+ * Reports (i.e. advertisements).
+ */
+struct chreBleAdvertisementEvent {
+ //! Reserved for future use; set to 0
+ uint16_t reserved;
+
+ //! Number of advertising reports in this event
+ uint16_t numReports;
+
+ //! Array of length numReports
+ const struct chreBleAdvertisingReport *reports;
+};
+
+/**
+ * The RSSI read on a particular LE connection handle, based on the parameters
+ * in BT Core Spec v5.3, Vol 4, Part E, Section 7.5.4, Read RSSI command
+ */
+struct chreBleReadRssiEvent {
+ //! Structure which contains the cookie associated with the original request,
+ //! along with an error code that indicates request success or failure.
+ struct chreAsyncResult result;
+
+ //! The handle upon which CHRE attempted to read RSSI.
+ uint16_t connectionHandle;
+
+ //! The RSSI of the last packet received on this connection, if valid
+ //! (-127 to 20)
+ int8_t rssi;
+};
+
+/**
+ * Describes the current status of the BLE request in the platform.
+ *
+ * @since v1.8
+ */
+struct chreBleScanStatus {
+ //! The currently configured report delay in the scan configuration.
+ //! If enabled is false, this value does not have meaning.
+ uint32_t reportDelayMs;
+
+ //! True if the BLE scan is currently enabled. This can be set to false
+ //! if BLE scan was temporarily disabled (e.g. BT subsystem is down,
+ //! or due to user settings).
+ bool enabled;
+
+ //! Reserved for future use - set to zero.
+ uint8_t reserved[3];
+};
+
+/**
+ * Retrieves a set of flags indicating the BLE features supported by the
+ * current CHRE implementation. The value returned by this function must be
+ * consistent for the entire duration of the nanoapp's execution.
+ *
+ * The client must allow for more flags to be set in this response than it knows
+ * about, for example if the implementation supports a newer version of the API
+ * than the client was compiled against.
+ *
+ * @return A bitmask with zero or more CHRE_BLE_CAPABILITIES_* flags set. @see
+ * CHRE_BLE_CAPABILITIES
+ *
+ * @since v1.6
+ */
+uint32_t chreBleGetCapabilities(void);
+
+/**
+ * Retrieves a set of flags indicating the BLE filtering features supported by
+ * the current CHRE implementation. The value returned by this function must be
+ * consistent for the entire duration of the nanoapp's execution.
+ *
+ * The client must allow for more flags to be set in this response than it knows
+ * about, for example if the implementation supports a newer version of the API
+ * than the client was compiled against.
+ *
+ * @return A bitmask with zero or more CHRE_BLE_FILTER_CAPABILITIES_* flags set.
+ * @see CHRE_BLE_FILTER_CAPABILITIES
+ *
+ * @since v1.6
+ */
+uint32_t chreBleGetFilterCapabilities(void);
+
+/**
+ * Helper function to extract event type from eventTypeAndDataStatus as defined
+ * in the BT Core Spec v5.2, Vol 4, Part E, Section 7.7.65.13, LE Extended
+ * Advertising Report event, entry Event_Type.
+ *
+ * @see CHRE_BLE_EVENT
+ *
+ * @param eventTypeAndDataStatus Combined event type and data status
+ *
+ * @return The event type portion of eventTypeAndDataStatus
+ */
+static inline uint8_t chreBleGetEventType(uint8_t eventTypeAndDataStatus) {
+ return (eventTypeAndDataStatus & CHRE_BLE_EVENT_MASK_TYPE);
+}
+
+/**
+ * Helper function to extract data status from eventTypeAndDataStatus as defined
+ * in the BT Core Spec v5.2, Vol 4, Part E, Section 7.7.65.13, LE Extended
+ * Advertising Report event, entry Event_Type.
+ *
+ * @see CHRE_BLE_EVENT
+ *
+ * @param eventTypeAndDataStatus Combined event type and data status
+ *
+ * @return The data status portion of eventTypeAndDataStatus
+ */
+static inline uint8_t chreBleGetDataStatus(uint8_t eventTypeAndDataStatus) {
+ return (eventTypeAndDataStatus & CHRE_BLE_EVENT_MASK_DATA_STATUS);
+}
+
+/**
+ * Helper function to to combine an event type with a data status to create
+ * eventTypeAndDataStatus as defined in the BT Core Spec v5.2, Vol 4, Part E,
+ * Section 7.7.65.13, LE Extended Advertising Report event, entry Event_Type.
+ *
+ * @see CHRE_BLE_EVENT
+ *
+ * @param eventType Event type
+ * @param dataStatus Data status
+ *
+ * @return A combined eventTypeAndDataStatus
+ */
+static inline uint8_t chreBleGetEventTypeAndDataStatus(uint8_t eventType,
+ uint8_t dataStatus) {
+ return ((eventType & CHRE_BLE_EVENT_MASK_TYPE) |
+ (dataStatus & CHRE_BLE_EVENT_MASK_DATA_STATUS));
+}
+
+/**
+ * Nanoapps must define CHRE_NANOAPP_USES_BLE somewhere in their build
+ * system (e.g. Makefile) if the nanoapp needs to use the following BLE APIs.
+ * In addition to allowing access to these APIs, defining this macro will also
+ * ensure CHRE enforces that all host clients this nanoapp talks to have the
+ * required Android permissions needed to access BLE functionality by adding
+ * metadata to the nanoapp.
+ */
+#if defined(CHRE_NANOAPP_USES_BLE) || !defined(CHRE_IS_NANOAPP_BUILD)
+
+/**
+ * Start Bluetooth LE (BLE) scanning on CHRE.
+ *
+ * The result of the operation will be delivered asynchronously via the CHRE
+ * event CHRE_EVENT_BLE_ASYNC_RESULT.
+ *
+ * The scan results will be delivered asynchronously via the CHRE event
+ * CHRE_EVENT_BLE_ADVERTISEMENT.
+ *
+ * If CHRE_USER_SETTING_BLE_AVAILABLE is disabled, CHRE is expected to return an
+ * async result with error CHRE_ERROR_FUNCTION_DISABLED. If this setting is
+ * enabled, the Bluetooth subsystem may still be powered down in the scenario
+ * where the main Bluetooth toggle is disabled, but the Bluetooth scanning
+ * setting is enabled, and there is no request for BLE to be enabled at the
+ * Android level. In this scenario, CHRE will return an async result with error
+ * CHRE_ERROR_FUNCTION_DISABLED.
+ *
+ * To ensure that Bluetooth remains powered on in this settings configuration so
+ * that a nanoapp can scan, the nanoapp's Android host entity should use the
+ * BluetoothAdapter.enableBLE() API to register this request with the Android
+ * Bluetooth stack.
+ *
+ * If chreBleStartScanAsync() is called while a previous scan has been started,
+ * the previous scan will be stopped first and replaced with the new scan.
+ *
+ * Note that some corresponding Android parameters are missing from the CHRE
+ * API, where the following default or typical parameters are used:
+ * Callback type: CALLBACK_TYPE_ALL_MATCHES
+ * Result type: SCAN_RESULT_TYPE_FULL
+ * Match mode: MATCH_MODE_AGGRESSIVE
+ * Number of matches per filter: MATCH_NUM_MAX_ADVERTISEMENT
+ * Legacy-only: false
+ * PHY type: PHY_LE_ALL_SUPPORTED
+ *
+ * For v1.8 and greater, a CHRE_EVENT_BLE_SCAN_STATUS_CHANGE will be generated
+ * if the values in chreBleScanStatus changes as a result of this call.
+ *
+ * @param mode Scanning mode selected among enum chreBleScanMode
+ * @param reportDelayMs Maximum requested batching delay in ms. 0 indicates no
+ * batching. Note that the system may deliver results
+ * before the maximum specified delay is reached.
+ * @param filter Pointer to the requested best-effort filter configuration as
+ * defined by struct chreBleScanFilter. The ownership of filter
+ * and its nested elements remains with the caller, and the caller
+ * may release it as soon as chreBleStartScanAsync() returns.
+ *
+ * @return True to indicate that the request was accepted. False otherwise.
+ *
+ * @since v1.6
+ */
+bool chreBleStartScanAsync(enum chreBleScanMode mode, uint32_t reportDelayMs,
+ const struct chreBleScanFilter *filter);
+/**
+ * Stops a CHRE BLE scan.
+ *
+ * The result of the operation will be delivered asynchronously via the CHRE
+ * event CHRE_EVENT_BLE_ASYNC_RESULT.
+ *
+ * @return True to indicate that the request was accepted. False otherwise.
+ *
+ * @since v1.6
+ */
+bool chreBleStopScanAsync(void);
+
+/**
+ * Requests to immediately deliver batched scan results. The nanoapp must
+ * have an active BLE scan request. If a request is accepted, it will be treated
+ * as though the reportDelayMs has expired for a batched scan. Upon accepting
+ * the request, CHRE works to immediately deliver scan results currently kept in
+ * batching memory, if any, via regular CHRE_EVENT_BLE_ADVERTISEMENT events,
+ * followed by a CHRE_EVENT_BLE_FLUSH_COMPLETE event.
+ *
+ * If the underlying system fails to complete the flush operation within
+ * CHRE_BLE_FLUSH_COMPLETE_TIMEOUT_NS, CHRE will send a
+ * CHRE_EVENT_BLE_FLUSH_COMPLETE event with CHRE_ERROR_TIMEOUT.
+ *
+ * If multiple flush requests are made prior to flush completion, then the
+ * requesting nanoapp will receive all batched samples existing at the time of
+ * the latest flush request. In this case, the number of
+ * CHRE_EVENT_BLE_FLUSH_COMPLETE events received must equal the number of flush
+ * requests made.
+ *
+ * If chreBleStopScanAsync() is called while a flush operation is in progress,
+ * it is unspecified whether the flush operation will complete successfully or
+ * return an error, such as CHRE_ERROR_FUNCTION_DISABLED, but in any case,
+ * CHRE_EVENT_BLE_FLUSH_COMPLETE must still be delivered. The same applies if
+ * the Bluetooth user setting is disabled during a flush operation.
+ *
+ * If called while running on a CHRE API version below v1.7, this function
+ * returns false and has no effect.
+ *
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent as a response to this request.
+ *
+ * @return True to indicate the request was accepted. False otherwise.
+ *
+ * @since v1.7
+ */
+bool chreBleFlushAsync(const void *cookie);
+
+/**
+ * Requests to read the RSSI of a peer device on the given LE connection
+ * handle.
+ *
+ * If the request is accepted, the response will be delivered in a
+ * CHRE_EVENT_BLE_RSSI_READ event with the same cookie.
+ *
+ * The request may be rejected if resources are not available to service the
+ * request (such as if too many outstanding requests already exist). If so, the
+ * client may retry later.
+ *
+ * Note that the connectionHandle is valid only while the connection remains
+ * active. If a peer device disconnects then reconnects, the handle may change.
+ * BluetoothDevice#getConnectionHandle() can be used from the Android framework
+ * to get the latest handle upon reconnection.
+ *
+ * @param connectionHandle
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * embedded in the response to this request.
+ * @return True if the request has been accepted and dispatched to the
+ * controller. False otherwise.
+ *
+ * @since v1.8
+ *
+ */
+bool chreBleReadRssiAsync(uint16_t connectionHandle, const void *cookie);
+
+/**
+ * Retrieves the current state of the BLE scan on the platform.
+ *
+ * @param status A non-null pointer to where the scan status will be
+ * populated.
+ *
+ * @return True if the status was obtained successfully.
+ *
+ * @since v1.8
+ */
+bool chreBleGetScanStatus(struct chreBleScanStatus *status);
+
+/**
+ * Definitions for handling unsupported CHRE BLE scenarios.
+ */
+#else // defined(CHRE_NANOAPP_USES_BLE) || !defined(CHRE_IS_NANOAPP_BUILD)
+
+#define CHRE_BLE_PERM_ERROR_STRING \
+ "CHRE_NANOAPP_USES_BLE must be defined when building this nanoapp in " \
+ "order to refer to "
+
+#define chreBleStartScanAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_BLE_PERM_ERROR_STRING "chreBleStartScanAsync")
+
+#define chreBleStopScanAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_BLE_PERM_ERROR_STRING "chreBleStopScanAsync")
+
+#define chreBleFlushAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_BLE_PERM_ERROR_STRING "chreBleFlushAsync")
+
+#define chreBleReadRssiAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_BLE_PERM_ERROR_STRING "chreBleReadRssiAsync")
+
+#endif // defined(CHRE_NANOAPP_USES_BLE) || !defined(CHRE_IS_NANOAPP_BUILD)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CHRE_BLE_H_ */
diff --git a/chre_api/legacy/v1_8/chre/common.h b/chre_api/legacy/v1_8/chre/common.h
new file mode 100644
index 00000000..8e2df597
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/common.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_COMMON_H_
+#define _CHRE_COMMON_H_
+
+/**
+ * @file
+ * Definitions shared across multiple CHRE header files
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Mask of the 5 most significant bytes in a 64-bit nanoapp or CHRE platform
+ * identifier, which represents the vendor ID portion of the ID.
+ */
+#define CHRE_VENDOR_ID_MASK UINT64_C(0xFFFFFFFFFF000000)
+
+/**
+ * Vendor ID "Googl". Used in nanoapp IDs and CHRE platform IDs developed and
+ * released by Google.
+ */
+#define CHRE_VENDOR_ID_GOOGLE UINT64_C(0x476F6F676C000000)
+
+/**
+ * Vendor ID "GoogT". Used for nanoapp IDs associated with testing done by
+ * Google.
+ */
+#define CHRE_VENDOR_ID_GOOGLE_TEST UINT64_C(0x476F6F6754000000)
+
+/**
+ * Helper macro to mask off all bytes other than the vendor ID (most significant
+ * 5 bytes) in 64-bit nanoapp and CHRE platform identifiers.
+ *
+ * @see chreGetNanoappInfo()
+ * @see chreGetPlatformId()
+ */
+#define CHRE_EXTRACT_VENDOR_ID(id) ((id) & CHRE_VENDOR_ID_MASK)
+
+/**
+ * Number of nanoseconds in one second, represented as an unsigned 64-bit
+ * integer
+ */
+#define CHRE_NSEC_PER_SEC UINT64_C(1000000000)
+
+/**
+ * General timeout for asynchronous API requests. Unless specified otherwise, a
+ * function call that returns data asynchronously via an event, such as
+ * CHRE_EVENT_ASYNC_GNSS_RESULT, must do so within this amount of time.
+ */
+#define CHRE_ASYNC_RESULT_TIMEOUT_NS (5 * CHRE_NSEC_PER_SEC)
+
+
+/**
+ * A generic listing of error codes for use in {@link #chreAsyncResult} and
+ * elsewhere. In general, module-specific error codes may be added to this enum,
+ * but effort should be made to come up with a generic name that still captures
+ * the meaning of the error.
+ */
+// LINT.IfChange
+enum chreError {
+ //! No error occurred
+ CHRE_ERROR_NONE = 0,
+
+ //! An unspecified failure occurred
+ CHRE_ERROR = 1,
+
+ //! One or more supplied arguments are invalid
+ CHRE_ERROR_INVALID_ARGUMENT = 2,
+
+ //! Unable to satisfy request because the system is busy
+ CHRE_ERROR_BUSY = 3,
+
+ //! Unable to allocate memory
+ CHRE_ERROR_NO_MEMORY = 4,
+
+ //! The requested feature is not supported
+ CHRE_ERROR_NOT_SUPPORTED = 5,
+
+ //! A timeout occurred while processing the request
+ CHRE_ERROR_TIMEOUT = 6,
+
+ //! The relevant capability is disabled, for example due to a user
+ //! configuration that takes precedence over this request
+ CHRE_ERROR_FUNCTION_DISABLED = 7,
+
+ //! The request was rejected due to internal rate limiting of the requested
+ //! functionality - the client may try its request again after waiting an
+ //! unspecified amount of time
+ CHRE_ERROR_REJECTED_RATE_LIMIT = 8,
+
+ //! The requested functionality is not currently accessible from the CHRE,
+ //! because another client, such as the main applications processor, is
+ //! currently controlling it.
+ CHRE_ERROR_FUNCTION_RESTRICTED_TO_OTHER_MASTER = 9,
+ CHRE_ERROR_FUNCTION_RESTRICTED_TO_OTHER_CLIENT = 9,
+
+ //! This request is no longer valid. It may have been replaced by a newer
+ //! request before taking effect.
+ CHRE_ERROR_OBSOLETE_REQUEST = 10,
+
+ //!< Do not exceed this value when adding new error codes
+ CHRE_ERROR_LAST = UINT8_MAX,
+};
+// LINT.ThenChange(../../../../core/include/chre/core/api_manager_common.h)
+
+/**
+ * Generic data structure to indicate the result of an asynchronous operation.
+ *
+ * @note
+ * The general model followed by CHRE for asynchronous operations is that a
+ * request function returns a boolean value that indicates whether the request
+ * was accepted for further processing. The actual result of the operation is
+ * provided in a subsequent event sent with an event type that is defined in the
+ * specific API. Typically, a "cookie" parameter is supplied to allow the client
+ * to tie the response to a specific request, or pass data through, etc. The
+ * response is expected to be delivered within CHRE_ASYNC_RESULT_TIMEOUT_NS if
+ * not specified otherwise.
+ *
+ * The CHRE implementation must allow for multiple asynchronous requests to be
+ * outstanding at a given time, under reasonable resource constraints. Further,
+ * requests must be processed in the same order as supplied by the client of the
+ * API in order to maintain causality. Using GNSS as an example, if a client
+ * calls chreGnssLocationSessionStartAsync() and then immediately calls
+ * chreGnssLocationSessionStopAsync(), the final result must be that the
+ * location session is stopped. Whether requests always complete in the
+ * order that they are given is implementation-defined. For example, if a client
+ * calls chreGnssLocationSessionStart() and then immediately calls
+ * chreGnssMeasurementSessionStart(), it is possible for the
+ * CHRE_EVENT_GNSS_RESULT associated with the measurement session to be
+ * delivered before the one for the location session.
+ */
+struct chreAsyncResult {
+ //! Indicates the request associated with this result. The interpretation of
+ //! values in this field is dependent upon the event type provided when this
+ //! result was delivered.
+ uint8_t requestType;
+
+ //! Set to true if the request was successfully processed
+ bool success;
+
+ //! If the request failed (success is false), this is set to a value from
+ //! enum chreError (other than CHRE_ERROR_NONE), which may provide
+ //! additional information about the nature of the failure.
+ //! @see #chreError
+ uint8_t errorCode;
+
+ //! Reserved for future use, set to 0
+ uint8_t reserved;
+
+ //! Set to the cookie parameter given to the request function tied to this
+ //! result
+ const void *cookie;
+};
+
+/**
+ * A structure to store an event describing the end of batched events.
+ *
+ * @since v1.8
+ */
+struct chreBatchCompleteEvent {
+ //! Indicates the type of event (of type CHRE_EVENT_TYPE_*) that was
+ //! batched.
+ uint16_t eventType;
+
+ //! Reserved for future use, set to 0
+ uint8_t reserved[2];
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHRE_COMMON_H_ */
diff --git a/chre_api/legacy/v1_8/chre/event.h b/chre_api/legacy/v1_8/chre/event.h
new file mode 100644
index 00000000..e519c3d3
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/event.h
@@ -0,0 +1,948 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_EVENT_H_
+#define _CHRE_EVENT_H_
+
+/**
+ * @file
+ * Context Hub Runtime Environment API dealing with events and messages.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <chre/toolchain.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The CHRE implementation is required to provide the following preprocessor
+ * defines via the build system.
+ *
+ * CHRE_MESSAGE_TO_HOST_MAX_SIZE: The maximum size, in bytes, allowed for
+ * a message sent to chreSendMessageToHostEndpoint(). This must be at least
+ * CHRE_MESSAGE_TO_HOST_MINIMUM_MAX_SIZE.
+ */
+
+#ifndef CHRE_MESSAGE_TO_HOST_MAX_SIZE
+#error CHRE_MESSAGE_TO_HOST_MAX_SIZE must be defined by the CHRE implementation
+#endif
+
+/**
+ * The minimum size, in bytes, any CHRE implementation will use for
+ * CHRE_MESSAGE_TO_HOST_MAX_SIZE is set to 1000 for v1.5+ CHRE implementations,
+ * and 128 for v1.0-v1.4 implementations (previously kept in
+ * CHRE_MESSAGE_TO_HOST_MINIMUM_MAX_SIZE, which has been removed).
+ *
+ * All CHRE implementations supporting v1.5+ must support the raised limit of
+ * 1000 bytes, however a nanoapp compiled against v1.5 cannot assume this
+ * limit if there is a possibility their binary will run on a v1.4 or earlier
+ * implementation that had a lower limit. To allow for nanoapp compilation in
+ * these situations, CHRE_MESSAGE_TO_HOST_MAX_SIZE must be set to the minimum
+ * value the nanoapp may encounter, and CHRE_NANOAPP_SUPPORTS_PRE_V1_5 can be
+ * defined to skip the compile-time check.
+ */
+#if (!defined(CHRE_NANOAPP_SUPPORTS_PRE_V1_5) && \
+ CHRE_MESSAGE_TO_HOST_MAX_SIZE < 1000) || \
+ (defined(CHRE_NANOAPP_SUPPORTS_PRE_V1_5) && \
+ CHRE_MESSAGE_TO_HOST_MAX_SIZE < 128)
+#error CHRE_MESSAGE_TO_HOST_MAX_SIZE is too small.
+#endif
+
+/**
+ * The lowest numerical value legal for a user-defined event.
+ *
+ * The system reserves all event values from 0 to 0x7FFF, inclusive.
+ * User events may use any value in the range 0x8000 to 0xFFFF, inclusive.
+ *
+ * Note that the same event values might be used by different nanoapps
+ * for different meanings. This is not a concern, as these values only
+ * have meaning when paired with the originating nanoapp.
+ */
+#define CHRE_EVENT_FIRST_USER_VALUE UINT16_C(0x8000)
+
+/**
+ * nanoappHandleEvent argument: struct chreMessageFromHostData
+ *
+ * The format of the 'message' part of this structure is left undefined,
+ * and it's up to the nanoapp and host to have an established protocol
+ * beforehand.
+ */
+#define CHRE_EVENT_MESSAGE_FROM_HOST UINT16_C(0x0001)
+
+/**
+ * nanoappHandleEvent argument: 'cookie' given to chreTimerSet() method.
+ *
+ * Indicates that a timer has elapsed, in accordance with how chreTimerSet() was
+ * invoked.
+ */
+#define CHRE_EVENT_TIMER UINT16_C(0x0002)
+
+/**
+ * nanoappHandleEvent argument: struct chreNanoappInfo
+ *
+ * Indicates that a nanoapp has successfully started (its nanoappStart()
+ * function has been called, and it returned true) and is able to receive events
+ * sent via chreSendEvent(). Note that this event is not sent for nanoapps that
+ * were started prior to the current nanoapp - use chreGetNanoappInfo() to
+ * determine if another nanoapp is already running.
+ *
+ * @see chreConfigureNanoappInfoEvents
+ * @since v1.1
+ */
+#define CHRE_EVENT_NANOAPP_STARTED UINT16_C(0x0003)
+
+/**
+ * nanoappHandleEvent argument: struct chreNanoappInfo
+ *
+ * Indicates that a nanoapp has stopped executing and is no longer able to
+ * receive events sent via chreSendEvent(). Any events sent prior to receiving
+ * this event are not guaranteed to have been delivered.
+ *
+ * @see chreConfigureNanoappInfoEvents
+ * @since v1.1
+ */
+#define CHRE_EVENT_NANOAPP_STOPPED UINT16_C(0x0004)
+
+/**
+ * nanoappHandleEvent argument: NULL
+ *
+ * Indicates that CHRE has observed the host wake from low-power sleep state.
+ *
+ * @see chreConfigureHostSleepStateEvents
+ * @since v1.2
+ */
+#define CHRE_EVENT_HOST_AWAKE UINT16_C(0x0005)
+
+/**
+ * nanoappHandleEvent argument: NULL
+ *
+ * Indicates that CHRE has observed the host enter low-power sleep state.
+ *
+ * @see chreConfigureHostSleepStateEvents
+ * @since v1.2
+ */
+#define CHRE_EVENT_HOST_ASLEEP UINT16_C(0x0006)
+
+/**
+ * nanoappHandleEvent argument: NULL
+ *
+ * Indicates that CHRE is collecting debug dumps. Nanoapps can call
+ * chreDebugDumpLog() to log their debug data while handling this event.
+ *
+ * @see chreConfigureDebugDumpEvent
+ * @see chreDebugDumpLog
+ * @since v1.4
+ */
+#define CHRE_EVENT_DEBUG_DUMP UINT16_C(0x0007)
+
+/**
+ * nanoappHandleEvent argument: struct chreHostEndpointNotification
+ *
+ * Notifications event regarding a host endpoint.
+ *
+ * @see chreConfigureHostEndpointNotifications
+ * @since v1.6
+ */
+#define CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION UINT16_C(0x0008)
+
+/**
+ * First possible value for CHRE_EVENT_SENSOR events.
+ *
+ * This allows us to separately define our CHRE_EVENT_SENSOR_* events in
+ * chre/sensor.h, without fear of collision with other event values.
+ */
+#define CHRE_EVENT_SENSOR_FIRST_EVENT UINT16_C(0x0100)
+
+/**
+ * Last possible value for CHRE_EVENT_SENSOR events.
+ *
+ * This allows us to separately define our CHRE_EVENT_SENSOR_* events in
+ * chre/sensor.h, without fear of collision with other event values.
+ */
+#define CHRE_EVENT_SENSOR_LAST_EVENT UINT16_C(0x02FF)
+
+/**
+ * First event in the block reserved for GNSS. These events are defined in
+ * chre/gnss.h.
+ */
+#define CHRE_EVENT_GNSS_FIRST_EVENT UINT16_C(0x0300)
+#define CHRE_EVENT_GNSS_LAST_EVENT UINT16_C(0x030F)
+
+/**
+ * First event in the block reserved for WiFi. These events are defined in
+ * chre/wifi.h.
+ */
+#define CHRE_EVENT_WIFI_FIRST_EVENT UINT16_C(0x0310)
+#define CHRE_EVENT_WIFI_LAST_EVENT UINT16_C(0x031F)
+
+/**
+ * First event in the block reserved for WWAN. These events are defined in
+ * chre/wwan.h.
+ */
+#define CHRE_EVENT_WWAN_FIRST_EVENT UINT16_C(0x0320)
+#define CHRE_EVENT_WWAN_LAST_EVENT UINT16_C(0x032F)
+
+/**
+ * First event in the block reserved for audio. These events are defined in
+ * chre/audio.h.
+ */
+#define CHRE_EVENT_AUDIO_FIRST_EVENT UINT16_C(0x0330)
+#define CHRE_EVENT_AUDIO_LAST_EVENT UINT16_C(0x033F)
+
+/**
+ * First event in the block reserved for settings changed notifications.
+ * These events are defined in chre/user_settings.h
+ *
+ * @since v1.5
+ */
+#define CHRE_EVENT_SETTING_CHANGED_FIRST_EVENT UINT16_C(0x340)
+#define CHRE_EVENT_SETTING_CHANGED_LAST_EVENT UINT16_C(0x34F)
+
+/**
+ * First event in the block reserved for Bluetooth LE. These events are defined
+ * in chre/ble.h.
+ */
+#define CHRE_EVENT_BLE_FIRST_EVENT UINT16_C(0x0350)
+#define CHRE_EVENT_BLE_LAST_EVENT UINT16_C(0x035F)
+
+/**
+ * First in the extended range of values dedicated for internal CHRE
+ * implementation usage.
+ *
+ * This range is semantically the same as the internal event range defined
+ * below, but has been extended to allow for more implementation-specific events
+ * to be used.
+ *
+ * @since v1.1
+ */
+#define CHRE_EVENT_INTERNAL_EXTENDED_FIRST_EVENT UINT16_C(0x7000)
+
+/**
+ * First in a range of values dedicated for internal CHRE implementation usage.
+ *
+ * If a CHRE wishes to use events internally, any values within this range
+ * are assured not to be taken by future CHRE API additions.
+ */
+#define CHRE_EVENT_INTERNAL_FIRST_EVENT UINT16_C(0x7E00)
+
+/**
+ * Last in a range of values dedicated for internal CHRE implementation usage.
+ *
+ * If a CHRE wishes to use events internally, any values within this range
+ * are assured not to be taken by future CHRE API additions.
+ */
+#define CHRE_EVENT_INTERNAL_LAST_EVENT UINT16_C(0x7FFF)
+
+/**
+ * A special value for the hostEndpoint argument in
+ * chreSendMessageToHostEndpoint() that indicates that the message should be
+ * delivered to all host endpoints. This value will not be used in the
+ * hostEndpoint field of struct chreMessageFromHostData supplied with
+ * CHRE_EVENT_MESSAGE_FROM_HOST.
+ *
+ * @since v1.1
+ */
+#define CHRE_HOST_ENDPOINT_BROADCAST UINT16_C(0xFFFF)
+
+/**
+ * A special value for hostEndpoint in struct chreMessageFromHostData that
+ * indicates that a host endpoint is unknown or otherwise unspecified. This
+ * value may be received in CHRE_EVENT_MESSAGE_FROM_HOST, but it is not valid to
+ * provide it to chreSendMessageToHostEndpoint().
+ *
+ * @since v1.1
+ */
+#define CHRE_HOST_ENDPOINT_UNSPECIFIED UINT16_C(0xFFFE)
+
+/**
+ * Bitmask values that can be given as input to the messagePermissions parameter
+ * of chreSendMessageWithPermissions(). These values are typically used by
+ * nanoapps when they used data from the corresponding CHRE APIs to produce the
+ * message contents being sent and is used to attribute permissions usage on
+ * the Android side. See chreSendMessageWithPermissions() for more details on
+ * how these values are used when sending a message.
+ *
+ * Values in the range
+ * [CHRE_MESSAGE_PERMISSION_VENDOR_START, CHRE_MESSAGE_PERMISSION_VENDOR_END]
+ * are reserved for vendors to use when adding support for permission-gated APIs
+ * in their implementations.
+ *
+ * On the Android side, CHRE permissions are mapped as follows:
+ * - CHRE_MESSAGE_PERMISSION_AUDIO: android.permission.RECORD_AUDIO
+ * - CHRE_MESSAGE_PERMISSION_GNSS, CHRE_MESSAGE_PERMISSION_WIFI, and
+ * CHRE_MESSAGE_PERMISSION_WWAN: android.permission.ACCESS_FINE_LOCATION, and
+ * android.permissions.ACCESS_BACKGROUND_LOCATION
+ *
+ * @since v1.5
+ *
+ * @defgroup CHRE_MESSAGE_PERMISSION
+ * @{
+ */
+
+#define CHRE_MESSAGE_PERMISSION_NONE UINT32_C(0)
+#define CHRE_MESSAGE_PERMISSION_AUDIO UINT32_C(1)
+#define CHRE_MESSAGE_PERMISSION_GNSS (UINT32_C(1) << 1)
+#define CHRE_MESSAGE_PERMISSION_WIFI (UINT32_C(1) << 2)
+#define CHRE_MESSAGE_PERMISSION_WWAN (UINT32_C(1) << 3)
+#define CHRE_MESSAGE_PERMISSION_BLE (UINT32_C(1) << 4)
+#define CHRE_MESSAGE_PERMISSION_VENDOR_START (UINT32_C(1) << 24)
+#define CHRE_MESSAGE_PERMISSION_VENDOR_END (UINT32_C(1) << 31)
+
+/** @} */
+
+/**
+ * @see chrePublishRpcServices
+ *
+ * @since v1.8
+ */
+#define CHRE_MINIMUM_RPC_SERVICE_LIMIT UINT8_C(4)
+
+/**
+ * Data provided with CHRE_EVENT_MESSAGE_FROM_HOST.
+ */
+struct chreMessageFromHostData {
+ /**
+ * Message type supplied by the host.
+ *
+ * @note In CHRE API v1.0, support for forwarding this field from the host
+ * was not strictly required, and some implementations did not support it.
+ * However, its support is mandatory as of v1.1.
+ */
+ union {
+ /**
+ * The preferred name to use when referencing this field.
+ *
+ * @since v1.1
+ */
+ uint32_t messageType;
+
+ /**
+ * @deprecated This is the name for the messageType field used in v1.0.
+ * Left to allow code to compile against both v1.0 and v1.1 of the API
+ * definition without needing to use #ifdefs. This will be removed in a
+ * future API update - use messageType instead.
+ */
+ uint32_t reservedMessageType;
+ };
+
+ /**
+ * The size, in bytes of the following 'message'.
+ *
+ * This can be 0.
+ */
+ uint32_t messageSize;
+
+ /**
+ * The message from the host.
+ *
+ * These contents are of a format that the host and nanoapp must have
+ * established beforehand.
+ *
+ * This data is 'messageSize' bytes in length. Note that if 'messageSize'
+ * is 0, this might be NULL.
+ */
+ const void *message;
+
+ /**
+ * An identifier for the host-side entity that sent this message. Unless
+ * this is set to CHRE_HOST_ENDPOINT_UNSPECIFIED, it can be used in
+ * chreSendMessageToHostEndpoint() to send a directed reply that will only
+ * be received by the given entity on the host. Endpoint identifiers are
+ * opaque values assigned at runtime, so they cannot be assumed to always
+ * describe a specific entity across restarts.
+ *
+ * If running on a CHRE API v1.0 implementation, this field will always be
+ * set to CHRE_HOST_ENDPOINT_UNSPECIFIED.
+ *
+ * @since v1.1
+ */
+ uint16_t hostEndpoint;
+};
+
+/**
+ * Provides metadata for a nanoapp in the system.
+ */
+struct chreNanoappInfo {
+ /**
+ * Nanoapp identifier. The convention for populating this value is to set
+ * the most significant 5 bytes to a value that uniquely identifies the
+ * vendor, and the lower 3 bytes identify the nanoapp.
+ */
+ uint64_t appId;
+
+ /**
+ * Nanoapp version. The semantics of this field are defined by the nanoapp,
+ * however nanoapps are recommended to follow the same scheme used for the
+ * CHRE version exposed in chreGetVersion(). That is, the most significant
+ * byte represents the major version, the next byte the minor version, and
+ * the lower two bytes the patch version.
+ */
+ uint32_t version;
+
+ /**
+ * The instance ID of this nanoapp, which can be used in chreSendEvent() to
+ * address an event specifically to this nanoapp. This identifier is
+ * guaranteed to be unique among all nanoapps in the system.
+ *
+ * As of CHRE API v1.6, instance ID is guaranteed to never be greater than
+ * UINT16_MAX. This allows for the instance ID be packed with other data
+ * inside a 32-bit integer (useful for RPC routing).
+ */
+ uint32_t instanceId;
+
+ /**
+ * Reserved for future use.
+ * Always set to 0.
+ */
+ uint8_t reserved[3];
+
+ /**
+ * The number of RPC services exposed by this nanoapp.
+ * The service details are available in the rpcServices array.
+ * Must always be set to 0 when running on a CHRE implementation prior to
+ * v1.8
+ *
+ * @since v1.8
+ */
+ uint8_t rpcServiceCount;
+
+ /*
+ * Array of RPC services published by this nanoapp.
+ * Services are published via chrePublishRpcServices.
+ * The array contains rpcServiceCount entries.
+ *
+ * The pointer is only valid when rpcServiceCount is greater than 0.
+ *
+ * @since v1.8
+ */
+ const struct chreNanoappRpcService *rpcServices;
+};
+
+/**
+ * The types of notification events that can be included in struct
+ * chreHostEndpointNotification.
+ *
+ * @defgroup HOST_ENDPOINT_NOTIFICATION_TYPE
+ * @{
+ */
+#define HOST_ENDPOINT_NOTIFICATION_TYPE_DISCONNECT UINT8_C(0)
+/** @} */
+
+/**
+ * Data provided in CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION.
+ */
+struct chreHostEndpointNotification {
+ /**
+ * The ID of the host endpoint that this notification is for.
+ */
+ uint16_t hostEndpointId;
+
+ /**
+ * The type of notification this event represents, which should be
+ * one of the HOST_ENDPOINT_NOTIFICATION_TYPE_* values.
+ */
+ uint8_t notificationType;
+
+ /**
+ * Reserved for future use, must be zero.
+ */
+ uint8_t reserved;
+};
+
+//! The maximum length of a host endpoint's name.
+#define CHRE_MAX_ENDPOINT_NAME_LEN (51)
+
+//! The maximum length of a host endpoint's tag.
+#define CHRE_MAX_ENDPOINT_TAG_LEN (51)
+
+/**
+ * The type of host endpoint that can be used in the hostEndpointType field
+ * of chreHostEndpointInfo.
+ *
+ * @since v1.6
+ *
+ * @defgroup CHRE_HOST_ENDPOINT_TYPE_
+ * @{
+ */
+
+//! The host endpoint is part of the Android system framework.
+#define CHRE_HOST_ENDPOINT_TYPE_FRAMEWORK UINT8_C(0)
+
+//! The host endpoint is an Android app.
+#define CHRE_HOST_ENDPOINT_TYPE_APP UINT8_C(1)
+
+//! The host endpoint is an Android native program.
+#define CHRE_HOST_ENDPOINT_TYPE_NATIVE UINT8_C(2)
+
+//! Values in the range [CHRE_HOST_ENDPOINT_TYPE_VENDOR_START,
+//! CHRE_HOST_ENDPOINT_TYPE_VENDOR_END] can be a custom defined host endpoint
+//! type for platform-specific vendor use.
+#define CHRE_HOST_ENDPOINT_TYPE_VENDOR_START UINT8_C(128)
+#define CHRE_HOST_ENDPOINT_TYPE_VENDOR_END UINT8_C(255)
+
+/** @} */
+
+/**
+ * Provides metadata for a host endpoint.
+ *
+ * @since v1.6
+ */
+struct chreHostEndpointInfo {
+ //! The endpoint ID of this host.
+ uint16_t hostEndpointId;
+
+ //! The type of host endpoint, which must be set to one of the
+ //! CHRE_HOST_ENDPOINT_TYPE_* values or a value in the vendor-reserved
+ //! range.
+ uint8_t hostEndpointType;
+
+ //! Flag indicating if the packageName/endpointName field is valid.
+ uint8_t isNameValid : 1;
+
+ //! Flag indicating if the attributionTag/endpointTag field is valid.
+ uint8_t isTagValid : 1;
+
+ //! A union of null-terminated host name strings.
+ union {
+ //! The Android package name associated with this host, valid if the
+ //! hostEndpointType is CHRE_HOST_ENDPOINT_TYPE_APP or
+ //! CHRE_HOST_ENDPOINT_TYPE_FRAMEWORK. Refer to the Android documentation
+ //! for the package attribute in the app manifest.
+ char packageName[CHRE_MAX_ENDPOINT_NAME_LEN];
+
+ //! A generic endpoint name that can be used for endpoints that
+ //! may not have a package name.
+ char endpointName[CHRE_MAX_ENDPOINT_NAME_LEN];
+ };
+
+ //! A union of null-terminated host tag strings for further identification.
+ union {
+ //! The attribution tag associated with this host that is used to audit
+ //! access to data, which can be valid if the hostEndpointType is
+ //! CHRE_HOST_ENDPOINT_TYPE_APP. Refer to the Android documentation
+ //! regarding data audit using attribution tags.
+ char attributionTag[CHRE_MAX_ENDPOINT_TAG_LEN];
+
+ //! A generic endpoint tag that can be used for endpoints that
+ //! may not have an attribution tag.
+ char endpointTag[CHRE_MAX_ENDPOINT_TAG_LEN];
+ };
+};
+
+/**
+ * An RPC service exposed by a nanoapp.
+ *
+ * The implementation of the RPC interface is not defined by the HAL, and is written
+ * at the messaging endpoint layers (Android app and/or CHRE nanoapp). NanoappRpcService
+ * contains the informational metadata to be consumed by the RPC interface layer.
+ */
+struct chreNanoappRpcService {
+ /**
+ * The unique 64-bit ID of an RPC service exposed by a nanoapp. Note that
+ * the uniqueness is only required within the nanoapp's domain (i.e. the
+ * combination of the nanoapp ID and service id must be unique).
+ */
+ uint64_t id;
+
+ /**
+ * The software version of this service, which follows the sematic
+ * versioning scheme (see semver.org). It follows the format
+ * major.minor.patch, where major and minor versions take up one byte
+ * each, and the patch version takes up the final 2 bytes.
+ */
+ uint32_t version;
+};
+
+/**
+ * Callback which frees data associated with an event.
+ *
+ * This callback is (optionally) provided to the chreSendEvent() method as
+ * a means for freeing the event data and performing any other cleanup
+ * necessary when the event is completed. When this callback is invoked,
+ * 'eventData' is no longer needed and can be released.
+ *
+ * @param eventType The 'eventType' argument from chreSendEvent().
+ * @param eventData The 'eventData' argument from chreSendEvent().
+ *
+ * @see chreSendEvent
+ */
+typedef void (chreEventCompleteFunction)(uint16_t eventType, void *eventData);
+
+/**
+ * Callback which frees a message.
+ *
+ * This callback is (optionally) provided to the chreSendMessageToHostEndpoint()
+ * method as a means for freeing the message. When this callback is invoked,
+ * 'message' is no longer needed and can be released. Note that this in
+ * no way assures that said message did or did not make it to the host, simply
+ * that this memory is no longer needed.
+ *
+ * @param message The 'message' argument from chreSendMessageToHostEndpoint().
+ * @param messageSize The 'messageSize' argument from
+ * chreSendMessageToHostEndpoint().
+ *
+ * @see chreSendMessageToHostEndpoint
+ */
+typedef void (chreMessageFreeFunction)(void *message, size_t messageSize);
+
+
+/**
+ * Enqueue an event to be sent to another nanoapp.
+ *
+ * @param eventType This is a user-defined event type, of at least the
+ * value CHRE_EVENT_FIRST_USER_VALUE. It is illegal to attempt to use any
+ * of the CHRE_EVENT_* values reserved for the CHRE.
+ * @param eventData A pointer value that will be understood by the receiving
+ * app. Note that NULL is perfectly acceptable. It also is not required
+ * that this be a valid pointer, although if this nanoapp is intended to
+ * work on arbitrary CHRE implementations, then the size of a
+ * pointer cannot be assumed to be a certain size. Note that the caller
+ * no longer owns this memory after the call.
+ * @param freeCallback A pointer to a callback function. After the lifetime
+ * of 'eventData' is over (either through successful delivery or the event
+ * being dropped), this callback will be invoked. This argument is allowed
+ * to be NULL, in which case no callback will be invoked.
+ * @param targetInstanceId The ID of the instance we're delivering this event
+ * to. Note that this is allowed to be our own instance. The instance ID
+ * of a nanoapp can be retrieved by using chreGetNanoappInfoByInstanceId().
+ * @return true if the event was enqueued, false otherwise. Note that even
+ * if this method returns 'false', the 'freeCallback' will be invoked,
+ * if non-NULL. Note in the 'false' case, the 'freeCallback' may be
+ * invoked directly from within chreSendEvent(), so it's necessary
+ * for nanoapp authors to avoid possible recursion with this.
+ *
+ * @see chreEventDataFreeFunction
+ */
+bool chreSendEvent(uint16_t eventType, void *eventData,
+ chreEventCompleteFunction *freeCallback,
+ uint32_t targetInstanceId);
+
+/**
+ * Send a message to the host, using the broadcast endpoint
+ * CHRE_HOST_ENDPOINT_BROADCAST. Refer to chreSendMessageToHostEndpoint() for
+ * further details.
+ *
+ * @see chreSendMessageToHostEndpoint
+ *
+ * @deprecated New code should use chreSendMessageToHostEndpoint() instead of
+ * this function. A future update to the API may cause references to this
+ * function to produce a compiler warning.
+ */
+bool chreSendMessageToHost(void *message, uint32_t messageSize,
+ uint32_t messageType,
+ chreMessageFreeFunction *freeCallback)
+ CHRE_DEPRECATED("Use chreSendMessageToHostEndpoint instead");
+
+/**
+ * Send a message to the host, using CHRE_MESSAGE_PERMISSION_NONE for the
+ * associated message permissions. This method must only be used if no data
+ * provided by CHRE's audio, GNSS, WiFi, and WWAN APIs was used to produce the
+ * contents of the message being sent. Refer to chreSendMessageWithPermissions()
+ * for further details.
+ *
+ * @see chreSendMessageWithPermissions
+ *
+ * @since v1.1
+ */
+bool chreSendMessageToHostEndpoint(void *message, size_t messageSize,
+ uint32_t messageType, uint16_t hostEndpoint,
+ chreMessageFreeFunction *freeCallback);
+
+/**
+ * Send a message to the host, waking it up if it is currently asleep.
+ *
+ * This message is by definition arbitrarily defined. Since we're not
+ * just a passing a pointer to memory around the system, but need to copy
+ * this into various buffers to send it to the host, the CHRE
+ * implementation cannot be asked to support an arbitrarily large message
+ * size. As a result, we have the CHRE implementation define
+ * CHRE_MESSAGE_TO_HOST_MAX_SIZE.
+ *
+ * CHRE_MESSAGE_TO_HOST_MAX_SIZE is not given a value by the Platform API. The
+ * Platform API does define CHRE_MESSAGE_TO_HOST_MINIMUM_MAX_SIZE, and requires
+ * that CHRE_MESSAGE_TO_HOST_MAX_SIZE is at least that value.
+ *
+ * As a result, if your message sizes are all less than
+ * CHRE_MESSAGE_TO_HOST_MINIMUM_MAX_SIZE, then you have no concerns on any
+ * CHRE implementation. If your message sizes are larger, you'll need to
+ * come up with a strategy for splitting your message across several calls
+ * to this method. As long as that strategy works for
+ * CHRE_MESSAGE_TO_HOST_MINIMUM_MAX_SIZE, it will work across all CHRE
+ * implementations (although on some implementations less calls to this
+ * method may be necessary).
+ *
+ * When sending a message to the host, the ContextHub service will enforce
+ * the host client has been granted Android-level permissions corresponding to
+ * the ones the nanoapp declares it uses through CHRE_NANOAPP_USES_AUDIO, etc.
+ * In addition to this, the permissions bitmask provided as input to this method
+ * results in the Android framework using app-ops to verify and log access upon
+ * message delivery to an application. This is primarily useful for ensuring
+ * accurate attribution for messages generated using permission-controlled data.
+ * The bitmask declared by the nanoapp for this message must be a
+ * subset of the permissions it declared it would use at build time or the
+ * message will be rejected.
+ *
+ * Nanoapps must use this method if the data they are sending contains or was
+ * derived from any data sampled through CHRE's audio, GNSS, WiFi, or WWAN APIs.
+ * Additionally, if vendors add APIs to expose data that would be guarded by a
+ * permission in Android, vendors must support declaring a message permission
+ * through this method.
+ *
+ * @param message Pointer to a block of memory to send to the host.
+ * NULL is acceptable only if messageSize is 0. If non-NULL, this
+ * must be a legitimate pointer (that is, unlike chreSendEvent(), a small
+ * integral value cannot be cast to a pointer for this). Note that the
+ * caller no longer owns this memory after the call.
+ * @param messageSize The size, in bytes, of the given message. If this exceeds
+ * CHRE_MESSAGE_TO_HOST_MAX_SIZE, the message will be rejected.
+ * @param messageType Message type sent to the app on the host.
+ * NOTE: In CHRE API v1.0, support for forwarding this field to the host was
+ * not strictly required, and some implementations did not support it.
+ * However, its support is mandatory as of v1.1.
+ * @param hostEndpoint An identifier for the intended recipient of the message,
+ * or CHRE_HOST_ENDPOINT_BROADCAST if all registered endpoints on the host
+ * should receive the message. Endpoint identifiers are assigned on the
+ * host side, and nanoapps may learn of the host endpoint ID of an intended
+ * recipient via an initial message sent by the host. This parameter is
+ * always treated as CHRE_HOST_ENDPOINT_BROADCAST if running on a CHRE API
+ * v1.0 implementation. CHRE_HOST_ENDPOINT_BROADCAST isn't allowed to be
+ * specified if anything other than CHRE_MESSAGE_PERMISSION_NONE is given
+ * as messagePermissions since doing so would potentially attribute
+ * permissions usage to host clients that don't intend to consume the data.
+ * @param messagePermissions Bitmasked CHRE_MESSAGE_PERMISSION_ values that will
+ * be converted to corresponding Android-level permissions and attributed
+ * the host endpoint upon consumption of the message.
+ * @param freeCallback A pointer to a callback function. After the lifetime
+ * of 'message' is over (which does not assure that 'message' made it to
+ * the host, just that the transport layer no longer needs this memory),
+ * this callback will be invoked. This argument is allowed
+ * to be NULL, in which case no callback will be invoked.
+ * @return true if the message was accepted for transmission, false otherwise.
+ * Note that even if this method returns 'false', the 'freeCallback' will
+ * be invoked, if non-NULL. In either case, the 'freeCallback' may be
+ * invoked directly from within chreSendMessageToHostEndpoint(), so it's
+ * necessary for nanoapp authors to avoid possible recursion with this.
+ *
+ * @see chreMessageFreeFunction
+ *
+ * @since v1.5
+ */
+bool chreSendMessageWithPermissions(void *message, size_t messageSize,
+ uint32_t messageType, uint16_t hostEndpoint,
+ uint32_t messagePermissions,
+ chreMessageFreeFunction *freeCallback);
+
+/**
+ * Queries for information about a nanoapp running in the system.
+ *
+ * In the current API, appId is required to be unique, i.e. there cannot be two
+ * nanoapps running concurrently with the same appId. If this restriction is
+ * removed in a future API version and multiple instances of the same appId are
+ * present, this function must always return the first app to start.
+ *
+ * @param appId Identifier for the nanoapp that the caller is requesting
+ * information about.
+ * @param info Output parameter. If this function returns true, this structure
+ * will be populated with details of the specified nanoapp.
+ * @return true if a nanoapp with the given ID is currently running, and the
+ * supplied info parameter was populated with its information.
+ *
+ * @since v1.1
+ */
+bool chreGetNanoappInfoByAppId(uint64_t appId, struct chreNanoappInfo *info);
+
+/**
+ * Queries for information about a nanoapp running in the system, using the
+ * runtime unique identifier. This method can be used to get information about
+ * the sender of an event.
+ *
+ * @param instanceId
+ * @param info Output parameter. If this function returns true, this structure
+ * will be populated with details of the specified nanoapp.
+ * @return true if a nanoapp with the given instance ID is currently running,
+ * and the supplied info parameter was populated with its information.
+ *
+ * @since v1.1
+ */
+bool chreGetNanoappInfoByInstanceId(uint32_t instanceId,
+ struct chreNanoappInfo *info);
+
+/**
+ * Configures whether this nanoapp will be notified when other nanoapps in the
+ * system start and stop, via CHRE_EVENT_NANOAPP_STARTED and
+ * CHRE_EVENT_NANOAPP_STOPPED. These events are disabled by default, and if a
+ * nanoapp is not interested in interacting with other nanoapps, then it does
+ * not need to register for them. However, if inter-nanoapp communication is
+ * desired, nanoapps are recommended to call this function from nanoappStart().
+ *
+ * If running on a CHRE platform that only supports v1.0 of the CHRE API, this
+ * function has no effect.
+ *
+ * @param enable true to enable these events, false to disable
+ *
+ * @see CHRE_EVENT_NANOAPP_STARTED
+ * @see CHRE_EVENT_NANOAPP_STOPPED
+ *
+ * @since v1.1
+ */
+void chreConfigureNanoappInfoEvents(bool enable);
+
+/**
+ * Configures whether this nanoapp will be notified when the host (applications
+ * processor) transitions between wake and sleep, via CHRE_EVENT_HOST_AWAKE and
+ * CHRE_EVENT_HOST_ASLEEP. As chreSendMessageToHostEndpoint() wakes the host if
+ * it is asleep, these events can be used to opportunistically send data to the
+ * host only when it wakes up for some other reason. Note that this event is
+ * not instantaneous - there is an inherent delay in CHRE observing power state
+ * changes of the host processor, which may be significant depending on the
+ * implementation, especially in the wake to sleep direction. Therefore,
+ * nanoapps are not guaranteed that messages sent to the host between AWAKE and
+ * ASLEEP events will not trigger a host wakeup. However, implementations must
+ * ensure that the nominal wake-up notification latency is strictly less than
+ * the minimum wake-sleep time of the host processor. Implementations are also
+ * encouraged to minimize this and related latencies where possible, to avoid
+ * unnecessary host wake-ups.
+ *
+ * These events are only sent on transitions, so the initial state will not be
+ * sent to the nanoapp as an event - use chreIsHostAwake().
+ *
+ * @param enable true to enable these events, false to disable
+ *
+ * @see CHRE_EVENT_HOST_AWAKE
+ * @see CHRE_EVENT_HOST_ASLEEP
+ *
+ * @since v1.2
+ */
+void chreConfigureHostSleepStateEvents(bool enable);
+
+/**
+ * Retrieves the current sleep/wake state of the host (applications processor).
+ * Note that, as with the CHRE_EVENT_HOST_AWAKE and CHRE_EVENT_HOST_ASLEEP
+ * events, there is no guarantee that CHRE's view of the host processor's sleep
+ * state is instantaneous, and it may also change between querying the state and
+ * performing a host-waking action like sending a message to the host.
+ *
+ * @return true if by CHRE's own estimation the host is currently awake,
+ * false otherwise
+ *
+ * @since v1.2
+ */
+bool chreIsHostAwake(void);
+
+/**
+ * Configures whether this nanoapp will be notified when CHRE is collecting
+ * debug dumps, via CHRE_EVENT_DEBUG_DUMP. This event is disabled by default,
+ * and if a nanoapp is not interested in logging its debug data, then it does
+ * not need to register for it.
+ *
+ * @param enable true to enable receipt of this event, false to disable.
+ *
+ * @see CHRE_EVENT_DEBUG_DUMP
+ * @see chreDebugDumpLog
+ *
+ * @since v1.4
+ */
+void chreConfigureDebugDumpEvent(bool enable);
+
+/**
+ * Configures whether this nanoapp will receive updates regarding a host
+ * endpoint that is connected with the Context Hub.
+ *
+ * If this API succeeds, the nanoapp will receive disconnection notifications,
+ * via the CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION event with an eventData of type
+ * chreHostEndpointNotification with its notificationType set to
+ * HOST_ENDPOINT_NOTIFICATION_TYPE_DISCONNECT, which can be invoked if the host
+ * has disconnected from the Context Hub either explicitly or implicitly (e.g.
+ * crashes). Nanoapps can use this notifications to clean up any resources
+ * associated with this host endpoint.
+ *
+ * @param hostEndpointId The host endpoint ID to configure notifications for.
+ * @param enable true to enable notifications.
+ *
+ * @return true on success
+ *
+ * @see chreMessageFromHostData
+ * @see chreHostEndpointNotification
+ * @see CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION
+ *
+ * @since v1.6
+ */
+bool chreConfigureHostEndpointNotifications(uint16_t hostEndpointId,
+ bool enable);
+
+/**
+ * Publishes RPC services from this nanoapp.
+ *
+ * When this API is invoked, the list of RPC services will be provided to
+ * host applications interacting with the nanoapp.
+ *
+ * This function must be invoked from nanoappStart(), to guarantee stable output
+ * of the list of RPC services supported by the nanoapp.
+ *
+ * Although nanoapps are recommended to only call this API once with all
+ * services it intends to publish, if it is called multiple times, each
+ * call will append to the list of published services.
+ *
+ * Starting in CHRE API v1.8, the implementation must allow for a nanoapp to
+ * publish at least CHRE_MINIMUM_RPC_SERVICE_LIMIT services and at most
+ * UINT8_MAX services. If calling this function would result in exceeding
+ * the limit, the services must not be published and it must return false.
+ *
+ * @param services A non-null pointer to the list of RPC services to publish.
+ * @param numServices The number of services to publish, i.e. the length of the
+ * services array.
+ *
+ * @return true if the publishing is successful.
+ *
+ * @since v1.6
+ */
+bool chrePublishRpcServices(struct chreNanoappRpcService *services,
+ size_t numServices);
+
+/**
+ * Retrieves metadata for a given host endpoint ID.
+ *
+ * This API will provide metadata regarding an endpoint associated with a
+ * host endpoint ID. The nanoapp should use this API to determine more
+ * information about a host endpoint that has sent a message to the nanoapp,
+ * after receiving a chreMessageFromHostData (which includes the endpoint ID).
+ *
+ * If the given host endpoint ID is not associated with a valid host (or if the
+ * client has disconnected from the Android or CHRE framework, i.e. no longer
+ * able to send messages to CHRE), this method will return false and info will
+ * not be populated.
+ *
+ * @param hostEndpointId The endpoint ID of the host to get info for.
+ * @param info The non-null pointer to where the metadata will be stored.
+ *
+ * @return true if info has been successfully populated.
+ *
+ * @since v1.6
+ */
+bool chreGetHostEndpointInfo(uint16_t hostEndpointId,
+ struct chreHostEndpointInfo *info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHRE_EVENT_H_ */
+
diff --git a/chre_api/legacy/v1_8/chre/gnss.h b/chre_api/legacy/v1_8/chre/gnss.h
new file mode 100644
index 00000000..79a8f46b
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/gnss.h
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_GNSS_H_
+#define _CHRE_GNSS_H_
+
+/**
+ * @file
+ * Global Navigation Satellite System (GNSS) API.
+ *
+ * These structures and definitions are based on the Android N GPS HAL.
+ * Refer to that header file (located at this path as of the time of this
+ * comment: hardware/libhardware/include/hardware/gps.h) and associated
+ * documentation for further details and explanations for these fields.
+ * References in comments like "(ref: GnssAccumulatedDeltaRangeState)" map to
+ * the relevant element in the GPS HAL where additional information can be
+ * found.
+ *
+ * In general, the parts of this API that are taken from the GPS HAL follow the
+ * naming conventions established in that interface rather than the CHRE API
+ * conventions, in order to avoid confusion and enable code re-use where
+ * applicable.
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <chre/common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The set of flags that may be returned by chreGnssGetCapabilities()
+ * @defgroup CHRE_GNSS_CAPABILITIES
+ * @{
+ */
+
+//! A lack of flags indicates that GNSS is not supported in this CHRE
+#define CHRE_GNSS_CAPABILITIES_NONE UINT32_C(0)
+
+//! GNSS position fixes are supported via chreGnssLocationSessionStartAsync()
+#define CHRE_GNSS_CAPABILITIES_LOCATION UINT32_C(1 << 0)
+
+//! GNSS raw measurements are supported via
+//! chreGnssMeasurementSessionStartAsync()
+#define CHRE_GNSS_CAPABILITIES_MEASUREMENTS UINT32_C(1 << 1)
+
+//! Location fixes supplied from chreGnssConfigurePassiveLocationListener()
+//! are tapped in at the GNSS engine level, so they include additional fixes
+//! such as those requested by the AP, and not just those requested by other
+//! nanoapps within CHRE (which is the case when this flag is not set)
+#define CHRE_GNSS_CAPABILITIES_GNSS_ENGINE_BASED_PASSIVE_LISTENER \
+ UINT32_C(1 << 2)
+
+/** @} */
+
+/**
+ * The current version of struct chreGnssDataEvent associated with this API
+ */
+#define CHRE_GNSS_DATA_EVENT_VERSION UINT8_C(0)
+
+/**
+ * The maximum time the CHRE implementation is allowed to elapse before sending
+ * an event with the result of an asynchronous request, unless specified
+ * otherwise
+ */
+#define CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS (5 * CHRE_NSEC_PER_SEC)
+
+/**
+ * Produce an event ID in the block of IDs reserved for GNSS
+ * @param offset Index into GNSS event ID block; valid range [0,15]
+ */
+#define CHRE_GNSS_EVENT_ID(offset) (CHRE_EVENT_GNSS_FIRST_EVENT + (offset))
+
+/**
+ * nanoappHandleEvent argument: struct chreAsyncResult
+ *
+ * Communicates the asynchronous result of a request to the GNSS API, such as
+ * starting a location session via chreGnssLocationSessionStartAsync(). The
+ * requestType field in chreAsyncResult is set to a value from enum
+ * chreGnssRequestType.
+ */
+#define CHRE_EVENT_GNSS_ASYNC_RESULT CHRE_GNSS_EVENT_ID(0)
+
+/**
+ * nanoappHandleEvent argument: struct chreGnssLocationEvent
+ *
+ * Represents a location fix provided by the GNSS subsystem.
+ */
+#define CHRE_EVENT_GNSS_LOCATION CHRE_GNSS_EVENT_ID(1)
+
+/**
+ * nanoappHandleEvent argument: struct chreGnssDataEvent
+ *
+ * Represents a set of GNSS measurements with associated clock data.
+ */
+#define CHRE_EVENT_GNSS_DATA CHRE_GNSS_EVENT_ID(2)
+
+// NOTE: Do not add new events with ID > 15; only values 0-15 are reserved
+// (see chre/event.h)
+
+// Flags indicating the Accumulated Delta Range's states
+// (ref: GnssAccumulatedDeltaRangeState)
+#define CHRE_GNSS_ADR_STATE_UNKNOWN UINT16_C(0)
+#define CHRE_GNSS_ADR_STATE_VALID UINT16_C(1 << 0)
+#define CHRE_GNSS_ADR_STATE_RESET UINT16_C(1 << 1)
+#define CHRE_GNSS_ADR_STATE_CYCLE_SLIP UINT16_C(1 << 2)
+
+// Flags to indicate what fields in chreGnssClock are valid (ref: GnssClockFlags)
+#define CHRE_GNSS_CLOCK_HAS_LEAP_SECOND UINT16_C(1 << 0)
+#define CHRE_GNSS_CLOCK_HAS_TIME_UNCERTAINTY UINT16_C(1 << 1)
+#define CHRE_GNSS_CLOCK_HAS_FULL_BIAS UINT16_C(1 << 2)
+#define CHRE_GNSS_CLOCK_HAS_BIAS UINT16_C(1 << 3)
+#define CHRE_GNSS_CLOCK_HAS_BIAS_UNCERTAINTY UINT16_C(1 << 4)
+#define CHRE_GNSS_CLOCK_HAS_DRIFT UINT16_C(1 << 5)
+#define CHRE_GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY UINT16_C(1 << 6)
+
+// Flags to indicate which values are valid in a GpsLocation
+// (ref: GpsLocationFlags)
+#define CHRE_GPS_LOCATION_HAS_LAT_LONG UINT16_C(1 << 0)
+#define CHRE_GPS_LOCATION_HAS_ALTITUDE UINT16_C(1 << 1)
+#define CHRE_GPS_LOCATION_HAS_SPEED UINT16_C(1 << 2)
+#define CHRE_GPS_LOCATION_HAS_BEARING UINT16_C(1 << 3)
+#define CHRE_GPS_LOCATION_HAS_ACCURACY UINT16_C(1 << 4)
+
+//! @since v1.3
+#define CHRE_GPS_LOCATION_HAS_ALTITUDE_ACCURACY UINT16_C(1 << 5)
+//! @since v1.3
+#define CHRE_GPS_LOCATION_HAS_SPEED_ACCURACY UINT16_C(1 << 6)
+//! @since v1.3
+#define CHRE_GPS_LOCATION_HAS_BEARING_ACCURACY UINT16_C(1 << 7)
+
+/**
+ * The maximum number of instances of struct chreGnssMeasurement that may be
+ * included in a single struct chreGnssDataEvent.
+ *
+ * The value of this struct was increased from 64 to 128 in CHRE v1.5. For
+ * nanoapps targeting CHRE v1.4 or lower, the measurement_count will be capped
+ * at 64.
+ */
+#define CHRE_GNSS_MAX_MEASUREMENT UINT8_C(128)
+#define CHRE_GNSS_MAX_MEASUREMENT_PRE_1_5 UINT8_C(64)
+
+// Flags indicating the GNSS measurement state (ref: GnssMeasurementState)
+#define CHRE_GNSS_MEASUREMENT_STATE_UNKNOWN UINT16_C(0)
+#define CHRE_GNSS_MEASUREMENT_STATE_CODE_LOCK UINT16_C(1 << 0)
+#define CHRE_GNSS_MEASUREMENT_STATE_BIT_SYNC UINT16_C(1 << 1)
+#define CHRE_GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC UINT16_C(1 << 2)
+#define CHRE_GNSS_MEASUREMENT_STATE_TOW_DECODED UINT16_C(1 << 3)
+#define CHRE_GNSS_MEASUREMENT_STATE_MSEC_AMBIGUOUS UINT16_C(1 << 4)
+#define CHRE_GNSS_MEASUREMENT_STATE_SYMBOL_SYNC UINT16_C(1 << 5)
+#define CHRE_GNSS_MEASUREMENT_STATE_GLO_STRING_SYNC UINT16_C(1 << 6)
+#define CHRE_GNSS_MEASUREMENT_STATE_GLO_TOD_DECODED UINT16_C(1 << 7)
+#define CHRE_GNSS_MEASUREMENT_STATE_BDS_D2_BIT_SYNC UINT16_C(1 << 8)
+#define CHRE_GNSS_MEASUREMENT_STATE_BDS_D2_SUBFRAME_SYNC UINT16_C(1 << 9)
+#define CHRE_GNSS_MEASUREMENT_STATE_GAL_E1BC_CODE_LOCK UINT16_C(1 << 10)
+#define CHRE_GNSS_MEASUREMENT_STATE_GAL_E1C_2ND_CODE_LOCK UINT16_C(1 << 11)
+#define CHRE_GNSS_MEASUREMENT_STATE_GAL_E1B_PAGE_SYNC UINT16_C(1 << 12)
+#define CHRE_GNSS_MEASUREMENT_STATE_SBAS_SYNC UINT16_C(1 << 13)
+
+#define CHRE_GNSS_MEASUREMENT_CARRIER_FREQUENCY_UNKNOWN 0.f
+
+/**
+ * Indicates a type of request made in this API. Used to populate the resultType
+ * field of struct chreAsyncResult sent with CHRE_EVENT_GNSS_ASYNC_RESULT.
+ */
+enum chreGnssRequestType {
+ CHRE_GNSS_REQUEST_TYPE_LOCATION_SESSION_START = 1,
+ CHRE_GNSS_REQUEST_TYPE_LOCATION_SESSION_STOP = 2,
+ CHRE_GNSS_REQUEST_TYPE_MEASUREMENT_SESSION_START = 3,
+ CHRE_GNSS_REQUEST_TYPE_MEASUREMENT_SESSION_STOP = 4,
+};
+
+/**
+ * Constellation type associated with an SV
+ */
+enum chreGnssConstellationType {
+ CHRE_GNSS_CONSTELLATION_UNKNOWN = 0,
+ CHRE_GNSS_CONSTELLATION_GPS = 1,
+ CHRE_GNSS_CONSTELLATION_SBAS = 2,
+ CHRE_GNSS_CONSTELLATION_GLONASS = 3,
+ CHRE_GNSS_CONSTELLATION_QZSS = 4,
+ CHRE_GNSS_CONSTELLATION_BEIDOU = 5,
+ CHRE_GNSS_CONSTELLATION_GALILEO = 6,
+};
+
+/**
+ * Enumeration of available values for the chreGnssMeasurement multipath indicator
+ */
+enum chreGnssMultipathIndicator {
+ //! The indicator is not available or unknown
+ CHRE_GNSS_MULTIPATH_INDICATOR_UNKNOWN = 0,
+ //! The measurement is indicated to be affected by multipath
+ CHRE_GNSS_MULTIPATH_INDICATOR_PRESENT = 1,
+ //! The measurement is indicated to be not affected by multipath
+ CHRE_GNSS_MULTIPATH_INDICATOR_NOT_PRESENT = 2,
+};
+
+/**
+ * Represents an estimate of the GNSS clock time (see the Android GPS HAL for
+ * more detailed information)
+ */
+struct chreGnssClock {
+ //! The GNSS receiver hardware clock value in nanoseconds, including
+ //! uncertainty
+ int64_t time_ns;
+
+ //! The difference between hardware clock inside GNSS receiver and the
+ //! estimated GNSS time in nanoseconds; contains bias uncertainty
+ int64_t full_bias_ns;
+
+ //! Sub-nanosecond bias, adds to full_bias_ns
+ float bias_ns;
+
+ //! The clock's drift in nanoseconds per second
+ float drift_nsps;
+
+ //! 1-sigma uncertainty associated with the clock's bias in nanoseconds
+ float bias_uncertainty_ns;
+
+ //! 1-sigma uncertainty associated with the clock's drift in nanoseconds
+ //! per second
+ float drift_uncertainty_nsps;
+
+ //! While this number stays the same, timeNs should flow continuously
+ uint32_t hw_clock_discontinuity_count;
+
+ //! A set of flags indicating the validity of the fields in this data
+ //! structure (see GNSS_CLOCK_HAS_*)
+ uint16_t flags;
+
+ //! Reserved for future use; set to 0
+ uint8_t reserved[2];
+};
+
+/**
+ * Represents a GNSS measurement; contains raw and computed information (see the
+ * Android GPS HAL for more detailed information)
+ */
+struct chreGnssMeasurement {
+ //! Hardware time offset from time_ns for this measurement, in nanoseconds
+ int64_t time_offset_ns;
+
+ //! Accumulated delta range since the last channel reset in micro-meters
+ int64_t accumulated_delta_range_um;
+
+ //! Received GNSS satellite time at the time of measurement, in nanoseconds
+ int64_t received_sv_time_in_ns;
+
+ //! 1-sigma uncertainty of received GNSS satellite time, in nanoseconds
+ int64_t received_sv_time_uncertainty_in_ns;
+
+ //! Pseudorange rate at the timestamp in meters per second (uncorrected)
+ float pseudorange_rate_mps;
+
+ //! 1-sigma uncertainty of pseudorange rate in meters per second
+ float pseudorange_rate_uncertainty_mps;
+
+ //! 1-sigma uncertainty of the accumulated delta range in meters
+ float accumulated_delta_range_uncertainty_m;
+
+ //! Carrier-to-noise density in dB-Hz, in the range of [0, 63]
+ float c_n0_dbhz;
+
+ //! Signal to noise ratio (dB), power above observed noise at correlators
+ float snr_db;
+
+ //! Satellite sync state flags (GNSS_MEASUREMENT_STATE_*) - sets modulus for
+ //! received_sv_time_in_ns
+ uint16_t state;
+
+ //! Set of ADR state flags (GNSS_ADR_STATE_*)
+ uint16_t accumulated_delta_range_state;
+
+ //! Satellite vehicle ID number
+ int16_t svid;
+
+ //! Constellation of the given satellite vehicle
+ //! @see #chreGnssConstellationType
+ uint8_t constellation;
+
+ //! @see #chreGnssMultipathIndicator
+ uint8_t multipath_indicator;
+
+ //! Carrier frequency of the signal tracked in Hz.
+ //! For example, it can be the GPS central frequency for L1 = 1575.45 MHz,
+ //! or L2 = 1227.60 MHz, L5 = 1176.45 MHz, various GLO channels, etc.
+ //!
+ //! Set to CHRE_GNSS_MEASUREMENT_CARRIER_FREQUENCY_UNKNOWN if not reported.
+ //!
+ //! For an L1, L5 receiver tracking a satellite on L1 and L5 at the same
+ //! time, two chreGnssMeasurement structs must be reported for this same
+ //! satellite, in one of the measurement structs, all the values related to
+ //! L1 must be filled, and in the other all of the values related to L5
+ //! must be filled.
+ //! @since v1.4
+ float carrier_frequency_hz;
+};
+
+/**
+ * Data structure sent with events associated with CHRE_EVENT_GNSS_DATA, enabled
+ * via chreGnssMeasurementSessionStartAsync()
+ */
+struct chreGnssDataEvent {
+ //! Indicates the version of the structure, for compatibility purposes.
+ //! Clients do not normally need to worry about this field; the CHRE
+ //! implementation guarantees that it only sends the client the structure
+ //! version it expects.
+ uint8_t version;
+
+ //! Number of chreGnssMeasurement entries included in this event. Must be in
+ //! the range [0, CHRE_GNSS_MAX_MEASUREMENT]
+ uint8_t measurement_count;
+
+ //! Reserved for future use; set to 0
+ uint8_t reserved[6];
+
+ struct chreGnssClock clock;
+
+ //! Pointer to an array containing measurement_count measurements
+ const struct chreGnssMeasurement *measurements;
+};
+
+/**
+ * Data structure sent with events of type CHRE_EVENT_GNSS_LOCATION, enabled via
+ * chreGnssLocationSessionStartAsync(). This is modeled after GpsLocation in the
+ * GPS HAL, but does not use the double data type.
+ */
+struct chreGnssLocationEvent {
+ //! UTC timestamp for location fix in milliseconds since January 1, 1970
+ uint64_t timestamp;
+
+ //! Fixed point latitude, degrees times 10^7 (roughly centimeter resolution)
+ int32_t latitude_deg_e7;
+
+ //! Fixed point longitude, degrees times 10^7 (roughly centimeter
+ //! resolution)
+ int32_t longitude_deg_e7;
+
+ //! Altitude in meters above the WGS 84 reference ellipsoid
+ float altitude;
+
+ //! Horizontal speed in meters per second
+ float speed;
+
+ //! Clockwise angle between north and current heading, in degrees; range
+ //! [0, 360)
+ float bearing;
+
+ //! Expected horizontal accuracy in meters such that a circle with a radius
+ //! of length 'accuracy' from the latitude and longitude has a 68%
+ //! probability of including the true location.
+ float accuracy;
+
+ //! A set of flags indicating which fields in this structure are valid.
+ //! If any fields are not available, the flag must not be set and the field
+ //! must be initialized to 0.
+ //! @see #GpsLocationFlags
+ uint16_t flags;
+
+ //! Reserved for future use; set to 0
+ //! @since v1.3
+ uint8_t reserved[2];
+
+ //! Expected vertical accuracy in meters such that a range of
+ //! 2 * altitude_accuracy centered around altitude has a 68% probability of
+ //! including the true altitude.
+ //! @since v1.3
+ float altitude_accuracy;
+
+ //! Expected speed accuracy in meters per second such that a range of
+ //! 2 * speed_accuracy centered around speed has a 68% probability of
+ //! including the true speed.
+ //! @since v1.3
+ float speed_accuracy;
+
+ //! Expected bearing accuracy in degrees such that a range of
+ //! 2 * bearing_accuracy centered around bearing has a 68% probability of
+ //! including the true bearing.
+ //! @since v1.3
+ float bearing_accuracy;
+};
+
+
+/**
+ * Retrieves a set of flags indicating the GNSS features supported by the
+ * current CHRE implementation. The value returned by this function must be
+ * consistent for the entire duration of the Nanoapp's execution.
+ *
+ * The client must allow for more flags to be set in this response than it knows
+ * about, for example if the implementation supports a newer version of the API
+ * than the client was compiled against.
+ *
+ * @return A bitmask with zero or more CHRE_GNSS_CAPABILITIES_* flags set
+ *
+ * @since v1.1
+ */
+uint32_t chreGnssGetCapabilities(void);
+
+/**
+ * Nanoapps must define CHRE_NANOAPP_USES_GNSS somewhere in their build
+ * system (e.g. Makefile) if the nanoapp needs to use the following GNSS APIs.
+ * In addition to allowing access to these APIs, defining this macro will also
+ * ensure CHRE enforces that all host clients this nanoapp talks to have the
+ * required Android permissions needed to listen to GNSS data by adding metadata
+ * to the nanoapp.
+ */
+#if defined(CHRE_NANOAPP_USES_GNSS) || !defined(CHRE_IS_NANOAPP_BUILD)
+
+/**
+ * Initiates a GNSS positioning session, or changes the requested interval of an
+ * existing session. If starting or modifying the session was successful, then
+ * the GNSS engine will work on determining the device's position.
+ *
+ * This result of this request is delivered asynchronously via an event of type
+ * CHRE_EVENT_GNSS_ASYNC_RESULT. Refer to the note in {@link #chreAsyncResult}
+ * for more details. If the "Location" setting is disabled at the Android level,
+ * the CHRE implementation is expected to return a result with
+ * CHRE_ERROR_FUNCTION_DISABLED.
+ *
+ * If chreGnssGetCapabilities() returns a value that does not have the
+ * CHRE_GNSS_CAPABILITIES_LOCATION flag set, then this method will return false.
+ *
+ * @param minIntervalMs The desired minimum interval between location fixes
+ * delivered to the client via CHRE_EVENT_GNSS_LOCATION, in milliseconds.
+ * The requesting client must allow for fixes to be delivered at shorter
+ * or longer interval than requested. For example, adverse RF conditions
+ * may result in fixes arriving at a longer interval, etc.
+ * @param minTimeToNextFixMs The desired minimum time to the next location fix.
+ * If this is 0, the GNSS engine should start working on the next fix
+ * immediately. If greater than 0, the GNSS engine should not spend
+ * measurable power to produce a location fix until this amount of time
+ * has elapsed.
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent in relation to this request.
+ *
+ * @return true if the request was accepted for processing, false otherwise
+ *
+ * @since v1.1
+ * @note Requires GNSS permission
+ */
+bool chreGnssLocationSessionStartAsync(uint32_t minIntervalMs,
+ uint32_t minTimeToNextFixMs,
+ const void *cookie);
+
+/**
+ * Terminates an existing GNSS positioning session. If no positioning session
+ * is active at the time of this request, it is treated as if an active session
+ * was successfully ended.
+ *
+ * This result of this request is delivered asynchronously via an event of type
+ * CHRE_EVENT_GNSS_ASYNC_RESULT. Refer to the note in {@link #chreAsyncResult}
+ * for more details.
+ *
+ * After CHRE_EVENT_GNSS_ASYNC_RESULT is delivered to the client, no more
+ * CHRE_EVENT_GNSS_LOCATION events will be delievered until a new location
+ * session is started.
+ *
+ * If chreGnssGetCapabilities() returns a value that does not have the
+ * CHRE_GNSS_CAPABILITIES_LOCATION flag set, then this method will return false.
+ *
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent in relation to this request.
+ *
+ * @return true if the request was accepted for processing, false otherwise
+ *
+ * @since v1.1
+ * @note Requires GNSS permission
+ */
+bool chreGnssLocationSessionStopAsync(const void *cookie);
+
+/**
+ * Initiates a request to receive raw GNSS measurements. A GNSS measurement
+ * session can exist independently of location sessions. In other words, a
+ * Nanoapp is able to receive measurements at its requested interval both with
+ * and without an active location session.
+ *
+ * This result of this request is delivered asynchronously via an event of type
+ * CHRE_EVENT_GNSS_ASYNC_RESULT. Refer to the note in {@link #chreAsyncResult}
+ * for more details. If the "Location" setting is disabled at the Android level,
+ * the CHRE implementation is expected to return a result with
+ * CHRE_ERROR_FUNCTION_DISABLED.
+ *
+ * If chreGnssGetCapabilities() returns a value that does not have the
+ * CHRE_GNSS_CAPABILITIES_MEASUREMENTS flag set, then this method will return
+ * false.
+ *
+ * @param minIntervalMs The desired minimum interval between measurement reports
+ * delivered via CHRE_EVENT_GNSS_DATA. When requested at 1000ms or
+ * faster, and GNSS measurements are tracked, device should report
+ * measurements as fast as requested, and shall report no slower than
+ * once every 1000ms, on average.
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent in relation to this request.
+ *
+ * @return true if the request was accepted for processing, false otherwise
+ *
+ * @since v1.1
+ * @note Requires GNSS permission
+ */
+bool chreGnssMeasurementSessionStartAsync(uint32_t minIntervalMs,
+ const void *cookie);
+
+/**
+ * Terminates an existing raw GNSS measurement session. If no measurement
+ * session is active at the time of this request, it is treated as if an active
+ * session was successfully ended.
+ *
+ * This result of this request is delivered asynchronously via an event of type
+ * CHRE_EVENT_GNSS_ASYNC_RESULT. Refer to the note in {@link #chreAsyncResult}
+ * for more details.
+ *
+ * If chreGnssGetCapabilities() returns a value that does not have the
+ * CHRE_GNSS_CAPABILITIES_MEASUREMENTS flag set, then this method will return
+ * false.
+ *
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent in relation to this request.
+ *
+ * @return true if the request was accepted for processing, false otherwise
+ *
+ * @since v1.1
+ * @note Requires GNSS permission
+ */
+bool chreGnssMeasurementSessionStopAsync(const void *cookie);
+
+/**
+ * Controls whether this nanoapp will passively receive GNSS-based location
+ * fixes produced as a result of location sessions initiated by other entities.
+ * This function allows a nanoapp to opportunistically receive location fixes
+ * via CHRE_EVENT_GNSS_LOCATION events without imposing additional power cost,
+ * though with no guarantees as to when or how often those events will arrive.
+ * There will be no duplication of events if a passive location listener and
+ * location session are enabled in parallel.
+ *
+ * Enabling passive location listening is not required to receive events for an
+ * active location session started via chreGnssLocationSessionStartAsync(). This
+ * setting is independent of the active location session, so modifying one does
+ * not have an effect on the other.
+ *
+ * If chreGnssGetCapabilities() returns a value that does not have the
+ * CHRE_GNSS_CAPABILITIES_LOCATION flag set or the value returned by
+ * chreGetApiVersion() is less than CHRE_API_VERSION_1_2, then this method will
+ * return false.
+ *
+ * If chreGnssGetCapabilities() includes
+ * CHRE_GNSS_CAPABILITIES_GNSS_ENGINE_BASED_PASSIVE_LISTENER, the passive
+ * registration is recorded at the GNSS engine level, so events include fixes
+ * requested by the applications processor and potentially other non-CHRE
+ * clients. If this flag is not set, then only fixes requested by other nanoapps
+ * within CHRE are provided.
+ *
+ * @param enable true to receive opportunistic location fixes, false to disable
+ *
+ * @return true if the configuration was processed successfully, false on error
+ * or if this feature is not supported
+ *
+ * @since v1.2
+ * @note Requires GNSS permission
+ */
+bool chreGnssConfigurePassiveLocationListener(bool enable);
+
+#else /* defined(CHRE_NANOAPP_USES_GNSS) || !defined(CHRE_IS_NANOAPP_BUILD) */
+#define CHRE_GNSS_PERM_ERROR_STRING \
+ "CHRE_NANOAPP_USES_GNSS must be defined when building this nanoapp in " \
+ "order to refer to "
+#define chreGnssLocationSessionStartAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_GNSS_PERM_ERROR_STRING \
+ "chreGnssLocationSessionStartAsync")
+#define chreGnssLocationSessionStopAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_GNSS_PERM_ERROR_STRING \
+ "chreGnssLocationSessionStopAsync")
+#define chreGnssMeasurementSessionStartAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_GNSS_PERM_ERROR_STRING \
+ "chreGnssMeasurementSessionStartAsync")
+#define chreGnssMeasurementSessionStopAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_GNSS_PERM_ERROR_STRING \
+ "chreGnssMeasurementSessionStopAsync")
+#define chreGnssConfigurePassiveLocationListener(...) \
+ CHRE_BUILD_ERROR(CHRE_GNSS_PERM_ERROR_STRING \
+ "chreGnssConfigurePassiveLocationListener")
+#endif /* defined(CHRE_NANOAPP_USES_GNSS) || !defined(CHRE_IS_NANOAPP_BUILD) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHRE_GNSS_H_ */
diff --git a/chre_api/legacy/v1_8/chre/nanoapp.h b/chre_api/legacy/v1_8/chre/nanoapp.h
new file mode 100644
index 00000000..da199ee0
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/nanoapp.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_NANOAPP_H_
+#define _CHRE_NANOAPP_H_
+
+/**
+ * @file
+ * Methods in the Context Hub Runtime Environment which must be implemented
+ * by the nanoapp.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Method invoked by the CHRE when loading the nanoapp.
+ *
+ * Every CHRE method is legal to call from this method.
+ *
+ * @return 'true' if the nanoapp successfully started. 'false' if the nanoapp
+ * failed to properly initialize itself (for example, could not obtain
+ * sufficient memory from the heap). If this method returns 'false', the
+ * nanoapp will be unloaded by the CHRE (and nanoappEnd will
+ * _not_ be invoked in that case).
+ * @see nanoappEnd
+ */
+bool nanoappStart(void);
+
+/**
+ * Method invoked by the CHRE when there is an event for this nanoapp.
+ *
+ * Every CHRE method is legal to call from this method.
+ *
+ * @param senderInstanceId The Instance ID for the source of this event.
+ * Note that this may be CHRE_INSTANCE_ID, indicating that the event
+ * was generated by the CHRE.
+ * @param eventType The event type. This might be one of the CHRE_EVENT_*
+ * types defined in this API. But it might also be a user-defined event.
+ * @param eventData The associated data, if any, for this specific type of
+ * event. From the nanoapp's perspective, this eventData's lifetime ends
+ * when this method returns, and thus any data the nanoapp wishes to
+ * retain must be copied. Note that interpretation of event data is
+ * given by the event type, and for some events may not be a valid
+ * pointer. See documentation of the specific CHRE_EVENT_* types for how to
+ * interpret this data for those. Note that for user events, you will
+ * need to establish what this data means.
+ */
+void nanoappHandleEvent(uint32_t senderInstanceId, uint16_t eventType,
+ const void *eventData);
+
+/**
+ * Method invoked by the CHRE when unloading the nanoapp.
+ *
+ * It is not valid to attempt to send events or messages, or to invoke functions
+ * which will generate events to this app, within the nanoapp implementation of
+ * this function. That means it is illegal for the nanoapp invoke any of the
+ * following:
+ *
+ * - chreSendEvent()
+ * - chreSendMessageToHost()
+ * - chreSensorConfigure()
+ * - chreSensorConfigureModeOnly()
+ * - chreTimerSet()
+ * - etc.
+ *
+ * @see nanoappStart
+ */
+void nanoappEnd(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHRE_NANOAPP_H_ */
diff --git a/chre_api/legacy/v1_8/chre/re.h b/chre_api/legacy/v1_8/chre/re.h
new file mode 100644
index 00000000..20a69b66
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/re.h
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_RE_H_
+#define _CHRE_RE_H_
+
+/**
+ * @file
+ * Some of the core Runtime Environment utilities of the Context Hub
+ * Runtime Environment.
+ *
+ * This includes functions for memory allocation, logging, and timers.
+ */
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <chre/toolchain.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The instance ID for the CHRE.
+ *
+ * This ID is used to identify events generated by the CHRE (as
+ * opposed to events generated by another nanoapp).
+ */
+#define CHRE_INSTANCE_ID UINT32_C(0)
+
+/**
+ * A timer ID representing an invalid timer.
+ *
+ * This valid is returned by chreTimerSet() if a timer cannot be
+ * started.
+ */
+#define CHRE_TIMER_INVALID UINT32_C(-1)
+
+
+/**
+ * The maximum size, in characters including null terminator, guaranteed for
+ * logging debug data with one call of chreDebugDumpLog() without getting
+ * truncated.
+ *
+ * @see chreDebugDumpLog
+ * @since v1.4
+ */
+#define CHRE_DEBUG_DUMP_MINIMUM_MAX_SIZE 1000
+
+/**
+ * Logging levels used to indicate severity level of logging messages.
+ *
+ * CHRE_LOG_ERROR: Something fatal has happened, i.e. something that will have
+ * user-visible consequences and won't be recoverable without explicitly
+ * deleting some data, uninstalling applications, wiping the data
+ * partitions or reflashing the entire phone (or worse).
+ * CHRE_LOG_WARN: Something that will have user-visible consequences but is
+ * likely to be recoverable without data loss by performing some explicit
+ * action, ranging from waiting or restarting an app all the way to
+ * re-downloading a new version of an application or rebooting the device.
+ * CHRE_LOG_INFO: Something interesting to most people happened, i.e. when a
+ * situation is detected that is likely to have widespread impact, though
+ * isn't necessarily an error.
+ * CHRE_LOG_DEBUG: Used to further note what is happening on the device that
+ * could be relevant to investigate and debug unexpected behaviors. You
+ * should log only what is needed to gather enough information about what
+ * is going on about your component.
+ *
+ * There is currently no API to turn on/off logging by level, but we anticipate
+ * adding such in future releases.
+ *
+ * @see chreLog
+ */
+enum chreLogLevel {
+ CHRE_LOG_ERROR,
+ CHRE_LOG_WARN,
+ CHRE_LOG_INFO,
+ CHRE_LOG_DEBUG
+};
+
+
+/**
+ * Get the application ID.
+ *
+ * The application ID is set by the loader of the nanoapp. This is not
+ * assured to be unique among all nanoapps running in the system.
+ *
+ * @return The application ID.
+ */
+uint64_t chreGetAppId(void);
+
+/**
+ * Get the instance ID.
+ *
+ * The instance ID is the CHRE handle to this nanoapp. This is assured
+ * to be unique among all nanoapps running in the system, and to be
+ * different from the CHRE_INSTANCE_ID. This is the ID used to communicate
+ * between nanoapps.
+ *
+ * @return The instance ID
+ */
+uint32_t chreGetInstanceId(void);
+
+/**
+ * A method for logging information about the system.
+ *
+ * The chreLog logging activity alone must not cause host wake-ups. For
+ * example, logs could be buffered in internal memory when the host is asleep,
+ * and delivered when appropriate (e.g. the host wakes up). If done this way,
+ * the internal buffer is recommended to be large enough (at least a few KB), so
+ * that multiple messages can be buffered. When these logs are sent to the host,
+ * they are strongly recommended to be made visible under the tag 'CHRE' in
+ * logcat - a future version of the CHRE API may make this a hard requirement.
+ *
+ * A log entry can have a variety of levels (@see LogLevel). This function
+ * allows a variable number of arguments, in a printf-style format.
+ *
+ * A nanoapp needs to be able to rely upon consistent printf format
+ * recognition across any platform, and thus we establish formats which
+ * are required to be handled by every CHRE implementation. Some of the
+ * integral formats may seem obscure, but this API heavily uses types like
+ * uint32_t and uint16_t. The platform independent macros for those printf
+ * formats, like PRId32 or PRIx16, end up using some of these "obscure"
+ * formats on some platforms, and thus are required.
+ *
+ * For the initial N release, our emphasis is on correctly getting information
+ * into the log, and minimizing the requirements for CHRE implementations
+ * beyond that. We're not as concerned about how the information is visually
+ * displayed. As a result, there are a number of format sub-specifiers which
+ * are "OPTIONAL" for the N implementation. "OPTIONAL" in this context means
+ * that a CHRE implementation is allowed to essentially ignore the specifier,
+ * but it must understand the specifier enough in order to properly skip it.
+ *
+ * For a nanoapp author, an OPTIONAL format means you might not get exactly
+ * what you want on every CHRE implementation, but you will always get
+ * something valid.
+ *
+ * To be clearer, here's an example with the OPTIONAL 0-padding for integers
+ * for different hypothetical CHRE implementations.
+ * Compliant, chose to implement OPTIONAL format:
+ * chreLog(level, "%04x", 20) ==> "0014"
+ * Compliant, chose not to implement OPTIONAL format:
+ * chreLog(level, "%04x", 20) ==> "14"
+ * Non-compliant, discarded format because the '0' was assumed to be incorrect:
+ * chreLog(level, "%04x", 20) ==> ""
+ *
+ * Note that some of the OPTIONAL specifiers will probably become
+ * required in future APIs.
+ *
+ * We also have NOT_SUPPORTED specifiers. Nanoapp authors should not use any
+ * NOT_SUPPORTED specifiers, as unexpected things could happen on any given
+ * CHRE implementation. A CHRE implementation is allowed to support this
+ * (for example, when using shared code which already supports this), but
+ * nanoapp authors need to avoid these.
+ *
+ * Unless specifically noted as OPTIONAL or NOT_SUPPORTED, format
+ * (sub-)specifiers listed below are required.
+ *
+ * OPTIONAL format sub-specifiers:
+ * - '-' (left-justify within the given field width)
+ * - '+' (precede the result with a '+' sign if it is positive)
+ * - ' ' (precede the result with a blank space if no sign is going to be
+ * output)
+ * - '#' (For 'o', 'x' or 'X', precede output with "0", "0x" or "0X",
+ * respectively. For floating point, unconditionally output a decimal
+ * point.)
+ * - '0' (left pad the number with zeroes instead of spaces when <width>
+ * needs padding)
+ * - <width> (A number representing the minimum number of characters to be
+ * output, left-padding with blank spaces if needed to meet the
+ * minimum)
+ * - '.'<precision> (A number which has different meaning depending on context.)
+ * - Integer context: Minimum number of digits to output, padding with
+ * leading zeros if needed to meet the minimum.
+ * - 'f' context: Number of digits to output after the decimal
+ * point (to the right of it).
+ * - 's' context: Maximum number of characters to output.
+ *
+ * Integral format specifiers:
+ * - 'd' (signed)
+ * - 'u' (unsigned)
+ * - 'o' (octal)
+ * - 'x' (hexadecimal, lower case)
+ * - 'X' (hexadecimal, upper case)
+ *
+ * Integral format sub-specifiers (as prefixes to an above integral format):
+ * - 'hh' (char)
+ * - 'h' (short)
+ * - 'l' (long)
+ * - 'll' (long long)
+ * - 'z' (size_t)
+ * - 't' (ptrdiff_t)
+ *
+ * Other format specifiers:
+ * - 'f' (floating point)
+ * - 'c' (character)
+ * - 's' (character string, terminated by '\0')
+ * - 'p' (pointer)
+ * - '%' (escaping the percent sign (i.e. "%%" becomes "%"))
+ *
+ * NOT_SUPPORTED specifiers:
+ * - 'n' (output nothing, but fill in a given pointer with the number
+ * of characters written so far)
+ * - '*' (indicates that the width/precision value comes from one of the
+ * arguments to the function)
+ * - 'e', 'E' (scientific notation output)
+ * - 'g', 'G' (Shortest floating point representation)
+ *
+ * @param level The severity level for this message.
+ * @param formatStr Either the entirety of the message, or a printf-style
+ * format string of the format documented above.
+ * @param ... A variable number of arguments necessary for the given
+ * 'formatStr' (there may be no additional arguments for some 'formatStr's).
+ */
+CHRE_PRINTF_ATTR(2, 3)
+void chreLog(enum chreLogLevel level, const char *formatStr, ...);
+
+/**
+ * Get the system time.
+ *
+ * This returns a time in nanoseconds in reference to some arbitrary
+ * time in the past. This method is only useful for determining timing
+ * between events on the system, and is not useful for determining
+ * any sort of absolute time.
+ *
+ * This value must always increase (and must never roll over). This
+ * value has no meaning across CHRE reboots.
+ *
+ * @return The system time, in nanoseconds.
+ */
+uint64_t chreGetTime(void);
+
+/**
+ * Retrieves CHRE's current estimated offset between the local CHRE clock
+ * exposed in chreGetTime(), and the host-side clock exposed in the Android API
+ * SystemClock.elapsedRealtimeNanos(). This offset is formed as host time minus
+ * CHRE time, so that it can be added to the value returned by chreGetTime() to
+ * determine the current estimate of the host time.
+ *
+ * A call to this function must not require waking up the host and should return
+ * quickly.
+ *
+ * This function must always return a valid value from the earliest point that
+ * it can be called by a nanoapp. In other words, it is not valid to return
+ * some fixed/invalid value while waiting for the initial offset estimate to be
+ * determined - this initial offset must be ready before nanoapps are started.
+ *
+ * @return An estimate of the offset between CHRE's time returned in
+ * chreGetTime() and the time on the host given in the Android API
+ * SystemClock.elapsedRealtimeNanos(), accurate to within +/- 10
+ * milliseconds, such that adding this offset to chreGetTime() produces the
+ * estimated current time on the host. This value may change over time to
+ * account for drift, etc., so multiple calls to this API may produce
+ * different results.
+ *
+ * @since v1.1
+ */
+int64_t chreGetEstimatedHostTimeOffset(void);
+
+/**
+ * Convenience function to retrieve CHRE's estimate of the current time on the
+ * host, corresponding to the Android API SystemClock.elapsedRealtimeNanos().
+ *
+ * @return An estimate of the current time on the host, accurate to within
+ * +/- 10 milliseconds. This estimate is *not* guaranteed to be
+ * monotonically increasing, and may move backwards as a result of receiving
+ * new information from the host.
+ *
+ * @since v1.1
+ */
+static inline uint64_t chreGetEstimatedHostTime(void) {
+ int64_t offset = chreGetEstimatedHostTimeOffset();
+ uint64_t time = chreGetTime();
+
+ // Just casting time to int64_t and adding the (potentially negative) offset
+ // should be OK under most conditions, but this way avoids issues if
+ // time >= 2^63, which is technically allowed since we don't specify a start
+ // value for chreGetTime(), though one would assume 0 is roughly boot time.
+ if (offset >= 0) {
+ time += (uint64_t) offset;
+ } else {
+ // Assuming chreGetEstimatedHostTimeOffset() is implemented properly,
+ // this will never underflow, because offset = hostTime - chreTime,
+ // and both times are monotonically increasing (e.g. when determining
+ // the offset, if hostTime is 0 and chreTime is 100 we'll have
+ // offset = -100, but chreGetTime() will always return >= 100 after that
+ // point).
+ time -= (uint64_t) (offset * -1);
+ }
+
+ return time;
+}
+
+/**
+ * Set a timer.
+ *
+ * When the timer fires, nanoappHandleEvent will be invoked with
+ * CHRE_EVENT_TIMER and with the given 'cookie'.
+ *
+ * A CHRE implementation is required to provide at least 32
+ * timers. However, there's no assurance there will be any available
+ * for any given nanoapp (if it's loaded late, etc).
+ *
+ * @param duration Time, in nanoseconds, before the timer fires.
+ * @param cookie Argument that will be sent to nanoappHandleEvent upon the
+ * timer firing. This is allowed to be NULL and does not need to be
+ * a valid pointer (assuming the nanoappHandleEvent code is expecting such).
+ * @param oneShot If true, the timer will just fire once. If false, the
+ * timer will continue to refire every 'duration', until this timer is
+ * canceled (@see chreTimerCancel).
+ *
+ * @return The timer ID. If the system is unable to set a timer
+ * (no more available timers, etc.) then CHRE_TIMER_INVALID will
+ * be returned.
+ *
+ * @see nanoappHandleEvent
+ */
+uint32_t chreTimerSet(uint64_t duration, const void *cookie, bool oneShot);
+
+/**
+ * Cancel a timer.
+ *
+ * After this method returns, the CHRE assures there will be no more
+ * events sent from this timer, and any enqueued events from this timer
+ * will need to be evicted from the queue by the CHRE.
+ *
+ * @param timerId A timer ID obtained by this nanoapp via chreTimerSet().
+ * @return true if the timer was cancelled, false otherwise. We may
+ * fail to cancel the timer if it's a one shot which (just) fired,
+ * or if the given timer ID is not owned by the calling app.
+ */
+bool chreTimerCancel(uint32_t timerId);
+
+/**
+ * Terminate this nanoapp.
+ *
+ * This takes effect immediately.
+ *
+ * The CHRE will no longer execute this nanoapp. The CHRE will not invoke
+ * nanoappEnd(), nor will it call any memory free callbacks in the nanoapp.
+ *
+ * The CHRE will unload/evict this nanoapp's code.
+ *
+ * @param abortCode A value indicating the reason for aborting. (Note that
+ * in this version of the API, there is no way for anyone to access this
+ * code, but future APIs may expose it.)
+ * @return Never. This method does not return, as the CHRE stops nanoapp
+ * execution immediately.
+ */
+void chreAbort(uint32_t abortCode);
+
+/**
+ * Allocate a given number of bytes from the system heap.
+ *
+ * The nanoapp is required to free this memory via chreHeapFree() prior to
+ * the nanoapp ending.
+ *
+ * While the CHRE implementation is required to free up heap resources of
+ * a nanoapp when unloading it, future requirements and tests focused on
+ * nanoapps themselves may check for memory leaks, and will require nanoapps
+ * to properly manage their heap resources.
+ *
+ * @param bytes The number of bytes requested.
+ * @return A pointer to 'bytes' contiguous bytes of heap memory, or NULL
+ * if the allocation could not be performed. This pointer must be suitably
+ * aligned for any kind of variable.
+ *
+ * @see chreHeapFree.
+ */
+void *chreHeapAlloc(uint32_t bytes);
+
+/**
+ * Free a heap allocation.
+ *
+ * This allocation must be from a value returned from a chreHeapAlloc() call
+ * made by this nanoapp. In other words, it is illegal to free memory
+ * allocated by another nanoapp (or the CHRE).
+ *
+ * @param ptr 'ptr' is required to be a value returned from chreHeapAlloc().
+ * Note that since chreHeapAlloc can return NULL, CHRE
+ * implementations must safely handle 'ptr' being NULL.
+ *
+ * @see chreHeapAlloc.
+ */
+void chreHeapFree(void *ptr);
+
+/**
+ * Logs the nanoapp's debug data into debug dumps.
+ *
+ * A debug dump is a string representation of information that can be used to
+ * diagnose and debug issues. While chreLog() is useful for logging events as
+ * they happen, the debug dump is a complementary function typically used to
+ * output a snapshot of a nanoapp's state, history, vital statistics, etc. The
+ * CHRE framework is required to pass this information to the debug method in
+ * the Context Hub HAL, where it can be captured in Android bugreports, etc.
+ *
+ * This function must only be called while handling CHRE_DEBUG_DUMP_EVENT,
+ * otherwise it will have no effect. A nanoapp can call this function multiple
+ * times while handling the event. If the resulting formatted string from a
+ * single call to this function is longer than CHRE_DEBUG_DUMP_MINIMUM_MAX_SIZE
+ * characters, it may get truncated.
+ *
+ * @param formatStr A printf-style format string of the format documented in
+ * chreLog().
+ * @param ... A variable number of arguments necessary for the given 'formatStr'
+ * (there may be no additional arguments for some 'formatStr's).
+ *
+ * @see chreConfigureDebugDumpEvent
+ * @see chreLog
+ *
+ * @since v1.4
+ */
+CHRE_PRINTF_ATTR(1, 2)
+void chreDebugDumpLog(const char *formatStr, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHRE_RE_H_ */
+
diff --git a/chre_api/legacy/v1_8/chre/sensor.h b/chre_api/legacy/v1_8/chre/sensor.h
new file mode 100644
index 00000000..41663741
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/sensor.h
@@ -0,0 +1,1119 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_SENSOR_H_
+#define _CHRE_SENSOR_H_
+
+/**
+ * @file
+ * API dealing with sensor interaction in the Context Hub Runtime
+ * Environment.
+ *
+ * This includes the definition of our sensor types and the ability to
+ * configure them for receiving events.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <chre/common.h>
+#include <chre/event.h>
+#include <chre/sensor_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Base value for all of the data events for sensors.
+ *
+ * The value for a data event FOO is
+ * CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_FOO
+ *
+ * This allows for easy mapping, and also explains why there are gaps
+ * in our values since we don't have all possible sensor types assigned.
+ */
+#define CHRE_EVENT_SENSOR_DATA_EVENT_BASE CHRE_EVENT_SENSOR_FIRST_EVENT
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorThreeAxisData
+ *
+ * The data can be interpreted using the 'x', 'y', and 'z' fields within
+ * 'readings', or by the 3D array 'v' (v[0] == x; v[1] == y; v[2] == z).
+ *
+ * All values are in SI units (m/s^2) and measure the acceleration applied to
+ * the device.
+ */
+#define CHRE_EVENT_SENSOR_ACCELEROMETER_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_ACCELEROMETER)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorOccurrenceData
+ *
+ * Since this is a one-shot sensor, after this event is delivered to the
+ * nanoapp, the sensor automatically goes into DONE mode. Sensors of this
+ * type must be configured with a ONE_SHOT mode.
+ */
+#define CHRE_EVENT_SENSOR_INSTANT_MOTION_DETECT_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorOccurrenceData
+ *
+ * Since this is a one-shot sensor, after this event is delivered to the
+ * nanoapp, the sensor automatically goes into DONE mode. Sensors of this
+ * type must be configured with a ONE_SHOT mode.
+ */
+#define CHRE_EVENT_SENSOR_STATIONARY_DETECT_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_STATIONARY_DETECT)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorThreeAxisData
+ *
+ * The data can be interpreted using the 'x', 'y', and 'z' fields within
+ * 'readings', or by the 3D array 'v' (v[0] == x; v[1] == y; v[2] == z).
+ *
+ * All values are in radians/second and measure the rate of rotation
+ * around the X, Y and Z axis.
+ */
+#define CHRE_EVENT_SENSOR_GYROSCOPE_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_GYROSCOPE)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorThreeAxisData
+ *
+ * The data can be interpreted using the 'x', 'y', and 'z' fields within
+ * 'readings', or by the 3D array 'v' (v[0] == x; v[1] == y; v[2] == z).
+ *
+ * All values are in micro-Tesla (uT) and measure the geomagnetic
+ * field in the X, Y and Z axis.
+ */
+#define CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorFloatData
+ *
+ * The data can be interpreted using the 'pressure' field within 'readings'.
+ * This value is in hectopascals (hPa).
+ */
+#define CHRE_EVENT_SENSOR_PRESSURE_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_PRESSURE)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorFloatData
+ *
+ * The data can be interpreted using the 'light' field within 'readings'.
+ * This value is in SI lux units.
+ */
+#define CHRE_EVENT_SENSOR_LIGHT_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_LIGHT)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorByteData
+ *
+ * The data is interpreted from the following fields in 'readings':
+ * o 'isNear': If set to 1, we are nearby (on the order of centimeters);
+ * if set to 0, we are far. The meaning of near/far in this field must be
+ * consistent with the Android definition.
+ * o 'invalid': If set to 1, this is not a valid reading of this data.
+ * As of CHRE API v1.2, this field is deprecated and must always be set to
+ * 0. If an invalid reading is generated by the sensor hardware, it must
+ * be dropped and not delivered to any nanoapp.
+ *
+ * In prior versions of the CHRE API, there can be an invalid event generated
+ * upon configuring this sensor. Thus, the 'invalid' field must be checked on
+ * the first event before interpreting 'isNear'.
+ */
+#define CHRE_EVENT_SENSOR_PROXIMITY_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_PROXIMITY)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorOccurrenceData
+ *
+ * This data is generated every time a step is taken by the user.
+ *
+ * This is backed by the same algorithm that feeds Android's
+ * SENSOR_TYPE_STEP_DETECTOR, and therefore sacrifices some accuracy to target
+ * an update latency of under 2 seconds.
+ *
+ * @since v1.3
+ */
+#define CHRE_EVENT_SENSOR_STEP_DETECT_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_STEP_DETECT)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorUint64Data
+ *
+ * The value of the data is the cumulative number of steps taken by the user
+ * since the last reboot while the sensor is active. This data is generated
+ * every time a step is taken by the user.
+ *
+ * This is backed by the same algorithm that feeds Android's
+ * SENSOR_TYPE_STEP_COUNTER, and therefore targets high accuracy with under
+ * 10 seconds of update latency.
+ *
+ * @since v1.5
+ */
+#define CHRE_EVENT_SENSOR_STEP_COUNTER_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_STEP_COUNTER)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorFloatData
+ *
+ * The value of the data is the measured hinge angle between 0 and 360 degrees
+ * inclusive.
+ *
+ * This is backed by the same algorithm that feeds Android's
+ * SENSOR_TYPE_HINGE_ANGLE.
+ *
+ * @since v1.5
+ */
+#define CHRE_EVENT_SENSOR_HINGE_ANGLE_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_HINGE_ANGLE)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorThreeAxisData
+ *
+ * The data can be interpreted using the 'x', 'y', and 'z' fields within
+ * 'readings', or by the 3D array 'v' (v[0] == x; v[1] == y; v[2] == z).
+ *
+ * All values are in SI units (m/s^2) and measure the acceleration applied to
+ * the device.
+ */
+#define CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorThreeAxisData
+ *
+ * The data can be interpreted using the 'x', 'y', and 'z' fields within
+ * 'readings', or by the 3D array 'v' (v[0] == x; v[1] == y; v[2] == z).
+ *
+ * All values are in radians/second and measure the rate of rotation
+ * around the X, Y and Z axis.
+ */
+#define CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorThreeAxisData
+ *
+ * The data can be interpreted using the 'x', 'y', and 'z' fields within
+ * 'readings', or by the 3D array 'v' (v[0] == x; v[1] == y; v[2] == z).
+ *
+ * All values are in micro-Tesla (uT) and measure the geomagnetic
+ * field in the X, Y and Z axis.
+ */
+#define CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorFloatData
+ *
+ * The data can be interpreted using the 'temperature' field within 'readings'.
+ * This value is in degrees Celsius.
+ */
+#define CHRE_EVENT_SENSOR_ACCELEROMETER_TEMPERATURE_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_ACCELEROMETER_TEMPERATURE)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorFloatData
+ *
+ * The data can be interpreted using the 'temperature' field within 'readings'.
+ * This value is in degrees Celsius.
+ */
+#define CHRE_EVENT_SENSOR_GYROSCOPE_TEMPERATURE_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_GYROSCOPE_TEMPERATURE)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorFloatData
+ *
+ * The data can be interpreted using the 'temperature' field within 'readings'.
+ * This value is in degrees Celsius.
+ */
+#define CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_TEMPERATURE_DATA \
+ (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD_TEMPERATURE)
+
+/**
+ * First value for sensor events which are not data from the sensor.
+ *
+ * Unlike the data event values, these other event values don't have any
+ * mapping to sensor types.
+ */
+#define CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE \
+ (CHRE_EVENT_SENSOR_FIRST_EVENT + 0x0100)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorSamplingStatusEvent
+ *
+ * Indicates that the interval and/or the latency which this sensor is
+ * sampling at has changed.
+ */
+#define CHRE_EVENT_SENSOR_SAMPLING_CHANGE \
+ (CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE + 0)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorThreeAxisData
+ *
+ * The data can be interpreted using the 'x_bias', 'y_bias', and 'z_bias'
+ * field within 'readings', or by the 3D array 'bias' (bias[0] == x_bias;
+ * bias[1] == y_bias; bias[2] == z_bias). Bias is subtracted from uncalibrated
+ * data to generate calibrated data.
+ *
+ * All values are in radians/second and measure the rate of rotation
+ * around the X, Y and Z axis.
+ *
+ * If bias delivery is supported, this event is generated by default when
+ * chreSensorConfigure is called to enable for the sensor of type
+ * CHRE_SENSOR_TYPE_GYROSCOPE, or if bias delivery is explicitly enabled
+ * through chreSensorConfigureBiasEvents() for the sensor.
+ */
+#define CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO \
+ (CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE + 1)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorThreeAxisData
+ *
+ * The data can be interpreted using the 'x_bias', 'y_bias', and 'z_bias'
+ * field within 'readings', or by the 3D array 'bias' (bias[0] == x_bias;
+ * bias[1] == y_bias; bias[2] == z_bias). Bias is subtracted from uncalibrated
+ * data to generate calibrated data.
+ *
+ * All values are in micro-Tesla (uT) and measure the geomagnetic
+ * field in the X, Y and Z axis.
+ *
+ * If bias delivery is supported, this event is generated by default when
+ * chreSensorConfigure is called to enable for the sensor of type
+ * CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD, or if bias delivery is explicitly enabled
+ * through chreSensorConfigureBiasEvents() for the sensor.
+ */
+#define CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO \
+ (CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE + 2)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorThreeAxisData
+ *
+ * The data can be interpreted using the 'x_bias', 'y_bias', and 'z_bias'
+ * field within 'readings', or by the 3D array 'bias' (bias[0] == x_bias;
+ * bias[1] == y_bias; bias[2] == z_bias). Bias is subtracted from uncalibrated
+ * data to generate calibrated data.
+ *
+ * All values are in SI units (m/s^2) and measure the acceleration applied to
+ * the device.
+ *
+ * If bias delivery is supported, this event is generated by default when
+ * chreSensorConfigure is called to enable for the sensor of type
+ * CHRE_SENSOR_TYPE_ACCELEROMETER, or if bias delivery is explicitly enabled
+ * through chreSensorConfigureBiasEvents() for the sensor.
+ *
+ * @since v1.3
+ */
+#define CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO \
+ (CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE + 3)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorFlushCompleteEvent
+ *
+ * An event indicating that a flush request made by chreSensorFlushAsync has
+ * completed.
+ *
+ * @see chreSensorFlushAsync
+ *
+ * @since v1.3
+ */
+#define CHRE_EVENT_SENSOR_FLUSH_COMPLETE \
+ (CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE + 4)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorThreeAxisData
+ *
+ * The data of this event is the same as that of
+ * CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO, except the sensorHandle field of
+ * chreSensorDataHeader contains the handle of the sensor of type
+ * CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE.
+ *
+ * This event is only generated if the bias reporting is explicitly enabled
+ * for a nanoapp through chreSensorConfigureBiasEvents() for the sensor of type
+ * CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE.
+ *
+ * @see CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO
+ *
+ * @since v1.3
+ */
+#define CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_BIAS_INFO \
+ (CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE + 5)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorThreeAxisData
+ *
+ * The data of this event is the same as that of
+ * CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO, except the sensorHandle field
+ * of chreSensorDataHeader contains the handle of the sensor of type
+ * CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD.
+ *
+ * This event is only generated if the bias reporting is explicitly enabled
+ * for a nanoapp through chreSensorConfigureBiasEvents() for the sensor of type
+ * CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD.
+ *
+ * @see CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO
+ *
+ * @since v1.3
+ */
+#define CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_BIAS_INFO \
+ (CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE + 6)
+
+/**
+ * nanoappHandleEvent argument: struct chreSensorThreeAxisData
+ *
+ * The data of this event is the same as that of
+ * CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO, except the sensorHandle field
+ * of chreSensorDataHeader contains the handle of the sensor of type
+ * CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER.
+ *
+ * This event is only generated if the bias reporting is explicitly enabled
+ * for a nanoapp through chreSensorConfigureBiasEvents for the sensor of type
+ * CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER.
+ *
+ * @see CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO
+ *
+ * @since v1.3
+ */
+#define CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_BIAS_INFO \
+ (CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE + 7)
+
+#if CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_BIAS_INFO > \
+ CHRE_EVENT_SENSOR_LAST_EVENT
+#error Too many sensor events.
+#endif
+
+/**
+ * Value indicating we want the smallest possible latency for a sensor.
+ *
+ * This literally translates to 0 nanoseconds for the chreSensorConfigure()
+ * argument. While we won't get exactly 0 nanoseconds, the CHRE will
+ * queue up this event As Soon As Possible.
+ */
+#define CHRE_SENSOR_LATENCY_ASAP UINT64_C(0)
+
+/**
+ * Special value indicating non-importance, or non-applicability of the sampling
+ * interval.
+ *
+ * @see chreSensorConfigure
+ * @see chreSensorSamplingStatus
+ */
+#define CHRE_SENSOR_INTERVAL_DEFAULT UINT64_C(-1)
+
+/**
+ * Special value indicating non-importance of the latency.
+ *
+ * @see chreSensorConfigure
+ * @see chreSensorSamplingStatus
+ */
+#define CHRE_SENSOR_LATENCY_DEFAULT UINT64_C(-1)
+
+/**
+ * A sensor index value indicating that it is the default sensor.
+ *
+ * @see chreSensorFind
+ */
+#define CHRE_SENSOR_INDEX_DEFAULT UINT8_C(0)
+
+/**
+ * Special value indicating non-importance of the batch interval.
+ *
+ * @see chreSensorConfigureWithBatchInterval
+ */
+#define CHRE_SENSOR_BATCH_INTERVAL_DEFAULT UINT64_C(-1)
+
+// This is used to define elements of enum chreSensorConfigureMode.
+#define CHRE_SENSOR_CONFIGURE_RAW_POWER_ON (1 << 0)
+
+// This is used to define elements of enum chreSensorConfigureMode.
+#define CHRE_SENSOR_CONFIGURE_RAW_REPORT_CONTINUOUS (1 << 1)
+
+// This is used to define elements of enum chreSensorConfigureMode.
+#define CHRE_SENSOR_CONFIGURE_RAW_REPORT_ONE_SHOT (2 << 1)
+
+/**
+ * The maximum amount of time allowed to elapse between the call to
+ * chreSensorFlushAsync() and when CHRE_EVENT_SENSOR_FLUSH_COMPLETE is delivered
+ * to the nanoapp on a successful flush.
+ */
+#define CHRE_SENSOR_FLUSH_COMPLETE_TIMEOUT_NS (5 * CHRE_NSEC_PER_SEC)
+
+/**
+ * Modes we can configure a sensor to use.
+ *
+ * Our mode will affect not only how/if we receive events, but
+ * also whether or not the sensor will be powered on our behalf.
+ *
+ * @see chreSensorConfigure
+ */
+enum chreSensorConfigureMode {
+ /**
+ * Get events from the sensor.
+ *
+ * Power: Turn on if not already on.
+ * Reporting: Continuous. Send each new event as it comes (subject to
+ * batching and latency).
+ */
+ CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS =
+ (CHRE_SENSOR_CONFIGURE_RAW_POWER_ON |
+ CHRE_SENSOR_CONFIGURE_RAW_REPORT_CONTINUOUS),
+
+ /**
+ * Get a single event from the sensor and then become DONE.
+ *
+ * Once the event is sent, the sensor automatically
+ * changes to CHRE_SENSOR_CONFIGURE_MODE_DONE mode.
+ *
+ * Power: Turn on if not already on.
+ * Reporting: One shot. Send the next event and then be DONE.
+ */
+ CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT =
+ (CHRE_SENSOR_CONFIGURE_RAW_POWER_ON |
+ CHRE_SENSOR_CONFIGURE_RAW_REPORT_ONE_SHOT),
+
+ /**
+ * Get events from a sensor that are generated for any client in the system.
+ *
+ * This is considered passive because the sensor will not be powered on for
+ * the sake of our nanoapp. If and only if another client in the system has
+ * requested this sensor power on will we get events.
+ *
+ * This can be useful for something which is interested in seeing data, but
+ * not interested enough to be responsible for powering on the sensor.
+ *
+ * Power: Do not power the sensor on our behalf.
+ * Reporting: Continuous. Send each event as it comes.
+ */
+ CHRE_SENSOR_CONFIGURE_MODE_PASSIVE_CONTINUOUS =
+ CHRE_SENSOR_CONFIGURE_RAW_REPORT_CONTINUOUS,
+
+ /**
+ * Get a single event from a sensor that is generated for any client in the
+ * system.
+ *
+ * See CHRE_SENSOR_CONFIGURE_MODE_PASSIVE_CONTINUOUS for more details on
+ * what the "passive" means.
+ *
+ * Power: Do not power the sensor on our behalf.
+ * Reporting: One shot. Send only the next event and then be DONE.
+ */
+ CHRE_SENSOR_CONFIGURE_MODE_PASSIVE_ONE_SHOT =
+ CHRE_SENSOR_CONFIGURE_RAW_REPORT_ONE_SHOT,
+
+ /**
+ * Indicate we are done using this sensor and no longer interested in it.
+ *
+ * See chreSensorConfigure for more details on expressing interest or
+ * lack of interest in a sensor.
+ *
+ * Power: Do not power the sensor on our behalf.
+ * Reporting: None.
+ */
+ CHRE_SENSOR_CONFIGURE_MODE_DONE = 0,
+};
+
+/**
+ * A structure containing information about a Sensor.
+ *
+ * See documentation of individual fields below.
+ */
+struct chreSensorInfo {
+ /**
+ * The name of the sensor.
+ *
+ * A text name, useful for logging/debugging, describing the Sensor. This
+ * is not assured to be unique (i.e. there could be multiple sensors with
+ * the name "Temperature").
+ *
+ * CHRE implementations may not set this as NULL. An empty
+ * string, while discouraged, is legal.
+ */
+ const char *sensorName;
+
+ /**
+ * One of the CHRE_SENSOR_TYPE_* defines above.
+ */
+ uint8_t sensorType;
+
+ /**
+ * Flag indicating if this sensor is on-change.
+ *
+ * An on-change sensor only generates events when underlying state
+ * changes. This has the same meaning as on-change does in the Android
+ * Sensors HAL. See sensors.h for much more details.
+ *
+ * A value of 1 indicates this is on-change. 0 indicates this is not
+ * on-change.
+ */
+ uint8_t isOnChange : 1;
+
+ /**
+ * Flag indicating if this sensor is one-shot.
+ *
+ * A one-shot sensor only triggers a single event, and then automatically
+ * disables itself.
+ *
+ * A value of 1 indicates this is one-shot. 0 indicates this is not
+ * on-change.
+ */
+ uint8_t isOneShot : 1;
+
+ /**
+ * Flag indicating if this sensor supports reporting bias info events.
+ *
+ * This field will be set to 0 when running on CHRE API versions prior to
+ * v1.3, but must be ignored (i.e. does not mean bias info event is not
+ * supported).
+ *
+ * @see chreSensorConfigureBiasEvents
+ *
+ * @since v1.3
+ */
+ uint8_t reportsBiasEvents : 1;
+
+ /**
+ * Flag indicating if this sensor supports passive mode requests.
+ *
+ * This field will be set to 0 when running on CHRE API versions prior to
+ * v1.4, and must be ignored (i.e. does not mean passive mode requests are
+ * not supported).
+ *
+ * @see chreSensorConfigure
+ *
+ * @since v1.4
+ */
+ uint8_t supportsPassiveMode : 1;
+
+ uint8_t unusedFlags : 4;
+
+ /**
+ * The minimum sampling interval supported by this sensor, in nanoseconds.
+ *
+ * Requests to chreSensorConfigure with a lower interval than this will
+ * fail. If the sampling interval is not applicable to this sensor, this
+ * will be set to CHRE_SENSOR_INTERVAL_DEFAULT.
+ *
+ * This field will be set to 0 when running on CHRE API versions prior to
+ * v1.1, indicating that the minimum interval is not known.
+ *
+ * @since v1.1
+ */
+ uint64_t minInterval;
+
+ /**
+ * Uniquely identifies the sensor for a given type. A value of 0 indicates
+ * that this is the "default" sensor, which is returned by
+ * chreSensorFindDefault().
+ *
+ * The sensor index of a given type must be stable across boots (i.e. must
+ * not change), and a different sensor of the same type must have different
+ * sensor index values, and the set of sensorIndex values for a given sensor
+ * type must be continuguous.
+ *
+ * @since v1.5
+ */
+ uint8_t sensorIndex;
+};
+
+/**
+ * The status of a sensor's sampling configuration.
+ */
+struct chreSensorSamplingStatus {
+ /**
+ * The interval, in nanoseconds, at which sensor data is being sampled at.
+ * This should be used by nanoapps to determine the rate at which samples
+ * will be generated and not to indicate what the sensor is truly sampling
+ * at since resampling may occur to limit incoming data.
+ *
+ * If this is CHRE_SENSOR_INTERVAL_DEFAULT, then a sampling interval
+ * isn't meaningful for this sensor.
+ *
+ * Note that if 'enabled' is false, this value is not meaningful.
+ */
+ uint64_t interval;
+
+ /**
+ * The latency, in nanoseconds, at which the sensor is now reporting.
+ *
+ * If this is CHRE_SENSOR_LATENCY_DEFAULT, then a latency
+ * isn't meaningful for this sensor.
+ *
+ * The effective batch interval can be derived from this value by
+ * adding the current sampling interval.
+ *
+ * Note that if 'enabled' is false, this value is not meaningful.
+ */
+ uint64_t latency;
+
+ /**
+ * True if the sensor is actively powered and sampling; false otherwise.
+ */
+ bool enabled;
+};
+
+/**
+ * The nanoappHandleEvent argument for CHRE_EVENT_SENSOR_SAMPLING_CHANGE.
+ *
+ * Note that only at least one of 'interval' or 'latency' must be
+ * different than it was prior to this event. Thus, one of these
+ * fields may be (but doesn't need to be) the same as before.
+ */
+struct chreSensorSamplingStatusEvent {
+ /**
+ * The handle of the sensor which has experienced a change in sampling.
+ */
+ uint32_t sensorHandle;
+
+ /**
+ * The new sampling status.
+ *
+ * At least one of the field in this struct will be different from
+ * the previous sampling status event.
+ */
+ struct chreSensorSamplingStatus status;
+};
+
+/**
+ * The nanoappHandleEvent argument for CHRE_EVENT_SENSOR_FLUSH_COMPLETE.
+ *
+ * @see chreSensorFlushAsync
+ *
+ * @since v1.3
+ */
+struct chreSensorFlushCompleteEvent {
+ /**
+ * The handle of the sensor which a flush was completed.
+ */
+ uint32_t sensorHandle;
+
+ /**
+ * Populated with a value from enum {@link #chreError}, indicating whether
+ * the flush failed, and if so, provides the cause of the failure.
+ */
+ uint8_t errorCode;
+
+ /**
+ * Reserved for future use. Set to 0.
+ */
+ uint8_t reserved[3];
+
+ /**
+ * Set to the cookie parameter given to chreSensorFlushAsync.
+ */
+ const void *cookie;
+};
+
+/**
+ * Find the default sensor for a given sensor type.
+ *
+ * @param sensorType One of the CHRE_SENSOR_TYPE_* constants.
+ * @param handle If a sensor is found, then the memory will be filled with
+ * the value for the sensor's handle. This argument must be non-NULL.
+ * @return true if a sensor was found, false otherwise.
+ */
+bool chreSensorFindDefault(uint8_t sensorType, uint32_t *handle);
+
+/**
+ * Finds a sensor of a given index and sensor type.
+ *
+ * For CHRE implementations that support multiple sensors of the same sensor
+ * type, this method can be used to get the non-default sensor(s). The default
+ * sensor, as defined in the chreSensorFindDefault(), will be returned if
+ * a sensor index of zero is specified.
+ *
+ * A simple example of iterating all available sensors of a given type is
+ * provided here:
+ *
+ * uint32_t handle;
+ * for (uint8_t i = 0; chreSensorFind(sensorType, i, &handle); i++) {
+ * chreLog(CHRE_LOG_INFO,
+ * "Found sensor index %" PRIu8 ", which has handle %" PRIu32,
+ * i, handle);
+ * }
+ *
+ * If this method is invoked for CHRE versions prior to v1.5, invocations with
+ * sensorIndex value of 0 will be equivalent to using chreSensorFindDefault, and
+ * if sensorIndex is non-zero will return false.
+ *
+ * In cases where multiple sensors are supported in both the Android sensors
+ * framework and CHRE, the sensorName of the chreSensorInfo struct for a given
+ * sensor instance must match exactly with that of the
+ * android.hardware.Sensor#getName() return value. This can be used to match a
+ * sensor instance between the Android and CHRE sensors APIs.
+ *
+ * @param sensorType One of the CHRE_SENSOR_TYPE_* constants.
+ * @param sensorIndex The index of the desired sensor.
+ * @param handle If a sensor is found, then the memory will be filled with
+ * the value for the sensor's handle. This argument must be non-NULL.
+ * @return true if a sensor was found, false otherwise.
+ *
+ * @since v1.5
+ */
+bool chreSensorFind(uint8_t sensorType, uint8_t sensorIndex, uint32_t *handle);
+
+/**
+ * Get the chreSensorInfo struct for a given sensor.
+ *
+ * @param sensorHandle The sensor handle, as obtained from
+ * chreSensorFindDefault() or passed to nanoappHandleEvent().
+ * @param info If the sensor is valid, then this memory will be filled with
+ * the SensorInfo contents for this sensor. This argument must be
+ * non-NULL.
+ * @return true if the senor handle is valid and 'info' was filled in;
+ * false otherwise.
+ */
+bool chreGetSensorInfo(uint32_t sensorHandle, struct chreSensorInfo *info);
+
+/**
+ * Get the chreSensorSamplingStatus struct for a given sensor.
+ *
+ * Note that this may be different from what was requested in
+ * chreSensorConfigure(), for multiple reasons. It's possible that the sensor
+ * does not exactly support the interval requested in chreSensorConfigure(), so
+ * a faster one was chosen.
+ *
+ * It's also possible that there is another user of this sensor who has
+ * requested a faster interval and/or lower latency. This latter scenario
+ * should be noted, because it means the sensor rate can change due to no
+ * interaction from this nanoapp. Note that the
+ * CHRE_EVENT_SENSOR_SAMPLING_CHANGE event will trigger in this case, so it's
+ * not necessary to poll for such a change.
+ *
+ * This function must return a valid status if the provided sensor is being
+ * actively sampled by a nanoapp and a CHRE_EVENT_SENSOR_SAMPLING_CHANGE has
+ * been delivered indicating their request has taken effect. It is not required
+ * to return a valid status if no nanoapp is actively sampling the sensor.
+ *
+ * @param sensorHandle The sensor handle, as obtained from
+ * chreSensorFindDefault() or passed to nanoappHandleEvent().
+ * @param status If the sensor is actively enabled by a nanoapp, then this
+ * memory must be filled with the sampling status contents for this sensor.
+ * This argument must be non-NULL.
+ * @return true if the sensor handle is valid and 'status' was filled in;
+ * false otherwise.
+ */
+bool chreGetSensorSamplingStatus(uint32_t sensorHandle,
+ struct chreSensorSamplingStatus *status);
+
+/**
+ * Configures a given sensor at a specific interval and latency and mode.
+ *
+ * If this sensor's chreSensorInfo has isOneShot set to 1,
+ * then the mode must be one of the ONE_SHOT modes, or this method will fail.
+ *
+ * The CHRE wants to power as few sensors as possible, in keeping with its
+ * low power design. As such, it only turns on sensors when there are clients
+ * actively interested in that sensor data, and turns off sensors as soon as
+ * there are no clients interested in them. Calling this method generally
+ * indicates an interest, and using CHRE_SENSOR_CONFIGURE_MODE_DONE shows
+ * when we are no longer interested.
+ *
+ * Thus, each initial Configure of a sensor (per nanoapp) needs to eventually
+ * have a DONE call made, either directly or on its behalf. Subsequent calls
+ * to a Configure method within the same nanoapp, when there has been no DONE
+ * in between, still only require a single DONE call.
+ *
+ * For example, the following is valid usage:
+ * <code>
+ * chreSensorConfigure(myHandle, mode, interval0, latency0);
+ * [...]
+ * chreSensorConfigure(myHandle, mode, interval1, latency0);
+ * [...]
+ * chreSensorConfigure(myHandle, mode, interval1, latency1);
+ * [...]
+ * chreSensorConfigureModeOnly(myHandle, CHRE_SENSOR_CONFIGURE_MODE_DONE);
+ * </code>
+ *
+ * The first call to Configure is the one which creates the requirement
+ * to eventually call with DONE. The subsequent calls are just changing the
+ * interval/latency. They have not changed the fact that this nanoapp is
+ * still interested in output from the sensor 'myHandle'. Thus, only one
+ * single call for DONE is needed.
+ *
+ * There is a special case. One-shot sensors, sensors which
+ * just trigger a single event and never trigger again, implicitly go into
+ * DONE mode after that single event triggers. Thus, the
+ * following are legitimate usages:
+ * <code>
+ * chreSensorConfigure(myHandle, MODE_ONE_SHOT, interval, latency);
+ * [...]
+ * [myHandle triggers an event]
+ * [no need to configure to DONE].
+ * </code>
+ *
+ * And:
+ * <code>
+ * chreSensorConfigure(myHandle, MODE_ONE_SHOT, interval, latency);
+ * [...]
+ * chreSensorConfigureModeOnly(myHandle, MODE_DONE);
+ * [we cancelled myHandle before it ever triggered an event]
+ * </code>
+ *
+ * Note that while PASSIVE modes, by definition, don't express an interest in
+ * powering the sensor, DONE is still necessary to silence the event reporting.
+ * Starting with CHRE API v1.4, for sensors that do not support passive mode, a
+ * request with mode set to CHRE_SENSOR_CONFIGURE_MODE_PASSIVE_CONTINUOUS or
+ * CHRE_SENSOR_CONFIGURE_MODE_PASSIVE_ONE_SHOT will be rejected. CHRE API
+ * versions 1.3 and older implicitly assume that passive mode is supported
+ * across all sensors, however this is not necessarily the case. Clients can
+ * call chreSensorInfo to identify whether a sensor supports passive mode.
+ *
+ * When a calibrated sensor (e.g. CHRE_SENSOR_TYPE_ACCELEROMETER) is
+ * successfully enabled through this method and if bias delivery is supported,
+ * by default CHRE will start delivering bias events for the sensor
+ * (e.g. CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO) to the nanoapp. If the
+ * nanoapp does not wish to receive these events, they can be disabled through
+ * chreSensorConfigureBiasEvents after enabling the sensor.
+ *
+ * @param sensorHandle The handle to the sensor, as obtained from
+ * chreSensorFindDefault().
+ * @param mode The mode to use. See descriptions within the
+ * chreSensorConfigureMode enum.
+ * @param interval The interval, in nanoseconds, at which we want events from
+ * the sensor. On success, the sensor will be set to 'interval', or a value
+ * less than 'interval'. There is a special value
+ * CHRE_SENSOR_INTERVAL_DEFAULT, in which we don't express a preference for
+ * the interval, and allow the sensor to choose what it wants. Note that
+ * due to batching, we may receive events less frequently than
+ * 'interval'.
+ * @param latency The maximum latency, in nanoseconds, allowed before the
+ * CHRE begins delivery of an event. This will control how many events
+ * can be queued by the sensor before requiring a delivery event.
+ * Latency is defined as the "timestamp when event is queued by the CHRE"
+ * minus "timestamp of oldest unsent data reading".
+ * There is a special value CHRE_SENSOR_LATENCY_DEFAULT, in which we don't
+ * express a preference for the latency, and allow the sensor to choose what
+ * it wants.
+ * Note that there is no assurance of how long it will take an event to
+ * get through a CHRE's queueing system, and thus there is no ability to
+ * request a minimum time from the occurrence of a phenomenon to when the
+ * nanoapp receives the information. The current CHRE API has no
+ * real-time elements, although future versions may introduce some to
+ * help with this issue.
+ * @return true if the configuration succeeded, false otherwise.
+ *
+ * @see chreSensorConfigureMode
+ * @see chreSensorFindDefault
+ * @see chreSensorInfo
+ * @see chreSensorConfigureBiasEvents
+ */
+bool chreSensorConfigure(uint32_t sensorHandle,
+ enum chreSensorConfigureMode mode,
+ uint64_t interval, uint64_t latency);
+
+/**
+ * Short cut for chreSensorConfigure where we only want to configure the mode
+ * and do not care about interval/latency.
+ *
+ * @see chreSensorConfigure
+ */
+static inline bool chreSensorConfigureModeOnly(
+ uint32_t sensorHandle, enum chreSensorConfigureMode mode) {
+ return chreSensorConfigure(sensorHandle,
+ mode,
+ CHRE_SENSOR_INTERVAL_DEFAULT,
+ CHRE_SENSOR_LATENCY_DEFAULT);
+}
+
+/**
+ * Convenience function that wraps chreSensorConfigure but enables batching to
+ * be controlled by specifying the desired maximum batch interval rather
+ * than maximum sample latency. Users may find the batch interval to be a more
+ * intuitive method of expressing the desired batching behavior.
+ *
+ * Batch interval is different from latency as the batch interval time is
+ * counted starting when the prior event containing a batch of sensor samples is
+ * delivered, while latency starts counting when the first sample is deferred to
+ * start collecting a batch. In other words, latency ignores the time between
+ * the last sample in a batch to the first sample of the next batch, while it's
+ * included in the batch interval, as illustrated below.
+ *
+ * Time 0 1 2 3 4 5 6 7 8
+ * Batch A B C
+ * Sample a1 a2 a3 b1 b2 b3 c1 c2 c3
+ * Latency [ ] [ ] [ ]
+ * BatchInt | | |
+ *
+ * In the diagram, the effective sample interval is 1 time unit, latency is 2
+ * time units, and batch interval is 3 time units.
+ *
+ * @param sensorHandle See chreSensorConfigure#sensorHandle
+ * @param mode See chreSensorConfigure#mode
+ * @param sampleInterval See chreSensorConfigure#interval, but note that
+ * CHRE_SENSOR_INTERVAL_DEFAULT is not a supported input to this method.
+ * @param batchInterval The desired maximum interval, in nanoseconds, between
+ * CHRE enqueuing each batch of sensor samples.
+ * @return Same as chreSensorConfigure
+ *
+ * @see chreSensorConfigure
+ *
+ * @since v1.1
+ */
+static inline bool chreSensorConfigureWithBatchInterval(
+ uint32_t sensorHandle, enum chreSensorConfigureMode mode,
+ uint64_t sampleInterval, uint64_t batchInterval) {
+ bool result = false;
+
+ if (sampleInterval != CHRE_SENSOR_INTERVAL_DEFAULT) {
+ uint64_t latency;
+ if (batchInterval == CHRE_SENSOR_BATCH_INTERVAL_DEFAULT) {
+ latency = CHRE_SENSOR_LATENCY_DEFAULT;
+ } else if (batchInterval > sampleInterval) {
+ latency = batchInterval - sampleInterval;
+ } else {
+ latency = CHRE_SENSOR_LATENCY_ASAP;
+ }
+ result = chreSensorConfigure(sensorHandle, mode, sampleInterval,
+ latency);
+ }
+
+ return result;
+}
+
+/**
+ * Configures the reception of bias events for a specific sensor.
+ *
+ * If bias event delivery is supported for a sensor, the sensor's chreSensorInfo
+ * has reportsBiasEvents set to 1. If supported, it must be supported for both
+ * calibrated and uncalibrated versions of the sensor. If supported, CHRE must
+ * provide bias events to the nanoapp by default when chreSensorConfigure is
+ * called to enable the calibrated version of the sensor (for backwards
+ * compatibility reasons, as this is the defined behavior for CHRE API v1.0).
+ * When configuring uncalibrated sensors, nanoapps must explicitly configure an
+ * enable request through this method to receive bias events. If bias event
+ * delivery is not supported for the sensor, this method will return false and
+ * no bias events will be generated.
+ *
+ * To enable bias event delivery (enable=true), the nanoapp must be registered
+ * to the sensor through chreSensorConfigure, and bias events will only be
+ * generated when the sensor is powered on. To disable the bias event delivery,
+ * this method can be invoked with enable=false.
+ *
+ * If an enable configuration is successful, the calling nanoapp will receive
+ * bias info events, e.g. CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO, when the
+ * bias status changes (or first becomes available). Calibrated data
+ * (e.g. CHRE_SENSOR_TYPE_ACCELEROMETER) is generated by subracting bias from
+ * uncalibrated data (e.g. CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER).
+ * Calibrated sensor events are generated by applying the most recent bias
+ * available (i.e. timestamp of calibrated data are greater than or equal to the
+ * timestamp of the bias data that has been applied to it). The configuration of
+ * bias event delivery persists until the sensor is unregistered by the nanoapp
+ * through chreSensorConfigure or modified through this method.
+ *
+ * To get an initial bias before new bias events, the nanoapp should get the
+ * bias synchronously after this method is invoked, e.g.:
+ *
+ * if (chreSensorConfigure(handle, ...)) {
+ * chreSensorConfigureBiasEvents(handle, true);
+ * chreSensorGetThreeAxisBias(handle, &bias);
+ * }
+ *
+ * Note that chreSensorGetThreeAxisBias() should be called after
+ * chreSensorConfigureBiasEvents() to ensure that no bias events are lost.
+ *
+ * If called while running on a CHRE API version below v1.3, this function
+ * returns false and has no effect. The default behavior regarding bias events
+ * is unchanged, meaning that the implementation may still send bias events
+ * when a calibrated sensor is registered (if supported), and will not send bias
+ * events when an uncalibrated sensor is registered.
+ *
+ * @param sensorHandle The handle to the sensor, as obtained from
+ * chreSensorFindDefault().
+ * @param enable true to receive bias events, false otherwise
+ *
+ * @return true if the configuration succeeded, false otherwise
+ *
+ * @since v1.3
+ */
+bool chreSensorConfigureBiasEvents(uint32_t sensorHandle, bool enable);
+
+/**
+ * Synchronously provides the most recent bias info available for a sensor. The
+ * bias will only be provided for a sensor that supports bias event delivery
+ * using the chreSensorThreeAxisData type. If the bias is not yet available
+ * (but is supported), this method will store data with a bias of 0 and the
+ * accuracy field in chreSensorDataHeader set to CHRE_SENSOR_ACCURACY_UNKNOWN.
+ *
+ * If called while running on a CHRE API version below v1.3, this function
+ * returns false.
+ *
+ * @param sensorHandle The handle to the sensor, as obtained from
+ * chreSensorFindDefault().
+ * @param bias A pointer to where the bias will be stored.
+ *
+ * @return true if the bias was successfully stored, false if sensorHandle was
+ * invalid or the sensor does not support three axis bias delivery
+ *
+ * @since v1.3
+ *
+ * @see chreSensorConfigureBiasEvents
+ */
+bool chreSensorGetThreeAxisBias(uint32_t sensorHandle,
+ struct chreSensorThreeAxisData *bias);
+
+/**
+ * Makes a request to flush all samples stored for batching. The nanoapp must be
+ * registered to the sensor through chreSensorConfigure, and the sensor must be
+ * powered on. If the request is accepted, all batched samples of the sensor
+ * are sent to nanoapps registered to the sensor. During a flush, it is treated
+ * as though the latency as given in chreSensorConfigure has expired. When all
+ * batched samples have been flushed (or the flush fails), the nanoapp will
+ * receive a unicast CHRE_EVENT_SENSOR_FLUSH_COMPLETE event. The time to deliver
+ * this event must not exceed CHRE_SENSOR_FLUSH_COMPLETE_TIMEOUT_NS after this
+ * method is invoked. If there are no samples in the batch buffer (either in
+ * hardware FIFO or software), then this method will return true and a
+ * CHRE_EVENT_SENSOR_FLUSH_COMPLETE event is delivered immediately.
+ *
+ * If a flush request is invalid (e.g. the sensor refers to a one-shot sensor,
+ * or the sensor was not enabled), and this API will return false and no
+ * CHRE_EVENT_SENSOR_FLUSH_COMPLETE event will be delivered.
+ *
+ * If multiple flush requests are made for a sensor prior to flush completion,
+ * then the requesting nanoapp will receive all batched samples existing at the
+ * time of the latest flush request. In this case, the number of
+ * CHRE_EVENT_SENSOR_FLUSH_COMPLETE events received must equal the number of
+ * flush requests made.
+ *
+ * If a sensor request is disabled after a flush request is made through this
+ * method but before the flush operation is completed, the nanoapp will receive
+ * a CHRE_EVENT_SENSOR_FLUSH_COMPLETE with the error code
+ * CHRE_ERROR_FUNCTION_DISABLED for any pending flush requests.
+ *
+ * Starting with CHRE API v1.3, implementations must support this capability
+ * across all exposed sensor types.
+ *
+ * @param sensorHandle The handle to the sensor, as obtained from
+ * chreSensorFindDefault().
+ * @param cookie An opaque value that will be included in the
+ * chreSensorFlushCompleteEvent sent in relation to this request.
+ *
+ * @return true if the request was accepted for processing, false otherwise
+ *
+ * @since v1.3
+ */
+bool chreSensorFlushAsync(uint32_t sensorHandle, const void *cookie);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHRE_SENSOR_H_ */
diff --git a/chre_api/legacy/v1_8/chre/sensor_types.h b/chre_api/legacy/v1_8/chre/sensor_types.h
new file mode 100644
index 00000000..63b495bb
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/sensor_types.h
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_SENSOR_TYPES_H_
+#define _CHRE_SENSOR_TYPES_H_
+
+/**
+ * @file
+ * Standalone definition of sensor types, and the data structures of the sample
+ * events they emit.
+ */
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ * The CHRE_SENSOR_TYPE_* defines are the sensor types supported.
+ *
+ * Unless otherwise noted, each of these sensor types is based off of a
+ * corresponding sensor type in the Android API's sensors.h interface.
+ * For a given CHRE_SENSOR_TYPE_FOO, it corresponds to the SENSOR_TYPE_FOO in
+ * hardware/libhardware/include/hardware/sensors.h of the Android code base.
+ *
+ * Unless otherwise noted below, a CHRE_SENSOR_TYPE_FOO should be assumed
+ * to work the same as the Android SENSOR_TYPE_FOO, as documented in the
+ * sensors.h documentation and as detailed within the Android Compatibility
+ * Definition Document.
+ *
+ * Note that every sensor will generate CHRE_EVENT_SENSOR_SAMPLING_CHANGE
+ * events, so it is not listed with each individual sensor.
+ */
+
+/**
+ * Start value for all of the vendor-defined private sensors.
+ *
+ * @since v1.2
+ */
+#define CHRE_SENSOR_TYPE_VENDOR_START UINT8_C(192)
+
+/**
+ * Accelerometer.
+ *
+ * Generates: CHRE_EVENT_SENSOR_ACCELEROMETER_DATA and
+ * optionally CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO
+ *
+ * Note that the ACCELEROMETER_DATA is always the fully calibrated data,
+ * including factory calibration and runtime calibration if available.
+ *
+ * @see chreConfigureSensorBiasEvents
+ */
+#define CHRE_SENSOR_TYPE_ACCELEROMETER UINT8_C(1)
+
+/**
+ * Instantaneous motion detection.
+ *
+ * Generates: CHRE_EVENT_SENSOR_INSTANT_MOTION_DETECT_DATA
+ *
+ * This is a one-shot sensor.
+ *
+ * This does not have a direct analogy within sensors.h. This is similar
+ * to SENSOR_TYPE_MOTION_DETECT, but this triggers instantly upon any
+ * motion, instead of waiting for a period of continuous motion.
+ */
+#define CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT UINT8_C(2)
+
+/**
+ * Stationary detection.
+ *
+ * Generates: CHRE_EVENT_SENSOR_STATIONARY_DETECT_DATA
+ *
+ * This is a one-shot sensor.
+ */
+#define CHRE_SENSOR_TYPE_STATIONARY_DETECT UINT8_C(3)
+
+/**
+ * Gyroscope.
+ *
+ * Generates: CHRE_EVENT_SENSOR_GYROSCOPE_DATA and
+ * optionally CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO
+ *
+ * Note that the GYROSCOPE_DATA is always the fully calibrated data, including
+ * factory calibration and runtime calibration if available.
+ *
+ * @see chreConfigureSensorBiasEvents
+ */
+#define CHRE_SENSOR_TYPE_GYROSCOPE UINT8_C(6)
+
+/**
+ * Uncalibrated gyroscope.
+ *
+ * Generates: CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA
+ *
+ * Note that the UNCALIBRATED_GYROSCOPE_DATA must be factory calibrated data,
+ * but not runtime calibrated.
+ */
+#define CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE UINT8_C(7)
+
+/**
+ * Magnetometer.
+ *
+ * Generates: CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_DATA and
+ * optionally CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO
+ *
+ * Note that the GEOMAGNETIC_FIELD_DATA is always the fully calibrated data,
+ * including factory calibration and runtime calibration if available.
+ *
+ * @see chreConfigureSensorBiasEvents
+ */
+#define CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD UINT8_C(8)
+
+/**
+ * Uncalibrated magnetometer.
+ *
+ * Generates: CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_DATA
+ *
+ * Note that the UNCALIBRATED_GEOMAGNETIC_FIELD_DATA must be factory calibrated
+ * data, but not runtime calibrated.
+ */
+#define CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD UINT8_C(9)
+
+/**
+ * Barometric pressure sensor.
+ *
+ * Generates: CHRE_EVENT_SENSOR_PRESSURE_DATA
+ */
+#define CHRE_SENSOR_TYPE_PRESSURE UINT8_C(10)
+
+/**
+ * Ambient light sensor.
+ *
+ * Generates: CHRE_EVENT_SENSOR_LIGHT_DATA
+ *
+ * This is an on-change sensor.
+ */
+#define CHRE_SENSOR_TYPE_LIGHT UINT8_C(12)
+
+/**
+ * Proximity detection.
+ *
+ * Generates: CHRE_EVENT_SENSOR_PROXIMITY_DATA
+ *
+ * This is an on-change sensor.
+ */
+#define CHRE_SENSOR_TYPE_PROXIMITY UINT8_C(13)
+
+/**
+ * Step detection.
+ *
+ * Generates: CHRE_EVENT_SENSOR_STEP_DETECT_DATA
+ *
+ * @since v1.3
+ */
+#define CHRE_SENSOR_TYPE_STEP_DETECT UINT8_C(23)
+
+/**
+ * Step counter.
+ *
+ * Generates: CHRE_EVENT_SENSOR_STEP_COUNTER_DATA
+ *
+ * This is an on-change sensor. Note that the data returned by this sensor must
+ * match the value that can be obtained via the Android sensors framework at the
+ * same point in time. This means, if CHRE reboots from the rest of the system,
+ * the counter must not reset to 0.
+ *
+ * @since v1.5
+ */
+#define CHRE_SENSOR_TYPE_STEP_COUNTER UINT8_C(24)
+
+/**
+ * Hinge angle sensor.
+ *
+ * Generates: CHRE_EVENT_SENSOR_HINGE_ANGLE_DATA
+ *
+ * This is an on-change sensor.
+ *
+ * A sensor of this type measures the angle, in degrees, between two
+ * integral parts of the device. Movement of a hinge measured by this sensor
+ * type is expected to alter the ways in which the user may interact with
+ * the device, for example by unfolding or revealing a display.
+ *
+ * @since v1.5
+ */
+#define CHRE_SENSOR_TYPE_HINGE_ANGLE UINT8_C(36)
+
+/**
+ * Uncalibrated accelerometer.
+ *
+ * Generates: CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_DATA
+ *
+ * Note that the UNCALIBRATED_ACCELEROMETER_DATA must be factory calibrated
+ * data, but not runtime calibrated.
+ */
+#define CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER UINT8_C(55)
+
+/**
+ * Accelerometer temperature.
+ *
+ * Generates: CHRE_EVENT_SENSOR_ACCELEROMETER_TEMPERATURE_DATA
+ */
+#define CHRE_SENSOR_TYPE_ACCELEROMETER_TEMPERATURE UINT8_C(56)
+
+/**
+ * Gyroscope temperature.
+ *
+ * Generates: CHRE_EVENT_SENSOR_GYROSCOPE_TEMPERATURE_DATA
+ */
+#define CHRE_SENSOR_TYPE_GYROSCOPE_TEMPERATURE UINT8_C(57)
+
+/**
+ * Magnetometer temperature.
+ *
+ * Generates: CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_TEMPERATURE_DATA
+ */
+#define CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD_TEMPERATURE UINT8_C(58)
+
+#if CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD_TEMPERATURE >= CHRE_SENSOR_TYPE_VENDOR_START
+#error Too many sensor types
+#endif
+
+/**
+ * Values that can be stored in the accuracy field of chreSensorDataHeader.
+ * If CHRE_SENSOR_ACCURACY_UNKNOWN is returned, then the driver did not provide
+ * accuracy information with the data. Values in the range
+ * [CHRE_SENSOR_ACCURACY_VENDOR_START, CHRE_SENSOR_ACCURACY_VENDOR_END] are
+ * reserved for vendor-specific values for vendor sensor types, and are not used
+ * by CHRE for standard sensor types.
+ *
+ * Otherwise, the values have the same meaning as defined in the Android
+ * Sensors definition:
+ * https://developer.android.com/reference/android/hardware/SensorManager
+ *
+ * @since v1.3
+ *
+ * @defgroup CHRE_SENSOR_ACCURACY
+ * @{
+ */
+
+#define CHRE_SENSOR_ACCURACY_UNKNOWN UINT8_C(0)
+#define CHRE_SENSOR_ACCURACY_UNRELIABLE UINT8_C(1)
+#define CHRE_SENSOR_ACCURACY_LOW UINT8_C(2)
+#define CHRE_SENSOR_ACCURACY_MEDIUM UINT8_C(3)
+#define CHRE_SENSOR_ACCURACY_HIGH UINT8_C(4)
+#define CHRE_SENSOR_ACCURACY_VENDOR_START UINT8_C(192)
+#define CHRE_SENSOR_ACCURACY_VENDOR_END UINT8_MAX
+
+/** @} */
+
+/**
+ * Header used in every structure containing batchable data from a sensor.
+ *
+ * The typical structure for sensor data looks like:
+ *
+ * struct chreSensorTypeData {
+ * struct chreSensorDataHeader header;
+ * struct chreSensorTypeSampleData {
+ * uint32_t timestampDelta;
+ * union {
+ * <type> value;
+ * <type> interpretation0;
+ * <type> interpretation1;
+ * };
+ * } readings[1];
+ * };
+ *
+ * Despite 'readings' being declared as an array of 1 element,
+ * an instance of the struct will actually have 'readings' as
+ * an array of header.readingCount elements (which may be 1).
+ * The 'timestampDelta' is in relation to the previous 'readings' (or
+ * the baseTimestamp for readings[0]. So,
+ * Timestamp for readings[0] == header.baseTimestamp +
+ * readings[0].timestampDelta.
+ * Timestamp for readings[1] == timestamp for readings[0] +
+ * readings[1].timestampDelta.
+ * And thus, in order to determine the timestamp for readings[N], it's
+ * necessary to process through all of the N-1 readings. The advantage,
+ * though, is that our entire readings can span an arbitrary length of time,
+ * just as long as any two consecutive readings differ by no more than
+ * 4.295 seconds (timestampDelta, like all time in the CHRE, is in
+ * nanoseconds).
+ *
+ * If a sensor has batched readings where two consecutive readings differ by
+ * more than 4.295 seconds, the CHRE will split them across multiple
+ * instances of the struct, and send multiple events.
+ *
+ * The value from the sensor is typically expressed in a union,
+ * allowing a generic access to the data ('value'), along with
+ * differently named access giving a more natural interpretation
+ * of the data for the specific sensor types which use this
+ * structure. This allows, for example, barometer code to
+ * reference readings[N].pressure, and an ambient light sensor
+ * to reference readings[N].light, while both use the same
+ * structure.
+ */
+struct chreSensorDataHeader {
+ /**
+ * The base timestamp, in nanoseconds; must be in the same time base as
+ * chreGetTime().
+ */
+ uint64_t baseTimestamp;
+
+ /**
+ * The handle of the sensor producing this event.
+ */
+ uint32_t sensorHandle;
+
+ /**
+ * The number elements in the 'readings' array.
+ *
+ * This must be at least 1.
+ */
+ uint16_t readingCount;
+
+ /**
+ * The accuracy of the sensor data.
+ *
+ * @ref CHRE_SENSOR_ACCURACY
+ *
+ * @since v1.3
+ */
+ uint8_t accuracy;
+
+ /**
+ * Reserved bytes.
+ *
+ * This must be 0.
+ */
+ uint8_t reserved;
+};
+
+/**
+ * Data for a sensor which reports on three axes.
+ *
+ * This is used by CHRE_EVENT_SENSOR_ACCELEROMETER_DATA,
+ * CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO,
+ * CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_DATA,
+ * CHRE_EVENT_SENSOR_GYROSCOPE_DATA,
+ * CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO,
+ * CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA,
+ * CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_DATA,
+ * CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO, and
+ * CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_DATA.
+ */
+struct chreSensorThreeAxisData {
+ /**
+ * @see chreSensorDataHeader
+ */
+ struct chreSensorDataHeader header;
+ struct chreSensorThreeAxisSampleData {
+ /**
+ * @see chreSensorDataHeader
+ */
+ uint32_t timestampDelta;
+ union {
+ float values[3];
+ float v[3];
+ struct {
+ float x;
+ float y;
+ float z;
+ };
+ float bias[3];
+ struct {
+ float x_bias;
+ float y_bias;
+ float z_bias;
+ };
+ };
+ } readings[1];
+};
+
+/**
+ * Data from a sensor where we only care about a event occurring.
+ *
+ * This is a bit unusual in that our readings have no data in addition
+ * to the timestamp. But since we only care about the occurrence, we
+ * don't need to know anything else.
+ *
+ * Used by: CHRE_EVENT_SENSOR_INSTANT_MOTION_DETECT_DATA,
+ * CHRE_EVENT_SENSOR_STATIONARY_DETECT_DATA, and
+ * CHRE_EVENT_SENSOR_STEP_DETECT_DATA.
+ */
+struct chreSensorOccurrenceData {
+ struct chreSensorDataHeader header;
+ struct chreSensorOccurrenceSampleData {
+ uint32_t timestampDelta;
+ // This space intentionally left blank.
+ // Only the timestamp is meaningful here, there
+ // is no additional data.
+ } readings[1];
+};
+
+/**
+ * This is used by CHRE_EVENT_SENSOR_LIGHT_DATA,
+ * CHRE_EVENT_SENSOR_PRESSURE_DATA,
+ * CHRE_EVENT_SENSOR_ACCELEROMETER_TEMPERATURE_DATA,
+ * CHRE_EVENT_SENSOR_GYROSCOPE_TEMPERATURE_DATA,
+ * CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_TEMPERATURE_DATA, and
+ * CHRE_EVENT_SENSOR_HINGE_ANGLE_DATA.
+ */
+struct chreSensorFloatData {
+ struct chreSensorDataHeader header;
+ struct chreSensorFloatSampleData {
+ uint32_t timestampDelta;
+ union {
+ float value;
+ float light; //!< Unit: lux
+ float pressure; //!< Unit: hectopascals (hPa)
+ float temperature; //!< Unit: degrees Celsius
+ float angle; //!< Unit: angular degrees
+ };
+ } readings[1];
+};
+
+/**
+ * CHRE_EVENT_SENSOR_PROXIMITY_DATA.
+ */
+struct chreSensorByteData {
+ struct chreSensorDataHeader header;
+ struct chreSensorByteSampleData {
+ uint32_t timestampDelta;
+ union {
+ uint8_t value;
+ struct {
+ uint8_t isNear : 1;
+ //! @deprecated As of v1.2, this field is deprecated and must
+ //! always be set to 0
+ uint8_t invalid : 1;
+ uint8_t padding0 : 6;
+ };
+ };
+ } readings[1];
+};
+
+/**
+ * Data for a sensor which reports a single uint64 value.
+ *
+ * This is used by CHRE_EVENT_SENSOR_STEP_COUNTER_DATA.
+ */
+struct chreSensorUint64Data {
+ struct chreSensorDataHeader header;
+ struct chreSensorUint64SampleData {
+ uint32_t timestampDelta;
+ uint64_t value;
+ } readings[1];
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHRE_SENSOR_TYPES_H_ */
diff --git a/chre_api/legacy/v1_8/chre/toolchain.h b/chre_api/legacy/v1_8/chre/toolchain.h
new file mode 100644
index 00000000..c2b87222
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/toolchain.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHRE_TOOLCHAIN_H_
+#define CHRE_TOOLCHAIN_H_
+
+/**
+ * @file
+ * Compiler/build toolchain-specific macros used by the CHRE API
+ */
+
+#if defined(__GNUC__) || defined(__clang__)
+// For GCC and clang
+
+#define CHRE_DEPRECATED(message) \
+ __attribute__((deprecated(message)))
+
+// Enable printf-style compiler warnings for mismatched format string and args
+#define CHRE_PRINTF_ATTR(formatPos, argStart) \
+ __attribute__((format(printf, formatPos, argStart)))
+
+#define CHRE_BUILD_ERROR(message) CHRE_DO_PRAGMA(GCC error message)
+#define CHRE_DO_PRAGMA(message) _Pragma(#message)
+
+#elif defined(__ICCARM__) || defined(__CC_ARM)
+// For IAR ARM and Keil MDK-ARM compilers
+
+#define CHRE_PRINTF_ATTR(formatPos, argStart)
+
+#elif defined(_MSC_VER)
+// For Microsoft Visual Studio
+
+#define CHRE_PRINTF_ATTR(formatPos, argStart)
+
+#else // if !defined(__GNUC__) && !defined(__clang__)
+
+#error Need to add support for new compiler
+
+#endif
+
+// For platforms that don't support error pragmas, utilize the best method of
+// showing an error depending on the platform support.
+#ifndef CHRE_BUILD_ERROR
+#ifdef __cplusplus // C++17 or greater assumed
+#define CHRE_BUILD_ERROR(message) static_assert(0, message)
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#define CHRE_BUILD_ERROR(message) _Static_assert(0, message)
+#else
+#define CHRE_BUILD_ERROR(message) char buildError[-1] = message
+#endif
+#endif
+
+#endif // CHRE_TOOLCHAIN_H_
diff --git a/chre_api/legacy/v1_8/chre/user_settings.h b/chre_api/legacy/v1_8/chre/user_settings.h
new file mode 100644
index 00000000..c40be90e
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/user_settings.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_USER_SETTINGS_H_
+#define _CHRE_USER_SETTINGS_H_
+
+/**
+ * @file
+ * The API for requesting notifications on changes in the settings of the
+ * active user. If the device is set up with one or more secondary users
+ * (see https://source.android.com/devices/tech/admin/multi-user), the user
+ * settings in CHRE reflect that of the currently active user.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <chre/event.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The user settings that nanoapps can request notifications for on a status
+ * change.
+ *
+ * NOTE: The WIFI available setting indicates the overall availability
+ * of WIFI related functionality. For example, if wifi is disabled for
+ * connectivity but enabled for location, the WIFI available setting is
+ * enabled.
+ *
+ * NOTE: The BLE available setting is the logical OR of the main Bluetooth
+ * setting and the Bluetooth scanning setting found under Location settings.
+ * Note that this indicates whether the user is allowing Bluetooth to be used,
+ * however the system may still fully power down the BLE chip in some scenarios
+ * if no request for it exists on the Android host side. See the
+ * chreBleStartScanAsync() API documentation for more information.
+ *
+ * @defgroup CHRE_USER_SETTINGS
+ * @{
+ */
+#define CHRE_USER_SETTING_LOCATION UINT8_C(0)
+#define CHRE_USER_SETTING_WIFI_AVAILABLE UINT8_C(1)
+#define CHRE_USER_SETTING_AIRPLANE_MODE UINT8_C(2)
+#define CHRE_USER_SETTING_MICROPHONE UINT8_C(3)
+#define CHRE_USER_SETTING_BLE_AVAILABLE UINT8_C(4)
+
+/** @} */
+
+/**
+ * Produce an event ID in the block of IDs reserved for settings notifications.
+ *
+ * @param offset Index into the event ID block, valid in the range [0,15]
+ */
+#define CHRE_SETTING_EVENT_ID(offset) (CHRE_EVENT_SETTING_CHANGED_FIRST_EVENT + (offset))
+
+/**
+ * nanoappHandleEvent argument: struct chreUserSettingChangedEvent
+ *
+ * Notify nanoapps of a change in the associated setting. Nanoapps must first
+ * register (via chreUserSettingConfigureEvents) for events before they are
+ * sent out.
+ */
+#define CHRE_EVENT_SETTING_CHANGED_LOCATION CHRE_SETTING_EVENT_ID(0)
+#define CHRE_EVENT_SETTING_CHANGED_WIFI_AVAILABLE CHRE_SETTING_EVENT_ID(1)
+#define CHRE_EVENT_SETTING_CHANGED_AIRPLANE_MODE CHRE_SETTING_EVENT_ID(2)
+#define CHRE_EVENT_SETTING_CHANGED_MICROPHONE CHRE_SETTING_EVENT_ID(3)
+#define CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE CHRE_SETTING_EVENT_ID(4)
+
+#if CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE > CHRE_EVENT_SETTING_CHANGED_LAST_EVENT
+#error Too many setting changed events.
+#endif
+
+/**
+ * Indicates the current state of a setting.
+ * The setting state is 'unknown' only in the following scenarios:
+ * - CHRE hasn't received the initial state yet on a restart.
+ * - The nanoapp is running on CHRE v1.4 or older
+ * - Nanoapp provided in invalid setting ID to chreUserSettingGetStatus.
+ */
+enum chreUserSettingState {
+ CHRE_USER_SETTING_STATE_UNKNOWN = -1,
+ CHRE_USER_SETTING_STATE_DISABLED = 0,
+ CHRE_USER_SETTING_STATE_ENABLED = 1
+};
+
+/**
+ * The nanoappHandleEvent argument for CHRE settings changed notifications.
+ */
+struct chreUserSettingChangedEvent {
+ //! Indicates the setting whose state has changed.
+ uint8_t setting;
+
+ //! A value that corresponds to a member in enum chreUserSettingState,
+ // indicating the latest value of the setting.
+ int8_t settingState;
+};
+
+/**
+ * Get the current state of a given setting.
+ *
+ * @param setting The setting to get the current status of.
+ *
+ * @return The current state of the requested setting. The state is returned
+ * as an int8_t to be consistent with the associated event data, but is
+ * guaranteed to be a valid enum chreUserSettingState member.
+ *
+ * @since v1.5
+ */
+int8_t chreUserSettingGetState(uint8_t setting);
+
+/**
+ * Register or deregister for a notification on a status change for a given
+ * setting. Note that registration does not produce an event with the initial
+ * (or current) state, though nanoapps can use chreUserSettingGetState() for
+ * this purpose.
+ *
+ * @param setting The setting on whose change a notification is desired.
+ * @param enable The nanoapp is registered to receive notifications on a
+ * change in the user settings if this parameter is true, otherwise the
+ * nanoapp receives no further notifications for this setting.
+ *
+ * @since v1.5
+ */
+void chreUserSettingConfigureEvents(uint8_t setting, bool enable);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHRE_USER_SETTINGS_H_ */
diff --git a/chre_api/legacy/v1_8/chre/version.h b/chre_api/legacy/v1_8/chre/version.h
new file mode 100644
index 00000000..6872fdde
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/version.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_VERSION_H_
+#define _CHRE_VERSION_H_
+
+/**
+ * @file
+ * Definitions and methods for the versioning of the Context Hub Runtime
+ * Environment.
+ *
+ * The CHRE API versioning pertains to all header files in the CHRE API.
+ */
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Value for version 0.1 of the Context Hub Runtime Environment API interface.
+ *
+ * This is a legacy version of the CHRE API. Version 1.0 is considered the first
+ * official CHRE API version.
+ *
+ * @see CHRE_API_VERSION
+ */
+#define CHRE_API_VERSION_0_1 UINT32_C(0x00010000)
+
+/**
+ * Value for version 1.0 of the Context Hub Runtime Environment API interface.
+ *
+ * This version of the CHRE API shipped with the Android Nougat release.
+ *
+ * @see CHRE_API_VERSION
+ */
+#define CHRE_API_VERSION_1_0 UINT32_C(0x01000000)
+
+/**
+ * Value for version 1.1 of the Context Hub Runtime Environment API interface.
+ *
+ * This version of the CHRE API shipped with the Android O release. It adds
+ * initial support for new GNSS, WiFi, and WWAN modules.
+ *
+ * @see CHRE_API_VERSION
+ */
+#define CHRE_API_VERSION_1_1 UINT32_C(0x01010000)
+
+/**
+ * Value for version 1.2 of the Context Hub Runtime Environment API interface.
+ *
+ * This version of the CHRE API shipped with the Android P release. It adds
+ * initial support for the new audio module.
+ *
+ * @see CHRE_API_VERSION
+ */
+#define CHRE_API_VERSION_1_2 UINT32_C(0x01020000)
+
+/**
+ * Value for version 1.3 of the Context Hub Runtime Environment API interface.
+ *
+ * This version of the CHRE API shipped with the Android Q release. It adds
+ * support for GNSS location altitude/speed/bearing accuracy. It also adds step
+ * detect as a standard CHRE sensor and supports bias event delivery and sensor
+ * data flushing.
+ *
+ * @see CHRE_API_VERSION
+ */
+#define CHRE_API_VERSION_1_3 UINT32_C(0x01030000)
+
+/**
+ * Value for version 1.4 of the Context Hub Runtime Environment API interface.
+ *
+ * This version of the CHRE API shipped with the Android R release. It adds
+ * support for collecting debug dump information from nanoapps, receiving L5
+ * GNSS measurements, determining if a sensor supports passive requests,
+ * receiving 5G cell info, and deprecates chreSendMessageToHost.
+ *
+ * @see CHRE_API_VERSION
+ */
+#define CHRE_API_VERSION_1_4 UINT32_C(0x01040000)
+
+/**
+ * Value for version 1.5 of the Context Hub Runtime Environment API interface.
+ *
+ * This version of the CHRE API shipped with the Android S release. It adds
+ * support for multiple sensors of the same type, permissions for sensitive CHRE
+ * APIs / data usage, ability to receive user settings updates, step counter and
+ * hinge angle sensors, improved WiFi scan preferences to support power
+ * optimization, new WiFi security types, increased the lower bound for the
+ * maximum CHRE to host message size, and increased GNSS measurements in
+ * chreGnssDataEvent.
+ *
+ * @see CHRE_API_VERSION
+ */
+#define CHRE_API_VERSION_1_5 UINT32_C(0x01050000)
+
+/**
+ * Value for version 1.6 of the Context Hub Runtime Environment API interface.
+ *
+ * This version of the CHRE API is shipped with the Android T release. It adds
+ * support for BLE scanning, subscribing to the WiFi NAN discovery engine,
+ * subscribing to host endpoint notifications, requesting metadata for a host
+ * endpoint ID, nanoapps publishing RPC services they support, and limits the
+ * nanoapp instance ID size to INT16_MAX.
+ *
+ * @see CHRE_API_VERSION
+ */
+#define CHRE_API_VERSION_1_6 UINT32_C(0x01060000)
+
+/**
+ * Value for version 1.7 of the Context Hub Runtime Environment API interface.
+ *
+ * This version of the CHRE API is shipped with a post-launch update to the
+ * Android T release. It adds the BLE flush API.
+ *
+ * @see CHRE_API_VERSION
+ */
+#define CHRE_API_VERSION_1_7 UINT32_C(0x01070000)
+
+/**
+ * Value for version 1.8 of the Context Hub Runtime Environment API interface.
+ *
+ * This version of the CHRE API is shipped with the Android U release.
+ *
+ * @note This version of the CHRE API has not been finalized yet, and is
+ * currently considered a preview that is subject to change.
+ *
+ * @see CHRE_API_VERSION
+ */
+#define CHRE_API_VERSION_1_8 UINT32_C(0x01080000)
+
+/**
+ * Major and Minor Version of this Context Hub Runtime Environment API.
+ *
+ * The major version changes when there is an incompatible API change.
+ *
+ * The minor version changes when there is an addition in functionality
+ * in a backwards-compatible manner.
+ *
+ * We define the version number as an unsigned 32-bit value. The most
+ * significant byte is the Major Version. The second-most significant byte
+ * is the Minor Version. The two least significant bytes are the Patch
+ * Version. The Patch Version is not defined by this header API, but
+ * is provided by a specific CHRE implementation (see chreGetVersion()).
+ *
+ * Note that version numbers can always be numerically compared with
+ * expected results, so 1.0.0 < 1.0.4 < 1.1.0 < 2.0.300 < 3.5.0.
+ */
+#define CHRE_API_VERSION CHRE_API_VERSION_1_8
+
+/**
+ * Utility macro to extract only the API major version of a composite CHRE
+ * version.
+ *
+ * @param version A uint32_t version, e.g. the value returned by
+ * chreGetApiVersion()
+ *
+ * @return The API major version in the least significant byte, e.g. 0x01
+ */
+#define CHRE_EXTRACT_MAJOR_VERSION(version) \
+ (uint32_t)(((version) & UINT32_C(0xFF000000)) >> 24)
+
+/**
+ * Utility macro to extract only the API minor version of a composite CHRE
+ * version.
+ *
+ * @param version A uint32_t version, e.g. the CHRE_API_VERSION constant
+ *
+ * @return The API minor version in the least significant byte, e.g. 0x01
+ */
+#define CHRE_EXTRACT_MINOR_VERSION(version) \
+ (uint32_t)(((version) & UINT32_C(0x00FF0000)) >> 16)
+
+/**
+ * Utility macro to extract only the API minor version of a composite CHRE
+ * version.
+ *
+ * @param version A complete uint32_t version, e.g. the value returned by
+ * chreGetVersion()
+ *
+ * @return The implementation patch version in the least significant two bytes,
+ * e.g. 0x0123, with all other bytes set to 0
+ */
+#define CHRE_EXTRACT_PATCH_VERSION(version) (uint32_t)((version) & UINT32_C(0xFFFF))
+
+/**
+ * Get the API version the CHRE implementation was compiled against.
+ *
+ * This is not necessarily the CHRE_API_VERSION in the header the nanoapp was
+ * built against, and indeed may not have even appeared in the context_hub_os.h
+ * header which this nanoapp was built against.
+ *
+ * By definition, this will have the two least significant bytes set to 0,
+ * and only contain the major and minor version number.
+ *
+ * @return The API version.
+ */
+uint32_t chreGetApiVersion(void);
+
+/**
+ * Get the version of this CHRE implementation.
+ *
+ * By definition, ((chreGetApiVersion() & UINT32_C(0xFFFF0000)) ==
+ * (chreGetVersion() & UINT32_C(0xFFFF0000))).
+ *
+ * The Patch Version, in the lower two bytes, only have meaning in context
+ * of this specific platform ID. It is increased by the platform every time
+ * a backwards-compatible bug fix is released.
+ *
+ * @return The version.
+ *
+ * @see chreGetPlatformId()
+ */
+uint32_t chreGetVersion(void);
+
+/**
+ * Get the Platform ID of this CHRE.
+ *
+ * The most significant five bytes are the vendor ID as set out by the
+ * NANOAPP_VENDOR convention in the original context hub HAL header file
+ * (context_hub.h), also used by nanoapp IDs.
+ *
+ * The least significant three bytes are set by the vendor, but must be
+ * unique for each different CHRE implementation/hardware that the vendor
+ * supplies.
+ *
+ * The idea is that in the case of known bugs in the field, a new nanoapp could
+ * be shipped with a workaround that would use this value, and chreGetVersion(),
+ * to have code that can conditionally work around the bug on a buggy version.
+ * Thus, we require this uniqueness to allow such a setup to work.
+ *
+ * @return The platform ID.
+ *
+ * @see CHRE_EXTRACT_VENDOR_ID
+ */
+uint64_t chreGetPlatformId(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHRE_VERSION_H_ */
diff --git a/chre_api/legacy/v1_8/chre/wifi.h b/chre_api/legacy/v1_8/chre/wifi.h
new file mode 100644
index 00000000..b4bda9c0
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/wifi.h
@@ -0,0 +1,1313 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_WIFI_H_
+#define _CHRE_WIFI_H_
+
+/**
+ * @file
+ * WiFi (IEEE 802.11) API, currently covering scanning features useful for
+ * determining location and offloading certain connectivity scans.
+ *
+ * In this file, specification references use the following shorthand:
+ *
+ * Shorthand | Full specification name
+ * ---------- | ------------------------
+ * "802.11" | IEEE Std 802.11-2007
+ * "HT" | IEEE Std 802.11n-2009
+ * "VHT" | IEEE Std 802.11ac-2013
+ * "WiFi 6" | IEEE Std 802.11ax draft
+ * "NAN" | Wi-Fi Neighbor Awareness Networking (NAN) Technical
+ * Specification (v3.2)
+ *
+ * In the current version of CHRE API, the 6GHz band introduced in WiFi 6 is
+ * not supported. A scan request from CHRE should not result in scanning 6GHz
+ * channels. In particular, if a 6GHz channel is specified in scanning or
+ * ranging request parameter, CHRE should return an error code of
+ * CHRE_ERROR_NOT_SUPPORTED. Additionally, CHRE implementations must not include
+ * observations of access points on 6GHz channels in scan results, especially
+ * those produced due to scan monitoring.
+ */
+
+#include "common.h"
+#include <chre/common.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The set of flags returned by chreWifiGetCapabilities().
+ * @defgroup CHRE_WIFI_CAPABILITIES
+ * @{
+ */
+
+//! No WiFi APIs are supported
+#define CHRE_WIFI_CAPABILITIES_NONE UINT32_C(0)
+
+//! Listening to scan results is supported, as enabled via
+//! chreWifiConfigureScanMonitorAsync()
+#define CHRE_WIFI_CAPABILITIES_SCAN_MONITORING UINT32_C(1 << 0)
+
+//! Requesting WiFi scans on-demand is supported via chreWifiRequestScanAsync()
+#define CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN UINT32_C(1 << 1)
+
+//! Specifying the radio chain preference in on-demand scan requests, and
+//! reporting it in scan events is supported
+//! @since v1.2
+#define CHRE_WIFI_CAPABILITIES_RADIO_CHAIN_PREF UINT32_C(1 << 2)
+
+//! Requesting RTT ranging is supported via chreWifiRequestRangingAsync()
+//! @since v1.2
+#define CHRE_WIFI_CAPABILITIES_RTT_RANGING UINT32_C(1 << 3)
+
+//! Specifies if WiFi NAN service subscription is supported. If a platform
+//! supports subscriptions, then it must also support RTT ranging for NAN
+//! services via chreWifiNanRequestRangingAsync()
+//! @since v1.6
+#define CHRE_WIFI_CAPABILITIES_NAN_SUB UINT32_C(1 << 4)
+
+/** @} */
+
+/**
+ * Produce an event ID in the block of IDs reserved for WiFi
+ * @param offset Index into WiFi event ID block; valid range [0,15]
+ */
+#define CHRE_WIFI_EVENT_ID(offset) (CHRE_EVENT_WIFI_FIRST_EVENT + (offset))
+
+/**
+ * nanoappHandleEvent argument: struct chreAsyncResult
+ *
+ * Communicates the asynchronous result of a request to the WiFi API. The
+ * requestType field in {@link #chreAsyncResult} is set to a value from enum
+ * chreWifiRequestType.
+ */
+#define CHRE_EVENT_WIFI_ASYNC_RESULT CHRE_WIFI_EVENT_ID(0)
+
+/**
+ * nanoappHandleEvent argument: struct chreWifiScanEvent
+ *
+ * Provides results of a WiFi scan.
+ */
+#define CHRE_EVENT_WIFI_SCAN_RESULT CHRE_WIFI_EVENT_ID(1)
+
+/**
+ * nanoappHandleEvent argument: struct chreWifiRangingEvent
+ *
+ * Provides results of an RTT ranging request.
+ */
+#define CHRE_EVENT_WIFI_RANGING_RESULT CHRE_WIFI_EVENT_ID(2)
+
+/**
+ * nanoappHandleEvent argument: struct chreWifiNanIdentifierEvent
+ *
+ * Lets the client know if the NAN engine was able to successfully assign
+ * an identifier to the subscribe call. The 'cookie' field in the event
+ * argument struct can be used to track which subscribe request this identifier
+ * maps to.
+ */
+#define CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT CHRE_WIFI_EVENT_ID(3)
+
+/**
+ * nanoappHandleEvent argument: struct chreWifiNanDiscoveryEvent
+ *
+ * Event that is sent whenever a NAN service matches the criteria specified
+ * in a subscription request.
+ */
+#define CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT CHRE_WIFI_EVENT_ID(4)
+
+/**
+ * nanoappHandleEvent argument: struct chreWifiNanSessionLostEvent
+ *
+ * Informs the client that a discovered service is no longer available or
+ * visible.
+ * The ID of the service on the client that was communicating with the extinct
+ * service is indicated by the event argument.
+ */
+#define CHRE_EVENT_WIFI_NAN_SESSION_LOST CHRE_WIFI_EVENT_ID(5)
+
+/**
+ * nanoappHandleEvent argument: struct chreWifiNanSessionTerminatedEvent
+ *
+ * Signals the end of a NAN subscription session. The termination can be due to
+ * the user turning the WiFi off, or other platform reasons like not being able
+ * to support NAN concurrency with the host. The terminated event will have a
+ * reason code appropriately populated to denote why the event was sent.
+ */
+#define CHRE_EVENT_WIFI_NAN_SESSION_TERMINATED CHRE_WIFI_EVENT_ID(6)
+
+// NOTE: Do not add new events with ID > 15; only values 0-15 are reserved
+// (see chre/event.h)
+
+/**
+ * The maximum amount of time that is allowed to elapse between a call to
+ * chreWifiRequestScanAsync() that returns true, and the associated
+ * CHRE_EVENT_WIFI_ASYNC_RESULT used to indicate whether the scan completed
+ * successfully or not.
+ */
+#define CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS (30 * CHRE_NSEC_PER_SEC)
+
+/**
+ * The maximum amount of time that is allowed to elapse between a call to
+ * chreWifiRequestRangingAsync() that returns true, and the associated
+ * CHRE_EVENT_WIFI_RANGING_RESULT used to indicate whether the ranging operation
+ * completed successfully or not.
+ */
+#define CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS (30 * CHRE_NSEC_PER_SEC)
+
+/**
+ * The current compatibility version of the chreWifiScanEvent structure,
+ * including nested structures.
+ */
+#define CHRE_WIFI_SCAN_EVENT_VERSION UINT8_C(1)
+
+/**
+ * The current compatibility version of the chreWifiRangingEvent structure,
+ * including nested structures.
+ */
+#define CHRE_WIFI_RANGING_EVENT_VERSION UINT8_C(0)
+
+/**
+ * Maximum number of frequencies that can be explicitly specified when
+ * requesting a scan
+ * @see #chreWifiScanParams
+ */
+#define CHRE_WIFI_FREQUENCY_LIST_MAX_LEN (20)
+
+/**
+ * Maximum number of SSIDs that can be explicitly specified when requesting a
+ * scan
+ * @see #chreWifiScanParams
+ */
+#define CHRE_WIFI_SSID_LIST_MAX_LEN (20)
+
+/**
+ * The maximum number of devices that can be specified in a single RTT ranging
+ * request.
+ * @see #chreWifiRangingParams
+ */
+#define CHRE_WIFI_RANGING_LIST_MAX_LEN (10)
+
+/**
+ * The maximum number of octets in an SSID (see 802.11 7.3.2.1)
+ */
+#define CHRE_WIFI_SSID_MAX_LEN (32)
+
+/**
+ * The number of octets in a BSSID (see 802.11 7.1.3.3.3)
+ */
+#define CHRE_WIFI_BSSID_LEN (6)
+
+/**
+ * Set of flags which can either indicate a frequency band. Specified as a bit
+ * mask to allow for combinations in future API versions.
+ * @defgroup CHRE_WIFI_BAND_MASK
+ * @{
+ */
+
+#define CHRE_WIFI_BAND_MASK_2_4_GHZ UINT8_C(1 << 0) //!< 2.4 GHz
+#define CHRE_WIFI_BAND_MASK_5_GHZ UINT8_C(1 << 1) //!< 5 GHz
+
+/** @} */
+
+/**
+ * Characteristics of a scanned device given in struct chreWifiScanResult.flags
+ * @defgroup CHRE_WIFI_SCAN_RESULT_FLAGS
+ * @{
+ */
+
+#define CHRE_WIFI_SCAN_RESULT_FLAGS_NONE UINT8_C(0)
+
+//! Element ID 61 (HT Operation) is present (see HT 7.3.2)
+#define CHRE_WIFI_SCAN_RESULT_FLAGS_HT_OPS_PRESENT UINT8_C(1 << 0)
+
+//! Element ID 192 (VHT Operation) is present (see VHT 8.4.2)
+#define CHRE_WIFI_SCAN_RESULT_FLAGS_VHT_OPS_PRESENT UINT8_C(1 << 1)
+
+//! Element ID 127 (Extended Capabilities) is present, and bit 70 (Fine Timing
+//! Measurement Responder) is set to 1 (see IEEE Std 802.11-2016 9.4.2.27)
+#define CHRE_WIFI_SCAN_RESULT_FLAGS_IS_FTM_RESPONDER UINT8_C(1 << 2)
+
+//! Retained for backwards compatibility
+//! @see CHRE_WIFI_SCAN_RESULT_FLAGS_IS_FTM_RESPONDER
+#define CHRE_WIFI_SCAN_RESULT_FLAGS_IS_80211MC_RTT_RESPONDER \
+ CHRE_WIFI_SCAN_RESULT_FLAGS_IS_FTM_RESPONDER
+
+//! HT Operation element indicates that a secondary channel is present
+//! (see HT 7.3.2.57)
+#define CHRE_WIFI_SCAN_RESULT_FLAGS_HAS_SECONDARY_CHANNEL_OFFSET UINT8_C(1 << 3)
+
+//! HT Operation element indicates that the secondary channel is below the
+//! primary channel (see HT 7.3.2.57)
+#define CHRE_WIFI_SCAN_RESULT_FLAGS_SECONDARY_CHANNEL_OFFSET_IS_BELOW \
+ UINT8_C(1 << 4)
+
+/** @} */
+
+/**
+ * Identifies the authentication methods supported by an AP. Note that not every
+ * combination of flags may be possible. Based on WIFI_PNO_AUTH_CODE_* from
+ * hardware/libhardware_legacy/include/hardware_legacy/gscan.h in Android.
+ * @defgroup CHRE_WIFI_SECURITY_MODE_FLAGS
+ * @{
+ */
+
+#define CHRE_WIFI_SECURITY_MODE_UNKONWN UINT8_C(0)
+
+#define CHRE_WIFI_SECURITY_MODE_OPEN UINT8_C(1 << 0) //!< No auth/security
+#define CHRE_WIFI_SECURITY_MODE_WEP UINT8_C(1 << 1)
+#define CHRE_WIFI_SECURITY_MODE_PSK UINT8_C(1 << 2) //!< WPA-PSK or WPA2-PSK
+#define CHRE_WIFI_SECURITY_MODE_EAP UINT8_C(1 << 3) //!< WPA-EAP or WPA2-EAP
+
+//! @since v1.5
+#define CHRE_WIFI_SECURITY_MODE_SAE UINT8_C(1 << 4)
+
+//! @since v1.5
+#define CHRE_WIFI_SECURITY_MODE_EAP_SUITE_B UINT8_C(1 << 5)
+
+//! @since v1.5
+#define CHRE_WIFI_SECURITY_MODE_OWE UINT8_C(1 << 6)
+
+/** @} */
+
+/**
+ * Identifies which radio chain was used to discover an AP. The underlying
+ * hardware does not necessarily support more than one radio chain.
+ * @defgroup CHRE_WIFI_RADIO_CHAIN_FLAGS
+ * @{
+ */
+
+#define CHRE_WIFI_RADIO_CHAIN_UNKNOWN UINT8_C(0)
+#define CHRE_WIFI_RADIO_CHAIN_0 UINT8_C(1 << 0)
+#define CHRE_WIFI_RADIO_CHAIN_1 UINT8_C(1 << 1)
+
+/** @} */
+
+//! Special value indicating that an LCI uncertainty fields is not provided
+//! Ref: RFC 6225
+#define CHRE_WIFI_LCI_UNCERTAINTY_UNKNOWN UINT8_C(0)
+
+/**
+ * Defines the flags that may be returned in
+ * {@link #chreWifiRangingResult.flags}. Undefined bits are reserved for future
+ * use and must be ignored by nanoapps.
+ * @defgroup CHRE_WIFI_RTT_RESULT_FLAGS
+ * @{
+ */
+
+//! If set, the nested chreWifiLci structure is populated; otherwise it is
+//! invalid and must be ignored
+#define CHRE_WIFI_RTT_RESULT_HAS_LCI UINT8_C(1 << 0)
+
+/** @} */
+
+/**
+ * Identifies a WiFi frequency band
+ */
+enum chreWifiBand {
+ CHRE_WIFI_BAND_2_4_GHZ = CHRE_WIFI_BAND_MASK_2_4_GHZ,
+ CHRE_WIFI_BAND_5_GHZ = CHRE_WIFI_BAND_MASK_5_GHZ,
+};
+
+/**
+ * Indicates the BSS operating channel width determined from the VHT and/or HT
+ * Operation elements. Refer to VHT 8.4.2.161 and HT 7.3.2.57.
+ */
+enum chreWifiChannelWidth {
+ CHRE_WIFI_CHANNEL_WIDTH_20_MHZ = 0,
+ CHRE_WIFI_CHANNEL_WIDTH_40_MHZ = 1,
+ CHRE_WIFI_CHANNEL_WIDTH_80_MHZ = 2,
+ CHRE_WIFI_CHANNEL_WIDTH_160_MHZ = 3,
+ CHRE_WIFI_CHANNEL_WIDTH_80_PLUS_80_MHZ = 4,
+};
+
+/**
+ * Indicates the type of scan requested or performed
+ */
+enum chreWifiScanType {
+ //! Perform a purely active scan using probe requests. Do not scan channels
+ //! restricted to use via Dynamic Frequency Selection (DFS) only.
+ CHRE_WIFI_SCAN_TYPE_ACTIVE = 0,
+
+ //! Perform an active scan on unrestricted channels, and also perform a
+ //! passive scan on channels that are restricted to use via Dynamic
+ //! Frequency Selection (DFS), e.g. the U-NII bands 5250-5350MHz and
+ //! 5470-5725MHz in the USA as mandated by FCC regulation.
+ CHRE_WIFI_SCAN_TYPE_ACTIVE_PLUS_PASSIVE_DFS = 1,
+
+ //! Perform a passive scan, only listening for beacons.
+ CHRE_WIFI_SCAN_TYPE_PASSIVE = 2,
+
+ //! Client has no preference for a particular scan type.
+ //! Only valid in a {@link #chreWifiScanParams}.
+ //!
+ //! On a v1.4 or earlier platform, this will fall back to
+ //! CHRE_WIFI_SCAN_TYPE_ACTIVE if {@link #chreWifiScanParams.channelSet} is
+ //! set to CHRE_WIFI_CHANNEL_SET_NON_DFS, and to
+ //! CHRE_WIFI_SCAN_TYPE_ACTIVE_PLUS_PASSIVE_DFS otherwise.
+ //!
+ //! If CHRE_WIFI_CAPABILITIES_RADIO_CHAIN_PREF is supported, a v1.5 or
+ //! later platform shall perform a type of scan optimized for {@link
+ //! #chreWifiScanParams.radioChainPref}.
+ //!
+ //! Clients are strongly encouraged to set this value in {@link
+ //! #chreWifiScanParams.scanType} and instead express their preferences
+ //! through {@link #chreWifiRadioChainPref} and {@link #chreWifiChannelSet}
+ //! so the platform can best optimize power and performance.
+ //!
+ //! @since v1.5
+ CHRE_WIFI_SCAN_TYPE_NO_PREFERENCE = 3,
+};
+
+/**
+ * Indicates whether RTT ranging with a specific device succeeded
+ */
+enum chreWifiRangingStatus {
+ //! Ranging completed successfully
+ CHRE_WIFI_RANGING_STATUS_SUCCESS = 0,
+
+ //! Ranging failed due to an unspecified error
+ CHRE_WIFI_RANGING_STATUS_ERROR = 1,
+};
+
+/**
+ * Possible values for {@link #chreWifiLci.altitudeType}. Ref: RFC 6225 2.4
+ */
+enum chreWifiLciAltitudeType {
+ CHRE_WIFI_LCI_ALTITUDE_TYPE_UNKNOWN = 0,
+ CHRE_WIFI_LCI_ALTITUDE_TYPE_METERS = 1,
+ CHRE_WIFI_LCI_ALTITUDE_TYPE_FLOORS = 2,
+};
+
+/**
+ * Indicates a type of request made in this API. Used to populate the resultType
+ * field of struct chreAsyncResult sent with CHRE_EVENT_WIFI_ASYNC_RESULT.
+ */
+enum chreWifiRequestType {
+ CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR = 1,
+ CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN = 2,
+ CHRE_WIFI_REQUEST_TYPE_RANGING = 3,
+ CHRE_WIFI_REQUEST_TYPE_NAN_SUBSCRIBE = 4,
+};
+
+/**
+ * Allows a nanoapp to express its preference for how multiple available
+ * radio chains should be used when performing an on-demand scan. This is only a
+ * preference from the nanoapp and is not guaranteed to be honored by the WiFi
+ * firmware.
+ */
+enum chreWifiRadioChainPref {
+ //! No preference for radio chain usage
+ CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT = 0,
+
+ //! In a scan result, indicates that the radio chain preference used for the
+ //! scan is not known
+ CHRE_WIFI_RADIO_CHAIN_PREF_UNKNOWN = CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT,
+
+ //! Prefer to use available radio chains in a way that minimizes time to
+ //! complete the scan
+ CHRE_WIFI_RADIO_CHAIN_PREF_LOW_LATENCY = 1,
+
+ //! Prefer to use available radio chains in a way that minimizes total power
+ //! consumed for the scan
+ CHRE_WIFI_RADIO_CHAIN_PREF_LOW_POWER = 2,
+
+ //! Prefer to use available radio chains in a way that maximizes accuracy of
+ //! the scan result, e.g. RSSI measurements
+ CHRE_WIFI_RADIO_CHAIN_PREF_HIGH_ACCURACY = 3,
+};
+
+/**
+ * WiFi NAN subscription type.
+ */
+enum chreWifiNanSubscribeType {
+ //! In the active mode, explicit transmission of a subscribe message is
+ //! requested, and publish messages are processed.
+ CHRE_WIFI_NAN_SUBSCRIBE_TYPE_ACTIVE = 0,
+
+ //! In the passive mode, no transmission of a subscribe message is
+ //! requested, but received publish messages are checked for matches.
+ CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE = 1,
+};
+
+/**
+ * Indicates the reason for a subscribe session termination.
+ */
+enum chreWifiNanTerminatedReason {
+ CHRE_WIFI_NAN_TERMINATED_BY_USER_REQUEST = 0,
+ CHRE_WIFI_NAN_TERMINATED_BY_TIMEOUT = 1,
+ CHRE_WIFI_NAN_TERMINATED_BY_FAILURE = 2,
+};
+
+/**
+ * SSID with an explicit length field, used when an array of SSIDs is supplied.
+ */
+struct chreWifiSsidListItem {
+ //! Number of valid bytes in ssid. Valid range [0, CHRE_WIFI_SSID_MAX_LEN]
+ uint8_t ssidLen;
+
+ //! Service Set Identifier (SSID)
+ uint8_t ssid[CHRE_WIFI_SSID_MAX_LEN];
+};
+
+/**
+ * Indicates the set of channels to be scanned.
+ *
+ * @since v1.5
+ */
+enum chreWifiChannelSet {
+ //! The set of channels that allows active scan using probe request.
+ CHRE_WIFI_CHANNEL_SET_NON_DFS = 0,
+
+ //! The set of all channels supported.
+ CHRE_WIFI_CHANNEL_SET_ALL = 1,
+};
+
+/**
+ * Data structure passed to chreWifiRequestScanAsync
+ */
+struct chreWifiScanParams {
+ //! Set to a value from @ref enum chreWifiScanType
+ uint8_t scanType;
+
+ //! Indicates whether the client is willing to tolerate receiving cached
+ //! results of a previous scan, and if so, the maximum age of the scan that
+ //! the client will accept. "Age" in this case is defined as the elapsed
+ //! time between when the most recent scan was completed and the request is
+ //! received, in milliseconds. If set to 0, no cached results may be
+ //! provided, and all scan results must come from a "fresh" WiFi scan, i.e.
+ //! one that completes strictly after this request is received. If more than
+ //! one scan is cached and meets this age threshold, only the newest scan is
+ //! provided.
+ uint32_t maxScanAgeMs;
+
+ //! If set to 0, scan all frequencies. Otherwise, this indicates the number
+ //! of frequencies to scan, as specified in the frequencyList array. Valid
+ //! range [0, CHRE_WIFI_FREQUENCY_LIST_MAX_LEN].
+ uint16_t frequencyListLen;
+
+ //! Pointer to an array of frequencies to scan, given as channel center
+ //! frequencies in MHz. This field may be NULL if frequencyListLen is 0.
+ const uint32_t *frequencyList;
+
+ //! If set to 0, do not restrict scan to any SSIDs. Otherwise, this
+ //! indicates the number of SSIDs in the ssidList array to be used for
+ //! directed probe requests. Not applicable and ignore when scanType is
+ //! CHRE_WIFI_SCAN_TYPE_PASSIVE.
+ uint8_t ssidListLen;
+
+ //! Pointer to an array of SSIDs to use for directed probe requests. May be
+ //! NULL if ssidListLen is 0.
+ const struct chreWifiSsidListItem *ssidList;
+
+ //! Set to a value from enum chreWifiRadioChainPref to specify the desired
+ //! trade-off between power consumption, accuracy, etc. If
+ //! chreWifiGetCapabilities() does not have the applicable bit set, this
+ //! parameter is ignored.
+ //! @since v1.2
+ uint8_t radioChainPref;
+
+ //! Set to a value from enum chreWifiChannelSet to specify the set of
+ //! channels to be scanned. This field is considered by the platform only
+ //! if scanType is CHRE_WIFI_SCAN_TYPE_NO_PREFERENCE and frequencyListLen
+ //! is equal to zero.
+ //!
+ //! @since v1.5
+ uint8_t channelSet;
+};
+
+/**
+ * Provides information about a single access point (AP) detected in a scan.
+ */
+struct chreWifiScanResult {
+ //! Number of milliseconds prior to referenceTime in the enclosing
+ //! chreWifiScanEvent struct when the probe response or beacon frame that
+ //! was used to populate this structure was received.
+ uint32_t ageMs;
+
+ //! Capability Information field sent by the AP (see 802.11 7.3.1.4). This
+ //! field must reflect native byte order and bit ordering, such that
+ //! (capabilityInfo & 1) gives the bit for the ESS subfield.
+ uint16_t capabilityInfo;
+
+ //! Number of valid bytes in ssid. Valid range [0, CHRE_WIFI_SSID_MAX_LEN]
+ uint8_t ssidLen;
+
+ //! Service Set Identifier (SSID), a series of 0 to 32 octets identifying
+ //! the access point. Note that this is commonly a human-readable ASCII
+ //! string, but this is not the required encoding per the standard.
+ uint8_t ssid[CHRE_WIFI_SSID_MAX_LEN];
+
+ //! Basic Service Set Identifier (BSSID), represented in big-endian byte
+ //! order, such that the first octet of the OUI is accessed in byte index 0.
+ uint8_t bssid[CHRE_WIFI_BSSID_LEN];
+
+ //! A set of flags from CHRE_WIFI_SCAN_RESULT_FLAGS_*
+ uint8_t flags;
+
+ //! RSSI (Received Signal Strength Indicator), in dBm. Typically negative.
+ //! If multiple radio chains were used to scan this AP, this is a "best
+ //! available" measure that may be a composite of measurements taken across
+ //! the radio chains.
+ int8_t rssi;
+
+ //! Operating band, set to a value from enum chreWifiBand
+ uint8_t band;
+
+ /**
+ * Indicates the center frequency of the primary 20MHz channel, given in
+ * MHz. This value is derived from the channel number via the formula:
+ *
+ * primaryChannel (MHz) = CSF + 5 * primaryChannelNumber
+ *
+ * Where CSF is the channel starting frequency (in MHz) given by the
+ * operating class/band (i.e. 2407 or 5000), and primaryChannelNumber is the
+ * channel number in the range [1, 200].
+ *
+ * Refer to VHT 22.3.14.
+ */
+ uint32_t primaryChannel;
+
+ /**
+ * If the channel width is 20 MHz, this field is not relevant and set to 0.
+ * If the channel width is 40, 80, or 160 MHz, then this denotes the channel
+ * center frequency (in MHz). If the channel is 80+80 MHz, then this denotes
+ * the center frequency of segment 0, which contains the primary channel.
+ * This value is derived from the frequency index using the same formula as
+ * for primaryChannel.
+ *
+ * Refer to VHT 8.4.2.161, and VHT 22.3.14.
+ *
+ * @see #primaryChannel
+ */
+ uint32_t centerFreqPrimary;
+
+ /**
+ * If the channel width is 80+80MHz, then this denotes the center frequency
+ * of segment 1, which does not contain the primary channel. Otherwise, this
+ * field is not relevant and set to 0.
+ *
+ * @see #centerFreqPrimary
+ */
+ uint32_t centerFreqSecondary;
+
+ //! @see #chreWifiChannelWidth
+ uint8_t channelWidth;
+
+ //! Flags from CHRE_WIFI_SECURITY_MODE_* indicating supported authentication
+ //! and associated security modes
+ //! @see CHRE_WIFI_SECURITY_MODE_FLAGS
+ uint8_t securityMode;
+
+ //! Identifies the radio chain(s) used to discover this AP
+ //! @see CHRE_WIFI_RADIO_CHAIN_FLAGS
+ //! @since v1.2
+ uint8_t radioChain;
+
+ //! If the CHRE_WIFI_RADIO_CHAIN_0 bit is set in radioChain, gives the RSSI
+ //! measured on radio chain 0 in dBm; otherwise invalid and set to 0. This
+ //! field, along with its relative rssiChain1, can be used to determine RSSI
+ //! measurements from each radio chain when multiple chains were used to
+ //! discover this AP.
+ //! @see #radioChain
+ //! @since v1.2
+ int8_t rssiChain0;
+ int8_t rssiChain1; //!< @see #rssiChain0
+
+ //! Reserved; set to 0
+ uint8_t reserved[7];
+};
+
+/**
+ * Data structure sent with events of type CHRE_EVENT_WIFI_SCAN_RESULT.
+ */
+struct chreWifiScanEvent {
+ //! Indicates the version of the structure, for compatibility purposes.
+ //! Clients do not normally need to worry about this field; the CHRE
+ //! implementation guarantees that the client only receives the structure
+ //! version it expects.
+ uint8_t version;
+
+ //! The number of entries in the results array in this event. The CHRE
+ //! implementation may split scan results across multiple events for memory
+ //! concerns, etc.
+ uint8_t resultCount;
+
+ //! The total number of results returned by the scan. Allows an event
+ //! consumer to identify when it has received all events associated with a
+ //! scan.
+ uint8_t resultTotal;
+
+ //! Sequence number for this event within the series of events comprising a
+ //! complete scan result. Scan events are delivered strictly in order, i.e.
+ //! this is monotonically increasing for the results of a single scan. Valid
+ //! range [0, <number of events for scan> - 1]. The number of events for a
+ //! scan is typically given by
+ //! ceil(resultTotal / <max results per event supported by platform>).
+ uint8_t eventIndex;
+
+ //! A value from enum chreWifiScanType indicating the type of scan performed
+ uint8_t scanType;
+
+ //! If a directed scan was performed to a limited set of SSIDs, then this
+ //! identifies the number of unique SSIDs included in the probe requests.
+ //! Otherwise, this is set to 0, indicating that the scan was not limited by
+ //! SSID. Note that if this is non-zero, the list of SSIDs used is not
+ //! included in the scan event.
+ uint8_t ssidSetSize;
+
+ //! If 0, indicates that all frequencies applicable for the scanType were
+ //! scanned. Otherwise, indicates the number of frequencies scanned, as
+ //! specified in scannedFreqList.
+ uint16_t scannedFreqListLen;
+
+ //! Timestamp when the scan was completed, from the same time base as
+ //! chreGetTime() (in nanoseconds)
+ uint64_t referenceTime;
+
+ //! Pointer to an array containing scannedFreqListLen values comprising the
+ //! set of frequencies that were scanned. Frequencies are specified as
+ //! channel center frequencies in MHz. May be NULL if scannedFreqListLen is
+ //! 0.
+ const uint32_t *scannedFreqList;
+
+ //! Pointer to an array containing resultCount entries. May be NULL if
+ //! resultCount is 0.
+ const struct chreWifiScanResult *results;
+
+ //! Set to a value from enum chreWifiRadioChainPref indicating the radio
+ //! chain preference used for the scan. If the applicable bit is not set in
+ //! chreWifiGetCapabilities(), this will always be set to
+ //! CHRE_WIFI_RADIO_CHAIN_PREF_UNKNOWN.
+ //! @since v1.2
+ uint8_t radioChainPref;
+};
+
+/**
+ * Identifies a device to perform RTT ranging against. These values are normally
+ * populated based on the contents of a scan result.
+ * @see #chreWifiScanResult
+ * @see chreWifiRangingTargetFromScanResult()
+ */
+struct chreWifiRangingTarget {
+ //! Device MAC address, specified in the same byte order as
+ //! {@link #chreWifiScanResult.bssid}
+ uint8_t macAddress[CHRE_WIFI_BSSID_LEN];
+
+ //! Center frequency of the primary 20MHz channel, in MHz
+ //! @see #chreWifiScanResult.primaryChannel
+ uint32_t primaryChannel;
+
+ //! Channel center frequency, in MHz, or 0 if not relevant
+ //! @see #chreWifiScanResult.centerFreqPrimary
+ uint32_t centerFreqPrimary;
+
+ //! Channel center frequency of segment 1 if channel width is 80+80MHz,
+ //! otherwise 0
+ //! @see #chreWifiScanResult.centerFreqSecondary
+ uint32_t centerFreqSecondary;
+
+ //! @see #chreWifiChannelWidth
+ uint8_t channelWidth;
+
+ //! Reserved for future use and ignored by CHRE
+ uint8_t reserved[3];
+};
+
+/**
+ * Parameters for an RTT ("Fine Timing Measurement" in terms of 802.11-2016)
+ * ranging request, supplied to chreWifiRequestRangingAsync().
+ */
+struct chreWifiRangingParams {
+ //! Number of devices to perform ranging against and the length of
+ //! targetList, in range [1, CHRE_WIFI_RANGING_LIST_MAX_LEN].
+ uint8_t targetListLen;
+
+ //! Array of macAddressListLen MAC addresses (e.g. BSSIDs) with which to
+ //! attempt RTT ranging.
+ const struct chreWifiRangingTarget *targetList;
+};
+
+/**
+ * Provides the result of RTT ranging with a single device.
+ */
+struct chreWifiRangingResult {
+ //! Time when the ranging operation on this device was performed, in the
+ //! same time base as chreGetTime() (in nanoseconds)
+ uint64_t timestamp;
+
+ //! MAC address of the device for which ranging was requested
+ uint8_t macAddress[CHRE_WIFI_BSSID_LEN];
+
+ //! Gives the result of ranging to this device. If not set to
+ //! CHRE_WIFI_RANGING_STATUS_SUCCESS, the ranging attempt to this device
+ //! failed, and other fields in this structure may be invalid.
+ //! @see #chreWifiRangingStatus
+ uint8_t status;
+
+ //! The mean RSSI measured during the RTT burst, in dBm. Typically negative.
+ //! If status is not CHRE_WIFI_RANGING_STATUS_SUCCESS, will be set to 0.
+ int8_t rssi;
+
+ //! Estimated distance to the device with the given BSSID, in millimeters.
+ //! Generally the mean of multiple measurements performed in a single burst.
+ //! If status is not CHRE_WIFI_RANGING_STATUS_SUCCESS, will be set to 0.
+ uint32_t distance;
+
+ //! Standard deviation of estimated distance across multiple measurements
+ //! performed in a single RTT burst, in millimeters. If status is not
+ //! CHRE_WIFI_RANGING_STATUS_SUCCESS, will be set to 0.
+ uint32_t distanceStdDev;
+
+ //! Location Configuration Information (LCI) information optionally returned
+ //! during the ranging procedure. Only valid if {@link #flags} has the
+ //! CHRE_WIFI_RTT_RESULT_HAS_LCI bit set. Refer to IEEE 802.11-2016
+ //! 9.4.2.22.10, 11.24.6.7, and RFC 6225 (July 2011) for more information.
+ //! Coordinates are to be interpreted according to the WGS84 datum.
+ struct chreWifiLci {
+ //! Latitude in degrees as 2's complement fixed-point with 25 fractional
+ //! bits, i.e. degrees * 2^25. Ref: RFC 6225 2.3
+ int64_t latitude;
+
+ //! Longitude, same format as {@link #latitude}
+ int64_t longitude;
+
+ //! Altitude represented as a 2's complement fixed-point value with 8
+ //! fractional bits. Interpretation depends on {@link #altitudeType}. If
+ //! UNKNOWN, this field must be ignored. If *METERS, distance relative
+ //! to the zero point in the vertical datum. If *FLOORS, a floor value
+ //! relative to the ground floor, potentially fractional, e.g. to
+ //! indicate mezzanine levels. Ref: RFC 6225 2.4
+ int32_t altitude;
+
+ //! Maximum extent of latitude uncertainty in degrees, decoded via this
+ //! formula: 2 ^ (8 - x) where "x" is the encoded value passed in this
+ //! field. Unknown if set to CHRE_WIFI_LCI_UNCERTAINTY_UNKNOWN.
+ //! Ref: RFC 6225 2.3.2
+ uint8_t latitudeUncertainty;
+
+ //! @see #latitudeUncertainty
+ uint8_t longitudeUncertainty;
+
+ //! Defines how to interpret altitude, set to a value from enum
+ //! chreWifiLciAltitudeType
+ uint8_t altitudeType;
+
+ //! Uncertainty in altitude, decoded via this formula: 2 ^ (21 - x)
+ //! where "x" is the encoded value passed in this field. Unknown if set
+ //! to CHRE_WIFI_LCI_UNCERTAINTY_UNKNOWN. Only applies when altitudeType
+ //! is CHRE_WIFI_LCI_ALTITUDE_TYPE_METERS. Ref: RFC 6225 2.4.5
+ uint8_t altitudeUncertainty;
+ } lci;
+
+ //! Refer to CHRE_WIFI_RTT_RESULT_FLAGS
+ uint8_t flags;
+
+ //! Reserved; set to 0
+ uint8_t reserved[7];
+};
+
+/**
+ * Data structure sent with events of type CHRE_EVENT_WIFI_RANGING_RESULT.
+ */
+struct chreWifiRangingEvent {
+ //! Indicates the version of the structure, for compatibility purposes.
+ //! Clients do not normally need to worry about this field; the CHRE
+ //! implementation guarantees that the client only receives the structure
+ //! version it expects.
+ uint8_t version;
+
+ //! The number of ranging results included in the results array; matches the
+ //! number of MAC addresses specified in the request
+ uint8_t resultCount;
+
+ //! Reserved; set to 0
+ uint8_t reserved[2];
+
+ //! Pointer to an array containing resultCount entries
+ const struct chreWifiRangingResult *results;
+};
+
+/**
+ * Indicates the WiFi NAN capabilities of the device. Must contain non-zero
+ * values if WiFi NAN is supported.
+ */
+struct chreWifiNanCapabilities {
+ //! Maximum length of the match filter arrays (applies to both tx and rx
+ //! match filters).
+ uint32_t maxMatchFilterLength;
+
+ //! Maximum length of the service specific information byte array.
+ uint32_t maxServiceSpecificInfoLength;
+
+ //! Maximum length of the service name. Includes the NULL terminator.
+ uint8_t maxServiceNameLength;
+
+ //! Reserved for future use.
+ uint8_t reserved[3];
+};
+
+/**
+ * Data structure sent with events of type
+ * CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT
+ */
+struct chreWifiNanIdentifierEvent {
+ //! A unique ID assigned by the NAN engine for the subscribe request
+ //! associated with the cookie encapsulated in the async result below. The
+ //! ID is set to 0 if there was a request failure in which case the async
+ //! result below contains the appropriate error code indicating the failure
+ //! reason.
+ uint32_t id;
+
+ //! Structure which contains the cookie associated with the publish/
+ //! subscribe request, along with an error code that indicates request
+ //! success or failure.
+ struct chreAsyncResult result;
+};
+
+/**
+ * Indicates the desired configuration for a WiFi NAN ranging request.
+ */
+struct chreWifiNanRangingParams {
+ //! MAC address of the NAN device for which range is to be determined.
+ uint8_t macAddress[CHRE_WIFI_BSSID_LEN];
+};
+
+/**
+ * Configuration parameters specific to the Subscribe Function (Spec 4.1.1.1)
+ */
+struct chreWifiNanSubscribeConfig {
+ //! Indicates the subscribe type, set to a value from @ref
+ //! chreWifiNanSubscribeType.
+ uint8_t subscribeType;
+
+ //! UTF-8 name string that identifies the service/application. Must be NULL
+ //! terminated. Note that the string length cannot be greater than the
+ //! maximum length specified by @ref chreWifiNanCapabilities. No
+ //! restriction is placed on the string case, since the service name
+ //! matching is expected to be case insensitive.
+ const char *service;
+
+ //! An array of bytes (and the associated array length) of service-specific
+ //! information. Note that the array length must be less than the
+ //! maxServiceSpecificInfoLength parameter obtained from the NAN
+ //! capabilities (@see struct chreWifiNanCapabilities).
+ const uint8_t *serviceSpecificInfo;
+ uint32_t serviceSpecificInfoSize;
+
+ //! Ordered sequence of {length | value} pairs that specify match criteria
+ //! beyond the service name. 'length' uses 1 byte, and its value indicates
+ //! the number of bytes of the match criteria that follow. The length of
+ //! the match filter array should not exceed the maximum match filter
+ //! length obtained from @ref chreWifiNanGetCapabilities. When a service
+ //! publish message discovery frame containing the Service ID being
+ //! subscribed to is received, the matching is done as follows:
+ //! Each {length | value} pair in the kth position (1 <= k <= #length-value
+ //! pairs) is compared against the kth {length | value} pair in the
+ //! matching filter field of the publish message.
+ //! - For a kth position {length | value} pair in the rx match filter with
+ //! a length of 0, a match is declared regardless of the tx match filter
+ //! contents.
+ //! - For a kth position {length | value} pair in the rx match with a non-
+ //! zero length, there must be an exact match with the kth position pair
+ //! in the match filter field of the received service descriptor for a
+ //! match to be found.
+ //! Please refer to Appendix H of the NAN spec for examples on matching.
+ //! The match filter length should not exceed the maxMatchFilterLength
+ //! obtained from @ref chreWifiNanCapabilities.
+ const uint8_t *matchFilter;
+ uint32_t matchFilterLength;
+};
+
+/**
+ * Data structure sent with events of type
+ * CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT.
+ */
+struct chreWifiNanDiscoveryEvent {
+ //! Identifier of the subscribe function instance that requested a
+ //! discovery.
+ uint32_t subscribeId;
+
+ //! Identifier of the publisher on the remote NAN device.
+ uint32_t publishId;
+
+ //! NAN interface address of the publisher
+ uint8_t publisherAddress[CHRE_WIFI_BSSID_LEN];
+
+ //! An array of bytes (and the associated array length) of service-specific
+ //! information. Note that the array length must be less than the
+ //! maxServiceSpecificInfoLength parameter obtained from the NAN
+ //! capabilities (@see struct chreWifiNanCapabilities).
+ const uint8_t *serviceSpecificInfo;
+ uint32_t serviceSpecificInfoSize;
+};
+
+/**
+ * Data structure sent with events of type CHRE_EVENT_WIFI_NAN_SESSION_LOST.
+ */
+struct chreWifiNanSessionLostEvent {
+ //! The original ID (returned by the NAN discovery engine) of the subscriber
+ //! instance.
+ uint32_t id;
+
+ //! The ID of the previously discovered publisher on a peer NAN device that
+ //! is no longer connected.
+ uint32_t peerId;
+};
+
+/**
+ * Data structure sent with events of type
+ * CHRE_EVENT_WIFI_NAN_SESSION_TERMINATED.
+ */
+struct chreWifiNanSessionTerminatedEvent {
+ //! The original ID (returned by the NAN discovery engine) of the subscriber
+ //! instance that was terminated.
+ uint32_t id;
+
+ //! A value that maps to one of the termination reasons in @ref enum
+ //! chreWifiNanTerminatedReason.
+ uint8_t reason;
+
+ //! Reserved for future use.
+ uint8_t reserved[3];
+};
+
+/**
+ * Retrieves a set of flags indicating the WiFi features supported by the
+ * current CHRE implementation. The value returned by this function must be
+ * consistent for the entire duration of the Nanoapp's execution.
+ *
+ * The client must allow for more flags to be set in this response than it knows
+ * about, for example if the implementation supports a newer version of the API
+ * than the client was compiled against.
+ *
+ * @return A bitmask with zero or more CHRE_WIFI_CAPABILITIES_* flags set
+ *
+ * @since v1.1
+ */
+uint32_t chreWifiGetCapabilities(void);
+
+/**
+ * Retrieves device-specific WiFi NAN capabilities, and populates them in
+ * the @ref chreWifiNanCapabilities structure.
+ *
+ * @param capabilities Structure into which the WiFi NAN capabilities of
+ * the device are populated into. Must not be NULL.
+ * @return true if WiFi NAN is supported, false otherwise.
+ *
+ * @since v1.6
+ */
+bool chreWifiNanGetCapabilities(struct chreWifiNanCapabilities *capabilities);
+
+/**
+ * Nanoapps must define CHRE_NANOAPP_USES_WIFI somewhere in their build
+ * system (e.g. Makefile) if the nanoapp needs to use the following WiFi APIs.
+ * In addition to allowing access to these APIs, defining this macro will also
+ * ensure CHRE enforces that all host clients this nanoapp talks to have the
+ * required Android permissions needed to listen to WiFi data by adding metadata
+ * to the nanoapp.
+ */
+#if defined(CHRE_NANOAPP_USES_WIFI) || !defined(CHRE_IS_NANOAPP_BUILD)
+
+/**
+ * Manages a client's request to receive the results of WiFi scans performed for
+ * other purposes, for example scans done to maintain connectivity and scans
+ * requested by other clients. The presence of this request has no effect on the
+ * frequency or configuration of the WiFi scans performed - it is purely a
+ * registration by the client to receive the results of scans that would
+ * otherwise occur normally. This should include all available scan results,
+ * including those that are not normally sent to the applications processor,
+ * such as Preferred Network Offload (PNO) scans. Scan results provided because
+ * of this registration must not contain cached results - they are always
+ * expected to contain the fresh results from a recent scan.
+ *
+ * An active scan monitor subscription must persist across temporary conditions
+ * under which no WiFi scans will be performed, for example if WiFi is
+ * completely disabled via user-controlled settings, or if the WiFi system
+ * restarts independently of CHRE. Likewise, a request to enable a scan monitor
+ * subscription must succeed under normal conditions, even in circumstances
+ * where no WiFi scans will be performed. In these cases, the scan monitor
+ * implementation must produce scan results once the temporary condition is
+ * cleared, for example after WiFi is enabled by the user.
+ *
+ * These scan results are delivered to the Nanoapp's handle event callback using
+ * CHRE_EVENT_WIFI_SCAN_RESULT.
+ *
+ * An active scan monitor subscription is not necessary to receive the results
+ * of an on-demand scan request sent via chreWifiRequestScanAsync(), and it does
+ * not result in duplicate delivery of scan results generated from
+ * chreWifiRequestScanAsync().
+ *
+ * If no monitor subscription is active at the time of a request with
+ * enable=false, it is treated as if an active subscription was successfully
+ * ended.
+ *
+ * The result of this request is delivered asynchronously via an event of type
+ * CHRE_EVENT_WIFI_ASYNC_RESULT. Refer to the note in {@link #chreAsyncResult}
+ * for more details.
+ *
+ * @param enable Set to true to enable monitoring scan results, false to
+ * disable
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent in relation to this request.
+ * @return true if the request was accepted for processing, false otherwise
+ *
+ * @since v1.1
+ * @note Requires WiFi permission
+ */
+bool chreWifiConfigureScanMonitorAsync(bool enable, const void *cookie);
+
+/**
+ * Sends an on-demand request for WiFi scan results. This may trigger a new
+ * scan, or be entirely serviced from cache, depending on the maxScanAgeMs
+ * parameter.
+ *
+ * This resulting status of this request is delivered asynchronously via an
+ * event of type CHRE_EVENT_WIFI_ASYNC_RESULT. The result must be delivered
+ * within CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS of the this request. Refer to the
+ * note in {@link #chreAsyncResult} for more details.
+ *
+ * A successful result provided in CHRE_EVENT_WIFI_ASYNC_RESULT indicates that
+ * the scan results are ready to be delivered in a subsequent event (or events,
+ * which arrive consecutively without any other scan results in between)
+ * of type CHRE_EVENT_WIFI_SCAN_RESULT.
+ *
+ * WiFi scanning must be disabled if both "WiFi scanning" and "WiFi" settings
+ * are disabled at the Android level. In this case, the CHRE implementation is
+ * expected to return a result with CHRE_ERROR_FUNCTION_DISABLED.
+ *
+ * It is not valid for a client to request a new scan while a result is pending
+ * based on a previous scan request from the same client. In this situation, the
+ * CHRE implementation is expected to return a result with CHRE_ERROR_BUSY.
+ * However, if a scan is currently pending or in progress due to a request from
+ * another client, whether within the CHRE or otherwise, the implementation must
+ * not fail the request for this reason. If the pending scan satisfies the
+ * client's request parameters, then the implementation should use its results
+ * to satisfy the request rather than scheduling a new scan.
+ *
+ * @param params A set of parameters for the scan request. Must not be NULL.
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent in relation to this request.
+ * @return true if the request was accepted for processing, false otherwise
+ *
+ * @since v1.1
+ * @note Requires WiFi permission
+ */
+bool chreWifiRequestScanAsync(const struct chreWifiScanParams *params,
+ const void *cookie);
+
+/**
+ * Convenience function which calls chreWifiRequestScanAsync() with a default
+ * set of scan parameters.
+ *
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent in relation to this request.
+ * @return true if the request was accepted for processing, false otherwise
+ *
+ * @since v1.1
+ * @note Requires WiFi permission
+ */
+static inline bool chreWifiRequestScanAsyncDefault(const void *cookie) {
+ static const struct chreWifiScanParams params = {
+ /*.scanType=*/ CHRE_WIFI_SCAN_TYPE_NO_PREFERENCE,
+ /*.maxScanAgeMs=*/ 5000, // 5 seconds
+ /*.frequencyListLen=*/ 0,
+ /*.frequencyList=*/ NULL,
+ /*.ssidListLen=*/ 0,
+ /*.ssidList=*/ NULL,
+ /*.radioChainPref=*/ CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT,
+ /*.channelSet=*/ CHRE_WIFI_CHANNEL_SET_NON_DFS
+ };
+ return chreWifiRequestScanAsync(&params, cookie);
+}
+
+/**
+ * Issues a request to initiate distance measurements using round-trip time
+ * (RTT), aka Fine Timing Measurement (FTM), to one or more devices identified
+ * by MAC address. Within CHRE, MACs are typically the BSSIDs of scanned APs
+ * that have the CHRE_WIFI_SCAN_RESULT_FLAGS_IS_FTM_RESPONDER flag set.
+ *
+ * This resulting status of this request is delivered asynchronously via an
+ * event of type CHRE_EVENT_WIFI_ASYNC_RESULT. The result must be delivered
+ * within CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS of the this request. Refer to the
+ * note in {@link #chreAsyncResult} for more details.
+ *
+ * WiFi RTT ranging must be disabled if any of the following is true:
+ * - Both "WiFi" and "WiFi Scanning" settings are disabled at the Android level.
+ * - The "Location" setting is disabled at the Android level.
+ * In this case, the CHRE implementation is expected to return a result with
+ * CHRE_ERROR_FUNCTION_DISABLED.
+ *
+ * A successful result provided in CHRE_EVENT_WIFI_ASYNC_RESULT indicates that
+ * the results of ranging will be delivered in a subsequent event of type
+ * CHRE_EVENT_WIFI_RANGING_RESULT. Note that the CHRE_EVENT_WIFI_ASYNC_RESULT
+ * gives an overall status - for example, it is used to indicate failure if the
+ * entire ranging request was rejected because WiFi is disabled. However, it is
+ * valid for this event to indicate success, but RTT ranging to fail for all
+ * requested devices - for example, they may be out of range. Therefore, it is
+ * also necessary to check the status field in {@link #chreWifiRangingResult}.
+ *
+ * @param params Structure containing the parameters of the scan request,
+ * including the list of devices to attempt ranging.
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent in relation to this request.
+ * @return true if the request was accepted for processing, false otherwise
+ *
+ * @since v1.2
+ * @note Requires WiFi permission
+ */
+bool chreWifiRequestRangingAsync(const struct chreWifiRangingParams *params,
+ const void *cookie);
+
+/**
+ * Helper function to populate an instance of struct chreWifiRangingTarget with
+ * the contents of a scan result provided in struct chreWifiScanResult.
+ * Populates other parameters that are not directly derived from the scan result
+ * with default values.
+ *
+ * @param scanResult The scan result to parse as input
+ * @param rangingTarget The RTT ranging target to populate as output
+ *
+ * @note Requires WiFi permission
+ */
+static inline void chreWifiRangingTargetFromScanResult(
+ const struct chreWifiScanResult *scanResult,
+ struct chreWifiRangingTarget *rangingTarget) {
+ memcpy(rangingTarget->macAddress, scanResult->bssid,
+ sizeof(rangingTarget->macAddress));
+ rangingTarget->primaryChannel = scanResult->primaryChannel;
+ rangingTarget->centerFreqPrimary = scanResult->centerFreqPrimary;
+ rangingTarget->centerFreqSecondary = scanResult->centerFreqSecondary;
+ rangingTarget->channelWidth = scanResult->channelWidth;
+
+ // Note that this is not strictly necessary (CHRE can see which API version
+ // the nanoapp was built against, so it knows to ignore these fields), but
+ // we do it here to keep things nice and tidy
+ memset(rangingTarget->reserved, 0, sizeof(rangingTarget->reserved));
+}
+
+/**
+ * Subscribe to a NAN service.
+ *
+ * Sends a subscription request to the NAN discovery engine with the
+ * specified configration parameters. If successful, a unique non-zero
+ * subscription ID associated with this instance of the subscription
+ * request is assigned by the NAN discovery engine. The subscription request
+ * is active until explicitly canceled, or if the connection was interrupted.
+ *
+ * Note that CHRE forwards any discovery events that it receives to the
+ * subscribe function instance, and does no duplicate filtering. If
+ * multiple events of the same discovery are undesirable, it is up to the
+ * platform NAN discovery engine implementation to implement redundancy
+ * detection mechanisms.
+ *
+ * If WiFi is turned off by the user at the Android level, an existing
+ * subscribe session is canceled, and a CHRE_EVENT_WIFI_ASYNC_RESULT event is
+ * event is sent to the subscriber. Nanoapps are expected to register for user
+ * settings notifications (@see chreUserSettingConfigureEvents), and
+ * re-establish a subscribe session on a WiFi re-enabled settings changed
+ * notification.
+ *
+ * @param config Service subscription configuration
+ * @param cookie A value that the nanoapp uses to track this particular
+ * subscription request.
+ * @return true if NAN is enabled and a subscription request was successfully
+ * made to the NAN engine. The actual result of the service discovery
+ * is sent via a CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT event.
+ *
+ * @since v1.6
+ * @note Requires WiFi permission
+ */
+bool chreWifiNanSubscribe(struct chreWifiNanSubscribeConfig *config,
+ const void *cookie);
+
+/**
+ * Cancel a subscribe function instance.
+ *
+ * @param subscriptionId The ID that was originally assigned to this instance
+ * of the subscribe function.
+ * @return true if NAN is enabled, the subscribe ID was found and the instance
+ * successfully canceled.
+ *
+ * @since v1.6
+ * @note Requires WiFi permission
+ */
+bool chreWifiNanSubscribeCancel(uint32_t subscriptionID);
+
+/**
+ * Request RTT ranging from a peer NAN device.
+ *
+ * Nanoapps can use this API to explicitly request measurement reports from
+ * the peer device. Note that both end points have to support ranging for a
+ * successful request. The MAC address of the peer NAN device for which ranging
+ * is desired may be obtained either from a NAN service discovery or from an
+ * out-of-band source (HAL service, BLE, etc.).
+ *
+ * If WiFi is turned off by the user at the Android level, an existing
+ * ranging session is canceled, and a CHRE_EVENT_WIFI_ASYNC_RESULT event is
+ * sent to the subscriber. Nanoapps are expected to register for user settings
+ * notifications (@see chreUserSettingConfigureEvents), and perform another
+ * ranging request on a WiFi re-enabled settings changed notification.
+ *
+ * A successful result provided in CHRE_EVENT_WIFI_ASYNC_RESULT indicates that
+ * the results of ranging will be delivered in a subsequent event of type
+ * CHRE_EVENT_WIFI_RANGING_RESULT.
+ *
+ * @param params Structure containing the parameters of the ranging request,
+ * including the MAC address of the peer NAN device to attempt ranging.
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent in relation to this request.
+ * @return true if the request was accepted for processing, false otherwise.
+ */
+bool chreWifiNanRequestRangingAsync(const struct chreWifiNanRangingParams *params,
+ const void *cookie);
+
+#else /* defined(CHRE_NANOAPP_USES_WIFI) || !defined(CHRE_IS_NANOAPP_BUILD) */
+#define CHRE_WIFI_PERM_ERROR_STRING \
+ "CHRE_NANOAPP_USES_WIFI must be defined when building this nanoapp in " \
+ "order to refer to "
+#define chreWifiConfigureScanMonitorAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_WIFI_PERM_ERROR_STRING \
+ "chreWifiConfigureScanMonitorAsync")
+#define chreWifiRequestScanAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_WIFI_PERM_ERROR_STRING \
+ "chreWifiRequestScanAsync")
+#define chreWifiRequestScanAsyncDefault(...) \
+ CHRE_BUILD_ERROR(CHRE_WIFI_PERM_ERROR_STRING \
+ "chreWifiRequestScanAsyncDefault")
+#define chreWifiRequestRangingAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_WIFI_PERM_ERROR_STRING "chreWifiRequestRangingAsync")
+#define chreWifiRangingTargetFromScanResult(...) \
+ CHRE_BUILD_ERROR(CHRE_WIFI_PERM_ERROR_STRING \
+ "chreWifiRangingTargetFromScanResult")
+#define chreWifiNanSubscribe(...) \
+ CHRE_BUILD_ERROR(CHRE_WIFI_PERM_ERROR_STRING "chreWifiNanSubscribe")
+#define chreWifiNanSubscribeCancel(...) \
+ CHRE_BUILD_ERROR(CHRE_WIFI_PERM_ERROR_STRING "chreWifiNanSubscribeCancel")
+#define chreWifiNanRequestRangingAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_WIFI_PERM_ERROR_STRING "chreWifiNanRequestRangingAsync")
+#endif /* defined(CHRE_NANOAPP_USES_WIFI) || !defined(CHRE_IS_NANOAPP_BUILD) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHRE_WIFI_H_ */
diff --git a/chre_api/legacy/v1_8/chre/wwan.h b/chre_api/legacy/v1_8/chre/wwan.h
new file mode 100644
index 00000000..51cf5f9d
--- /dev/null
+++ b/chre_api/legacy/v1_8/chre/wwan.h
@@ -0,0 +1,591 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CHRE_WWAN_H_
+#define _CHRE_WWAN_H_
+
+/**
+ * @file
+ * Wireless Wide Area Network (WWAN, i.e. mobile/cellular network) API relevant
+ * for querying cell tower identity and associated information that can be
+ * useful in determining location.
+ *
+ * Based on Android N RIL definitions (located at this path as of the time of
+ * this comment: hardware/ril/include/telephony/ril.h), version 12. Updated
+ * based on Android radio HAL definition (hardware/interfaces/radio) for more
+ * recent Android builds. Refer to those files and associated documentation for
+ * further details.
+ *
+ * In general, the parts of this API that are taken from the RIL follow the
+ * field naming conventions established in that interface rather than the CHRE
+ * API conventions, in order to avoid confusion and enable code re-use where
+ * applicable. Note that structure names include the chreWwan* prefix rather
+ * than RIL_*, but field names are the same. If necessary to enable code
+ * sharing, it is recommended to create typedefs that map from the CHRE
+ * structures to the associated RIL type names, for example "typedef struct
+ * chreWwanCellIdentityGsm RIL_CellIdentityGsm_v12", etc.
+ */
+
+#include <chre/common.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The set of flags returned by chreWwanGetCapabilities().
+ * @defgroup CHRE_WWAN_CAPABILITIES
+ * @{
+ */
+
+//! No WWAN APIs are supported
+#define CHRE_WWAN_CAPABILITIES_NONE UINT32_C(0)
+
+//! Current cell information can be queried via chreWwanGetCellInfoAsync()
+#define CHRE_WWAN_GET_CELL_INFO UINT32_C(1 << 0)
+
+/** @} */
+
+/**
+ * Produce an event ID in the block of IDs reserved for WWAN
+ * @param offset Index into WWAN event ID block; valid range [0,15]
+ */
+#define CHRE_WWAN_EVENT_ID(offset) (CHRE_EVENT_WWAN_FIRST_EVENT + (offset))
+
+/**
+ * nanoappHandleEvent argument: struct chreWwanCellInfoResult
+ *
+ * Provides the result of an asynchronous request for cell info sent via
+ * chreWwanGetCellInfoAsync().
+ */
+#define CHRE_EVENT_WWAN_CELL_INFO_RESULT CHRE_WWAN_EVENT_ID(0)
+
+// NOTE: Do not add new events with ID > 15; only values 0-15 are reserved
+// (see chre/event.h)
+
+/**
+ * The current version of struct chreWwanCellInfoResult associated with this
+ * API definition.
+ */
+#define CHRE_WWAN_CELL_INFO_RESULT_VERSION UINT8_C(1)
+
+//! Reference: RIL_CellIdentityGsm_v12
+struct chreWwanCellIdentityGsm {
+ //! 3-digit Mobile Country Code, 0..999, INT32_MAX if unknown
+ int32_t mcc;
+
+ //! 2 or 3-digit Mobile Network Code, 0..999, INT32_MAX if unknown
+ int32_t mnc;
+
+ //! 16-bit Location Area Code, 0..65535, INT32_MAX if unknown
+ int32_t lac;
+
+ //! 16-bit GSM Cell Identity described in TS 27.007, 0..65535,
+ //! INT32_MAX if unknown
+ int32_t cid;
+
+ //! 16-bit GSM Absolute RF channel number, INT32_MAX if unknown
+ int32_t arfcn;
+
+ //! 6-bit Base Station Identity Code, UINT8_MAX if unknown
+ uint8_t bsic;
+
+ //! Reserved for future use; must be set to 0
+ uint8_t reserved[3];
+};
+
+//! Reference: RIL_CellIdentityWcdma_v12
+struct chreWwanCellIdentityWcdma {
+ //! 3-digit Mobile Country Code, 0..999, INT32_MAX if unknown
+ int32_t mcc;
+
+ //! 2 or 3-digit Mobile Network Code, 0..999, INT32_MAX if unknown
+ int32_t mnc;
+
+ //! 16-bit Location Area Code, 0..65535, INT32_MAX if unknown
+ int32_t lac;
+
+ //! 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455,
+ //! INT32_MAX if unknown
+ int32_t cid;
+
+ //! 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511,
+ //! INT32_MAX if unknown
+ int32_t psc;
+
+ //! 16-bit UMTS Absolute RF Channel Number, INT32_MAX if unknown
+ int32_t uarfcn;
+};
+
+//! Reference: RIL_CellIdentityCdma
+struct chreWwanCellIdentityCdma {
+ //! Network Id 0..65535, INT32_MAX if unknown
+ int32_t networkId;
+
+ //! CDMA System Id 0..32767, INT32_MAX if unknown
+ int32_t systemId;
+
+ //! Base Station Id 0..65535, INT32_MAX if unknown
+ int32_t basestationId;
+
+ //! Longitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
+ //! It is represented in units of 0.25 seconds and ranges from -2592000
+ //! to 2592000, both values inclusive (corresponding to a range of -180
+ //! to +180 degrees). INT32_MAX if unknown
+ int32_t longitude;
+
+ //! Latitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
+ //! It is represented in units of 0.25 seconds and ranges from -1296000
+ //! to 1296000, both values inclusive (corresponding to a range of -90
+ //! to +90 degrees). INT32_MAX if unknown
+ int32_t latitude;
+};
+
+//! Reference: RIL_CellIdentityLte_v12
+struct chreWwanCellIdentityLte {
+ //! 3-digit Mobile Country Code, 0..999, INT32_MAX if unknown
+ int32_t mcc;
+
+ //! 2 or 3-digit Mobile Network Code, 0..999, INT32_MAX if unknown
+ int32_t mnc;
+
+ //! 28-bit Cell Identity described in TS ???, INT32_MAX if unknown
+ int32_t ci;
+
+ //! physical cell id 0..503, INT32_MAX if unknown
+ int32_t pci;
+
+ //! 16-bit tracking area code, INT32_MAX if unknown
+ int32_t tac;
+
+ //! 18-bit LTE Absolute RF Channel Number, INT32_MAX if unknown
+ int32_t earfcn;
+};
+
+//! Reference: RIL_CellIdentityTdscdma
+struct chreWwanCellIdentityTdscdma {
+ //! 3-digit Mobile Country Code, 0..999, INT32_MAX if unknown
+ int32_t mcc;
+
+ //! 2 or 3-digit Mobile Network Code, 0..999, INT32_MAX if unknown
+ int32_t mnc;
+
+ //! 16-bit Location Area Code, 0..65535, INT32_MAX if unknown
+ int32_t lac;
+
+ //! 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455,
+ //! INT32_MAX if unknown
+ int32_t cid;
+
+ //! 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT32_MAX if
+ //! unknown
+ int32_t cpid;
+};
+
+//! Reference: android.hardware.radio@1.4 CellIdentityNr
+//! @since v1.4
+struct chreWwanCellIdentityNr {
+ //! 3-digit Mobile Country Code, in range [0, 999]. This value must be valid
+ //! for registered or camped cells. INT32_MAX means invalid/unreported.
+ int32_t mcc;
+
+ //! 2 or 3-digit Mobile Network Code, in range [0, 999]. This value must be
+ //! valid for registered or camped cells. INT32_MAX means
+ //! invalid/unreported.
+ int32_t mnc;
+
+ //! NR Cell Identity in range [0, 68719476735] (36 bits), which
+ //! unambiguously identifies a cell within a public land mobile network
+ //! (PLMN). This value must be valid for registered or camped cells.
+ //! Reference: TS 38.413 section 9.3.1.7.
+ //!
+ //! Note: for backward compatibility reasons, the nominally int64_t nci is
+ //! split into two uint32_t values, with nci0 being the least significant 4
+ //! bytes. If chreWwanUnpackNrNci returns INT64_MAX, it means nci is
+ //! invalid/unreported.
+ //!
+ //! Users are recommended to use the helper accessor chreWwanUnpackNrNci to
+ //! access the nci field.
+ //!
+ //! @see chreWwanUnpackNrNci
+ uint32_t nci0;
+ uint32_t nci1;
+
+ //! Physical cell id in range [0, 1007]. This value must be valid.
+ //! Reference: TS 38.331 section 6.3.2.
+ int32_t pci;
+
+ //! 24-bit tracking area code in range [0, 16777215]. INT32_MAX means
+ //! invalid/unreported.
+ //! Reference: TS 38.413 section 9.3.3.10 and TS 29.571 section 5.4.2.
+ int32_t tac;
+
+ //! NR Absolute Radio Frequency Channel Number, in range [0, 3279165]. This
+ //! value must be valid.
+ //! Reference: TS 38.101-1 section 5.4.2.1 and TS 38.101-2 section 5.4.2.1.
+ int32_t nrarfcn;
+};
+
+//! Reference: RIL_GSM_SignalStrength_v12
+struct chreWwanSignalStrengthGsm {
+ //! Valid values are (0-31, 99) as defined in TS 27.007 8.5
+ //! INT32_MAX means invalid/unreported.
+ int32_t signalStrength;
+
+ //! bit error rate (0-7, 99) as defined in TS 27.007 8.5
+ //! INT32_MAX means invalid/unreported.
+ int32_t bitErrorRate;
+
+ //! Timing Advance in bit periods. 1 bit period = 48.13 us.
+ //! INT32_MAX means invalid/unreported.
+ int32_t timingAdvance;
+};
+
+//! Reference: RIL_SignalStrengthWcdma
+struct chreWwanSignalStrengthWcdma {
+ //! Valid values are (0-31, 99) as defined in TS 27.007 8.5
+ //! INT32_MAX means invalid/unreported.
+ int32_t signalStrength;
+
+ //! bit error rate (0-7, 99) as defined in TS 27.007 8.5
+ //! INT32_MAX means invalid/unreported.
+ int32_t bitErrorRate;
+};
+
+//! Reference: RIL_CDMA_SignalStrength
+struct chreWwanSignalStrengthCdma {
+ //! Valid values are positive integers. This value is the actual RSSI value
+ //! multiplied by -1. Example: If the actual RSSI is -75, then this
+ //! response value will be 75.
+ //! INT32_MAX means invalid/unreported.
+ int32_t dbm;
+
+ //! Valid values are positive integers. This value is the actual Ec/Io
+ //! multiplied by -10. Example: If the actual Ec/Io is -12.5 dB, then this
+ //! response value will be 125.
+ //! INT32_MAX means invalid/unreported.
+ int32_t ecio;
+};
+
+//! Reference: RIL_EVDO_SignalStrength
+struct chreWwanSignalStrengthEvdo {
+ //! Valid values are positive integers. This value is the actual RSSI value
+ //! multiplied by -1. Example: If the actual RSSI is -75, then this
+ //! response value will be 75.
+ //! INT32_MAX means invalid/unreported.
+ int32_t dbm;
+
+ //! Valid values are positive integers. This value is the actual Ec/Io
+ //! multiplied by -10. Example: If the actual Ec/Io is -12.5 dB, then this
+ //! response value will be 125.
+ //! INT32_MAX means invalid/unreported.
+ int32_t ecio;
+
+ //! Valid values are 0-8. 8 is the highest signal to noise ratio.
+ //! INT32_MAX means invalid/unreported.
+ int32_t signalNoiseRatio;
+};
+
+//! Reference: RIL_LTE_SignalStrength_v8
+struct chreWwanSignalStrengthLte {
+ //! Valid values are (0-31, 99) as defined in TS 27.007 8.5
+ int32_t signalStrength;
+
+ //! The current Reference Signal Receive Power in dBm multiplied by -1.
+ //! Range: 44 to 140 dBm
+ //! INT32_MAX means invalid/unreported.
+ //! Reference: 3GPP TS 36.133 9.1.4
+ int32_t rsrp;
+
+ //! The current Reference Signal Receive Quality in dB multiplied by -1.
+ //! Range: 3 to 20 dB.
+ //! INT32_MAX means invalid/unreported.
+ //! Reference: 3GPP TS 36.133 9.1.7
+ int32_t rsrq;
+
+ //! The current reference signal signal-to-noise ratio in 0.1 dB units.
+ //! Range: -200 to +300 (-200 = -20.0 dB, +300 = 30dB).
+ //! INT32_MAX means invalid/unreported.
+ //! Reference: 3GPP TS 36.101 8.1.1
+ int32_t rssnr;
+
+ //! The current Channel Quality Indicator.
+ //! Range: 0 to 15.
+ //! INT32_MAX means invalid/unreported.
+ //! Reference: 3GPP TS 36.101 9.2, 9.3, A.4
+ int32_t cqi;
+
+ //! timing advance in micro seconds for a one way trip from cell to device.
+ //! Approximate distance can be calculated using 300m/us * timingAdvance.
+ //! Range: 0 to 0x7FFFFFFE
+ //! INT32_MAX means invalid/unreported.
+ //! Reference: 3GPP 36.321 section 6.1.3.5
+ //! also: http://www.cellular-planningoptimization.com/2010/02/timing-advance-with-calculation.html
+ int32_t timingAdvance;
+};
+
+//! Reference: RIL_TD_SCDMA_SignalStrength
+struct chreWwanSignalStrengthTdscdma {
+ //! The Received Signal Code Power in dBm multiplied by -1.
+ //! Range : 25 to 120
+ //! INT32_MAX means invalid/unreported.
+ //! Reference: 3GPP TS 25.123, section 9.1.1.1
+ int32_t rscp;
+};
+
+//! Reference: android.hardware.radio@1.4 NrSignalStrength
+//! @since v1.4
+struct chreWwanSignalStrengthNr {
+ //! SS (second synchronization) reference signal received power in dBm
+ //! multiplied by -1.
+ //! Range [44, 140], INT32_MAX means invalid/unreported.
+ //! Reference: TS 38.215 section 5.1.1 and TS 38.133 section 10.1.6.
+ int32_t ssRsrp;
+
+ //! SS reference signal received quality in 0.5 dB units.
+ //! Range [-86, 41] with -86 = -43.0 dB and 41 = 20.5 dB.
+ //! INT32_MAX means invalid/unreported.
+ //! Reference: TS 38.215 section 5.1.3 and TS 38.133 section 10.1.11.1.
+ int32_t ssRsrq;
+
+ //! SS signal-to-noise and interference ratio in 0.5 dB units.
+ //! Range [-46, 81] with -46 = -23.0 dB and 81 = 40.5 dB.
+ //! INT32_MAX means invalid/unreported.
+ //! Reference: TS 38.215 section 5.1.5 and TS 38.133 section 10.1.16.1.
+ int32_t ssSinr;
+
+ //! CSI reference signal received power in dBm multiplied by -1.
+ //! Range [44, 140], INT32_MAX means invalid/unreported.
+ //! Reference: TS 38.215 section 5.1.2 and TS 38.133 section 10.1.6.
+ int32_t csiRsrp;
+
+ //! CSI reference signal received quality in 0.5 dB units.
+ //! Range [-86, 41] with -86 = -43.0 dB and 41 = 20.5 dB.
+ //! INT32_MAX means invalid/unreported.
+ //! Reference: TS 38.215 section 5.1.4 and TS 38.133 section 10.1.11.1.
+ int32_t csiRsrq;
+
+ //! CSI signal-to-noise and interference ratio in 0.5 dB units.
+ //! Range [-46, 81] with -46 = -23.0 dB and 81 = 40.5 dB.
+ //! INT32_MAX means invalid/unreported.
+ //! Reference: TS 38.215 section 5.1.6 and TS 38.133 section 10.1.16.1.
+ int32_t csiSinr;
+};
+
+//! Reference: RIL_CellInfoGsm_v12
+struct chreWwanCellInfoGsm {
+ struct chreWwanCellIdentityGsm cellIdentityGsm;
+ struct chreWwanSignalStrengthGsm signalStrengthGsm;
+};
+
+//! Reference: RIL_CellInfoWcdma_v12
+struct chreWwanCellInfoWcdma {
+ struct chreWwanCellIdentityWcdma cellIdentityWcdma;
+ struct chreWwanSignalStrengthWcdma signalStrengthWcdma;
+};
+
+//! Reference: RIL_CellInfoCdma
+struct chreWwanCellInfoCdma {
+ struct chreWwanCellIdentityCdma cellIdentityCdma;
+ struct chreWwanSignalStrengthCdma signalStrengthCdma;
+ struct chreWwanSignalStrengthEvdo signalStrengthEvdo;
+};
+
+//! Reference: RIL_CellInfoLte_v12
+struct chreWwanCellInfoLte {
+ struct chreWwanCellIdentityLte cellIdentityLte;
+ struct chreWwanSignalStrengthLte signalStrengthLte;
+};
+
+//! Reference: RIL_CellInfoTdscdma
+struct chreWwanCellInfoTdscdma {
+ struct chreWwanCellIdentityTdscdma cellIdentityTdscdma;
+ struct chreWwanSignalStrengthTdscdma signalStrengthTdscdma;
+};
+
+//! Reference: android.hardware.radio@1.4 CellInfoNr
+//! @since v1.4
+struct chreWwanCellInfoNr {
+ struct chreWwanCellIdentityNr cellIdentityNr;
+ struct chreWwanSignalStrengthNr signalStrengthNr;
+};
+
+//! Reference: RIL_CellInfoType
+//! All other values are reserved and should be ignored by nanoapps.
+enum chreWwanCellInfoType {
+ CHRE_WWAN_CELL_INFO_TYPE_GSM = 1,
+ CHRE_WWAN_CELL_INFO_TYPE_CDMA = 2,
+ CHRE_WWAN_CELL_INFO_TYPE_LTE = 3,
+ CHRE_WWAN_CELL_INFO_TYPE_WCDMA = 4,
+ CHRE_WWAN_CELL_INFO_TYPE_TD_SCDMA = 5,
+ CHRE_WWAN_CELL_INFO_TYPE_NR = 6, //! @since v1.4
+};
+
+//! Reference: RIL_TimeStampType
+enum chreWwanCellTimeStampType {
+ CHRE_WWAN_CELL_TIMESTAMP_TYPE_UNKNOWN = 0,
+ CHRE_WWAN_CELL_TIMESTAMP_TYPE_ANTENNA = 1,
+ CHRE_WWAN_CELL_TIMESTAMP_TYPE_MODEM = 2,
+ CHRE_WWAN_CELL_TIMESTAMP_TYPE_OEM_RIL = 3,
+ CHRE_WWAN_CELL_TIMESTAMP_TYPE_JAVA_RIL = 4,
+};
+
+//! Reference: RIL_CellInfo_v12
+struct chreWwanCellInfo {
+ //! Timestamp in nanoseconds; must be in the same time base as chreGetTime()
+ uint64_t timeStamp;
+
+ //! A value from enum {@link #CellInfoType} indicating the radio access
+ //! technology of the cell, and which field in union CellInfo can be used
+ //! to retrieve additional information
+ uint8_t cellInfoType;
+
+ //! A value from enum {@link #CellTimeStampType} that identifies the source
+ //! of the value in timeStamp. This is typically set to
+ //! CHRE_WWAN_CELL_TIMESTAMP_TYPE_OEM_RIL, and indicates the time given by
+ //! chreGetTime() that an intermediate module received the data from the
+ //! modem and forwarded it to the requesting CHRE client.
+ uint8_t timeStampType;
+
+ //! !0 if this cell is registered, 0 if not registered
+ uint8_t registered;
+
+ //! Reserved for future use; must be set to 0
+ uint8_t reserved;
+
+ //! The value in cellInfoType indicates which field in this union is valid
+ union chreWwanCellInfoPerRat {
+ struct chreWwanCellInfoGsm gsm;
+ struct chreWwanCellInfoCdma cdma;
+ struct chreWwanCellInfoLte lte;
+ struct chreWwanCellInfoWcdma wcdma;
+ struct chreWwanCellInfoTdscdma tdscdma;
+ struct chreWwanCellInfoNr nr; //! @since v1.4
+ } CellInfo;
+};
+
+/**
+ * Data structure provided with events of type CHRE_EVENT_WWAN_CELL_INFO_RESULT.
+ */
+struct chreWwanCellInfoResult {
+ //! Indicates the version of the structure, for compatibility purposes.
+ //! Clients do not normally need to worry about this field; the CHRE
+ //! implementation guarantees that the client only receives the structure
+ //! version it expects.
+ uint8_t version;
+
+ //! Populated with a value from enum {@link #chreError}, indicating whether
+ //! the request failed, and if so, provides the cause of the failure
+ uint8_t errorCode;
+
+ //! The number of valid entries in cells[]
+ uint8_t cellInfoCount;
+
+ //! Reserved for future use; must be set to 0
+ uint8_t reserved;
+
+ //! Set to the cookie parameter given to chreWwanGetCellInfoAsync()
+ const void *cookie;
+
+ //! Pointer to an array of cellInfoCount elements containing information
+ //! about serving and neighbor cells
+ const struct chreWwanCellInfo *cells;
+};
+
+
+/**
+ * Retrieves a set of flags indicating the WWAN features supported by the
+ * current CHRE implementation. The value returned by this function must be
+ * consistent for the entire duration of the Nanoapp's execution.
+ *
+ * The client must allow for more flags to be set in this response than it knows
+ * about, for example if the implementation supports a newer version of the API
+ * than the client was compiled against.
+ *
+ * @return A bitmask with zero or more CHRE_WWAN_CAPABILITIES_* flags set
+ *
+ * @since v1.1
+ */
+uint32_t chreWwanGetCapabilities(void);
+
+/**
+ * Nanoapps must define CHRE_NANOAPP_USES_WWAN somewhere in their build
+ * system (e.g. Makefile) if the nanoapp needs to use the following WWAN APIs.
+ * In addition to allowing access to these APIs, defining this macro will also
+ * ensure CHRE enforces that all host clients this nanoapp talks to have the
+ * required Android permissions needed to listen to WWAN data by adding metadata
+ * to the nanoapp.
+ */
+#if defined(CHRE_NANOAPP_USES_WWAN) || !defined(CHRE_IS_NANOAPP_BUILD)
+
+/**
+ * Query information about the current serving cell and its neighbors. This does
+ * not perform a network scan, but should return state from the current network
+ * registration data stored in the cellular modem. This is effectively the same
+ * as a request for RIL_REQUEST_GET_CELL_INFO_LIST in the RIL.
+ *
+ * The requested cellular information is returned asynchronously via
+ * CHRE_EVENT_WWAN_CELL_INFO_RESULT. The implementation must send this event,
+ * either with successful data or an error status, within
+ * CHRE_ASYNC_RESULT_TIMEOUT_NS.
+ *
+ * If the airplane mode setting is enabled at the Android level, the CHRE
+ * implementation is expected to return a successful asynchronous result with an
+ * empty cell info list.
+ *
+ * @param cookie An opaque value that will be included in the chreAsyncResult
+ * sent in relation to this request.
+ *
+ * @return true if the request was accepted for processing, false otherwise
+ *
+ * @since v1.1
+ * @note Requires WWAN permission
+ */
+bool chreWwanGetCellInfoAsync(const void *cookie);
+
+/**
+ * Helper accessor for nci in the chreWwanCellIdentityNr struct.
+ *
+ * @return nci or INT64_MAX if invalid/unreported.
+ *
+ * @see chreWwanCellIdentityNr
+ *
+ * @since v1.4
+ * @note Requires WWAN permission
+ */
+static inline int64_t chreWwanUnpackNrNci(
+ const struct chreWwanCellIdentityNr *nrCellId) {
+ return (int64_t) (((uint64_t) nrCellId->nci1 << 32) | nrCellId->nci0);
+}
+
+#else /* defined(CHRE_NANOAPP_USES_WWAN) || !defined(CHRE_IS_NANOAPP_BUILD) */
+#define CHRE_WWAN_PERM_ERROR_STRING \
+ "CHRE_NANOAPP_USES_WWAN must be defined when building this nanoapp in " \
+ "order to refer to "
+#define chreWwanGetCellInfoAsync(...) \
+ CHRE_BUILD_ERROR(CHRE_WWAN_PERM_ERROR_STRING "chreWwanGetCellInfoAsync")
+#define chreWwanUnpackNrNci(...) \
+ CHRE_BUILD_ERROR(CHRE_WWAN_PERM_ERROR_STRING "chreWwanUnpackNrNci")
+#endif /* defined(CHRE_NANOAPP_USES_WWAN) || !defined(CHRE_IS_NANOAPP_BUILD) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHRE_WWAN_H_ */
diff --git a/chre_daemon.rc b/chre_daemon.rc
index 120da10d..58bf3d98 100644
--- a/chre_daemon.rc
+++ b/chre_daemon.rc
@@ -14,6 +14,9 @@
# limitations under the License.
#
+on post-fs-data
+ mkdir /data/vendor/chre 0770 context_hub context_hub
+
service vendor.chre /vendor/bin/chre
class late_start
user context_hub
diff --git a/chre_flags.aconfig b/chre_flags.aconfig
new file mode 100644
index 00000000..70c6586e
--- /dev/null
+++ b/chre_flags.aconfig
@@ -0,0 +1,36 @@
+package: "android.chre.flags"
+
+flag {
+ name: "flag_log_nanoapp_load_metrics"
+ namespace: "context_hub"
+ description: "This flag controls nanoapp load failure logging in the HAL and the addition of MetricsReporter"
+ bug: "298459533"
+}
+
+flag {
+ name: "metrics_reporter_in_the_daemon"
+ namespace: "context_hub"
+ description: "This flag controls the addition of MetricsReporter into the CHRE daemon"
+ bug: "298459533"
+}
+
+flag {
+ name: "wait_for_preloaded_nanoapp_start"
+ namespace: "context_hub"
+ description: "This flag controls the waiting-for-nanoapp-start behavior in the CHRE daemon"
+ bug: "298459533"
+}
+
+flag {
+ name: "remove_ap_wakeup_metric_report_limit"
+ namespace: "context_hub"
+ description: "This flag controls removing a count limit on reporting the AP wakeup metric"
+ bug: "298459533"
+}
+
+flag {
+ name: "context_hub_callback_uuid_enabled"
+ namespace: "context_hub"
+ description: "Call IContextHubCallback.getUuid() to retrieve the UUID when this flag is on"
+ bug: "247124878"
+}
diff --git a/core/ble_request.cc b/core/ble_request.cc
index 7924349a..f097c0c1 100644
--- a/core/ble_request.cc
+++ b/core/ble_request.cc
@@ -32,31 +32,49 @@ bool filtersMatch(const chreBleGenericFilter &filter,
(memcmp(filter.dataMask, otherFilter.dataMask, filter.len) == 0);
}
+bool broadcasterFiltersMatch(
+ const chreBleBroadcasterAddressFilter &filter,
+ const chreBleBroadcasterAddressFilter &otherFilter) {
+ return (memcmp(filter.broadcasterAddress, otherFilter.broadcasterAddress,
+ sizeof(filter.broadcasterAddress)) == 0);
+}
+
} // namespace
-BleRequest::BleRequest() : BleRequest(0, false) {}
+BleRequest::BleRequest()
+ : BleRequest(0 /* instanceId */, false /* enable */, nullptr /* cookie */) {
+}
-BleRequest::BleRequest(uint16_t instanceId, bool enable)
+BleRequest::BleRequest(uint16_t instanceId, bool enable, const void *cookie)
: BleRequest(instanceId, enable, CHRE_BLE_SCAN_MODE_BACKGROUND,
- 0 /* reportDelayMs */, nullptr /* filter */) {}
+ 0 /* reportDelayMs */, nullptr /* filter */, cookie) {}
BleRequest::BleRequest(uint16_t instanceId, bool enable, chreBleScanMode mode,
- uint32_t reportDelayMs, const chreBleScanFilter *filter)
+ uint32_t reportDelayMs,
+ const chreBleScanFilterV1_9 *filter, const void *cookie)
: mReportDelayMs(reportDelayMs),
mInstanceId(instanceId),
mMode(mode),
mEnabled(enable),
mRssiThreshold(CHRE_BLE_RSSI_THRESHOLD_NONE),
- mStatus(RequestStatus::PENDING_REQ) {
+ mStatus(RequestStatus::PENDING_REQ),
+ mCookie(cookie) {
if (filter != nullptr) {
mRssiThreshold = filter->rssiThreshold;
- if (filter->scanFilterCount > 0) {
- if (!mFilters.resize(filter->scanFilterCount)) {
+ if (filter->genericFilterCount > 0) {
+ if (!mGenericFilters.resize(filter->genericFilterCount)) {
FATAL_ERROR("Unable to reserve filter count");
}
- for (size_t i = 0; i < filter->scanFilterCount; i++) {
- mFilters[i] = filter->scanFilters[i];
+ memcpy(mGenericFilters.data(), filter->genericFilters,
+ sizeof(chreBleGenericFilter) * filter->genericFilterCount);
+ }
+ if (filter->broadcasterAddressFilterCount > 0) {
+ if (!mBroadcasterFilters.resize(filter->broadcasterAddressFilterCount)) {
+ FATAL_ERROR("Unable to reserve broadcaster address filter count");
}
+ memcpy(mBroadcasterFilters.data(), filter->broadcasterAddressFilters,
+ sizeof(chreBleBroadcasterAddressFilter) *
+ filter->broadcasterAddressFilterCount);
}
}
}
@@ -70,9 +88,11 @@ BleRequest &BleRequest::operator=(BleRequest &&other) {
mMode = other.mMode;
mReportDelayMs = other.mReportDelayMs;
mRssiThreshold = other.mRssiThreshold;
- mFilters = std::move(other.mFilters);
+ mGenericFilters = std::move(other.mGenericFilters);
+ mBroadcasterFilters = std::move(other.mBroadcasterFilters);
mEnabled = other.mEnabled;
mStatus = other.mStatus;
+ mCookie = other.mCookie;
return *this;
}
@@ -103,10 +123,11 @@ bool BleRequest::mergeWith(const BleRequest &request) {
attributesChanged = true;
}
}
- const DynamicVector<chreBleGenericFilter> &otherFilters = request.mFilters;
+ const DynamicVector<chreBleGenericFilter> &otherFilters =
+ request.mGenericFilters;
for (const chreBleGenericFilter &otherFilter : otherFilters) {
bool addFilter = true;
- for (const chreBleGenericFilter &filter : mFilters) {
+ for (const chreBleGenericFilter &filter : mGenericFilters) {
if (filtersMatch(filter, otherFilter)) {
addFilter = false;
break;
@@ -114,7 +135,25 @@ bool BleRequest::mergeWith(const BleRequest &request) {
}
if (addFilter) {
attributesChanged = true;
- if (!mFilters.push_back(otherFilter)) {
+ if (!mGenericFilters.push_back(otherFilter)) {
+ FATAL_ERROR("Unable to merge filters");
+ }
+ }
+ }
+ const DynamicVector<chreBleBroadcasterAddressFilter>
+ &otherBroadcasterFilters = request.mBroadcasterFilters;
+ for (const chreBleBroadcasterAddressFilter &otherFilter :
+ otherBroadcasterFilters) {
+ bool addFilter = true;
+ for (const chreBleBroadcasterAddressFilter &filter : mBroadcasterFilters) {
+ if (broadcasterFiltersMatch(filter, otherFilter)) {
+ addFilter = false;
+ break;
+ }
+ }
+ if (addFilter) {
+ attributesChanged = true;
+ if (!mBroadcasterFilters.push_back(otherFilter)) {
FATAL_ERROR("Unable to merge filters");
}
}
@@ -123,14 +162,26 @@ bool BleRequest::mergeWith(const BleRequest &request) {
}
bool BleRequest::isEquivalentTo(const BleRequest &request) {
- const DynamicVector<chreBleGenericFilter> &otherFilters = request.mFilters;
- bool isEquivalent = (mEnabled && request.mEnabled && mMode == request.mMode &&
- mReportDelayMs == request.mReportDelayMs &&
- mRssiThreshold == request.mRssiThreshold &&
- mFilters.size() == otherFilters.size());
+ const DynamicVector<chreBleGenericFilter> &otherFilters =
+ request.mGenericFilters;
+ const DynamicVector<chreBleBroadcasterAddressFilter>
+ &otherBroadcasterFilters = request.mBroadcasterFilters;
+ bool isEquivalent =
+ (mEnabled && request.mEnabled && mMode == request.mMode &&
+ mReportDelayMs == request.mReportDelayMs &&
+ mRssiThreshold == request.mRssiThreshold &&
+ mGenericFilters.size() == otherFilters.size() &&
+ mBroadcasterFilters.size() == otherBroadcasterFilters.size());
if (isEquivalent) {
for (size_t i = 0; i < otherFilters.size(); i++) {
- if (!filtersMatch(mFilters[i], otherFilters[i])) {
+ if (!filtersMatch(mGenericFilters[i], otherFilters[i])) {
+ isEquivalent = false;
+ break;
+ }
+ }
+ for (size_t i = 0; i < otherBroadcasterFilters.size(); i++) {
+ if (!broadcasterFiltersMatch(mBroadcasterFilters[i],
+ otherBroadcasterFilters[i])) {
isEquivalent = false;
break;
}
@@ -165,18 +216,29 @@ void BleRequest::setRequestStatus(RequestStatus status) {
const DynamicVector<chreBleGenericFilter> &BleRequest::getGenericFilters()
const {
- return mFilters;
+ return mGenericFilters;
}
-chreBleScanFilter BleRequest::getScanFilter() const {
- return chreBleScanFilter{
- mRssiThreshold, static_cast<uint8_t>(mFilters.size()), mFilters.data()};
+const DynamicVector<chreBleBroadcasterAddressFilter> &
+BleRequest::getBroadcasterFilters() const {
+ return mBroadcasterFilters;
+}
+
+chreBleScanFilterV1_9 BleRequest::getScanFilter() const {
+ return chreBleScanFilterV1_9{
+ mRssiThreshold, static_cast<uint8_t>(mGenericFilters.size()),
+ mGenericFilters.data(), static_cast<uint8_t>(mBroadcasterFilters.size()),
+ mBroadcasterFilters.data()};
}
bool BleRequest::isEnabled() const {
return mEnabled;
}
+const void *BleRequest::getCookie() const {
+ return mCookie;
+}
+
void BleRequest::logStateToBuffer(DebugDumpWrapper &debugDump,
bool isPlatformRequest) const {
if (!isPlatformRequest) {
@@ -189,8 +251,8 @@ void BleRequest::logStateToBuffer(DebugDumpWrapper &debugDump,
" mode=%" PRIu8 " reportDelayMs=%" PRIu32 " rssiThreshold=%" PRId8,
static_cast<uint8_t>(mMode), mReportDelayMs, mRssiThreshold);
if (isPlatformRequest) {
- debugDump.print(" filters=[");
- for (const chreBleGenericFilter &filter : mFilters) {
+ debugDump.print(" genericFilters=[");
+ for (const chreBleGenericFilter &filter : mGenericFilters) {
debugDump.print("(type=%" PRIx8, filter.type);
if (filter.len > 0) {
debugDump.print(" data=%s dataMask=%s len=%" PRIu8 "), ",
@@ -200,9 +262,21 @@ void BleRequest::logStateToBuffer(DebugDumpWrapper &debugDump,
}
}
debugDump.print("]\n");
+ debugDump.print(" broadcasterAddressFilters=[");
+ for (const chreBleBroadcasterAddressFilter &filter :
+ mBroadcasterFilters) {
+ debugDump.print(
+ "(address=%02X:%02X:%02X:%02X:%02X:%02X), ",
+ filter.broadcasterAddress[5], filter.broadcasterAddress[4],
+ filter.broadcasterAddress[3], filter.broadcasterAddress[2],
+ filter.broadcasterAddress[1], filter.broadcasterAddress[0]);
+ }
+ debugDump.print("]\n");
} else {
- debugDump.print(" filterCount=%" PRIu8 "\n",
- static_cast<uint8_t>(mFilters.size()));
+ debugDump.print(" genericFilterCount=%" PRIu8
+ " broadcasterFilterCount=%" PRIu8 "\n",
+ static_cast<uint8_t>(mGenericFilters.size()),
+ static_cast<uint8_t>(mBroadcasterFilters.size()));
}
}
}
diff --git a/core/ble_request_manager.cc b/core/ble_request_manager.cc
index 469b357a..0b1237f6 100644
--- a/core/ble_request_manager.cc
+++ b/core/ble_request_manager.cc
@@ -19,7 +19,9 @@
#include "chre/core/event_loop_manager.h"
#include "chre/platform/fatal_error.h"
#include "chre/platform/log.h"
+#include "chre/util/fixed_size_vector.h"
#include "chre/util/nested_data_ptr.h"
+#include "chre/util/system/ble_util.h"
#include "chre/util/system/event_callbacks.h"
namespace chre {
@@ -46,19 +48,20 @@ void BleRequestManager::handleExistingRequest(uint16_t instanceId,
foundRequest->getRequestStatus() != RequestStatus::APPLIED) {
handleAsyncResult(instanceId, foundRequest->isEnabled(),
false /* success */, CHRE_ERROR_OBSOLETE_REQUEST,
- true /* forceUnregister */);
+ foundRequest->getCookie(), true /* forceUnregister */);
}
}
bool BleRequestManager::compliesWithBleSetting(uint16_t instanceId,
bool enabled,
bool hasExistingRequest,
- size_t requestIndex) {
+ size_t requestIndex,
+ const void *cookie) {
bool success = true;
if (enabled && !bleSettingEnabled()) {
success = false;
handleAsyncResult(instanceId, enabled, false /* success */,
- CHRE_ERROR_FUNCTION_DISABLED);
+ CHRE_ERROR_FUNCTION_DISABLED, cookie);
if (hasExistingRequest) {
bool requestChanged = false;
mRequests.removeRequest(requestIndex, &requestChanged);
@@ -85,18 +88,18 @@ bool BleRequestManager::updateRequests(BleRequest &&request,
return success;
}
-bool BleRequestManager::startScanAsync(Nanoapp *nanoapp, chreBleScanMode mode,
- uint32_t reportDelayMs,
- const struct chreBleScanFilter *filter) {
+bool BleRequestManager::startScanAsync(
+ Nanoapp *nanoapp, chreBleScanMode mode, uint32_t reportDelayMs,
+ const struct chreBleScanFilterV1_9 *filter, const void *cookie) {
CHRE_ASSERT(nanoapp);
- BleRequest request(nanoapp->getInstanceId(), true, mode, reportDelayMs,
- filter);
+ BleRequest request(nanoapp->getInstanceId(), true /* enable */, mode,
+ reportDelayMs, filter, cookie);
return configure(std::move(request));
}
-bool BleRequestManager::stopScanAsync(Nanoapp *nanoapp) {
+bool BleRequestManager::stopScanAsync(Nanoapp *nanoapp, const void *cookie) {
CHRE_ASSERT(nanoapp);
- BleRequest request(nanoapp->getInstanceId(), false /* enable */);
+ BleRequest request(nanoapp->getInstanceId(), false /* enable */, cookie);
return configure(std::move(request));
}
@@ -112,7 +115,8 @@ uint32_t BleRequestManager::disableActiveScan(const Nanoapp *nanoapp) {
return 0;
}
- BleRequest request(nanoapp->getInstanceId(), false /* enable */);
+ BleRequest request(nanoapp->getInstanceId(), false /* enable */,
+ nullptr /* cookie */);
configure(std::move(request));
return 1;
}
@@ -141,6 +145,32 @@ bool BleRequestManager::readRssiAsync(Nanoapp *nanoapp,
}
#endif
+bool BleRequestManager::flushAsync(Nanoapp *nanoapp, const void *cookie) {
+ CHRE_ASSERT(nanoapp);
+
+ bool supportsFlush =
+ getCapabilities() & CHRE_BLE_CAPABILITIES_SCAN_RESULT_BATCHING;
+ if (!supportsFlush) {
+ return false;
+ }
+
+ bool success = false;
+ const BleRequest *foundRequest =
+ mRequests.findRequest(nanoapp->getInstanceId(), nullptr);
+ if (foundRequest == nullptr) {
+ LOGE("Nanoapp with instance ID: %" PRIu16
+ " does not have an existing BLE request and cannot flush",
+ nanoapp->getInstanceId());
+ } else if (mFlushRequestQueue.full()) {
+ LOG_OOM();
+ } else {
+ mFlushRequestQueue.emplace(nanoapp->getInstanceId(), cookie);
+ success = processFlushRequests();
+ }
+
+ return success;
+}
+
void BleRequestManager::addBleRequestLog(uint32_t instanceId, bool enabled,
size_t requestIndex,
bool compliesWithBleSetting) {
@@ -165,8 +195,9 @@ bool BleRequestManager::configure(BleRequest &&request) {
uint16_t instanceId = request.getInstanceId();
uint8_t enabled = request.isEnabled();
handleExistingRequest(instanceId, &hasExistingRequest, &requestIndex);
- bool compliant = compliesWithBleSetting(instanceId, enabled,
- hasExistingRequest, requestIndex);
+ bool compliant =
+ compliesWithBleSetting(instanceId, enabled, hasExistingRequest,
+ requestIndex, request.getCookie());
if (compliant) {
success = updateRequests(std::move(request), hasExistingRequest,
&requestChanged, &requestIndex);
@@ -174,7 +205,7 @@ bool BleRequestManager::configure(BleRequest &&request) {
if (!mPlatformRequestInProgress) {
if (!requestChanged) {
handleAsyncResult(instanceId, enabled, true /* success */,
- CHRE_ERROR_NONE);
+ CHRE_ERROR_NONE, request.getCookie());
if (requestIndex < mRequests.getRequests().size()) {
mRequests.getMutableRequests()[requestIndex].setRequestStatus(
RequestStatus::APPLIED);
@@ -202,17 +233,20 @@ bool BleRequestManager::controlPlatform() {
bool success = false;
const BleRequest &maxRequest = mRequests.getCurrentMaximalRequest();
bool enable = bleSettingEnabled() && maxRequest.isEnabled();
+
if (enable) {
- chreBleScanFilter filter = maxRequest.getScanFilter();
+ chreBleScanFilterV1_9 filter = maxRequest.getScanFilter();
success = mPlatformBle.startScanAsync(
maxRequest.getMode(), maxRequest.getReportDelayMs(), &filter);
- mPendingPlatformRequest =
- BleRequest(0, enable, maxRequest.getMode(),
- maxRequest.getReportDelayMs(), &filter);
+ mPendingPlatformRequest = BleRequest(
+ 0 /* instanceId */, enable, maxRequest.getMode(),
+ maxRequest.getReportDelayMs(), &filter, nullptr /* cookie */);
} else {
success = mPlatformBle.stopScanAsync();
- mPendingPlatformRequest = BleRequest(0, enable);
+ mPendingPlatformRequest =
+ BleRequest(0 /* instanceId */, enable, nullptr /* cookie */);
}
+
if (success) {
for (BleRequest &req : mRequests.getMutableRequests()) {
if (req.getRequestStatus() == RequestStatus::PENDING_REQ) {
@@ -240,17 +274,21 @@ void BleRequestManager::freeAdvertisingEventCallback(uint16_t /* eventType */,
void BleRequestManager::handleAdvertisementEvent(
struct chreBleAdvertisementEvent *event) {
+ for (uint16_t i = 0; i < event->numReports; i++) {
+ populateLegacyAdvertisingReportFields(
+ const_cast<chreBleAdvertisingReport &>(event->reports[i]));
+ }
EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
CHRE_EVENT_BLE_ADVERTISEMENT, event, freeAdvertisingEventCallback);
}
void BleRequestManager::handlePlatformChange(bool enable, uint8_t errorCode) {
auto callback = [](uint16_t /*type*/, void *data, void *extraData) {
- bool enable = NestedDataPtr<bool>(data);
- uint8_t errorCode = NestedDataPtr<uint8_t>(extraData);
+ bool enableCb = NestedDataPtr<bool>(data);
+ uint8_t errorCodeCb = NestedDataPtr<uint8_t>(extraData);
EventLoopManagerSingleton::get()
->getBleRequestManager()
- .handlePlatformChangeSync(enable, errorCode);
+ .handlePlatformChangeSync(enableCb, errorCodeCb);
};
EventLoopManagerSingleton::get()->deferCallback(
@@ -272,7 +310,7 @@ void BleRequestManager::handlePlatformChangeSync(bool enable,
for (BleRequest &req : mRequests.getMutableRequests()) {
if (req.getRequestStatus() == RequestStatus::PENDING_RESP) {
handleAsyncResult(req.getInstanceId(), req.isEnabled(), success,
- errorCode);
+ errorCode, req.getCookie());
if (success) {
req.setRequestStatus(RequestStatus::APPLIED);
}
@@ -288,56 +326,46 @@ void BleRequestManager::handlePlatformChangeSync(bool enable,
mActivePlatformRequest = std::move(mPendingPlatformRequest);
}
- dispatchPendingRequests();
-
- // Only clear mResyncPending if the request succeeded or after all pending
- // requests are dispatched and a resync request can be issued with only the
- // requests that were previously applied.
- if (mResyncPending) {
- if (success) {
- mResyncPending = false;
- } else if (!success && !mPlatformRequestInProgress) {
- mResyncPending = false;
- updatePlatformRequest(true /* forceUpdate */);
- }
+ if (mRequests.hasRequests(RequestStatus::PENDING_REQ)) {
+ dispatchPendingRequests();
+ } else if (!success && mResyncPending) {
+ updatePlatformRequest(true /* forceUpdate */);
}
- // Finish dispatching pending requests before processing the setting change
- // request to ensure nanoapps receive CHRE_ERROR_FUNCTION_DISABLED responses.
- // If both a resync and a setting change are pending, prioritize the resync.
- // If the resync successfully completes, the PAL will be in the correct state
- // and updatePlatformRequest will not begin a new request.
- if (mSettingChangePending && !mPlatformRequestInProgress) {
+
+ if (!mPlatformRequestInProgress && mSettingChangePending) {
updatePlatformRequest();
- mSettingChangePending = false;
}
+
+ mResyncPending = false;
+ mSettingChangePending = false;
}
void BleRequestManager::dispatchPendingRequests() {
- if (mRequests.hasRequests(RequestStatus::PENDING_REQ)) {
- uint8_t errorCode = CHRE_ERROR_NONE;
- if (!bleSettingEnabled() && mRequests.isMaximalRequestEnabled()) {
- errorCode = CHRE_ERROR_FUNCTION_DISABLED;
- } else if (!controlPlatform()) {
- errorCode = CHRE_ERROR;
- }
- if (errorCode != CHRE_ERROR_NONE) {
- for (const BleRequest &req : mRequests.getRequests()) {
- if (req.getRequestStatus() == RequestStatus::PENDING_REQ) {
- handleAsyncResult(req.getInstanceId(), req.isEnabled(),
- false /* success */, errorCode);
- }
+ uint8_t errorCode = CHRE_ERROR_NONE;
+ if (!bleSettingEnabled() && mRequests.isMaximalRequestEnabled()) {
+ errorCode = CHRE_ERROR_FUNCTION_DISABLED;
+ } else if (!controlPlatform()) {
+ errorCode = CHRE_ERROR;
+ }
+ if (errorCode != CHRE_ERROR_NONE) {
+ for (const BleRequest &req : mRequests.getRequests()) {
+ if (req.getRequestStatus() == RequestStatus::PENDING_REQ) {
+ handleAsyncResult(req.getInstanceId(), req.isEnabled(),
+ false /* success */, errorCode, req.getCookie());
}
- mRequests.removeRequests(RequestStatus::PENDING_REQ);
}
+ mRequests.removeRequests(RequestStatus::PENDING_REQ);
}
}
void BleRequestManager::handleAsyncResult(uint16_t instanceId, bool enabled,
bool success, uint8_t errorCode,
+ const void *cookie,
bool forceUnregister) {
uint8_t requestType = enabled ? CHRE_BLE_REQUEST_TYPE_START_SCAN
: CHRE_BLE_REQUEST_TYPE_STOP_SCAN;
- postAsyncResultEventFatal(instanceId, requestType, success, errorCode);
+ postAsyncResultEventFatal(instanceId, requestType, success, errorCode,
+ cookie);
handleNanoappEventRegistration(instanceId, enabled, success, forceUnregister);
}
@@ -464,6 +492,21 @@ uint8_t BleRequestManager::readRssi(uint16_t connectionHandle) {
}
#endif
+void BleRequestManager::handleFlushComplete(uint8_t errorCode) {
+ if (mFlushRequestTimerHandle != CHRE_TIMER_INVALID) {
+ EventLoopManagerSingleton::get()->cancelDelayedCallback(
+ mFlushRequestTimerHandle);
+ mFlushRequestTimerHandle = CHRE_TIMER_INVALID;
+ }
+
+ handleFlushCompleteInternal(errorCode);
+}
+
+void BleRequestManager::handleFlushCompleteTimeout() {
+ mFlushRequestTimerHandle = CHRE_TIMER_INVALID;
+ handleFlushCompleteInternal(CHRE_ERROR_TIMEOUT);
+}
+
bool BleRequestManager::getScanStatus(struct chreBleScanStatus * /* status */) {
// TODO(b/266820139): Implement this
return false;
@@ -496,6 +539,106 @@ void BleRequestManager::updatePlatformRequest(bool forceUpdate) {
}
}
+void BleRequestManager::handleFlushCompleteInternal(uint8_t errorCode) {
+ auto callback = [](uint16_t /* type */, void *data, void * /* extraData */) {
+ uint8_t cbErrorCode = NestedDataPtr<uint8_t>(data);
+ EventLoopManagerSingleton::get()
+ ->getBleRequestManager()
+ .handleFlushCompleteSync(cbErrorCode);
+ };
+
+ if (!EventLoopManagerSingleton::get()->deferCallback(
+ SystemCallbackType::BleFlushComplete,
+ NestedDataPtr<uint8_t>(errorCode), callback)) {
+ FATAL_ERROR("Unable to defer flush complete callback");
+ }
+}
+
+void BleRequestManager::handleFlushCompleteSync(uint8_t errorCode) {
+ if (mFlushRequestQueue.empty() || !mFlushRequestQueue.front().isActive) {
+ LOGE(
+ "handleFlushCompleteSync was called, but there is no active flush "
+ "request");
+ return;
+ }
+
+ FlushRequest &flushRequest = mFlushRequestQueue.front();
+ sendFlushCompleteEventOrDie(flushRequest, errorCode);
+ mFlushRequestQueue.pop();
+
+ processFlushRequests();
+}
+
+uint8_t BleRequestManager::doFlushRequest() {
+ CHRE_ASSERT(!mFlushRequestQueue.empty());
+
+ FlushRequest &flushRequest = mFlushRequestQueue.front();
+ if (flushRequest.isActive) {
+ return CHRE_ERROR_NONE;
+ }
+
+ Nanoseconds now = SystemTime::getMonotonicTime();
+ uint8_t errorCode = CHRE_ERROR_NONE;
+ if (now >= flushRequest.deadlineTimestamp) {
+ LOGE("BLE flush request for nanoapp with instance ID: %" PRIu16
+ " failed: deadline exceeded",
+ flushRequest.nanoappInstanceId);
+ errorCode = CHRE_ERROR_TIMEOUT;
+ } else {
+ auto timeoutCallback = [](uint16_t /* type */, void * /* data */,
+ void * /* extraData */) {
+ EventLoopManagerSingleton::get()
+ ->getBleRequestManager()
+ .handleFlushCompleteTimeout();
+ };
+ mFlushRequestTimerHandle =
+ EventLoopManagerSingleton::get()->setDelayedCallback(
+ SystemCallbackType::BleFlushTimeout, nullptr, timeoutCallback,
+ flushRequest.deadlineTimestamp - now);
+
+ if (!mPlatformBle.flushAsync()) {
+ LOGE("Could not request flush from BLE platform");
+ errorCode = CHRE_ERROR;
+ EventLoopManagerSingleton::get()->cancelDelayedCallback(
+ mFlushRequestTimerHandle);
+ mFlushRequestTimerHandle = CHRE_TIMER_INVALID;
+ } else {
+ flushRequest.isActive = true;
+ }
+ }
+ return errorCode;
+}
+
+void BleRequestManager::sendFlushCompleteEventOrDie(
+ const FlushRequest &flushRequest, uint8_t errorCode) {
+ chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
+ if (event == nullptr) {
+ FATAL_ERROR("Unable to allocate chreAsyncResult");
+ }
+
+ event->requestType = CHRE_BLE_REQUEST_TYPE_FLUSH;
+ event->success = errorCode == CHRE_ERROR_NONE;
+ event->errorCode = errorCode;
+ event->reserved = 0;
+ event->cookie = flushRequest.cookie;
+ EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+ CHRE_EVENT_BLE_FLUSH_COMPLETE, event, freeEventDataCallback,
+ flushRequest.nanoappInstanceId);
+}
+
+bool BleRequestManager::processFlushRequests() {
+ while (!mFlushRequestQueue.empty()) {
+ uint8_t errorCode = doFlushRequest();
+ if (errorCode == CHRE_ERROR_NONE) {
+ return true;
+ }
+
+ sendFlushCompleteEventOrDie(mFlushRequestQueue.front(), errorCode);
+ mFlushRequestQueue.pop();
+ }
+ return false;
+}
+
// TODO(b/290860901): require data & ~mask == 0
bool BleRequestManager::validateParams(const BleRequest &request) {
bool valid = true;
@@ -517,7 +660,8 @@ bool BleRequestManager::validateParams(const BleRequest &request) {
void BleRequestManager::postAsyncResultEventFatal(uint16_t instanceId,
uint8_t requestType,
bool success,
- uint8_t errorCode) {
+ uint8_t errorCode,
+ const void *cookie) {
chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
if (event == nullptr) {
FATAL_ERROR("Failed to alloc BLE async result");
@@ -525,6 +669,7 @@ void BleRequestManager::postAsyncResultEventFatal(uint16_t instanceId,
event->requestType = requestType;
event->success = success;
event->errorCode = errorCode;
+ event->cookie = cookie;
event->reserved = 0;
EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
@@ -566,10 +711,11 @@ void BleRequestManager::logStateToBuffer(DebugDumpWrapper &debugDump) const {
log.timestamp.toRawNanoseconds(), log.instanceId,
log.enable ? "enable" : "disable\n");
if (log.enable && log.compliesWithBleSetting) {
- debugDump.print(" mode=%" PRIu8 " reportDelayMs=%" PRIu32
- " rssiThreshold=%" PRId8 " scanCount=%" PRIu8 "\n",
- static_cast<uint8_t>(log.mode), log.reportDelayMs,
- log.rssiThreshold, log.scanFilterCount);
+ debugDump.print(
+ " mode=%" PRIu8 " reportDelayMs=%" PRIu32 " rssiThreshold=%" PRId8
+ " scanCount=%" PRIu8 " broadcasterAddressCount=%" PRIu8 "\n",
+ static_cast<uint8_t>(log.mode), log.reportDelayMs, log.rssiThreshold,
+ log.scanFilterCount, log.broadcasterFilterCount);
} else if (log.enable) {
debugDump.print(" request did not comply with BLE setting\n");
}
diff --git a/core/ble_request_multiplexer.cc b/core/ble_request_multiplexer.cc
index eb32b33a..13a9ec1b 100644
--- a/core/ble_request_multiplexer.cc
+++ b/core/ble_request_multiplexer.cc
@@ -26,9 +26,11 @@ DynamicVector<BleRequest> &BleRequestMultiplexer::getMutableRequests() {
const BleRequest *BleRequestMultiplexer::findRequest(uint16_t instanceId,
size_t *index) {
- for (size_t i = 0; i < mRequests.size(); i++) {
+ for (size_t i = 0; i < mRequests.size(); ++i) {
if (mRequests[i].getInstanceId() == instanceId) {
- *index = i;
+ if (index != nullptr) {
+ *index = i;
+ }
return &mRequests[i];
}
}
diff --git a/core/event_loop.cc b/core/event_loop.cc
index 56354c91..493d457b 100644
--- a/core/event_loop.cc
+++ b/core/event_loop.cc
@@ -192,10 +192,6 @@ bool EventLoop::startNanoapp(UniquePtr<Nanoapp> &nanoapp) {
} else if (!mNanoapps.prepareForPush()) {
LOG_OOM();
} else {
- nanoapp->setInstanceId(eventLoopManager->getNextInstanceId());
- LOGD("Instance ID %" PRIu16 " assigned to app ID 0x%016" PRIx64,
- nanoapp->getInstanceId(), nanoapp->getAppId());
-
Nanoapp *newNanoapp = nanoapp.get();
{
LockGuard<Mutex> lock(mNanoappsLock);
@@ -208,16 +204,10 @@ bool EventLoop::startNanoapp(UniquePtr<Nanoapp> &nanoapp) {
success = newNanoapp->start();
mCurrentApp = nullptr;
if (!success) {
- // TODO: to be fully safe, need to purge/flush any events and messages
- // sent by the nanoapp here (but don't call nanoappEnd). For now, we just
- // destroy the Nanoapp instance.
LOGE("Nanoapp %" PRIu16 " failed to start", newNanoapp->getInstanceId());
-
- // Note that this lock protects against concurrent read and modification
- // of mNanoapps, but we are assured that no new nanoapps were added since
- // we pushed the new nanoapp
- LockGuard<Mutex> lock(mNanoappsLock);
- mNanoapps.pop_back();
+ unloadNanoapp(newNanoapp->getInstanceId(),
+ /*allowSystemNanoappUnload=*/true,
+ /*nanoappStarted=*/false);
} else {
notifyAppStatusChange(CHRE_EVENT_NANOAPP_STARTED, *newNanoapp);
}
@@ -227,7 +217,8 @@ bool EventLoop::startNanoapp(UniquePtr<Nanoapp> &nanoapp) {
}
bool EventLoop::unloadNanoapp(uint16_t instanceId,
- bool allowSystemNanoappUnload) {
+ bool allowSystemNanoappUnload,
+ bool nanoappStarted) {
bool unloaded = false;
for (size_t i = 0; i < mNanoapps.size(); i++) {
@@ -252,13 +243,17 @@ bool EventLoop::unloadNanoapp(uint16_t instanceId,
flushInboundEventQueue();
// Post the unload event now (so we can reference the Nanoapp instance
- // directly), but nanoapps won't get it until after the unload completes
- notifyAppStatusChange(CHRE_EVENT_NANOAPP_STOPPED, *mStoppingNanoapp);
+ // directly), but nanoapps won't get it until after the unload
+ // completes. No need to notify status change if nanoapps failed to
+ // start.
+ if (nanoappStarted) {
+ notifyAppStatusChange(CHRE_EVENT_NANOAPP_STOPPED, *mStoppingNanoapp);
+ }
// Finally, we are at a point where there should not be any pending
// events or messages sent by the app that could potentially reference
// the nanoapp's memory, so we are safe to unload it
- unloadNanoappAtIndex(i);
+ unloadNanoappAtIndex(i, nanoappStarted);
mStoppingNanoapp = nullptr;
LOGD("Unloaded nanoapp with instanceId %" PRIu16, instanceId);
@@ -303,7 +298,7 @@ void EventLoop::postEventOrDie(uint16_t eventType, void *eventData,
if (mRunning) {
if (hasNoSpaceForHighPriorityEvent() ||
!allocateAndPostEvent(eventType, eventData, freeCallback,
- false /*isLowPriority*/, kSystemInstanceId,
+ /* isLowPriority= */ false, kSystemInstanceId,
targetInstanceId, targetGroupMask)) {
FATAL_ERROR("Failed to post critical system event 0x%" PRIx16, eventType);
}
@@ -343,20 +338,14 @@ bool EventLoop::postLowPriorityEventOrFree(
bool eventPosted = false;
if (mRunning) {
-#ifdef CHRE_STATIC_EVENT_LOOP
- if (mEventPool.getFreeBlockCount() > kMinReservedHighPriorityEventCount)
-#else
- if (mEventPool.getFreeSpaceCount() > kMinReservedHighPriorityEventCount)
-#endif
- {
- eventPosted = allocateAndPostEvent(
- eventType, eventData, freeCallback, true /*isLowPriority*/,
- senderInstanceId, targetInstanceId, targetGroupMask);
- if (!eventPosted) {
- LOGE("Failed to allocate event 0x%" PRIx16 " to instanceId %" PRIu16,
- eventType, targetInstanceId);
- ++mNumDroppedLowPriEvents;
- }
+ eventPosted =
+ allocateAndPostEvent(eventType, eventData, freeCallback,
+ /* isLowPriority= */ true, senderInstanceId,
+ targetInstanceId, targetGroupMask);
+ if (!eventPosted) {
+ LOGE("Failed to allocate event 0x%" PRIx16 " to instanceId %" PRIu16,
+ eventType, targetInstanceId);
+ ++mNumDroppedLowPriEvents;
}
}
@@ -421,12 +410,25 @@ void EventLoop::logStateToBuffer(DebugDumpWrapper &debugDump) const {
uint64_t durationMins =
kIntervalWakeupBucket.toRawNanoseconds() / kOneMinuteInNanoseconds;
debugDump.print(" Nanoapp host wakeup tracking: cycled %" PRIu64
- "mins ago, bucketDuration=%" PRIu64 "mins\n",
+ " mins ago, bucketDuration=%" PRIu64 "mins\n",
timeSinceMins, durationMins);
debugDump.print("\nNanoapps:\n");
- for (const UniquePtr<Nanoapp> &app : mNanoapps) {
- app->logStateToBuffer(debugDump);
+
+ if (mNanoapps.size()) {
+ for (const UniquePtr<Nanoapp> &app : mNanoapps) {
+ app->logStateToBuffer(debugDump);
+ }
+
+ mNanoapps[0]->logMemAndComputeHeader(debugDump);
+ for (const UniquePtr<Nanoapp> &app : mNanoapps) {
+ app->logMemAndComputeEntry(debugDump);
+ }
+
+ mNanoapps[0]->logMessageHistoryHeader(debugDump);
+ for (const UniquePtr<Nanoapp> &app : mNanoapps) {
+ app->logMessageHistoryEntry(debugDump);
+ }
}
}
@@ -534,7 +536,7 @@ void EventLoop::notifyAppStatusChange(uint16_t eventType,
}
}
-void EventLoop::unloadNanoappAtIndex(size_t index) {
+void EventLoop::unloadNanoappAtIndex(size_t index, bool nanoappStarted) {
const UniquePtr<Nanoapp> &nanoapp = mNanoapps[index];
// Lock here to prevent the nanoapp instance from being accessed between the
@@ -543,7 +545,12 @@ void EventLoop::unloadNanoappAtIndex(size_t index) {
// Let the app know it's going away
mCurrentApp = nanoapp.get();
- nanoapp->end();
+
+ // nanoappEnd() is not invoked for nanoapps that return false in
+ // nanoappStart(), per CHRE API
+ if (nanoappStarted) {
+ nanoapp->end();
+ }
// Cleanup resources.
#ifdef CHRE_WIFI_SUPPORT_ENABLED
@@ -594,21 +601,19 @@ void EventLoop::unloadNanoappAtIndex(size_t index) {
nanoapp.get());
logDanglingResources("heap blocks", numFreedBlocks);
- mCurrentApp = nullptr;
-
// Destroy the Nanoapp instance
mNanoapps.erase(index);
+
+ mCurrentApp = nullptr;
}
void EventLoop::handleNanoappWakeupBuckets() {
Nanoseconds now = SystemTime::getMonotonicTime();
Nanoseconds duration = now - mTimeLastWakeupBucketCycled;
if (duration > kIntervalWakeupBucket) {
- size_t numBuckets = static_cast<size_t>(
- duration.toRawNanoseconds() / kIntervalWakeupBucket.toRawNanoseconds());
mTimeLastWakeupBucketCycled = now;
for (auto &nanoapp : mNanoapps) {
- nanoapp->cycleWakeupBuckets(numBuckets);
+ nanoapp->cycleWakeupBuckets(now);
}
}
}
diff --git a/core/event_loop_manager.cc b/core/event_loop_manager.cc
index 51167711..4baf5d63 100644
--- a/core/event_loop_manager.cc
+++ b/core/event_loop_manager.cc
@@ -16,6 +16,7 @@
#include "chre/core/event_loop_manager.h"
+#include "chre/platform/atomic.h"
#include "chre/platform/fatal_error.h"
#include "chre/platform/memory.h"
#include "chre/util/lock_guard.h"
@@ -31,18 +32,19 @@ Nanoapp *EventLoopManager::validateChreApiCall(const char *functionName) {
}
uint16_t EventLoopManager::getNextInstanceId() {
- ++mLastInstanceId;
+ // Get the next available instance ID and mask off the upper 16 bit.
+ uint16_t instanceId =
+ static_cast<uint16_t>(mNextInstanceId.fetch_increment() & 0x0000FFFF);
- // ~4 billion instance IDs should be enough for anyone... if we need to
+ // 65536 instance IDs should be enough for normal use cases. If we need to
// support wraparound for stress testing load/unload, then we can set a flag
// when wraparound occurs and use EventLoop::findNanoappByInstanceId to ensure
// we avoid conflicts
- if (mLastInstanceId == kBroadcastInstanceId ||
- mLastInstanceId == kSystemInstanceId) {
+ if (instanceId == kBroadcastInstanceId || instanceId == kSystemInstanceId) {
FATAL_ERROR("Exhausted instance IDs!");
}
- return mLastInstanceId;
+ return instanceId;
}
void EventLoopManager::lateInit() {
diff --git a/core/host_comms_manager.cc b/core/host_comms_manager.cc
index 81afa58e..102813fa 100644
--- a/core/host_comms_manager.cc
+++ b/core/host_comms_manager.cc
@@ -20,6 +20,7 @@
#include "chre/core/event_loop_manager.h"
#include "chre/core/host_comms_manager.h"
#include "chre/platform/assert.h"
+#include "chre/platform/context.h"
#include "chre/platform/host_link.h"
#include "chre/util/macros.h"
@@ -67,13 +68,17 @@ bool HostCommsManager::sendMessageToHostFromNanoapp(
success = HostLink::sendMessage(msgToHost);
if (!success) {
mMessagePool.deallocate(msgToHost);
- } else if (wokeHost) {
- // If message successfully sent and host was suspended before sending
- EventLoopManagerSingleton::get()
- ->getEventLoop()
- .handleNanoappWakeupBuckets();
- mIsNanoappBlamedForWakeup = true;
- nanoapp->blameHostWakeup();
+ } else {
+ if (wokeHost) {
+ // If message successfully sent and host was suspended before sending
+ EventLoopManagerSingleton::get()
+ ->getEventLoop()
+ .handleNanoappWakeupBuckets();
+ mIsNanoappBlamedForWakeup = true;
+ nanoapp->blameHostWakeup();
+ }
+ // Record the nanoapp having sent a message to the host
+ nanoapp->blameHostMessageSent();
}
}
}
@@ -196,6 +201,11 @@ void HostCommsManager::onMessageToHostComplete(const MessageToHost *message) {
// EventLoop context.
if (msgToHost->toHostData.nanoappFreeFunction == nullptr) {
mMessagePool.deallocate(msgToHost);
+ } else if (inEventLoopThread()) {
+ // If we're already within the event pool context, it is safe to call the
+ // free callback synchronously.
+ EventLoopManagerSingleton::get()->getHostCommsManager().freeMessageToHost(
+ msgToHost);
} else {
auto freeMsgCallback = [](uint16_t /*type*/, void *data,
void * /*extraData*/) {
diff --git a/core/include/chre/core/ble_request.h b/core/include/chre/core/ble_request.h
index 66667fb3..e442e795 100644
--- a/core/include/chre/core/ble_request.h
+++ b/core/include/chre/core/ble_request.h
@@ -40,10 +40,11 @@ class BleRequest : public NonCopyable {
public:
BleRequest();
- BleRequest(uint16_t instanceId, bool enable);
+ BleRequest(uint16_t instanceId, bool enable, const void *cookie);
BleRequest(uint16_t instanceId, bool enable, chreBleScanMode mode,
- uint32_t reportDelayMs, const chreBleScanFilter *filter);
+ uint32_t reportDelayMs, const chreBleScanFilterV1_9 *filter,
+ const void *cookie);
BleRequest(BleRequest &&other);
@@ -103,10 +104,21 @@ class BleRequest : public NonCopyable {
const DynamicVector<chreBleGenericFilter> &getGenericFilters() const;
/**
- * @return chreBleScanFilter that is valid only as long as the internal
+ * @return Broadcaster address filters of this request.
+ */
+ const DynamicVector<chreBleBroadcasterAddressFilter> &getBroadcasterFilters()
+ const;
+
+ /**
+ * @return The cookie this request.
+ */
+ const void *getCookie() const;
+
+ /**
+ * @return chreBleScanFilterV1_9 that is valid only as long as the internal
* contents of this class are not modified
*/
- chreBleScanFilter getScanFilter() const;
+ chreBleScanFilterV1_9 getScanFilter() const;
/**
* @return true if nanoapp intends to enable a request.
@@ -136,7 +148,7 @@ class BleRequest : public NonCopyable {
chreBleScanMode mMode;
// Whether a nanoapp intends to enable this request. If set to false, the
- // following members are invalid: mMode, mReportDelayMs, mFilter.
+ // following members are invalid: mMode, mReportDelayMs, mGenericFilters.
bool mEnabled;
// RSSI threshold filter.
@@ -148,7 +160,13 @@ class BleRequest : public NonCopyable {
RequestStatus mStatus;
// Generic scan filters.
- DynamicVector<chreBleGenericFilter> mFilters;
+ DynamicVector<chreBleGenericFilter> mGenericFilters;
+
+ // Broadcaster address filters.
+ DynamicVector<chreBleBroadcasterAddressFilter> mBroadcasterFilters;
+
+ // Cookie value included in this request, supplied by the nanoapp.
+ const void *mCookie;
};
} // namespace chre
diff --git a/core/include/chre/core/ble_request_manager.h b/core/include/chre/core/ble_request_manager.h
index 747b5a72..16d280fc 100644
--- a/core/include/chre/core/ble_request_manager.h
+++ b/core/include/chre/core/ble_request_manager.h
@@ -21,7 +21,9 @@
#include "chre/core/ble_request_multiplexer.h"
#include "chre/core/nanoapp.h"
#include "chre/core/settings.h"
+#include "chre/core/timer_pool.h"
#include "chre/platform/platform_ble.h"
+#include "chre/platform/system_time.h"
#include "chre/util/array_queue.h"
#include "chre/util/non_copyable.h"
#include "chre/util/system/debug_dump.h"
@@ -61,24 +63,29 @@ class BleRequestManager : public NonCopyable {
* batching. Note that the system may deliver results
* before the maximum specified delay is reached.
* @param filter Pointer to the requested best-effort filter configuration as
- * defined by struct chreBleScanFilter. The ownership of filter
- * and its nested elements remains with the caller, and the
- * caller may release it as soon as chreBleStartScanAsync()
- * returns.
+ * defined by struct chreBleScanFilterV1_9. The ownership of
+ * filter and its nested elements remains with the caller, and
+ * the caller may release it as soon as
+ * chreBleStartScanAsyncV1_9() returns.
+ * @param cookie The cookie to be provided to the nanoapp. This is
+ * round-tripped from the nanoapp to provide context.
* @return true if scan was successfully enabled.
*/
bool startScanAsync(Nanoapp *nanoapp, chreBleScanMode mode,
uint32_t reportDelayMs,
- const struct chreBleScanFilter *filter);
+ const struct chreBleScanFilterV1_9 *filter,
+ const void *cookie);
/**
* End a BLE scan asynchronously. The result is delivered through a
* CHRE_EVENT_BLE_ASYNC_RESULT event.
*
* @param nanoapp The nanoapp stopping the request.
+ * @param cookie A cookie that is round-tripped back to the nanoapp to
+ * provide a context when making the request.
* @return whether the scan was successfully ended.
*/
- bool stopScanAsync(Nanoapp *nanoapp);
+ bool stopScanAsync(Nanoapp *nanoapp, const void *cookie);
#ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED
/**
@@ -111,6 +118,18 @@ class BleRequestManager : public NonCopyable {
#endif
/**
+ * Initiates a flush operation where all batched advertisement events will be
+ * immediately processed and delivered. The nanoapp must have an existing
+ * active BLE scan.
+ *
+ * @param nanoapp the nanoapp requesting the flush operation.
+ * @param cookie the cookie value stored with the request.
+ * @return true if the request has been accepted and dispatched to the
+ * controller. false otherwise.
+ */
+ bool flushAsync(Nanoapp *nanoapp, const void *cookie);
+
+ /**
* Disables active scan for a nanoapp (no-op if no active scan).
*
* @param nanoapp A non-null pointer to the nanoapp.
@@ -173,6 +192,17 @@ class BleRequestManager : public NonCopyable {
#endif
/**
+ * Handler for the flush complete operation. Called when a flush operation is
+ * complete. Processes in an asynchronous manner.
+ *
+ * @param errorCode the error code from the flush operation.
+ */
+ void handleFlushComplete(uint8_t errorCode);
+
+ //! Timeout handler for the flush operation. Called on a timeout.
+ void handleFlushCompleteTimeout();
+
+ /**
* Retrieves the current scan status.
*
* @param status A non-null pointer to where the scan status will be
@@ -201,6 +231,23 @@ class BleRequestManager : public NonCopyable {
void logStateToBuffer(DebugDumpWrapper &debugDump) const;
private:
+ //! An internal structure to store incoming sensor flush requests
+ struct FlushRequest {
+ FlushRequest(uint16_t id, const void *cookiePtr)
+ : nanoappInstanceId(id), cookie(cookiePtr) {}
+
+ //! The timestamp at which this request should complete.
+ Nanoseconds deadlineTimestamp =
+ SystemTime::getMonotonicTime() +
+ Nanoseconds(CHRE_BLE_FLUSH_COMPLETE_TIMEOUT_NS);
+ //! The ID of the nanoapp that requested the flush.
+ uint16_t nanoappInstanceId;
+ //! The opaque pointer provided in flushAsync().
+ const void *cookie;
+ //! True if this flush request is active and is pending completion.
+ bool isActive = false;
+ };
+
// Multiplexer used to keep track of BLE requests from nanoapps.
BleRequestMultiplexer mRequests;
@@ -222,6 +269,13 @@ class BleRequestManager : public NonCopyable {
// True if a setting change request is pending to be processed.
bool mSettingChangePending;
+ //! A queue of flush requests made by nanoapps.
+ static constexpr size_t kMaxFlushRequests = 16;
+ ArrayQueue<FlushRequest, kMaxFlushRequests> mFlushRequestQueue;
+
+ //! The timer handle for the flush operation. Used to track a flush timeout.
+ TimerHandle mFlushRequestTimerHandle = CHRE_TIMER_INVALID;
+
#ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED
// A pending request from a nanoapp
struct BleReadRssiRequest {
@@ -238,17 +292,19 @@ class BleRequestManager : public NonCopyable {
// Struct to hold ble request data for logging
struct BleRequestLog {
- BleRequestLog(Nanoseconds timestamp, uint32_t instanceId, bool enable,
- bool compliesWithBleSetting)
- : timestamp(timestamp),
- instanceId(instanceId),
- enable(enable),
- compliesWithBleSetting(compliesWithBleSetting) {}
+ BleRequestLog(Nanoseconds timestamp_, uint32_t instanceId_, bool enable_,
+ bool compliesWithBleSetting_)
+ : timestamp(timestamp_),
+ instanceId(instanceId_),
+ enable(enable_),
+ compliesWithBleSetting(compliesWithBleSetting_) {}
void populateRequestData(const BleRequest &req) {
mode = req.getMode();
reportDelayMs = req.getReportDelayMs();
rssiThreshold = req.getRssiThreshold();
scanFilterCount = static_cast<uint8_t>(req.getGenericFilters().size());
+ broadcasterFilterCount =
+ static_cast<uint8_t>(req.getBroadcasterFilters().size());
}
Nanoseconds timestamp;
uint32_t instanceId;
@@ -258,6 +314,7 @@ class BleRequestManager : public NonCopyable {
uint32_t reportDelayMs;
int8_t rssiThreshold;
uint8_t scanFilterCount;
+ uint8_t broadcasterFilterCount;
};
// List of most recent ble request logs
@@ -301,11 +358,13 @@ class BleRequestManager : public NonCopyable {
* to the nanoapp instance id of the new request.
* @param requestIndex If hasExistingRequest is true, requestIndex
* corresponds to the index of that request.
+ * @param cookie The cookie to be provided to the nanoapp.
* @return true if the request does not attempt to enable the platform while
* the BLE setting is disabled.
*/
bool compliesWithBleSetting(uint16_t instanceId, bool enabled,
- bool hasExistingRequest, size_t requestIndex);
+ bool hasExistingRequest, size_t requestIndex,
+ const void *cookie);
/**
* Add a log to list of BLE request logs possibly pushing out the oldest log.
@@ -375,10 +434,13 @@ class BleRequestManager : public NonCopyable {
* @param success Whether the request was processed by the PAL successfully
* @param errorCode Error code resulting from the request
* @param forceUnregister Whether the nanoapp should be force unregistered
+ * @param cookie The cookie to be provided to the nanoapp. This is
+ * round-tripped from the nanoapp to provide context.
* from BLE broadcast events.
*/
void handleAsyncResult(uint16_t instanceId, bool enabled, bool success,
- uint8_t errorCode, bool forceUnregister = false);
+ uint8_t errorCode, const void *cookie,
+ bool forceUnregister = false);
/**
* Invoked as a result of a requestStateResync() callback from the BLE PAL.
@@ -396,6 +458,54 @@ class BleRequestManager : public NonCopyable {
void updatePlatformRequest(bool forceUpdate = false);
/**
+ * Helper function for flush complete handling in all cases - normal and
+ * timeout. This function defers a call to handleFlushCompleteSync.
+ *
+ * @param errorCode the error code for the flush operation.
+ */
+ void handleFlushCompleteInternal(uint8_t errorCode);
+
+ /**
+ * Synchronously processed a flush complete operation. Starts a new flush
+ * operation if there is one in the queue. Properly sends the flush complete
+ * event.
+ *
+ * @param errorCode the error code for the flush operation.
+ */
+ void handleFlushCompleteSync(uint8_t errorCode);
+
+ /**
+ * Sends the flush request to the controller if there is a non-active flush
+ * request in the flush request queue. Sets the timer callback to handle
+ * timeouts.
+ *
+ * @return the error code, chreError enum (CHRE_ERROR_NONE for success).
+ */
+ uint8_t doFlushRequest();
+
+ /**
+ * Sends the flush complete event or aborts CHRE.
+ *
+ * @param flushRequest the current active flush request.
+ * @param errorCode the error code, chreError enum.
+ */
+ void sendFlushCompleteEventOrDie(const FlushRequest &flushRequest,
+ uint8_t errorCode);
+
+ /**
+ * Processes flush requests in the flush request queue in order. Calls
+ * doFlushRequest on the request. If an error is detected, it sends the flush
+ * complete event with the error. This function continues to process requests
+ * until one flush request is successfully made. Once this happens, the
+ * request manager waits for a timeout or for a callback from the BLE
+ * platform.
+ *
+ * @return true if there was one flush request that was successfully
+ * initiated, false otherwise.
+ */
+ bool processFlushRequests();
+
+ /**
* Validates the parameters given to ensure that they can be issued to the
* PAL.
*
@@ -410,10 +520,11 @@ class BleRequestManager : public NonCopyable {
* @param requestType The type of BLE request the nanoapp issued.
* @param success true if the operation was successful.
* @param errorCode the error code as a result of this operation.
+ * @param cookie The cookie to be provided to the nanoapp.
*/
static void postAsyncResultEventFatal(uint16_t instanceId,
uint8_t requestType, bool success,
- uint8_t errorCode);
+ uint8_t errorCode, const void *cookie);
/**
* @return True if the given advertisement type is valid
diff --git a/core/include/chre/core/ble_request_multiplexer.h b/core/include/chre/core/ble_request_multiplexer.h
index 46357852..e25747c9 100644
--- a/core/include/chre/core/ble_request_multiplexer.h
+++ b/core/include/chre/core/ble_request_multiplexer.h
@@ -43,12 +43,12 @@ class BleRequestMultiplexer : public RequestMultiplexer<BleRequest> {
/**
* Searches through the list of BLE requests for a request owned by the
- * given nanoapp. The provided non-null index pointer is populated with the
- * index of the request if it is found.
+ * given nanoapp. The provided index pointer is populated with the
+ * index of the request if it is found and the pointer is not null.
*
* @param instanceId The instance ID of the nanoapp whose request is being
* searched for.
- * @param index A non-null pointer to an index that is populated if a
+ * @param index A pointer to an index that is populated if a
* request for this nanoapp is found.
* @return A pointer to a BleRequest that is owned by the provided
* nanoapp if one is found otherwise nullptr.
diff --git a/core/include/chre/core/event_loop.h b/core/include/chre/core/event_loop.h
index 34034109..6a64956f 100644
--- a/core/include/chre/core/event_loop.h
+++ b/core/include/chre/core/event_loop.h
@@ -57,13 +57,6 @@
#define CHRE_MAX_EVENT_BLOCKS 4
#endif
-#ifndef CHRE_UNSCHEDULED_EVENT_PER_BLOCK
-#define CHRE_UNSCHEDULED_EVENT_PER_BLOCK 24
-#endif
-
-#ifndef CHRE_MAX_UNSCHEDULED_EVENT_BLOCKS
-#define CHRE_MAX_UNSCHEDULED_EVENT_BLOCKS 4
-#endif
#endif
namespace chre {
@@ -78,7 +71,7 @@ class EventLoop : public NonCopyable {
EventLoop()
:
#ifndef CHRE_STATIC_EVENT_LOOP
- mEvents(kMaxUnscheduleEventBlocks),
+ mEvents(kMaxEventBlock),
#endif
mTimeLastWakeupBucketCycled(SystemTime::getMonotonicTime()),
mRunning(true) {
@@ -159,10 +152,12 @@ class EventLoop : public NonCopyable {
* @param instanceId The nanoapp's unique instance identifier
* @param allowSystemNanoappUnload If false, this function will reject
* attempts to unload a system nanoapp
+ * @param nanoappStarted Indicates whether the nanoapp successfully started
*
* @return true if the nanoapp with the given instance ID was found & unloaded
*/
- bool unloadNanoapp(uint16_t instanceId, bool allowSystemNanoappUnload);
+ bool unloadNanoapp(uint16_t instanceId, bool allowSystemNanoappUnload,
+ bool nanoappStarted = true);
/**
* Executes the loop that blocks on the event queue and delivers received
@@ -356,10 +351,6 @@ class EventLoop : public NonCopyable {
//! The maximum number of events that can be active in the system.
static constexpr size_t kMaxEventCount = CHRE_MAX_EVENT_COUNT;
- //! The minimum number of events to reserve in the event pool for high
- //! priority events.
- static constexpr size_t kMinReservedHighPriorityEventCount = 16;
-
//! The maximum number of events that are awaiting to be scheduled. These
//! events are in a queue to be distributed to apps.
static constexpr size_t kMaxUnscheduledEventCount =
@@ -382,28 +373,15 @@ class EventLoop : public NonCopyable {
static constexpr size_t kMaxEventCount =
CHRE_EVENT_PER_BLOCK * CHRE_MAX_EVENT_BLOCKS;
- //! The minimum number of events to reserve in the event pool for high
- //! priority events.
- static constexpr size_t kMinReservedHighPriorityEventCount = 16;
-
- //! The maximum number of events per block that are awaiting to be scheduled.
- //! These events are in a queue to be distributed to apps.
- static constexpr size_t kMaxUnscheduledEventPerBlock =
- CHRE_UNSCHEDULED_EVENT_PER_BLOCK;
-
- //! The maximum number of event blocks that mEvents can hold.
- static constexpr size_t kMaxUnscheduleEventBlocks =
- CHRE_MAX_UNSCHEDULED_EVENT_BLOCKS;
-
//! The memory pool to allocate incoming events from.
SynchronizedExpandableMemoryPool<Event, kEventPerBlock, kMaxEventBlock>
mEventPool;
//! The blocking queue of incoming events from the system that have not been
//! distributed out to apps yet.
- BlockingSegmentedQueue<Event *, kMaxUnscheduledEventPerBlock> mEvents;
+ BlockingSegmentedQueue<Event *, kEventPerBlock> mEvents;
#endif
- //! The time interval of nanoapp wakeup buckets, adjust in conjuction with
+ //! The time interval of nanoapp wakeup buckets, adjust in conjunction with
//! Nanoapp::kMaxSizeWakeupBuckets.
static constexpr Nanoseconds kIntervalWakeupBucket =
Nanoseconds(180 * kOneMinuteInNanoseconds);
@@ -551,8 +529,12 @@ class EventLoop : public NonCopyable {
* be any pending events in this nanoapp's queue, and there must not be any
* outstanding events sent by this nanoapp, as they may reference the
* nanoapp's own memory (even if there is no free callback).
+ *
+ * @param index Index of the nanoapp in the list of nanoapps managed by event
+ * loop.
+ * @param nanoappStarted Indicates whether the nanoapp successfully started
*/
- void unloadNanoappAtIndex(size_t index);
+ void unloadNanoappAtIndex(size_t index, bool nanoappStarted = true);
/**
* Logs dangling resources when a nanoapp is unloaded.
diff --git a/core/include/chre/core/event_loop_common.h b/core/include/chre/core/event_loop_common.h
index e487cbce..c6f4946e 100644
--- a/core/include/chre/core/event_loop_common.h
+++ b/core/include/chre/core/event_loop_common.h
@@ -70,6 +70,9 @@ enum class SystemCallbackType : uint16_t {
BleRequestResyncEvent,
RequestTimeoutEvent,
BleReadRssiEvent,
+ BleFlushComplete,
+ BleFlushTimeout,
+ PulseResponse,
};
//! Deferred/delayed callbacks use the event subsystem but are invariably sent
diff --git a/core/include/chre/core/event_loop_manager.h b/core/include/chre/core/event_loop_manager.h
index f6e7d749..b5f52b3c 100644
--- a/core/include/chre/core/event_loop_manager.h
+++ b/core/include/chre/core/event_loop_manager.h
@@ -24,6 +24,7 @@
#include "chre/core/host_endpoint_manager.h"
#include "chre/core/settings.h"
#include "chre/core/system_health_monitor.h"
+#include "chre/platform/atomic.h"
#include "chre/platform/memory_manager.h"
#include "chre/platform/mutex.h"
#include "chre/util/always_false.h"
@@ -349,8 +350,8 @@ class EventLoopManager : public NonCopyable {
void lateInit();
private:
- //! The instance ID that was previously generated by getNextInstanceId()
- uint16_t mLastInstanceId = kSystemInstanceId;
+ //! The instance ID generated by getNextInstanceId().
+ AtomicUint32 mNextInstanceId{kSystemInstanceId + 1};
#ifdef CHRE_AUDIO_SUPPORT_ENABLED
//! The audio request manager handles requests for all nanoapps and manages
diff --git a/core/include/chre/core/gnss_manager.h b/core/include/chre/core/gnss_manager.h
index 7b88d31a..d4885ff3 100644
--- a/core/include/chre/core/gnss_manager.h
+++ b/core/include/chre/core/gnss_manager.h
@@ -413,11 +413,11 @@ class GnssManager : public NonCopyable {
GnssSession &getLocationSession() {
return mLocationSession;
- };
+ }
GnssSession &getMeasurementSession() {
return mMeasurementSession;
- };
+ }
/**
* Invoked when the host notifies CHRE of a settings change.
diff --git a/core/include/chre/core/host_endpoint_manager.h b/core/include/chre/core/host_endpoint_manager.h
index 40781bbc..8fd7e099 100644
--- a/core/include/chre/core/host_endpoint_manager.h
+++ b/core/include/chre/core/host_endpoint_manager.h
@@ -90,6 +90,6 @@ class HostEndpointManager : public NonCopyable {
auto getHostNotificationCallback();
};
-}; // namespace chre
+} // namespace chre
#endif // CHRE_CORE_HOST_ENDPOINT_MANAGER_H_
diff --git a/core/include/chre/core/nanoapp.h b/core/include/chre/core/nanoapp.h
index ae72327e..9fb9a986 100644
--- a/core/include/chre/core/nanoapp.h
+++ b/core/include/chre/core/nanoapp.h
@@ -25,6 +25,7 @@
#include "chre/core/event_ref_queue.h"
#include "chre/platform/heap_block_header.h"
#include "chre/platform/platform_nanoapp.h"
+#include "chre/platform/system_time.h"
#include "chre/util/dynamic_vector.h"
#include "chre/util/fixed_size_vector.h"
#include "chre/util/system/debug_dump.h"
@@ -56,6 +57,10 @@ class Nanoapp : public PlatformNanoapp {
Nanoapp();
+ // The nanoapp instance ID should only come from the event loop manager. This
+ // constructor should never be called except for use in unit tests.
+ Nanoapp(uint16_t instanceId);
+
/**
* Calls the start function of the nanoapp. For dynamically loaded nanoapps,
* this must also result in calling through to any of the nanoapp's static
@@ -76,14 +81,6 @@ class Nanoapp : public PlatformNanoapp {
}
/**
- * Assigns an instance ID to this Nanoapp. This must be called prior to
- * starting this Nanoapp.
- */
- void setInstanceId(uint16_t instanceId) {
- mInstanceId = instanceId;
- }
-
- /**
* @return The current total number of bytes the nanoapp has allocated.
*/
size_t getTotalAllocatedBytes() const {
@@ -188,14 +185,23 @@ class Nanoapp : public PlatformNanoapp {
*/
void blameHostWakeup();
+ /**
+ * Log info about a single message sent to the host that this nanoapp
+ * triggered by storing the count of messages in mNumMessagesSentSinceBoot.
+ */
+ void blameHostMessageSent();
+
/*
* If buckets not full, then just pushes a 0 to back of buckets. If full, then
* shifts down all buckets from back to front and sets back to 0, losing the
* latest bucket value that was in front.
*
- * @param numBuckets the number of buckets to cycle into to mWakeupBuckets
+ * With nanoapps tracking their cycling time, there is no reason to ever
+ * cycle more than one bucket at a time. Doing more wastes valuable data
+ *
+ * @param timestamp the current time when this bucket was created
*/
- void cycleWakeupBuckets(size_t numBuckets);
+ void cycleWakeupBuckets(Nanoseconds timestamp);
/**
* Prints state in a string buffer. Must only be called from the context of
@@ -206,6 +212,39 @@ class Nanoapp : public PlatformNanoapp {
void logStateToBuffer(DebugDumpWrapper &debugDump) const;
/**
+ * Prints header for memory allocation and event processing time stats table
+ * in a string buffer. Must only be called from the context of the main CHRE
+ * thread.
+ *
+ * @param debugDump The object that is printed into for debug dump logs.
+ */
+ void logMemAndComputeHeader(DebugDumpWrapper &debugDump) const;
+
+ /**
+ * Prints memory allocation and event processing time stats in a string
+ * buffer. Must only be called from the context of the main CHRE thread.
+ *
+ * @param debugDump The object that is printed into for debug dump logs.
+ */
+ void logMemAndComputeEntry(DebugDumpWrapper &debugDump) const;
+
+ /**
+ * Prints header for wakeup and host message stats table in a string buffer.
+ * Must only be called from the context of the main CHRE thread.
+ *
+ * @param debugDump The object that is printed into for debug dump logs.
+ */
+ void logMessageHistoryHeader(DebugDumpWrapper &debugDump) const;
+
+ /**
+ * Prints wakeup and host message stats in a string buffer. Must only be
+ * called from the context of the main CHRE thread.
+ *
+ * @param debugDump The object that is printed into for debug dump logs.
+ */
+ void logMessageHistoryEntry(DebugDumpWrapper &debugDump) const;
+
+ /**
* @return true if the nanoapp is permitted to use the provided permission.
*/
bool permitPermissionUse(uint32_t permission) const;
@@ -269,6 +308,12 @@ class Nanoapp : public PlatformNanoapp {
//! The total number of wakeup counts for a nanoapp.
uint32_t mNumWakeupsSinceBoot = 0;
+ //! The total number of messages sent to host by this nanoapp.
+ uint32_t mNumMessagesSentSinceBoot = 0;
+
+ //! The total time in ms spend processing events by this nanoapp.
+ uint64_t mEventProcessTimeSinceBoot = 0;
+
/**
* Head of the singly linked list of heap block headers.
*
@@ -284,13 +329,28 @@ class Nanoapp : public PlatformNanoapp {
//! The peak total number of bytes allocated by the nanoapp.
size_t mPeakAllocatedBytes = 0;
+ //! Container for "bucketed" stats associated with wakeup logging
+ struct BucketedStats {
+ BucketedStats(uint16_t wakeupCount_, uint16_t hostMessageCount_,
+ uint64_t eventProcessTime_, uint64_t creationTimestamp_)
+ : wakeupCount(wakeupCount_),
+ hostMessageCount(hostMessageCount_),
+ eventProcessTime(eventProcessTime_),
+ creationTimestamp(creationTimestamp_) {}
+
+ uint16_t wakeupCount = 0;
+ uint16_t hostMessageCount = 0;
+ uint64_t eventProcessTime = 0;
+ uint64_t creationTimestamp = 0;
+ };
+
//! The number of buckets for wakeup logging, adjust along with
- //! EventLoop::kIntervalWakupBucketInMins.
- static constexpr size_t kMaxSizeWakeupBuckets = 4;
+ //! EventLoop::kIntervalWakeupBucket.
+ static constexpr size_t kMaxSizeWakeupBuckets = 5;
//! A fixed size buffer of buckets that keeps track of the number of host
//! wakeups over time intervals.
- FixedSizeVector<uint16_t, kMaxSizeWakeupBuckets> mWakeupBuckets;
+ FixedSizeVector<BucketedStats, kMaxSizeWakeupBuckets> mWakeupBuckets;
//! Collects process time in nanoseconds of each event
StatsContainer<uint64_t> mEventProcessTime;
diff --git a/core/include/chre/core/request_multiplexer_impl.h b/core/include/chre/core/request_multiplexer_impl.h
index 63b742fd..a5dfb342 100644
--- a/core/include/chre/core/request_multiplexer_impl.h
+++ b/core/include/chre/core/request_multiplexer_impl.h
@@ -27,7 +27,7 @@ bool RequestMultiplexer<RequestType>::addRequest(const RequestType &request,
size_t *index,
bool *maximalRequestChanged) {
CHRE_ASSERT_NOT_NULL(index);
- CHRE_ASSERT(maximalRequestChanged);
+ CHRE_ASSERT_NOT_NULL(maximalRequestChanged);
bool requestStored = mRequests.push_back(request);
if (requestStored) {
@@ -43,7 +43,7 @@ bool RequestMultiplexer<RequestType>::addRequest(RequestType &&request,
size_t *index,
bool *maximalRequestChanged) {
CHRE_ASSERT_NOT_NULL(index);
- CHRE_ASSERT(maximalRequestChanged);
+ CHRE_ASSERT_NOT_NULL(maximalRequestChanged);
bool requestStored = mRequests.push_back(std::move(request));
if (requestStored) {
@@ -57,7 +57,7 @@ bool RequestMultiplexer<RequestType>::addRequest(RequestType &&request,
template <typename RequestType>
void RequestMultiplexer<RequestType>::updateRequest(
size_t index, const RequestType &request, bool *maximalRequestChanged) {
- CHRE_ASSERT(maximalRequestChanged);
+ CHRE_ASSERT_NOT_NULL(maximalRequestChanged);
CHRE_ASSERT(index < mRequests.size());
if (index < mRequests.size()) {
@@ -114,6 +114,8 @@ const RequestType &RequestMultiplexer<RequestType>::getCurrentMaximalRequest()
template <typename RequestType>
void RequestMultiplexer<RequestType>::updateMaximalRequest(
bool *maximalRequestChanged) {
+ CHRE_ASSERT_NOT_NULL(maximalRequestChanged);
+
RequestType maximalRequest;
for (size_t i = 0; i < mRequests.size(); i++) {
maximalRequest.mergeWith(mRequests[i]);
diff --git a/core/include/chre/core/system_health_monitor.h b/core/include/chre/core/system_health_monitor.h
index 2b203a4b..ea4af24f 100644
--- a/core/include/chre/core/system_health_monitor.h
+++ b/core/include/chre/core/system_health_monitor.h
@@ -17,6 +17,8 @@
#ifndef CHRE_CORE_SYSTEM_HEALTH_MONITOR_H_
#define CHRE_CORE_SYSTEM_HEALTH_MONITOR_H_
+#include <cstdint>
+
#include "chre/platform/assert.h"
#include "chre/platform/log.h"
#include "chre/util/enum.h"
diff --git a/core/include/chre/core/timer_pool.h b/core/include/chre/core/timer_pool.h
index fc447853..d6dd2046 100644
--- a/core/include/chre/core/timer_pool.h
+++ b/core/include/chre/core/timer_pool.h
@@ -149,10 +149,10 @@ class TimerPool : public NonCopyable {
uint16_t instanceId;
/**
- * Provides a greater than comparison of TimerRequests.
+ * Returns whether the current request expires after the passed one.
*
- * @param request The other request to compare against.
- * @return Returns true if this request is greater than the provided
+ * @param request The other request.
+ * @return Returns whether this request expires after the provided
* request.
*/
bool operator>(const TimerRequest &request) const;
diff --git a/core/log.cc b/core/log.cc
index c8ac7660..f95b8885 100644
--- a/core/log.cc
+++ b/core/log.cc
@@ -16,6 +16,7 @@
#ifdef CHRE_TOKENIZED_LOGGING_ENABLED
#include "chre/platform/log.h"
+#include "pw_log_tokenized/config.h"
#include "pw_tokenizer/encode_args.h"
#include "pw_tokenizer/tokenize.h"
@@ -26,7 +27,8 @@ void EncodeTokenizedMessage(uint32_t level, pw_tokenizer_Token token,
pw_tokenizer_ArgTypes types, ...) {
va_list args;
va_start(args, types);
- pw::tokenizer::EncodedMessage encodedMessage(token, types, args);
+ pw::tokenizer::EncodedMessage<pw::log_tokenized::kEncodingBufferSizeBytes>
+ encodedMessage(token, types, args);
va_end(args);
chrePlatformEncodedLogToBuffer(static_cast<chreLogLevel>(level),
diff --git a/core/nanoapp.cc b/core/nanoapp.cc
index 789f2da0..faf00daa 100644
--- a/core/nanoapp.cc
+++ b/core/nanoapp.cc
@@ -36,13 +36,18 @@ namespace chre {
constexpr size_t Nanoapp::kMaxSizeWakeupBuckets;
-Nanoapp::Nanoapp() {
+Nanoapp::Nanoapp()
+ : Nanoapp(EventLoopManagerSingleton::get()->getNextInstanceId()) {}
+
+Nanoapp::Nanoapp(uint16_t instanceId) {
// Push first bucket onto wakeup bucket queue
- cycleWakeupBuckets(1);
+ cycleWakeupBuckets(SystemTime::getMonotonicTime());
+ mInstanceId = instanceId;
}
bool Nanoapp::start() {
- traceRegisterNanoapp(getInstanceId(), getAppName());
+ // TODO(b/294116163): update trace with nanoapp instance id and nanoapp name
+ CHRE_TRACE_INSTANT("Nanoapp start");
mIsInNanoappStart = true;
bool success = PlatformNanoapp::start();
mIsInNanoappStart = false;
@@ -134,37 +139,49 @@ void Nanoapp::configureUserSettingEvent(uint8_t setting, bool enable) {
void Nanoapp::processEvent(Event *event) {
Nanoseconds eventStartTime = SystemTime::getMonotonicTime();
- traceNanoappHandleEventStart(getInstanceId(), event->eventType);
+ // TODO(b/294116163): update trace with event type and nanoapp name so it can
+ // be differentiated from other events
+ CHRE_TRACE_START("Handle event", "nanoapp", getInstanceId());
if (event->eventType == CHRE_EVENT_GNSS_DATA) {
handleGnssMeasurementDataEvent(event);
} else {
handleEvent(event->senderInstanceId, event->eventType, event->eventData);
}
- traceNanoappHandleEventEnd(getInstanceId());
+ // TODO(b/294116163): update trace with nanoapp name
+ CHRE_TRACE_END("Handle event", "nanoapp", getInstanceId());
Nanoseconds eventProcessTime =
SystemTime::getMonotonicTime() - eventStartTime;
+ uint64_t eventTimeMs = Milliseconds(eventProcessTime).getMilliseconds();
if (Milliseconds(eventProcessTime) >= Milliseconds(100)) {
LOGE("Nanoapp 0x%" PRIx64 " took %" PRIu64
- " ms to process event type %" PRIu16,
- getAppId(), Milliseconds(eventProcessTime).getMilliseconds(),
- event->eventType);
+ " ms to process event type 0x%" PRIx16,
+ getAppId(), eventTimeMs, event->eventType);
}
- mEventProcessTime.addValue(Milliseconds(eventProcessTime).getMilliseconds());
+ mEventProcessTime.addValue(eventTimeMs);
+ mEventProcessTimeSinceBoot += eventTimeMs;
+ mWakeupBuckets.back().eventProcessTime += eventTimeMs;
}
void Nanoapp::blameHostWakeup() {
- if (mWakeupBuckets.back() < UINT16_MAX) ++mWakeupBuckets.back();
+ if (mWakeupBuckets.back().wakeupCount < UINT16_MAX) {
+ ++mWakeupBuckets.back().wakeupCount;
+ }
if (mNumWakeupsSinceBoot < UINT32_MAX) ++mNumWakeupsSinceBoot;
}
-void Nanoapp::cycleWakeupBuckets(size_t numBuckets) {
- numBuckets = std::min(numBuckets, kMaxSizeWakeupBuckets);
- for (size_t i = 0; i < numBuckets; ++i) {
- if (mWakeupBuckets.full()) {
- mWakeupBuckets.erase(0);
- }
- mWakeupBuckets.push_back(0);
+void Nanoapp::blameHostMessageSent() {
+ if (mWakeupBuckets.back().hostMessageCount < UINT16_MAX) {
+ ++mWakeupBuckets.back().hostMessageCount;
+ }
+ if (mNumMessagesSentSinceBoot < UINT32_MAX) ++mNumMessagesSentSinceBoot;
+}
+
+void Nanoapp::cycleWakeupBuckets(Nanoseconds timestamp) {
+ if (mWakeupBuckets.full()) {
+ mWakeupBuckets.erase(0);
}
+ mWakeupBuckets.push_back(
+ BucketedStats(0, 0, 0, timestamp.toRawNanoseconds()));
}
void Nanoapp::logStateToBuffer(DebugDumpWrapper &debugDump) const {
@@ -172,27 +189,134 @@ void Nanoapp::logStateToBuffer(DebugDumpWrapper &debugDump) const {
getAppId());
PlatformNanoapp::logStateToBuffer(debugDump);
debugDump.print(" v%" PRIu32 ".%" PRIu32 ".%" PRIu32 " tgtAPI=%" PRIu32
- ".%" PRIu32 " curAlloc=%zu peakAlloc=%zu",
+ ".%" PRIu32 "\n",
CHRE_EXTRACT_MAJOR_VERSION(getAppVersion()),
CHRE_EXTRACT_MINOR_VERSION(getAppVersion()),
CHRE_EXTRACT_PATCH_VERSION(getAppVersion()),
CHRE_EXTRACT_MAJOR_VERSION(getTargetApiVersion()),
- CHRE_EXTRACT_MINOR_VERSION(getTargetApiVersion()),
- getTotalAllocatedBytes(), getPeakAllocatedBytes());
- debugDump.print(" hostWakeups=[ cur->");
- // Get buckets latest -> earliest except last one
- for (size_t i = mWakeupBuckets.size() - 1; i > 0; --i) {
- debugDump.print("%" PRIu16 ", ", mWakeupBuckets[i]);
- }
- // Earliest bucket gets no comma
- debugDump.print("%" PRIu16 " ]", mWakeupBuckets.front());
-
- // Print total wakeups since boot
- debugDump.print(" totWakeups=%" PRIu32 " ", mNumWakeupsSinceBoot);
-
- // Print mean and max event process time
- debugDump.print("eventProcessTimeMs: mean=%" PRIu64 ", max=%" PRIu64 "\n",
- mEventProcessTime.getMean(), mEventProcessTime.getMax());
+ CHRE_EXTRACT_MINOR_VERSION(getTargetApiVersion()));
+}
+
+void Nanoapp::logMemAndComputeHeader(DebugDumpWrapper &debugDump) const {
+ // Print table header
+ // Nanoapp column sized to accommodate largest known name
+ debugDump.print("\n%10sNanoapp%9s| Mem Alloc (Bytes) |%7sEvent Time (Ms)\n",
+ "", "", "");
+ debugDump.print("%26s| Current | Max | Mean | Max | Total\n",
+ "");
+}
+
+void Nanoapp::logMemAndComputeEntry(DebugDumpWrapper &debugDump) const {
+ debugDump.print("%*s |", 25, getAppName());
+ debugDump.print(" %*zu |", 7, getTotalAllocatedBytes());
+ debugDump.print(" %*zu |", 7, getPeakAllocatedBytes());
+ debugDump.print(" %*" PRIu64 " |", 7, mEventProcessTime.getMean());
+ debugDump.print(" %*" PRIu64 " |", 7, mEventProcessTime.getMax());
+ debugDump.print(" %*" PRIu64 "\n", 7, mEventProcessTimeSinceBoot);
+}
+
+void Nanoapp::logMessageHistoryHeader(DebugDumpWrapper &debugDump) const {
+ // Print time ranges for buckets
+ Nanoseconds now = SystemTime::getMonotonicTime();
+ uint64_t currentTimeMins = 0;
+ uint64_t nextTimeMins = 0;
+ uint64_t nanosecondsSince = 0;
+ char bucketLabel = 'A';
+
+ char bucketTags[kMaxSizeWakeupBuckets][4];
+ for (int32_t i = kMaxSizeWakeupBuckets - 1; i >= 0; --i) {
+ bucketTags[i][0] = '[';
+ bucketTags[i][1] = bucketLabel++;
+ bucketTags[i][2] = ']';
+ bucketTags[i][3] = '\0';
+ }
+
+ debugDump.print(
+ "\nHistogram stat buckets cover the following time ranges:\n");
+
+ for (int32_t i = kMaxSizeWakeupBuckets - 1;
+ i > static_cast<int32_t>(mWakeupBuckets.size() - 1); --i) {
+ debugDump.print(" Bucket%s: N/A (unused)\n", bucketTags[i]);
+ }
+
+ for (int32_t i = static_cast<int32_t>(mWakeupBuckets.size() - 1); i >= 0;
+ --i) {
+ size_t idx = static_cast<size_t>(i);
+ nanosecondsSince =
+ now.toRawNanoseconds() - mWakeupBuckets[idx].creationTimestamp;
+ currentTimeMins = (nanosecondsSince / kOneMinuteInNanoseconds);
+
+ debugDump.print(" Bucket%s:", bucketTags[idx]);
+ debugDump.print(" %*" PRIu64 "", 3, nextTimeMins);
+ debugDump.print(" - %*" PRIu64 " mins ago\n", 3, currentTimeMins);
+ nextTimeMins = currentTimeMins;
+ }
+
+ int wuHistColWidth = 2 + (4 * kMaxSizeWakeupBuckets);
+ int messageHistColWidth = 2 + (4 * kMaxSizeWakeupBuckets);
+ int eventHistColWidth = 2 + (7 * kMaxSizeWakeupBuckets);
+
+ // Print table header
+ debugDump.print("\n%*s|", 26, " Nanoapp ");
+ debugDump.print("%*s|", 11, " Total w/u ");
+ debugDump.print("%*s|", wuHistColWidth, " Wakeup Histogram ");
+ debugDump.print("%*s|", 12, " Total Msgs ");
+ debugDump.print("%*s|", messageHistColWidth, " Message Histogram ");
+ debugDump.print("%*s|", 12, " Event Time ");
+ debugDump.print("%*s", eventHistColWidth, " Event Time Histogram (ms) ");
+
+ debugDump.print("\n%26s|%11s|", "", "");
+ for (int32_t i = kMaxSizeWakeupBuckets - 1; i >= 0; --i) {
+ debugDump.print(" %*s", 3, bucketTags[i]);
+ }
+ debugDump.print(" |%*s|", 12, "");
+ for (int32_t i = kMaxSizeWakeupBuckets - 1; i >= 0; --i) {
+ debugDump.print(" %*s", 3, bucketTags[i]);
+ }
+ debugDump.print(" |%*s|", 12, "");
+ for (int32_t i = kMaxSizeWakeupBuckets - 1; i >= 0; --i) {
+ debugDump.print(" %*s", 7, bucketTags[i]);
+ }
+ debugDump.print("\n");
+}
+
+void Nanoapp::logMessageHistoryEntry(DebugDumpWrapper &debugDump) const {
+ debugDump.print("%*s |", 25, getAppName());
+
+ // Print wakeupCount and histogram
+ debugDump.print(" %*" PRIu32 " | ", 9, mNumWakeupsSinceBoot);
+ for (size_t i = kMaxSizeWakeupBuckets - 1; i > 0; --i) {
+ if (i >= mWakeupBuckets.size()) {
+ debugDump.print(" --,");
+ } else {
+ debugDump.print(" %*" PRIu16 ",", 2, mWakeupBuckets[i].wakeupCount);
+ }
+ }
+ debugDump.print(" %*" PRIu16 " |", 2, mWakeupBuckets.front().wakeupCount);
+
+ // Print hostMessage count and histogram
+ debugDump.print(" %*" PRIu32 " | ", 10, mNumMessagesSentSinceBoot);
+ for (size_t i = kMaxSizeWakeupBuckets - 1; i > 0; --i) {
+ if (i >= mWakeupBuckets.size()) {
+ debugDump.print(" --,");
+ } else {
+ debugDump.print(" %*" PRIu16 ",", 2, mWakeupBuckets[i].hostMessageCount);
+ }
+ }
+ debugDump.print(" %*" PRIu16 " |", 2,
+ mWakeupBuckets.front().hostMessageCount);
+
+ // Print eventProcessingTime count and histogram
+ debugDump.print(" %*" PRIu64 " | ", 10, mEventProcessTimeSinceBoot);
+ for (size_t i = kMaxSizeWakeupBuckets - 1; i > 0; --i) {
+ if (i >= mWakeupBuckets.size()) {
+ debugDump.print(" --,");
+ } else {
+ debugDump.print(" %*" PRIu64 ",", 6, mWakeupBuckets[i].eventProcessTime);
+ }
+ }
+ debugDump.print(" %*" PRIu64 "\n", 6,
+ mWakeupBuckets.front().eventProcessTime);
}
bool Nanoapp::permitPermissionUse(uint32_t permission) const {
diff --git a/core/telemetry_manager.cc b/core/telemetry_manager.cc
index 1cb47f07..6772cb5a 100644
--- a/core/telemetry_manager.cc
+++ b/core/telemetry_manager.cc
@@ -24,7 +24,7 @@
#include "chre/util/macros.h"
#include "chre/util/nested_data_ptr.h"
#include "chre/util/time.h"
-#include "chre_metrics.nanopb.h"
+#include "core/chre_metrics.nanopb.h"
namespace chre {
@@ -42,11 +42,15 @@ namespace {
_android_chre_metrics_ChrePalType:: \
android_chre_metrics_ChrePalType_CHRE_PAL_TYPE_##x
+// These IDs must be kept in sync with
+// hardware/google/pixel/pixelstats/pixelatoms.proto.
+constexpr uint32_t kEventQueueSnapshotReportedId = 105035;
+constexpr uint32_t kPalOpenedFailedId = 105032;
+
void sendMetricToHost(uint32_t atomId, const pb_field_t fields[],
const void *data) {
size_t size;
- if (!pb_get_encoded_size(&size, CHREATOMS_GET(ChrePalOpenFailed_fields),
- data)) {
+ if (!pb_get_encoded_size(&size, fields, data)) {
LOGE("Failed to get message size");
} else {
pb_byte_t *bytes = static_cast<pb_byte_t *>(memoryAlloc(size));
@@ -54,13 +58,12 @@ void sendMetricToHost(uint32_t atomId, const pb_field_t fields[],
LOG_OOM();
} else {
pb_ostream_t stream = pb_ostream_from_buffer(bytes, size);
- if (!pb_encode(&stream, CHREATOMS_GET(ChrePalOpenFailed_fields), data)) {
+ if (!pb_encode(&stream, fields, data)) {
LOGE("Failed to metric error %s", PB_GET_ERROR(&stream));
} else {
HostCommsManager &manager =
EventLoopManagerSingleton::get()->getHostCommsManager();
- if (!manager.sendMetricLog(CHREATOMS_GET(Atom_chre_pal_open_failed_tag),
- bytes, size)) {
+ if (!manager.sendMetricLog(atomId, bytes, size)) {
LOGE("Failed to send metric message");
}
}
@@ -78,8 +81,8 @@ void sendPalOpenFailedMetric(_android_chre_metrics_ChrePalType pal) {
result.type = _android_chre_metrics_ChrePalOpenFailed_Type::
android_chre_metrics_ChrePalOpenFailed_Type_INITIAL_OPEN;
- sendMetricToHost(CHREATOMS_GET(Atom_chre_pal_open_failed_tag),
- CHREATOMS_GET(ChrePalOpenFailed_fields), &result);
+ sendMetricToHost(kPalOpenedFailedId, CHREATOMS_GET(ChrePalOpenFailed_fields),
+ &result);
}
void sendEventLoopStats(uint32_t maxQueueSize, uint32_t meanQueueSize,
@@ -97,7 +100,7 @@ void sendEventLoopStats(uint32_t maxQueueSize, uint32_t meanQueueSize,
result.has_num_dropped_events = true;
result.num_dropped_events = numDroppedEvents;
- sendMetricToHost(CHREATOMS_GET(Atom_chre_event_queue_snapshot_reported_tag),
+ sendMetricToHost(kEventQueueSnapshotReportedId,
CHREATOMS_GET(ChreEventQueueSnapshotReported_fields),
&result);
}
@@ -158,7 +161,7 @@ void TelemetryManager::collectSystemMetrics() {
}
void TelemetryManager::scheduleMetricTimer() {
- constexpr Seconds kDelay = Seconds(60 * 60 * 24); // 24 hours
+ constexpr Seconds kDelay = Seconds(kOneDayInSeconds);
auto callback = [](uint16_t /* eventType */, void * /* data */,
void * /* extraData */) {
EventLoopManagerSingleton::get()
diff --git a/core/tests/ble_request_test.cc b/core/tests/ble_request_test.cc
index bc0dbc5c..e8ed98e3 100644
--- a/core/tests/ble_request_test.cc
+++ b/core/tests/ble_request_test.cc
@@ -30,12 +30,12 @@ TEST(BleRequest, DefaultMinimalRequest) {
}
TEST(BleRequest, AggressiveModeIsHigherThanBackground) {
- BleRequest backgroundMode(0 /* instanceId */, true /* enable */,
- CHRE_BLE_SCAN_MODE_BACKGROUND,
- 0 /* reportDelayMs */, nullptr /* filter */);
- BleRequest aggressiveMode(0 /* instanceId */, true /* enable */,
- CHRE_BLE_SCAN_MODE_AGGRESSIVE,
- 0 /* reportDelayMs */, nullptr /* filter */);
+ BleRequest backgroundMode(
+ 0 /* instanceId */, true /* enable */, CHRE_BLE_SCAN_MODE_BACKGROUND,
+ 0 /* reportDelayMs */, nullptr /* filter */, nullptr /* cookie */);
+ BleRequest aggressiveMode(
+ 0 /* instanceId */, true /* enable */, CHRE_BLE_SCAN_MODE_AGGRESSIVE,
+ 0 /* reportDelayMs */, nullptr /* filter */, nullptr /* cookie */);
BleRequest mergedRequest;
EXPECT_TRUE(mergedRequest.mergeWith(aggressiveMode));
@@ -48,14 +48,15 @@ TEST(BleRequest, AggressiveModeIsHigherThanBackground) {
}
TEST(BleRequest, MergeWithReplacesParametersOfDisabledRequest) {
- chreBleScanFilter filter;
+ chreBleScanFilterV1_9 filter;
filter.rssiThreshold = -5;
- filter.scanFilterCount = 1;
+ filter.genericFilterCount = 1;
auto scanFilters = std::make_unique<chreBleGenericFilter>();
scanFilters->type = CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE;
scanFilters->len = 2;
- filter.scanFilters = scanFilters.get();
- BleRequest enabled(0, true, CHRE_BLE_SCAN_MODE_AGGRESSIVE, 20, &filter);
+ filter.genericFilters = scanFilters.get();
+ BleRequest enabled(0, true, CHRE_BLE_SCAN_MODE_AGGRESSIVE, 20, &filter,
+ nullptr /* cookie */);
BleRequest mergedRequest;
EXPECT_FALSE(mergedRequest.isEnabled());
@@ -71,72 +72,84 @@ TEST(BleRequest, MergeWithReplacesParametersOfDisabledRequest) {
}
TEST(BleRequest, IsEquivalentToBasic) {
- BleRequest backgroundMode(0 /* instanceId */, true /* enable */,
- CHRE_BLE_SCAN_MODE_BACKGROUND,
- 0 /* reportDelayMs */, nullptr /* filter */);
+ BleRequest backgroundMode(
+ 0 /* instanceId */, true /* enable */, CHRE_BLE_SCAN_MODE_BACKGROUND,
+ 0 /* reportDelayMs */, nullptr /* filter */, nullptr /* cookie */);
EXPECT_TRUE(backgroundMode.isEquivalentTo(backgroundMode));
}
TEST(BleRequest, IsNotEquivalentToBasic) {
- BleRequest backgroundMode(0 /* instanceId */, true /* enable */,
- CHRE_BLE_SCAN_MODE_BACKGROUND,
- 0 /* reportDelayMs */, nullptr /* filter */);
- BleRequest aggressiveMode(0 /* instanceId */, true /* enable */,
- CHRE_BLE_SCAN_MODE_AGGRESSIVE,
- 0 /* reportDelayMs */, nullptr /* filter */);
+ BleRequest backgroundMode(
+ 0 /* instanceId */, true /* enable */, CHRE_BLE_SCAN_MODE_BACKGROUND,
+ 0 /* reportDelayMs */, nullptr /* filter */, nullptr /* cookie */);
+ BleRequest aggressiveMode(
+ 0 /* instanceId */, true /* enable */, CHRE_BLE_SCAN_MODE_AGGRESSIVE,
+ 0 /* reportDelayMs */, nullptr /* filter */, nullptr /* cookie */);
EXPECT_FALSE(backgroundMode.isEquivalentTo(aggressiveMode));
}
+TEST(BleRequest, IsNotEquivalentWithCookie) {
+ constexpr uint32_t kCookieOne = 123;
+ constexpr uint32_t kCookieTwo = 234;
+ BleRequest requestOne(0 /* instanceId */, true /* enable */,
+ CHRE_BLE_SCAN_MODE_BACKGROUND, 0 /* reportDelayMs */,
+ nullptr /* filter */, &kCookieOne);
+ BleRequest requestTwo(0 /* instanceId */, true /* enable */,
+ CHRE_BLE_SCAN_MODE_BACKGROUND, 0 /* reportDelayMs */,
+ nullptr /* filter */, &kCookieTwo);
+ EXPECT_TRUE(requestOne.isEquivalentTo(requestTwo));
+}
+
TEST(BleRequest, IsEquivalentToAdvanced) {
- chreBleScanFilter filter;
+ chreBleScanFilterV1_9 filter;
filter.rssiThreshold = -5;
- filter.scanFilterCount = 1;
+ filter.genericFilterCount = 1;
auto scanFilters = std::make_unique<chreBleGenericFilter>();
scanFilters->type = CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE;
scanFilters->len = 4;
- filter.scanFilters = scanFilters.get();
+ filter.genericFilters = scanFilters.get();
- BleRequest backgroundMode(100 /* instanceId */, true /* enable */,
- CHRE_BLE_SCAN_MODE_BACKGROUND,
- 100 /* reportDelayMs */, &filter);
+ BleRequest backgroundMode(
+ 100 /* instanceId */, true /* enable */, CHRE_BLE_SCAN_MODE_BACKGROUND,
+ 100 /* reportDelayMs */, &filter, nullptr /* cookie */);
EXPECT_TRUE(backgroundMode.isEquivalentTo(backgroundMode));
}
TEST(BleRequest, IsNotEquivalentToAdvanced) {
- chreBleScanFilter filter;
+ chreBleScanFilterV1_9 filter;
filter.rssiThreshold = -5;
- filter.scanFilterCount = 1;
+ filter.genericFilterCount = 1;
auto scanFilters = std::make_unique<chreBleGenericFilter>();
scanFilters->type = CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE;
scanFilters->len = 4;
- filter.scanFilters = scanFilters.get();
+ filter.genericFilters = scanFilters.get();
- BleRequest backgroundMode(100 /* instanceId */, true /* enable */,
- CHRE_BLE_SCAN_MODE_BACKGROUND,
- 100 /* reportDelayMs */, &filter /* filter */);
- BleRequest aggressiveMode(0 /* instanceId */, true /* enable */,
- CHRE_BLE_SCAN_MODE_AGGRESSIVE,
- 0 /* reportDelayMs */, nullptr /* filter */);
+ BleRequest backgroundMode(
+ 100 /* instanceId */, true /* enable */, CHRE_BLE_SCAN_MODE_BACKGROUND,
+ 100 /* reportDelayMs */, &filter /* filter */, nullptr /* cookie */);
+ BleRequest aggressiveMode(
+ 0 /* instanceId */, true /* enable */, CHRE_BLE_SCAN_MODE_AGGRESSIVE,
+ 0 /* reportDelayMs */, nullptr /* filter */, nullptr /* cookie */);
EXPECT_FALSE(backgroundMode.isEquivalentTo(aggressiveMode));
}
TEST(BleRequest, GetScanFilter) {
- chreBleScanFilter filter;
+ chreBleScanFilterV1_9 filter;
filter.rssiThreshold = -5;
- filter.scanFilterCount = 1;
+ filter.genericFilterCount = 1;
auto scanFilters = std::make_unique<chreBleGenericFilter>();
scanFilters->type = CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE;
scanFilters->len = 4;
- filter.scanFilters = scanFilters.get();
+ filter.genericFilters = scanFilters.get();
- BleRequest backgroundMode(100 /* instanceId */, true /* enable */,
- CHRE_BLE_SCAN_MODE_BACKGROUND,
- 100 /* reportDelayMs */, &filter /* filter */);
+ BleRequest backgroundMode(
+ 100 /* instanceId */, true /* enable */, CHRE_BLE_SCAN_MODE_BACKGROUND,
+ 100 /* reportDelayMs */, &filter /* filter */, nullptr /* cookie */);
- chreBleScanFilter retFilter = backgroundMode.getScanFilter();
+ chreBleScanFilterV1_9 retFilter = backgroundMode.getScanFilter();
EXPECT_EQ(filter.rssiThreshold, retFilter.rssiThreshold);
- EXPECT_EQ(filter.scanFilterCount, retFilter.scanFilterCount);
- EXPECT_EQ(0, memcmp(scanFilters.get(), retFilter.scanFilters,
+ EXPECT_EQ(filter.genericFilterCount, retFilter.genericFilterCount);
+ EXPECT_EQ(0, memcmp(scanFilters.get(), retFilter.genericFilters,
sizeof(chreBleGenericFilter)));
}
diff --git a/core/tests/memory_manager_test.cc b/core/tests/memory_manager_test.cc
index 69e07a08..b7b151ce 100644
--- a/core/tests/memory_manager_test.cc
+++ b/core/tests/memory_manager_test.cc
@@ -16,10 +16,12 @@
#include "gtest/gtest.h"
+#include "chre/core/event.h"
#include "chre/platform/log.h"
#include "chre/platform/memory.h"
#include "chre/platform/memory_manager.h"
+using chre::kInvalidInstanceId;
using chre::MemoryManager;
using chre::Nanoapp;
@@ -36,7 +38,7 @@ TEST(MemoryManager, DefaultTotalMemoryAllocatedIsZero) {
TEST(MemoryManager, BasicAllocationFree) {
MemoryManager manager;
- Nanoapp app;
+ Nanoapp app(kInvalidInstanceId);
void *ptr = manager.nanoappAlloc(&app, 1u);
EXPECT_NE(ptr, nullptr);
EXPECT_EQ(manager.getTotalAllocatedBytes(), 1u);
@@ -48,7 +50,7 @@ TEST(MemoryManager, BasicAllocationFree) {
TEST(MemoryManager, NullPointerFree) {
MemoryManager manager;
- Nanoapp app;
+ Nanoapp app(kInvalidInstanceId);
manager.nanoappFree(&app, nullptr);
EXPECT_EQ(manager.getTotalAllocatedBytes(), 0u);
EXPECT_EQ(manager.getAllocationCount(), 0u);
@@ -56,7 +58,7 @@ TEST(MemoryManager, NullPointerFree) {
TEST(MemoryManager, ZeroAllocationFails) {
MemoryManager manager;
- Nanoapp app;
+ Nanoapp app(kInvalidInstanceId);
void *ptr = manager.nanoappAlloc(&app, 0u);
EXPECT_EQ(ptr, nullptr);
EXPECT_EQ(manager.getTotalAllocatedBytes(), 0u);
@@ -65,7 +67,7 @@ TEST(MemoryManager, ZeroAllocationFails) {
TEST(MemoryManager, HugeAllocationFails) {
MemoryManager manager;
- Nanoapp app;
+ Nanoapp app(kInvalidInstanceId);
void *ptr = manager.nanoappAlloc(&app, manager.getMaxAllocationBytes() + 1);
EXPECT_EQ(ptr, nullptr);
EXPECT_EQ(manager.getTotalAllocatedBytes(), 0u);
@@ -73,7 +75,7 @@ TEST(MemoryManager, HugeAllocationFails) {
TEST(MemoryManager, ManyAllocationsTest) {
MemoryManager manager;
- Nanoapp app;
+ Nanoapp app(kInvalidInstanceId);
size_t maxCount = manager.getMaxAllocationCount();
node *head = static_cast<node *>(manager.nanoappAlloc(&app, sizeof(node)));
node *curr = nullptr, *prev = head;
@@ -99,7 +101,7 @@ TEST(MemoryManager, ManyAllocationsTest) {
TEST(MemoryManager, NegativeAllocationFails) {
MemoryManager manager;
- Nanoapp app;
+ Nanoapp app(kInvalidInstanceId);
void *ptr = manager.nanoappAlloc(&app, -1u);
EXPECT_EQ(ptr, nullptr);
EXPECT_EQ(manager.getTotalAllocatedBytes(), 0u);
diff --git a/core/timer_pool.cc b/core/timer_pool.cc
index 2db3a296..521300c3 100644
--- a/core/timer_pool.cc
+++ b/core/timer_pool.cc
@@ -81,16 +81,22 @@ TimerHandle TimerPool::setTimer(uint16_t instanceId, Nanoseconds duration,
timerRequest.callbackType = callbackType;
timerRequest.isOneShot = isOneShot;
- bool newTimerExpiresEarliest =
- (!mTimerRequests.empty() && mTimerRequests.top() > timerRequest);
bool success = insertTimerRequestLocked(timerRequest);
if (success) {
- if (newTimerExpiresEarliest) {
- mSystemTimer.set(handleSystemTimerCallback, this, duration);
- } else if (mTimerRequests.size() == 1) {
+ if (mTimerRequests.size() == 1) {
// If this timer request was the first, schedule it.
handleExpiredTimersAndScheduleNextLocked();
+ } else {
+ // If there was already a timer pending before this, and we just inserted
+ // to the top of the queue, just update the system timer. This is slightly
+ // more efficient than calling into
+ // handleExpiredTimersAndScheduleNextLocked().
+ bool newRequestExpiresFirst =
+ timerRequest.timerHandle == mTimerRequests.top().timerHandle;
+ if (newRequestExpiresFirst) {
+ mSystemTimer.set(handleSystemTimerCallback, this, duration);
+ }
}
}
@@ -132,7 +138,7 @@ TimerPool::TimerRequest *TimerPool::getTimerRequestByTimerHandleLocked(
}
bool TimerPool::TimerRequest::operator>(const TimerRequest &request) const {
- return (expirationTime > request.expirationTime);
+ return expirationTime > request.expirationTime;
}
TimerHandle TimerPool::generateTimerHandleLocked() {
@@ -264,7 +270,7 @@ bool TimerPool::handleExpiredTimersAndScheduleNextLocked() {
// insert operation (thereby invalidating it).
TimerRequest cyclicTimerRequest = currentTimerRequest;
cyclicTimerRequest.expirationTime =
- currentTime + currentTimerRequest.duration;
+ currentTimerRequest.expirationTime + currentTimerRequest.duration;
popTimerRequestLocked();
CHRE_ASSERT(insertTimerRequestLocked(cyclicTimerRequest));
} else {
diff --git a/doc/porting_guide.md b/doc/porting_guide.md
index 1c960b74..7fa43455 100644
--- a/doc/porting_guide.md
+++ b/doc/porting_guide.md
@@ -51,7 +51,7 @@ Platform-specific code can be further subdivided into:
`platform_sensor_base.h` respectively, or required macros
* **Fully platform-specific headers**: these typically appear at
- `platform/<platform_name>/include/chre/platform/<platform_name/<file_name>.h`
+ `platform/<platform_name>/include/chre/platform/<platform_name>/<file_name>.h`
and may only be included by other platform-specific code
## Open Sourcing
diff --git a/external/pigweed/pw_rpc.mk b/external/pigweed/pw_rpc.mk
deleted file mode 100644
index 35fb25f5..00000000
--- a/external/pigweed/pw_rpc.mk
+++ /dev/null
@@ -1,241 +0,0 @@
-#
-# Makefile for Pigweed's RPC module
-#
-# NOTE: In order to use this, you *must* have the following:
-# - Installed mypy-protobuf and protoc
-# - nanopb-c git repo checked out
-#
-
-ifneq ($(PW_RPC_SRCS),)
-
-# Environment Checks ###########################################################
-
-# Location of various Pigweed modules
-PIGWEED_DIR = $(ANDROID_BUILD_TOP)/external/pigweed
-CHRE_PREFIX = $(ANDROID_BUILD_TOP)/system/chre
-CHRE_UTIL_DIR = $(CHRE_PREFIX)/util
-CHRE_API_DIR = $(CHRE_PREFIX)/chre_api
-PIGWEED_CHRE_DIR=$(CHRE_PREFIX)/external/pigweed
-PIGWEED_CHRE_UTIL_DIR = $(CHRE_UTIL_DIR)/pigweed
-
-ifeq ($(NANOPB_PREFIX),)
-$(error "PW_RPC_SRCS is non-empty. You must supply a NANOPB_PREFIX environment \
- variable containing a path to the nanopb project. Example: \
- export NANOPB_PREFIX=$$HOME/path/to/nanopb/nanopb-c")
-endif
-
-ifeq ($(PROTOC),)
-PROTOC=protoc
-endif
-
-PW_RPC_GEN_PATH = $(OUT)/pw_rpc_gen
-
-# Create proto used for header generation ######################################
-
-PW_RPC_PROTO_GENERATOR = $(PIGWEED_DIR)/pw_protobuf_compiler/py/pw_protobuf_compiler/generate_protos.py
-PW_RPC_GENERATOR_PROTO = $(PIGWEED_DIR)/pw_rpc/internal/packet.proto
-PW_RPC_GENERATOR_COMPILED_PROTO = $(PW_RPC_GEN_PATH)/py/pw_rpc/internal/packet_pb2.py
-PW_PROTOBUF_PROTOS = $(PIGWEED_DIR)/pw_protobuf/pw_protobuf_protos/common.proto \
- $(PIGWEED_DIR)/pw_protobuf/pw_protobuf_protos/field_options.proto \
- $(PIGWEED_DIR)/pw_protobuf/pw_protobuf_protos/status.proto
-
-# Modifies PYTHONPATH so that python can see all of pigweed's modules used by
-# their protoc plugins
-PW_RPC_GENERATOR_CMD = PYTHONPATH=$$PYTHONPATH:$(PW_RPC_GEN_PATH)/py:$\
- $(PIGWEED_DIR)/pw_status/py:$(PIGWEED_DIR)/pw_protobuf/py:$\
- $(PIGWEED_DIR)/pw_protobuf_compiler/py $(PYTHON)
-
-$(PW_RPC_GENERATOR_COMPILED_PROTO): $(PW_RPC_GENERATOR_PROTO)
- @echo " [PW_RPC] $<"
- $(V)mkdir -p $(PW_RPC_GEN_PATH)/py/pw_rpc/internal
- $(V)mkdir -p $(PW_RPC_GEN_PATH)/py/pw_protobuf_codegen_protos
- $(V)mkdir -p $(PW_RPC_GEN_PATH)/py/pw_protobuf_protos
- $(V)cp -R $(PIGWEED_DIR)/pw_rpc/py/pw_rpc $(PW_RPC_GEN_PATH)/py/
-
- $(PROTOC) -I$(PIGWEED_DIR)/pw_protobuf/pw_protobuf_protos \
- --experimental_allow_proto3_optional \
- --python_out=$(PW_RPC_GEN_PATH)/py/pw_protobuf_protos \
- $(PW_PROTOBUF_PROTOS)
-
- $(PROTOC) -I$(PIGWEED_DIR)/pw_protobuf/pw_protobuf_codegen_protos \
- --experimental_allow_proto3_optional \
- --python_out=$(PW_RPC_GEN_PATH)/py/pw_protobuf_codegen_protos \
- $(PIGWEED_DIR)/pw_protobuf/pw_protobuf_codegen_protos/codegen_options.proto
-
- $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) --out-dir=$(PW_RPC_GEN_PATH)/py/pw_rpc/internal \
- --compile-dir=$(dir $<) --sources $(PW_RPC_GENERATOR_PROTO) \
- --language python
-
- $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) \
- --plugin-path=$(PIGWEED_DIR)/pw_protobuf/py/pw_protobuf/plugin.py \
- --compile-dir=$(dir $<) --sources $(PW_RPC_GENERATOR_PROTO) \
- --language pwpb
-
-# Generated PW RPC Files #######################################################
-
-PW_RPC_GEN_SRCS = $(patsubst %.proto, \
- $(PW_RPC_GEN_PATH)/%.pb.c, \
- $(PW_RPC_SRCS))
-
-# Include to-be-generated files
-COMMON_CFLAGS += -I$(PW_RPC_GEN_PATH)
-COMMON_CFLAGS += -I$(PW_RPC_GEN_PATH)/$(PIGWEED_DIR)
-COMMON_CFLAGS += $(addprefix -I$(PW_RPC_GEN_PATH)/, $(abspath $(dir $(PW_RPC_SRCS))))
-
-COMMON_SRCS += $(PW_RPC_GEN_SRCS)
-
-# PW RPC library ###############################################################
-
-# Pigweed RPC include paths
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_assert/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_bytes/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_containers/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_function/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_log/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_polyfill/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_polyfill/public_overrides
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_polyfill/standard_library_public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_preprocessor/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_protobuf/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_result/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_rpc/nanopb/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_rpc/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_rpc/pwpb/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_rpc/raw/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_span/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_span/public_overrides
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_status/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_stream/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_string/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_sync/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_toolchain/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_varint/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/third_party/fuchsia/repo/sdk/lib/fit/include
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/third_party/fuchsia/repo/sdk/lib/stdcompat/include
-
-# Pigweed RPC sources
-COMMON_SRCS += $(PIGWEED_DIR)/pw_assert_log/assert_log.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_containers/intrusive_list.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_protobuf/decoder.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_protobuf/encoder.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_protobuf/stream_decoder.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/call.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/channel.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/channel_list.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/client.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/client_call.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/endpoint.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/packet.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/server.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/server_call.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/service.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/nanopb/common.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/nanopb/method.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/nanopb/server_reader_writer.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_rpc/pwpb/server_reader_writer.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_stream/memory_stream.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_varint/stream.cc
-COMMON_SRCS += $(PIGWEED_DIR)/pw_varint/varint.cc
-
-# NanoPB header includes
-COMMON_CFLAGS += -I$(NANOPB_PREFIX)
-
-COMMON_CFLAGS += -DPW_RPC_USE_GLOBAL_MUTEX=0
-COMMON_CFLAGS += -DPW_RPC_YIELD_MODE=PW_RPC_YIELD_MODE_BUSY_LOOP
-
-# Enable closing a client stream.
-COMMON_CFLAGS += -DPW_RPC_CLIENT_STREAM_END_CALLBACK
-
-
-# Use dynamic channel allocation
-COMMON_CFLAGS += -DPW_RPC_DYNAMIC_ALLOCATION
-COMMON_CFLAGS += -DPW_RPC_DYNAMIC_CONTAINER\(type\)="chre::DynamicVector<type>"
-COMMON_CFLAGS += -DPW_RPC_DYNAMIC_CONTAINER_INCLUDE='"chre/util/dynamic_vector.h"'
-
-# NanoPB sources
-COMMON_SRCS += $(NANOPB_PREFIX)/pb_common.c
-COMMON_SRCS += $(NANOPB_PREFIX)/pb_decode.c
-COMMON_SRCS += $(NANOPB_PREFIX)/pb_encode.c
-
-COMMON_CFLAGS += -DPB_NO_PACKED_STRUCTS=1
-
-# Add CHRE Pigweed util sources since nanoapps should always use these
-COMMON_SRCS += $(PIGWEED_CHRE_UTIL_DIR)/chre_channel_output.cc
-COMMON_SRCS += $(PIGWEED_CHRE_UTIL_DIR)/rpc_client.cc
-COMMON_SRCS += $(PIGWEED_CHRE_UTIL_DIR)/rpc_helper.cc
-COMMON_SRCS += $(PIGWEED_CHRE_UTIL_DIR)/rpc_server.cc
-COMMON_SRCS += $(CHRE_UTIL_DIR)/nanoapp/callbacks.cc
-COMMON_SRCS += $(CHRE_UTIL_DIR)/dynamic_vector_base.cc
-
-# CHRE Pigweed overrides
-COMMON_CFLAGS += -I$(PIGWEED_CHRE_DIR)/pw_log_nanoapp/public_overrides
-COMMON_CFLAGS += -I$(PIGWEED_CHRE_DIR)/pw_assert_nanoapp/public_overrides
-
-# Generate PW RPC headers ######################################################
-
-$(PW_RPC_GEN_PATH)/%.pb.c \
- $(PW_RPC_GEN_PATH)/%.pb.h \
- $(PW_RPC_GEN_PATH)/%.rpc.pb.h \
- $(PW_RPC_GEN_PATH)/%.raw_rpc.pb.h: %.proto \
- %.options \
- $(NANOPB_GENERATOR_SRCS) \
- $(PW_RPC_GENERATOR_COMPILED_PROTO)
- @echo " [PW_RPC] $<"
- $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
- --plugin-path=$(NANOPB_PROTOC) \
- --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language nanopb \
- --sources $<
-
- $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
- --plugin-path=$(PIGWEED_DIR)/pw_protobuf/py/pw_protobuf/plugin.py \
- --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language pwpb \
- --sources $<
-
- $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
- --plugin-path=$(PIGWEED_DIR)/pw_rpc/py/pw_rpc/plugin_nanopb.py \
- --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language nanopb_rpc \
- --sources $<
-
- $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
- --plugin-path=$(PIGWEED_DIR)/pw_rpc/py/pw_rpc/plugin_raw.py \
- --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language raw_rpc \
- --sources $<
-
- $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
- --plugin-path=$(PIGWEED_DIR)/pw_rpc/py/pw_rpc/plugin_pwpb.py \
- --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language pwpb_rpc \
- --sources $<
-
-$(PW_RPC_GEN_PATH)/%.pb.c \
- $(PW_RPC_GEN_PATH)/%.pb.h \
- $(PW_RPC_GEN_PATH)/%.rpc.pb.h \
- $(PW_RPC_GEN_PATH)/%.raw_rpc.pb.h: %.proto \
- $(NANOPB_OPTIONS) \
- $(NANOPB_GENERATOR_SRCS) \
- $(PW_RPC_GENERATOR_COMPILED_PROTO)
- @echo " [PW_RPC] $<"
- $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
- --plugin-path=$(NANOPB_PROTOC) \
- --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language nanopb \
- --sources $<
-
- $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
- --plugin-path=$(PIGWEED_DIR)/pw_protobuf/py/pw_protobuf/plugin.py \
- --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language pwpb \
- --sources $<
-
- $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
- --plugin-path=$(PIGWEED_DIR)/pw_rpc/py/pw_rpc/plugin_nanopb.py \
- --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language nanopb_rpc \
- --sources $<
-
- $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
- --plugin-path=$(PIGWEED_DIR)/pw_rpc/py/pw_rpc/plugin_raw.py \
- --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language raw_rpc \
- --sources $<
-
- $(V)$(PW_RPC_GENERATOR_CMD) $(PW_RPC_PROTO_GENERATOR) \
- --plugin-path=$(PIGWEED_DIR)/pw_rpc/py/pw_rpc/plugin_pwpb.py \
- --out-dir=$(PW_RPC_GEN_PATH)/$(dir $<) --compile-dir=$(dir $<) --language pwpb_rpc \
- --sources $<
-endif \ No newline at end of file
diff --git a/external/pigweed/pw_tokenizer.mk b/external/pigweed/pw_tokenizer.mk
index 15b5c5a4..e214e6ba 100644
--- a/external/pigweed/pw_tokenizer.mk
+++ b/external/pigweed/pw_tokenizer.mk
@@ -24,13 +24,17 @@ TOKEN_MAP_CSV_GEN_CMD = $(PYTHON) $(PIGWEED_SCRIPTS_DIR)/database.py create \
COMMON_SRCS += $(PIGWEED_DIR)/pw_tokenizer/encode_args.cc
COMMON_SRCS += $(PIGWEED_DIR)/pw_tokenizer/tokenize.cc
COMMON_SRCS += $(PIGWEED_DIR)/pw_varint/varint.cc
+COMMON_SRCS += $(PIGWEED_DIR)/pw_varint/varint_c.c
# Pigweed include paths
COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_containers/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_log_tokenized/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_log/public
COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_polyfill/public
COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_polyfill/standard_library_public
COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_preprocessor/public
COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_span/public
COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_span/public_overrides
COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_tokenizer/public
-COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_varint/public/
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_varint/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/third_party/fuchsia/repo/sdk/lib/stdcompat/include \ No newline at end of file
diff --git a/external/pigweed/pw_trace.mk b/external/pigweed/pw_trace.mk
new file mode 100644
index 00000000..1a8328bb
--- /dev/null
+++ b/external/pigweed/pw_trace.mk
@@ -0,0 +1,17 @@
+#
+# Makefile for Pigweed's trace module
+#
+
+# Environment Checks
+ifeq ($(ANDROID_BUILD_TOP),)
+$(error "You should supply an ANDROID_BUILD_TOP environment variable \
+ containing a path to the Android source tree. This is typically \
+ provided by initializing the Android build environment.")
+endif
+
+# Location of Pigweed
+PIGWEED_DIR = $(ANDROID_BUILD_TOP)/external/pigweed
+
+# Pigweed include paths
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_trace/public
+COMMON_CFLAGS += -I$(PIGWEED_DIR)/pw_preprocessor/public \ No newline at end of file
diff --git a/host/common/chre_aidl_hal_client.cc b/host/common/chre_aidl_hal_client.cc
index eb2f425e..d4a60eab 100644
--- a/host/common/chre_aidl_hal_client.cc
+++ b/host/common/chre_aidl_hal_client.cc
@@ -30,26 +30,30 @@
#include <regex>
#include <stdexcept>
#include <string>
+#include <unordered_set>
#include <vector>
#include "chre_api/chre/version.h"
#include "chre_host/file_stream.h"
+#include "chre_host/hal_client.h"
#include "chre_host/napp_header.h"
-using aidl::android::hardware::contexthub::AsyncEventType;
-using aidl::android::hardware::contexthub::BnContextHubCallback;
-using aidl::android::hardware::contexthub::ContextHubInfo;
-using aidl::android::hardware::contexthub::ContextHubMessage;
-using aidl::android::hardware::contexthub::HostEndpointInfo;
-using aidl::android::hardware::contexthub::IContextHub;
-using aidl::android::hardware::contexthub::NanoappBinary;
-using aidl::android::hardware::contexthub::NanoappInfo;
-using aidl::android::hardware::contexthub::NanSessionRequest;
-using aidl::android::hardware::contexthub::Setting;
-using android::chre::NanoAppBinaryHeader;
-using android::chre::readFileContents;
-using android::internal::ToString;
-using ndk::ScopedAStatus;
+using ::aidl::android::hardware::contexthub::AsyncEventType;
+using ::aidl::android::hardware::contexthub::BnContextHubCallback;
+using ::aidl::android::hardware::contexthub::ContextHubInfo;
+using ::aidl::android::hardware::contexthub::ContextHubMessage;
+using ::aidl::android::hardware::contexthub::HostEndpointInfo;
+using ::aidl::android::hardware::contexthub::IContextHub;
+using ::aidl::android::hardware::contexthub::MessageDeliveryStatus;
+using ::aidl::android::hardware::contexthub::NanoappBinary;
+using ::aidl::android::hardware::contexthub::NanoappInfo;
+using ::aidl::android::hardware::contexthub::NanSessionRequest;
+using ::aidl::android::hardware::contexthub::Setting;
+using ::android::chre::HalClient;
+using ::android::chre::NanoAppBinaryHeader;
+using ::android::chre::readFileContents;
+using ::android::internal::ToString;
+using ::ndk::ScopedAStatus;
namespace {
// A default id 0 is used for every command requiring a context hub id. When
@@ -58,7 +62,17 @@ namespace {
constexpr uint32_t kContextHubId = 0;
constexpr int32_t kLoadTransactionId = 1;
constexpr int32_t kUnloadTransactionId = 2;
+
+// Though IContextHub.aidl says loading operation is capped at 30s to finish,
+// multiclient HAL can terminate a load/unload transaction after 5s to avoid
+// blocking other load/unload transactions.
constexpr auto kTimeOutThresholdInSec = std::chrono::seconds(5);
+
+// 34a3a27e-9b83-4098-b564-e83b0c28d4bb
+constexpr std::array<uint8_t, 16> kUuid = {0x34, 0xa3, 0xa2, 0x7e, 0x9b, 0x83,
+ 0x40, 0x98, 0xb5, 0x64, 0xe8, 0x3b,
+ 0x0c, 0x28, 0xd4, 0xbb};
+
// Locations should be searched in the sequence defined below:
const char *kPredefinedNanoappPaths[] = {
"/vendor/etc/chre/",
@@ -66,41 +80,8 @@ const char *kPredefinedNanoappPaths[] = {
"/vendor/dsp/sdsp/",
"/vendor/lib/rfsa/adsp/",
};
-// Please keep kUsage in alphabetical order
-constexpr char kUsage[] = R"(
-Usage: chre_aidl_hal_client COMMAND [ARGS]
-COMMAND ARGS...:
- connect - connect to HAL, register the callback and keep
- the session alive while user can execute other
- commands. Use `exit` to quit the session.
- connectEndpoint <HEX_HOST_ENDPOINT_ID>
- - associate an endpoint with the current client
- and notify HAL.
- disableSetting <SETTING> - disable a setting identified by a number defined
- in android/hardware/contexthub/Setting.aidl.
- disableTestMode - disable test mode.
- disconnectEndpoint <HEX_HOST_ENDPOINT_ID>
- - remove an endpoint with the current client and
- notify HAL.
- enableSetting <SETTING> - enable a setting identified by a number defined
- in android/hardware/contexthub/Setting.aidl.
- enableTestMode - enable test mode.
- getContextHubs - get all the context hubs.
- list <PATH_OF_NANOAPPS> - list all the nanoapps' header info in the path.
- load <APP_NAME> - load the nanoapp specified by the name.
- If an absolute path like /path/to/awesome.so,
- which is optional, is not provided then default
- locations are searched.
- query - show all loaded nanoapps (system apps excluded)
- sendMessage <HEX_HOST_ENDPOINT_ID> <HEX_NANOAPP_ID | APP_NAME> <HEX_PAYLOAD>
- - send a payload to a nanoapp.
- unload <HEX_NANOAPP_ID | APP_NAME>
- - unload the nanoapp specified by either the
- nanoapp id in hex format or the app name.
- If an absolute path like /path/to/awesome.so,
- which is optional, is not provided then default
- locations are searched.
-)";
+
+const std::string kClientName{"ChreAidlHalClient"};
inline void throwError(const std::string &message) {
throw std::system_error{std::error_code(), message};
@@ -176,29 +157,30 @@ class ContextHubCallback : public BnContextHubCallback {
<< "\n\trpcServices: " << ToString(app.rpcServices) << "\n}"
<< std::endl;
}
- setPromiseAndRefresh();
+ resetPromise();
return ScopedAStatus::ok();
}
ScopedAStatus handleContextHubMessage(
const ContextHubMessage &message,
const std::vector<std::string> & /*msgContentPerms*/) override {
- std::cout << "Received a message with type " << message.messageType
- << " size " << message.messageBody.size() << " from nanoapp 0x"
- << std::hex << message.nanoappId
- << " sent to the host endpoint 0x"
- << static_cast<int>(message.hostEndPoint) << std::endl;
- std::cout << "message: 0x";
+ std::cout << "Received a message!" << std::endl
+ << " From: 0x" << std::hex << message.nanoappId << std::endl
+ << " To: 0x" << static_cast<int>(message.hostEndPoint)
+ << std::endl
+ << " Body: (type " << message.messageType << " size "
+ << message.messageBody.size() << ") 0x";
for (const uint8_t &data : message.messageBody) {
- std::cout << std::hex << static_cast<uint32_t>(data);
+ std::cout << std::hex << static_cast<uint16_t>(data);
}
- std::cout << std::endl;
- setPromiseAndRefresh();
+ std::cout << std::endl << std::endl;
+ resetPromise();
return ScopedAStatus::ok();
}
- ScopedAStatus handleContextHubAsyncEvent(AsyncEventType /*event*/) override {
- setPromiseAndRefresh();
+ ScopedAStatus handleContextHubAsyncEvent(AsyncEventType event) override {
+ std::cout << "Received async event " << toString(event) << std::endl;
+ resetPromise();
return ScopedAStatus::ok();
}
@@ -207,27 +189,66 @@ class ContextHubCallback : public BnContextHubCallback {
bool success) override {
std::cout << parseTransactionId(transactionId) << " transaction is "
<< (success ? "successful" : "failed") << std::endl;
- setPromiseAndRefresh();
+ resetPromise();
return ScopedAStatus::ok();
}
ScopedAStatus handleNanSessionRequest(
const NanSessionRequest & /* request */) override {
+ resetPromise();
return ScopedAStatus::ok();
}
- std::promise<void> promise;
+ ScopedAStatus handleMessageDeliveryStatus(
+ char16_t /* hostEndPointId */,
+ const MessageDeliveryStatus & /* messageDeliveryStatus */) override {
+ resetPromise();
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus getUuid(std::array<uint8_t, 16> *out_uuid) override {
+ *out_uuid = kUuid;
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus getName(std::string *out_name) override {
+ *out_name = kClientName;
+ return ScopedAStatus::ok();
+ }
- private:
- void setPromiseAndRefresh() {
+ void resetPromise() {
promise.set_value();
promise = std::promise<void>{};
}
+
+ // TODO(b/247124878):
+ // This promise is shared among all the HAL callbacks to simplify the
+ // implementation. This is based on the assumption that every command should
+ // get a response before timeout and the first callback triggered is for the
+ // response.
+ //
+ // In very rare cases, however, the assumption doesn't hold:
+ // - multiple callbacks are triggered by a command and come back out of order
+ // - one command is timed out and the user typed in another command then the
+ // first callback for the first command is triggered
+ // Once we have a chance we should consider refactor this design to let each
+ // callback use their specific promises.
+ std::promise<void> promise;
};
std::shared_ptr<IContextHub> gContextHub = nullptr;
std::shared_ptr<ContextHubCallback> gCallback = nullptr;
+void registerHostCallback() {
+ if (gCallback != nullptr) {
+ gCallback.reset();
+ }
+ gCallback = ContextHubCallback::make<ContextHubCallback>();
+ if (!gContextHub->registerCallback(kContextHubId, gCallback).isOk()) {
+ throwError("Failed to register the callback");
+ }
+}
+
/** Initializes gContextHub and register gCallback. */
std::shared_ptr<IContextHub> getContextHub() {
if (gContextHub == nullptr) {
@@ -238,11 +259,9 @@ std::shared_ptr<IContextHub> getContextHub() {
throwError("Could not find Context Hub HAL");
}
gContextHub = IContextHub::fromBinder(binder);
- gCallback = ContextHubCallback::make<ContextHubCallback>();
-
- if (!gContextHub->registerCallback(kContextHubId, gCallback).isOk()) {
- throwError("Failed to register the callback");
- }
+ }
+ if (gCallback == nullptr) {
+ registerHostCallback();
}
return gContextHub;
}
@@ -304,6 +323,7 @@ void readNanoappHeaders(std::map<std::string, NanoAppBinaryHeader> &nanoapps,
void verifyStatus(const std::string &operation, const ScopedAStatus &status) {
if (!status.isOk()) {
+ gCallback->resetPromise();
throwError(operation + " fails with abnormal status " +
ToString(status.getMessage()) + " error code " +
ToString(status.getServiceSpecificError()));
@@ -317,6 +337,7 @@ void verifyStatusAndSignal(const std::string &operation,
std::future_status future_status =
future_signal.wait_for(kTimeOutThresholdInSec);
if (future_status != std::future_status::ready) {
+ gCallback->resetPromise();
throwError(operation + " doesn't finish within " +
ToString(kTimeOutThresholdInSec.count()) + " seconds");
}
@@ -359,7 +380,6 @@ std::unique_ptr<NanoAppBinaryHeader> findHeaderAndNormalizePath(
continue;
}
pathAndName = predefinedPath + appName + ".so";
- std::cout << "Found the nanoapp header for " << pathAndName << std::endl;
return result;
}
throwError("Unable to find the nanoapp header for " + pathAndName);
@@ -435,19 +455,23 @@ void queryNanoapps() {
gCallback->promise.get_future());
}
-void onEndpointConnected(const std::string &hexEndpointId) {
- auto contextHub = getContextHub();
+HostEndpointInfo createHostEndpointInfo(const std::string &hexEndpointId) {
uint16_t hostEndpointId = verifyAndConvertEndpointHexId(hexEndpointId);
- HostEndpointInfo info = {
+ return {
.hostEndpointId = hostEndpointId,
.type = HostEndpointInfo::Type::NATIVE,
.packageName = "chre_aidl_hal_client",
.attributionTag{},
};
+}
+
+void onEndpointConnected(const std::string &hexEndpointId) {
+ auto contextHub = getContextHub();
+ HostEndpointInfo info = createHostEndpointInfo(hexEndpointId);
// connect the endpoint to HAL
verifyStatus(/* operation= */ "connect endpoint",
contextHub->onHostEndpointConnected(info));
- std::cout << "onHostEndpointConnected() is called. " << std::endl;
+ std::cout << "Connected." << std::endl;
}
void onEndpointDisconnected(const std::string &hexEndpointId) {
@@ -456,13 +480,12 @@ void onEndpointDisconnected(const std::string &hexEndpointId) {
// disconnect the endpoint from HAL
verifyStatus(/* operation= */ "disconnect endpoint",
contextHub->onHostEndpointDisconnected(hostEndpointId));
- std::cout << "onHostEndpointDisconnected() is called. " << std::endl;
+ std::cout << "Disconnected." << std::endl;
}
-/** Sends a hexPayload from hexHostEndpointId to appIdOrName. */
-void sendMessageToNanoapp(const std::string &hexHostEndpointId,
- std::string &appIdOrName,
- const std::string &hexPayload) {
+ContextHubMessage createContextHubMessage(const std::string &hexHostEndpointId,
+ std::string &appIdOrName,
+ const std::string &hexPayload) {
if (!isValidHexNumber(hexPayload)) {
throwError("Invalid hex payload.");
}
@@ -479,13 +502,20 @@ void sendMessageToNanoapp(const std::string &hexHostEndpointId,
contextHubMessage.messageBody.push_back(
std::stoi(hexPayload.substr(i, 2), /* idx= */ nullptr, /* base= */ 16));
}
+ return contextHubMessage;
+}
+
+/** Sends a hexPayload from hexHostEndpointId to appIdOrName. */
+void sendMessageToNanoapp(const std::string &hexHostEndpointId,
+ std::string &appIdOrName,
+ const std::string &hexPayload) {
+ ContextHubMessage contextHubMessage =
+ createContextHubMessage(hexHostEndpointId, appIdOrName, hexPayload);
// send the message
auto contextHub = getContextHub();
- onEndpointConnected(hexHostEndpointId);
auto status = contextHub->sendMessageToHub(kContextHubId, contextHubMessage);
verifyStatusAndSignal(/* operation= */ "sending a message to " + appIdOrName,
status, gCallback->promise.get_future());
- onEndpointDisconnected(hexHostEndpointId);
}
void changeSetting(const std::string &setting, bool enabled) {
@@ -504,14 +534,23 @@ void changeSetting(const std::string &setting, bool enabled) {
void enableTestModeOnContextHub() {
auto status = getContextHub()->setTestMode(true);
- verifyStatusAndSignal(/* operation= */ "enabling test mode", status,
- gCallback->promise.get_future());
+ verifyStatus(/* operation= */ "enabling test mode", status);
+ std::cout << "Test mode is enabled" << std::endl;
}
void disableTestModeOnContextHub() {
auto status = getContextHub()->setTestMode(false);
- verifyStatusAndSignal(/* operation= */ "disabling test mode", status,
- gCallback->promise.get_future());
+ verifyStatus(/* operation= */ "disabling test mode", status);
+ std::cout << "Test mode is disabled" << std::endl;
+}
+
+void getAllPreloadedNanoappIds() {
+ std::vector<int64_t> appIds{};
+ verifyStatus("get preloaded nanoapp ids",
+ getContextHub()->getPreloadedNanoappIds(kContextHubId, &appIds));
+ for (const auto &appId : appIds) {
+ std::cout << "0x" << std::hex << appId << std::endl;
+ }
}
// Please keep Command in alphabetical order
@@ -524,9 +563,11 @@ enum Command {
enableSetting,
enableTestMode,
getContextHubs,
+ getPreloadedNanoappIds,
list,
load,
query,
+ registerCallback,
sendMessage,
unload,
unsupported
@@ -534,34 +575,137 @@ enum Command {
struct CommandInfo {
Command cmd;
- u_int8_t numofArgs; // including cmd;
+ u_int8_t numOfArgs; // including cmd;
+ std::string argsFormat;
+ std::string usage;
};
-Command parseCommand(const std::vector<std::string> &cmdLine) {
- std::map<std::string, CommandInfo> commandMap{
- {"connect", {connect, 1}},
- {"connectEndpoint", {connectEndpoint, 2}},
- {"disableSetting", {disableSetting, 2}},
- {"disableTestMode", {disableTestMode, 1}},
- {"disconnectEndpoint", {disconnectEndpoint, 2}},
- {"enableSetting", {enableSetting, 2}},
- {"enableTestMode", {enableTestMode, 1}},
- {"getContextHubs", {getContextHubs, 1}},
- {"list", {list, 2}},
- {"load", {load, 2}},
- {"query", {query, 1}},
- {"sendMessage", {sendMessage, 4}},
- {"unload", {unload, 2}},
- };
- if (cmdLine.empty() || commandMap.find(cmdLine[0]) == commandMap.end()) {
+const std::map<std::string, CommandInfo> kAllCommands{
+ {"connect",
+ {.cmd = connect,
+ .numOfArgs = 1,
+ .argsFormat = "",
+ .usage = "connect to HAL using hal_client library and keep the session "
+ "alive while user can execute other commands. Use 'exit' to "
+ "quit the session."}},
+ {"connectEndpoint",
+ {.cmd = connectEndpoint,
+ .numOfArgs = 2,
+ .argsFormat = "<HEX_ENDPOINT_ID>",
+ .usage =
+ "associate an endpoint with the current client and notify HAL."}},
+ {"disableSetting",
+ {.cmd = disableSetting,
+ .numOfArgs = 2,
+ .argsFormat = "<SETTING>",
+ .usage = "disable a setting identified by a number defined in "
+ "android/hardware/contexthub/Setting.aidl."}},
+ {"disableTestMode",
+ {.cmd = disableTestMode,
+ .numOfArgs = 1,
+ .argsFormat = "",
+ .usage = "disable test mode."}},
+ {"disconnectEndpoint",
+ {.cmd = disconnectEndpoint,
+ .numOfArgs = 2,
+ .argsFormat = "<HEX_ENDPOINT_ID>",
+ .usage = "remove an endpoint with the current client and notify HAL."}},
+ {"enableSetting",
+ {.cmd = enableSetting,
+ .numOfArgs = 2,
+ .argsFormat = "<SETTING>",
+ .usage = "enable a setting identified by a number defined in "
+ "android/hardware/contexthub/Setting.aidl."}},
+ {"enableTestMode",
+ {.cmd = enableTestMode,
+ .numOfArgs = 1,
+ .argsFormat = "",
+ .usage = "enable test mode."}},
+ {"getContextHubs",
+ {.cmd = getContextHubs,
+ .numOfArgs = 1,
+ .argsFormat = "",
+ .usage = "get all the context hubs."}},
+ {"getPreloadedNanoappIds",
+ {.cmd = getPreloadedNanoappIds,
+ .numOfArgs = 1,
+ .argsFormat = "",
+ .usage = "get a list of ids for the preloaded nanoapps."}},
+ {"list",
+ {.cmd = list,
+ .numOfArgs = 2,
+ .argsFormat = "</PATH/TO/NANOAPPS>",
+ .usage = "list all the nanoapps' header info in the path."}},
+ {"load",
+ {.cmd = load,
+ .numOfArgs = 2,
+ .argsFormat = "<APP_NAME | /PATH/TO/APP_NAME>",
+ .usage = "load the nanoapp specified by the name. If an absolute path is "
+ "not provided the default locations are searched."}},
+ {"query",
+ {.cmd = query,
+ .numOfArgs = 1,
+ .argsFormat = "",
+ .usage = "show all loaded nanoapps (system apps excluded)."}},
+ {"registerCallback",
+ {.cmd = registerCallback,
+ .numOfArgs = 1,
+ .argsFormat = "",
+ .usage = "register a callback for the current client."}},
+ {"sendMessage",
+ {.cmd = sendMessage,
+ .numOfArgs = 4,
+ .argsFormat = "<HEX_ENDPOINT_ID> <HEX_NANOAPP_ID | APP_NAME | "
+ "/PATH/TO/APP_NAME> <HEX_PAYLOAD>",
+ .usage = "send a payload to a nanoapp. If an absolute path is not "
+ "provided the default locations are searched."}},
+ {"unload",
+ {.cmd = unload,
+ .numOfArgs = 2,
+ .argsFormat = "<HEX_NANOAPP_ID | APP_NAME | /PATH/TO/APP_NAME>",
+ .usage = "unload the nanoapp specified by either the nanoapp id or the "
+ "app name. If an absolute path is not provided the default "
+ "locations are searched."}},
+};
+
+void fillSupportedCommandMap(
+ const std::unordered_set<std::string> &supportedCommands,
+ std::map<std::string, CommandInfo> &supportedCommandMap) {
+ std::copy_if(kAllCommands.begin(), kAllCommands.end(),
+ std::inserter(supportedCommandMap, supportedCommandMap.begin()),
+ [&](auto const &kv_pair) {
+ return supportedCommands.find(kv_pair.first) !=
+ supportedCommands.end();
+ });
+}
+
+void printUsage(const std::map<std::string, CommandInfo> &supportedCommands) {
+ constexpr uint32_t kCommandLength = 40;
+ std::cout << std::left << "Usage: COMMAND [ARGUMENTS]" << std::endl;
+ for (auto const &kv_pair : supportedCommands) {
+ std::string cmdLine = kv_pair.first + " " + kv_pair.second.argsFormat;
+ std::cout << std::setw(kCommandLength) << cmdLine;
+ if (cmdLine.size() > kCommandLength) {
+ std::cout << std::endl << std::string(kCommandLength, ' ');
+ }
+ std::cout << " - " + kv_pair.second.usage << std::endl;
+ }
+ std::cout << std::endl;
+}
+
+Command parseCommand(
+ const std::vector<std::string> &cmdLine,
+ const std::map<std::string, CommandInfo> &supportedCommandMap) {
+ if (cmdLine.empty() ||
+ supportedCommandMap.find(cmdLine[0]) == supportedCommandMap.end()) {
return unsupported;
}
- auto cmdInfo = commandMap.at(cmdLine[0]);
- return cmdLine.size() == cmdInfo.numofArgs ? cmdInfo.cmd : unsupported;
+ auto cmdInfo = supportedCommandMap.at(cmdLine[0]);
+ return cmdLine.size() == cmdInfo.numOfArgs ? cmdInfo.cmd : unsupported;
}
void executeCommand(std::vector<std::string> cmdLine) {
- switch (parseCommand(cmdLine)) {
+ switch (parseCommand(cmdLine, kAllCommands)) {
case connectEndpoint: {
onEndpointConnected(cmdLine[1]);
break;
@@ -590,6 +734,10 @@ void executeCommand(std::vector<std::string> cmdLine) {
getAllContextHubs();
break;
}
+ case getPreloadedNanoappIds: {
+ getAllPreloadedNanoappIds();
+ break;
+ }
case list: {
std::map<std::string, NanoAppBinaryHeader> nanoapps{};
readNanoappHeaders(nanoapps, cmdLine[1]);
@@ -607,6 +755,10 @@ void executeCommand(std::vector<std::string> cmdLine) {
queryNanoapps();
break;
}
+ case registerCallback: {
+ registerHostCallback();
+ break;
+ }
case sendMessage: {
sendMessageToNanoapp(cmdLine[1], cmdLine[2], cmdLine[3]);
break;
@@ -616,7 +768,7 @@ void executeCommand(std::vector<std::string> cmdLine) {
break;
}
default:
- std::cout << kUsage;
+ printUsage(kAllCommands);
}
}
@@ -642,22 +794,63 @@ std::vector<std::string> getCommandLine() {
}
void connectToHal() {
- auto hub = getContextHub();
- std::cout << "Connected to context hub." << std::endl;
+ if (gCallback == nullptr) {
+ gCallback = ContextHubCallback::make<ContextHubCallback>();
+ }
+ std::unique_ptr<HalClient> halClient = HalClient::create(gCallback);
+ if (halClient == nullptr) {
+ LOGE("Failed to init the connection to HAL.");
+ return;
+ }
+ std::unordered_set<std::string> supportedCommands = {
+ "connectEndpoint", "disconnectEndpoint", "query", "sendMessage"};
+ std::map<std::string, CommandInfo> supportedCommandMap{};
+ fillSupportedCommandMap(supportedCommands, supportedCommandMap);
+
while (true) {
auto cmdLine = getCommandLine();
if (cmdLine.empty()) {
continue;
}
- if (cmdLine.size() == 1 && cmdLine[0] == "connect") {
- std::cout << "Already in a live session." << std::endl;
- continue;
- }
if (cmdLine.size() == 1 && cmdLine[0] == "exit") {
break;
}
try {
- executeCommand(cmdLine);
+ switch (parseCommand(cmdLine, supportedCommandMap)) {
+ case connectEndpoint: {
+ HostEndpointInfo info =
+ createHostEndpointInfo(/* hexEndpointId= */ cmdLine[1]);
+ verifyStatus(/* operation= */ "connect endpoint",
+ halClient->connectEndpoint(info));
+ break;
+ }
+
+ case query: {
+ verifyStatusAndSignal(/* operation= */ "querying nanoapps",
+ halClient->queryNanoapps(),
+ gCallback->promise.get_future());
+ break;
+ }
+
+ case disconnectEndpoint: {
+ uint16_t hostEndpointId =
+ verifyAndConvertEndpointHexId(/* number= */ cmdLine[1]);
+ verifyStatus(/* operation= */ "disconnect endpoint",
+ halClient->disconnectEndpoint(hostEndpointId));
+ break;
+ }
+ case sendMessage: {
+ ContextHubMessage message = createContextHubMessage(
+ /* hexHostEndpointId= */ cmdLine[1],
+ /* appIdOrName= */ cmdLine[2], /* hexPayload= */ cmdLine[3]);
+ verifyStatusAndSignal(
+ /* operation= */ "sending a message to " + cmdLine[2],
+ halClient->sendMessage(message), gCallback->promise.get_future());
+ break;
+ }
+ default:
+ printUsage(supportedCommandMap);
+ }
} catch (std::system_error &e) {
std::cerr << e.what() << std::endl;
}
@@ -673,15 +866,15 @@ int main(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
cmdLine.emplace_back(argv[i]);
}
- if (cmdLine.size() == 1 && cmdLine[0] == "connect") {
- connectToHal();
- return 0;
- }
try {
+ if (cmdLine.size() == 1 && cmdLine[0] == "connect") {
+ connectToHal();
+ return 0;
+ }
executeCommand(cmdLine);
} catch (std::system_error &e) {
std::cerr << e.what() << std::endl;
return -1;
}
return 0;
-} \ No newline at end of file
+}
diff --git a/host/common/daemon_base.cc b/host/common/daemon_base.cc
index 48737f01..b7681cbb 100644
--- a/host/common/daemon_base.cc
+++ b/host/common/daemon_base.cc
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// TODO(b/298459533): metrics_reporter_in_the_daemon ramp up -> remove old
+// code
+
#include <signal.h>
#include <cstdlib>
#include <fstream>
@@ -25,12 +28,9 @@
#include "chre_host/napp_header.h"
#ifdef CHRE_DAEMON_METRIC_ENABLED
+#include <android_chre_flags.h>
#include <chre_atoms_log.h>
#include <system/chre/core/chre_metrics.pb.h>
-
-using ::aidl::android::frameworks::stats::IStats;
-using ::aidl::android::frameworks::stats::VendorAtom;
-using ::aidl::android::frameworks::stats::VendorAtomValue;
#endif // CHRE_DAEMON_METRIC_ENABLED
// Aliased for consistency with the way these symbols are referenced in
@@ -40,6 +40,17 @@ namespace fbs = ::chre::fbs;
namespace android {
namespace chre {
+#ifdef CHRE_DAEMON_METRIC_ENABLED
+using ::aidl::android::frameworks::stats::IStats;
+using ::aidl::android::frameworks::stats::VendorAtom;
+using ::aidl::android::frameworks::stats::VendorAtomValue;
+
+using ::android::chre::Atoms::CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED;
+using ::android::chre::Atoms::CHRE_PAL_OPEN_FAILED;
+using ::android::chre::Atoms::ChrePalOpenFailed;
+using ::android::chre::flags::metrics_reporter_in_the_daemon;
+#endif // CHRE_DAEMON_METRIC_ENABLED
+
namespace {
void signalHandler(void *ctx) {
@@ -153,46 +164,66 @@ void ChreDaemonBase::handleMetricLog(const ::chre::fbs::MetricLogT *metricMsg) {
const std::vector<int8_t> &encodedMetric = metricMsg->encoded_metric;
switch (metricMsg->id) {
- case Atoms::CHRE_PAL_OPEN_FAILED: {
+ case CHRE_PAL_OPEN_FAILED: {
metrics::ChrePalOpenFailed metric;
if (!metric.ParseFromArray(encodedMetric.data(), encodedMetric.size())) {
LOGE("Failed to parse metric data");
} else {
- std::vector<VendorAtomValue> values(2);
- values[0].set<VendorAtomValue::intValue>(metric.pal());
- values[1].set<VendorAtomValue::intValue>(metric.type());
- const VendorAtom atom{
- .atomId = Atoms::CHRE_PAL_OPEN_FAILED,
- .values{std::move(values)},
- };
- reportMetric(atom);
+ if (metrics_reporter_in_the_daemon()) {
+ ChrePalOpenFailed::ChrePalType pal =
+ static_cast<ChrePalOpenFailed::ChrePalType>(metric.pal());
+ ChrePalOpenFailed::Type type =
+ static_cast<ChrePalOpenFailed::Type>(metric.type());
+ if (!mMetricsReporter.logPalOpenFailed(pal, type)) {
+ LOGE("Could not log the PAL open failed metric");
+ }
+ } else {
+ std::vector<VendorAtomValue> values(2);
+ values[0].set<VendorAtomValue::intValue>(metric.pal());
+ values[1].set<VendorAtomValue::intValue>(metric.type());
+ const VendorAtom atom{
+ .atomId = Atoms::CHRE_PAL_OPEN_FAILED,
+ .values{std::move(values)},
+ };
+ reportMetric(atom);
+ }
}
break;
}
- case Atoms::CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED: {
+ case CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED: {
metrics::ChreEventQueueSnapshotReported metric;
if (!metric.ParseFromArray(encodedMetric.data(), encodedMetric.size())) {
LOGE("Failed to parse metric data");
} else {
- std::vector<VendorAtomValue> values(6);
- values[0].set<VendorAtomValue::intValue>(
- metric.snapshot_chre_get_time_ms());
- values[1].set<VendorAtomValue::intValue>(metric.max_event_queue_size());
- values[2].set<VendorAtomValue::intValue>(
- metric.mean_event_queue_size());
- values[3].set<VendorAtomValue::intValue>(metric.num_dropped_events());
- // Last two values are not currently populated and will be implemented
- // later. To avoid confusion of the interpretation, we use UINT32_MAX
- // as a placeholder value.
- values[4].set<VendorAtomValue::intValue>(
- UINT32_MAX); // max_queue_delay_us
- values[5].set<VendorAtomValue::intValue>(
- UINT32_MAX); // mean_queue_delay_us
- const VendorAtom atom{
- .atomId = Atoms::CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED,
- .values{std::move(values)},
- };
- reportMetric(atom);
+ if (metrics_reporter_in_the_daemon()) {
+ if (!mMetricsReporter.logEventQueueSnapshotReported(
+ metric.snapshot_chre_get_time_ms(),
+ metric.max_event_queue_size(), metric.mean_event_queue_size(),
+ metric.num_dropped_events())) {
+ LOGE("Could not log the event queue snapshot metric");
+ }
+ } else {
+ std::vector<VendorAtomValue> values(6);
+ values[0].set<VendorAtomValue::intValue>(
+ metric.snapshot_chre_get_time_ms());
+ values[1].set<VendorAtomValue::intValue>(
+ metric.max_event_queue_size());
+ values[2].set<VendorAtomValue::intValue>(
+ metric.mean_event_queue_size());
+ values[3].set<VendorAtomValue::intValue>(metric.num_dropped_events());
+ // Last two values are not currently populated and will be implemented
+ // later. To avoid confusion of the interpretation, we use UINT32_MAX
+ // as a placeholder value.
+ values[4].set<VendorAtomValue::intValue>(
+ UINT32_MAX); // max_queue_delay_us
+ values[5].set<VendorAtomValue::intValue>(
+ UINT32_MAX); // mean_queue_delay_us
+ const VendorAtom atom{
+ .atomId = Atoms::CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED,
+ .values{std::move(values)},
+ };
+ reportMetric(atom);
+ }
}
break;
}
diff --git a/host/common/fbs_daemon_base.cc b/host/common/fbs_daemon_base.cc
index 94f07708..b41926f5 100644
--- a/host/common/fbs_daemon_base.cc
+++ b/host/common/fbs_daemon_base.cc
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// TODO(b/298459533): metrics_reporter_in_the_daemon ramp up -> remove old
+// code
+
#include <cstdlib>
#include <fstream>
@@ -26,11 +29,8 @@
#ifdef CHRE_DAEMON_METRIC_ENABLED
#include <aidl/android/frameworks/stats/IStats.h>
#include <android/binder_manager.h>
+#include <android_chre_flags.h>
#include <chre_atoms_log.h>
-
-using ::aidl::android::frameworks::stats::IStats;
-using ::aidl::android::frameworks::stats::VendorAtom;
-using ::aidl::android::frameworks::stats::VendorAtomValue;
#endif // CHRE_DAEMON_METRIC_ENABLED
// Aliased for consistency with the way these symbols are referenced in
@@ -40,6 +40,14 @@ namespace fbs = ::chre::fbs;
namespace android {
namespace chre {
+#ifdef CHRE_DAEMON_METRIC_ENABLED
+using ::aidl::android::frameworks::stats::IStats;
+using ::aidl::android::frameworks::stats::VendorAtom;
+using ::aidl::android::frameworks::stats::VendorAtomValue;
+using ::android::chre::Atoms::ChreHalNanoappLoadFailed;
+using ::android::chre::flags::metrics_reporter_in_the_daemon;
+#endif // CHRE_DAEMON_METRIC_ENABLED
+
bool FbsDaemonBase::sendNanoappLoad(uint64_t appId, uint32_t appVersion,
uint32_t appTargetApiVersion,
const std::string &appBinaryName,
@@ -145,6 +153,9 @@ void FbsDaemonBase::onMessageReceived(const unsigned char *messageBuffer,
fbs::UnPackMessageContainer(messageBuffer);
handleNanConfigurationRequest(
container->message.AsNanConfigurationRequest());
+ } else if (messageType == fbs::ChreMessage::NanoappInstanceIdInfo) {
+ // TODO(b/242760291): Use this info to map nanoapp log detokenizers with
+ // instance ID in log message parser.
} else if (hostClientId == kHostClientIdDaemon) {
handleDaemonMessage(messageBuffer);
} else if (hostClientId == ::chre::kHostClientIdUnspecified) {
@@ -176,18 +187,27 @@ void FbsDaemonBase::handleDaemonMessage(const uint8_t *message) {
mPreloadedNanoappPendingTransactions.front().transactionId);
#ifdef CHRE_DAEMON_METRIC_ENABLED
- std::vector<VendorAtomValue> values(3);
- values[0].set<VendorAtomValue::longValue>(
- mPreloadedNanoappPendingTransactions.front().nanoappId);
- values[1].set<VendorAtomValue::intValue>(
- Atoms::ChreHalNanoappLoadFailed::TYPE_PRELOADED);
- values[2].set<VendorAtomValue::intValue>(
- Atoms::ChreHalNanoappLoadFailed::REASON_ERROR_GENERIC);
- const VendorAtom atom{
- .atomId = Atoms::CHRE_HAL_NANOAPP_LOAD_FAILED,
- .values{std::move(values)},
- };
- reportMetric(atom);
+ if (metrics_reporter_in_the_daemon()) {
+ if (!mMetricsReporter.logNanoappLoadFailed(
+ mPreloadedNanoappPendingTransactions.front().nanoappId,
+ ChreHalNanoappLoadFailed::TYPE_PRELOADED,
+ ChreHalNanoappLoadFailed::REASON_ERROR_GENERIC)) {
+ LOGE("Could not log the nanoapp load failed metric");
+ }
+ } else {
+ std::vector<VendorAtomValue> values(3);
+ values[0].set<VendorAtomValue::longValue>(
+ mPreloadedNanoappPendingTransactions.front().nanoappId);
+ values[1].set<VendorAtomValue::intValue>(
+ Atoms::ChreHalNanoappLoadFailed::TYPE_PRELOADED);
+ values[2].set<VendorAtomValue::intValue>(
+ Atoms::ChreHalNanoappLoadFailed::REASON_ERROR_GENERIC);
+ const VendorAtom atom{
+ .atomId = Atoms::CHRE_HAL_NANOAPP_LOAD_FAILED,
+ .values{std::move(values)},
+ };
+ reportMetric(atom);
+ }
#endif // CHRE_DAEMON_METRIC_ENABLED
}
mPreloadedNanoappPendingTransactions.pop();
diff --git a/host/common/fragmented_load_transaction.cc b/host/common/fragmented_load_transaction.cc
index c3c26d33..42c910d8 100644
--- a/host/common/fragmented_load_transaction.cc
+++ b/host/common/fragmented_load_transaction.cc
@@ -49,9 +49,8 @@ inline std::vector<uint8_t> getSubVector(const std::vector<uint8_t> &source,
FragmentedLoadTransaction::FragmentedLoadTransaction(
uint32_t transactionId, uint64_t appId, uint32_t appVersion,
uint32_t appFlags, uint32_t targetApiVersion,
- const std::vector<uint8_t> &appBinary, size_t fragmentSize) {
- mTransactionId = transactionId;
-
+ const std::vector<uint8_t> &appBinary, size_t fragmentSize)
+ : mTransactionId(transactionId), mNanoappId(appId) {
// Start with fragmentId at 1 since 0 is used to indicate
// legacy behavior at CHRE
size_t fragmentId = 1;
@@ -64,7 +63,7 @@ FragmentedLoadTransaction::FragmentedLoadTransaction(
getSubVector(appBinary, byteIndex, fragmentSize));
} else {
mFragmentRequests.emplace_back(
- fragmentId++, transactionId,
+ fragmentId++, transactionId, appId,
getSubVector(appBinary, byteIndex, fragmentSize));
}
diff --git a/host/common/hal_client.cc b/host/common/hal_client.cc
new file mode 100644
index 00000000..6a1c0bfa
--- /dev/null
+++ b/host/common/hal_client.cc
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOG_TAG
+#define LOG_TAG "CHRE.HAL.CLIENT"
+#endif
+
+#include "chre_host/hal_client.h"
+
+#include <utils/SystemClock.h>
+
+#include <cinttypes>
+#include <thread>
+
+namespace android::chre {
+
+using ::aidl::android::hardware::contexthub::IContextHub;
+using ::aidl::android::hardware::contexthub::IContextHubCallback;
+using ::ndk::ScopedAStatus;
+
+std::unique_ptr<HalClient> HalClient::create(
+ const std::shared_ptr<IContextHubCallback> &callback,
+ int32_t contextHubId) {
+ if (callback == nullptr) {
+ LOGE("Callback function must not be null.");
+ return nullptr;
+ }
+ auto halClient =
+ std::unique_ptr<HalClient>(new HalClient(callback, contextHubId));
+ if (halClient->initConnection() != HalError::SUCCESS) {
+ return nullptr;
+ }
+ return halClient;
+}
+
+HalError HalClient::initConnection() {
+ std::lock_guard<std::shared_mutex> lockGuard{mConnectionLock};
+
+ if (mContextHub != nullptr) {
+ LOGW("Context hub is already connected.");
+ return HalError::SUCCESS;
+ }
+
+ // Wait to connect to the service. Note that we don't do local retries because
+ // we're relying on the internal retries in AServiceManager_waitForService().
+ // If HAL service has just restarted, it can take a few seconds to connect.
+ ndk::SpAIBinder binder{
+ AServiceManager_waitForService(kAidlServiceName.c_str())};
+ if (binder.get() == nullptr) {
+ return HalError::BINDER_CONNECTION_FAILED;
+ }
+
+ // Link the death recipient to handle the binder disconnection event.
+ if (AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(), this) !=
+ STATUS_OK) {
+ LOGE("Failed to link the binder death recipient");
+ return HalError::LINK_DEATH_RECIPIENT_FAILED;
+ }
+
+ // Retrieve a handle of context hub service.
+ mContextHub = IContextHub::fromBinder(binder);
+ if (mContextHub == nullptr) {
+ LOGE("Got null context hub from the binder connection");
+ return HalError::NULL_CONTEXT_HUB_FROM_BINDER;
+ }
+
+ // Register an IContextHubCallback.
+ ScopedAStatus status =
+ mContextHub->registerCallback(kDefaultContextHubId, mCallback);
+ if (!status.isOk()) {
+ LOGE("Unable to register callback: %s", status.getDescription().c_str());
+ return HalError::CALLBACK_REGISTRATION_FAILED;
+ }
+ LOGI("Successfully connected to HAL.");
+ return HalError::SUCCESS;
+}
+
+void HalClient::onHalDisconnected(void *cookie) {
+ LOGW("CHRE HAL is disconnected. Reconnecting...");
+ int64_t startTime = ::android::elapsedRealtime();
+ auto *halClient = static_cast<HalClient *>(cookie);
+ {
+ std::lock_guard<std::shared_mutex> lock(halClient->mConnectionLock);
+ halClient->mContextHub = nullptr;
+ }
+
+ HalError result = halClient->initConnection();
+ uint64_t duration = ::android::elapsedRealtime() - startTime;
+ if (result != HalError::SUCCESS) {
+ LOGE("Failed to fully reconnect to HAL after %" PRIu64
+ "ms, HalErrorCode: %" PRIi32,
+ duration, result);
+ return;
+ }
+ tryReconnectEndpoints(halClient);
+ LOGI("Reconnected to HAL after %" PRIu64 "ms", duration);
+}
+
+ScopedAStatus HalClient::connectEndpoint(
+ const HostEndpointInfo &hostEndpointInfo) {
+ HostEndpointId endpointId = hostEndpointInfo.hostEndpointId;
+ if (isEndpointConnected(endpointId)) {
+ // Connecting the endpoint again even though it is already connected to let
+ // HAL and/or CHRE be the single place to control the behavior.
+ LOGW("Endpoint id %" PRIu16 " is already connected.", endpointId);
+ }
+ ScopedAStatus result = callIfConnected(
+ [&]() { return mContextHub->onHostEndpointConnected(hostEndpointInfo); });
+ if (result.isOk()) {
+ insertConnectedEndpoint(hostEndpointInfo);
+ } else {
+ LOGE("Failed to connect the endpoint id %" PRIu16,
+ hostEndpointInfo.hostEndpointId);
+ }
+ return result;
+}
+
+ScopedAStatus HalClient::disconnectEndpoint(HostEndpointId hostEndpointId) {
+ if (!isEndpointConnected(hostEndpointId)) {
+ // Disconnecting the endpoint again even though it is already disconnected
+ // to let HAL and/or CHRE be the single place to control the behavior.
+ LOGW("Endpoint id %" PRIu16 " is already disconnected.", hostEndpointId);
+ }
+ ScopedAStatus result = callIfConnected([&]() {
+ return mContextHub->onHostEndpointDisconnected(hostEndpointId);
+ });
+ if (result.isOk()) {
+ removeConnectedEndpoint(hostEndpointId);
+ } else {
+ LOGE("Failed to disconnect the endpoint id %" PRIu16, hostEndpointId);
+ }
+ return result;
+}
+
+ScopedAStatus HalClient::sendMessage(const ContextHubMessage &message) {
+ uint16_t hostEndpointId = message.hostEndPoint;
+ if (!isEndpointConnected(hostEndpointId)) {
+ // For now this is still allowed but in the future
+ // HalError::UNEXPECTED_ENDPOINT_STATE will be returned.
+ LOGW("Endpoint id %" PRIu16
+ " is unknown or disconnected. Message sending will be skipped in the "
+ "future.");
+ }
+ return callIfConnected(
+ [&]() { return mContextHub->sendMessageToHub(mContextHubId, message); });
+}
+
+void HalClient::tryReconnectEndpoints(HalClient *halClient) {
+ std::lock_guard<std::shared_mutex> lock(halClient->mStateLock);
+ for (const auto &[endpointId, endpointInfo] :
+ halClient->mConnectedEndpoints) {
+ if (!halClient
+ ->callIfConnected([&]() {
+ return halClient->mContextHub->onHostEndpointConnected(
+ endpointInfo);
+ })
+ .isOk()) {
+ LOGE("Failed to set up the connected state for endpoint %" PRIu16
+ " after HAL restarts.",
+ endpointId);
+ halClient->mConnectedEndpoints.erase(endpointId);
+ } else {
+ LOGI("Reconnected endpoint %" PRIu16 " to CHRE HAL.", endpointId);
+ }
+ }
+}
+} // namespace android::chre \ No newline at end of file
diff --git a/host/common/host_protocol_host.cc b/host/common/host_protocol_host.cc
index 24932061..a24ec94e 100644
--- a/host/common/host_protocol_host.cc
+++ b/host/common/host_protocol_host.cc
@@ -250,5 +250,10 @@ void HostProtocolHost::encodeNanconfigurationUpdate(
finalize(builder, fbs::ChreMessage::NanConfigurationUpdate, message.Union());
}
+void HostProtocolHost::encodePulseRequest(FlatBufferBuilder &builder) {
+ auto message = fbs::CreatePulseRequest(builder);
+ finalize(builder, fbs::ChreMessage::PulseRequest, message.Union());
+}
+
} // namespace chre
} // namespace android
diff --git a/host/common/include/chre_host/daemon_base.h b/host/common/include/chre_host/daemon_base.h
index c0c6e730..453a8665 100644
--- a/host/common/include/chre_host/daemon_base.h
+++ b/host/common/include/chre_host/daemon_base.h
@@ -25,10 +25,14 @@
* implement.
*/
+// TODO(b/298459533): metrics_reporter_in_the_daemon ramp up -> remove old
+// code
+
#include <atomic>
#include <csignal>
#include <cstdint>
#include <map>
+#include <mutex>
#include <queue>
#include <string>
#include <thread>
@@ -40,6 +44,8 @@
#ifdef CHRE_DAEMON_METRIC_ENABLED
#include <aidl/android/frameworks/stats/IStats.h>
#include <android/binder_manager.h>
+
+#include "chre_host/metrics_reporter.h"
#endif // CHRE_DAEMON_METRIC_ENABLED
namespace android {
@@ -230,16 +236,15 @@ class ChreDaemonBase {
#ifdef CHRE_LOG_ATOM_EXTENSION_ENABLED
/**
* Handles additional metrics that aren't logged by the common CHRE code.
- *
*/
virtual void handleVendorMetricLog(
const ::chre::fbs::MetricLogT *metric_msg) = 0;
#endif // CHRE_LOG_ATOM_EXTENSION_ENABLED
/**
- * Create and report CHRE vendor atom and send it to stats_client
+ * Create and report CHRE vendor atom and send it to stats_client.
*
- * @param atom the vendor atom to be reported
+ * @param atom the vendor atom to be reported.
*/
void reportMetric(const aidl::android::frameworks::stats::VendorAtom &atom);
#endif // CHRE_DAEMON_METRIC_ENABLED
@@ -263,6 +268,10 @@ class ChreDaemonBase {
//! Server used to communicate with daemon clients
SocketServer mServer;
+#ifdef CHRE_DAEMON_METRIC_ENABLED
+ android::chre::MetricsReporter mMetricsReporter;
+#endif // CHRE_DAEMON_METRIC_ENABLED
+
private:
LogMessageParser mLogger;
diff --git a/host/common/include/chre_host/fragmented_load_transaction.h b/host/common/include/chre_host/fragmented_load_transaction.h
index f0b9ff45..1d60b3e4 100644
--- a/host/common/include/chre_host/fragmented_load_transaction.h
+++ b/host/common/include/chre_host/fragmented_load_transaction.h
@@ -50,8 +50,8 @@ struct FragmentedLoadRequest {
std::vector<uint8_t> binary;
FragmentedLoadRequest(size_t fragmentId, uint32_t transactionId,
- const std::vector<uint8_t> &binary)
- : FragmentedLoadRequest(fragmentId, transactionId, 0, 0, 0, 0, 0,
+ uint64_t appId, const std::vector<uint8_t> &binary)
+ : FragmentedLoadRequest(fragmentId, transactionId, appId, 0, 0, 0, 0,
binary) {}
FragmentedLoadRequest(size_t fragmentId, uint32_t transactionId,
@@ -115,10 +115,15 @@ class FragmentedLoadTransaction {
return mTransactionId;
}
+ uint64_t getNanoappId() const {
+ return mNanoappId;
+ }
+
private:
std::vector<FragmentedLoadRequest> mFragmentRequests;
size_t mCurrentRequestIndex = 0;
uint32_t mTransactionId;
+ uint64_t mNanoappId;
static constexpr size_t kDefaultFragmentSize =
CHRE_HOST_DEFAULT_FRAGMENT_SIZE;
diff --git a/host/common/include/chre_host/generated/host_messages_generated.h b/host/common/include/chre_host/generated/host_messages_generated.h
index 9b80d2ec..262bb3ff 100644
--- a/host/common/include/chre_host/generated/host_messages_generated.h
+++ b/host/common/include/chre_host/generated/host_messages_generated.h
@@ -45,6 +45,10 @@ struct LoadNanoappResponse;
struct LoadNanoappResponseBuilder;
struct LoadNanoappResponseT;
+struct NanoappInstanceIdInfo;
+struct NanoappInstanceIdInfoBuilder;
+struct NanoappInstanceIdInfoT;
+
struct UnloadNanoappRequest;
struct UnloadNanoappRequestBuilder;
struct UnloadNanoappRequestT;
@@ -129,6 +133,14 @@ struct DebugConfiguration;
struct DebugConfigurationBuilder;
struct DebugConfigurationT;
+struct PulseRequest;
+struct PulseRequestBuilder;
+struct PulseRequestT;
+
+struct PulseResponse;
+struct PulseResponseBuilder;
+struct PulseResponseT;
+
struct HostAddress;
struct MessageContainer;
@@ -340,11 +352,14 @@ enum class ChreMessage : uint8_t {
NanConfigurationRequest = 26,
NanConfigurationUpdate = 27,
DebugConfiguration = 28,
+ PulseRequest = 29,
+ PulseResponse = 30,
+ NanoappInstanceIdInfo = 31,
MIN = NONE,
- MAX = DebugConfiguration
+ MAX = NanoappInstanceIdInfo
};
-inline const ChreMessage (&EnumValuesChreMessage())[29] {
+inline const ChreMessage (&EnumValuesChreMessage())[32] {
static const ChreMessage values[] = {
ChreMessage::NONE,
ChreMessage::NanoappMessage,
@@ -374,13 +389,16 @@ inline const ChreMessage (&EnumValuesChreMessage())[29] {
ChreMessage::BatchedMetricLog,
ChreMessage::NanConfigurationRequest,
ChreMessage::NanConfigurationUpdate,
- ChreMessage::DebugConfiguration
+ ChreMessage::DebugConfiguration,
+ ChreMessage::PulseRequest,
+ ChreMessage::PulseResponse,
+ ChreMessage::NanoappInstanceIdInfo
};
return values;
}
inline const char * const *EnumNamesChreMessage() {
- static const char * const names[30] = {
+ static const char * const names[33] = {
"NONE",
"NanoappMessage",
"HubInfoRequest",
@@ -410,13 +428,16 @@ inline const char * const *EnumNamesChreMessage() {
"NanConfigurationRequest",
"NanConfigurationUpdate",
"DebugConfiguration",
+ "PulseRequest",
+ "PulseResponse",
+ "NanoappInstanceIdInfo",
nullptr
};
return names;
}
inline const char *EnumNameChreMessage(ChreMessage e) {
- if (flatbuffers::IsOutRange(e, ChreMessage::NONE, ChreMessage::DebugConfiguration)) return "";
+ if (flatbuffers::IsOutRange(e, ChreMessage::NONE, ChreMessage::NanoappInstanceIdInfo)) return "";
const size_t index = static_cast<size_t>(e);
return EnumNamesChreMessage()[index];
}
@@ -537,6 +558,18 @@ template<> struct ChreMessageTraits<chre::fbs::DebugConfiguration> {
static const ChreMessage enum_value = ChreMessage::DebugConfiguration;
};
+template<> struct ChreMessageTraits<chre::fbs::PulseRequest> {
+ static const ChreMessage enum_value = ChreMessage::PulseRequest;
+};
+
+template<> struct ChreMessageTraits<chre::fbs::PulseResponse> {
+ static const ChreMessage enum_value = ChreMessage::PulseResponse;
+};
+
+template<> struct ChreMessageTraits<chre::fbs::NanoappInstanceIdInfo> {
+ static const ChreMessage enum_value = ChreMessage::NanoappInstanceIdInfo;
+};
+
struct ChreMessageUnion {
ChreMessage type;
void *value;
@@ -793,6 +826,30 @@ struct ChreMessageUnion {
return type == ChreMessage::DebugConfiguration ?
reinterpret_cast<const chre::fbs::DebugConfigurationT *>(value) : nullptr;
}
+ chre::fbs::PulseRequestT *AsPulseRequest() {
+ return type == ChreMessage::PulseRequest ?
+ reinterpret_cast<chre::fbs::PulseRequestT *>(value) : nullptr;
+ }
+ const chre::fbs::PulseRequestT *AsPulseRequest() const {
+ return type == ChreMessage::PulseRequest ?
+ reinterpret_cast<const chre::fbs::PulseRequestT *>(value) : nullptr;
+ }
+ chre::fbs::PulseResponseT *AsPulseResponse() {
+ return type == ChreMessage::PulseResponse ?
+ reinterpret_cast<chre::fbs::PulseResponseT *>(value) : nullptr;
+ }
+ const chre::fbs::PulseResponseT *AsPulseResponse() const {
+ return type == ChreMessage::PulseResponse ?
+ reinterpret_cast<const chre::fbs::PulseResponseT *>(value) : nullptr;
+ }
+ chre::fbs::NanoappInstanceIdInfoT *AsNanoappInstanceIdInfo() {
+ return type == ChreMessage::NanoappInstanceIdInfo ?
+ reinterpret_cast<chre::fbs::NanoappInstanceIdInfoT *>(value) : nullptr;
+ }
+ const chre::fbs::NanoappInstanceIdInfoT *AsNanoappInstanceIdInfo() const {
+ return type == ChreMessage::NanoappInstanceIdInfo ?
+ reinterpret_cast<const chre::fbs::NanoappInstanceIdInfoT *>(value) : nullptr;
+ }
};
bool VerifyChreMessage(flatbuffers::Verifier &verifier, const void *obj, ChreMessage type);
@@ -2026,6 +2083,80 @@ inline flatbuffers::Offset<LoadNanoappResponse> CreateLoadNanoappResponse(
flatbuffers::Offset<LoadNanoappResponse> CreateLoadNanoappResponse(flatbuffers::FlatBufferBuilder &_fbb, const LoadNanoappResponseT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+struct NanoappInstanceIdInfoT : public flatbuffers::NativeTable {
+ typedef NanoappInstanceIdInfo TableType;
+ uint32_t instance_id;
+ uint64_t app_id;
+ NanoappInstanceIdInfoT()
+ : instance_id(0),
+ app_id(0) {
+ }
+};
+
+struct NanoappInstanceIdInfo FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef NanoappInstanceIdInfoT NativeTableType;
+ typedef NanoappInstanceIdInfoBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_INSTANCE_ID = 4,
+ VT_APP_ID = 6
+ };
+ uint32_t instance_id() const {
+ return GetField<uint32_t>(VT_INSTANCE_ID, 0);
+ }
+ bool mutate_instance_id(uint32_t _instance_id) {
+ return SetField<uint32_t>(VT_INSTANCE_ID, _instance_id, 0);
+ }
+ uint64_t app_id() const {
+ return GetField<uint64_t>(VT_APP_ID, 0);
+ }
+ bool mutate_app_id(uint64_t _app_id) {
+ return SetField<uint64_t>(VT_APP_ID, _app_id, 0);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<uint32_t>(verifier, VT_INSTANCE_ID) &&
+ VerifyField<uint64_t>(verifier, VT_APP_ID) &&
+ verifier.EndTable();
+ }
+ NanoappInstanceIdInfoT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(NanoappInstanceIdInfoT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<NanoappInstanceIdInfo> Pack(flatbuffers::FlatBufferBuilder &_fbb, const NanoappInstanceIdInfoT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct NanoappInstanceIdInfoBuilder {
+ typedef NanoappInstanceIdInfo Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_instance_id(uint32_t instance_id) {
+ fbb_.AddElement<uint32_t>(NanoappInstanceIdInfo::VT_INSTANCE_ID, instance_id, 0);
+ }
+ void add_app_id(uint64_t app_id) {
+ fbb_.AddElement<uint64_t>(NanoappInstanceIdInfo::VT_APP_ID, app_id, 0);
+ }
+ explicit NanoappInstanceIdInfoBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ NanoappInstanceIdInfoBuilder &operator=(const NanoappInstanceIdInfoBuilder &);
+ flatbuffers::Offset<NanoappInstanceIdInfo> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<NanoappInstanceIdInfo>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<NanoappInstanceIdInfo> CreateNanoappInstanceIdInfo(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ uint32_t instance_id = 0,
+ uint64_t app_id = 0) {
+ NanoappInstanceIdInfoBuilder builder_(_fbb);
+ builder_.add_app_id(app_id);
+ builder_.add_instance_id(instance_id);
+ return builder_.Finish();
+}
+
+flatbuffers::Offset<NanoappInstanceIdInfo> CreateNanoappInstanceIdInfo(flatbuffers::FlatBufferBuilder &_fbb, const NanoappInstanceIdInfoT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
struct UnloadNanoappRequestT : public flatbuffers::NativeTable {
typedef UnloadNanoappRequest TableType;
uint32_t transaction_id;
@@ -2760,7 +2891,8 @@ struct LogMessageV2 FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
/// uint8_t - Log metadata, encoded as follows:
/// [EI(Upper nibble) | Level(Lower nibble)]
/// * Log Type
- /// (0 = No encoding, 1 = Tokenized log, 2 = BT snoop log)
+ /// (0 = No encoding, 1 = Tokenized log,
+ /// 2 = BT snoop log, 3 = Nanoapp Tokenized log)
/// * LogBuffer log level (1 = error, 2 = warn,
/// 3 = info, 4 = debug,
/// 5 = verbose)
@@ -2772,7 +2904,7 @@ struct LogMessageV2 FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
/// terminated string (eg: pass to string manipulation functions, get its
/// size via strlen(), etc.).
///
- /// * Encoded logs: The first byte of the log buffer indicates the size of
+ /// * Tokenized logs: The first byte of the log buffer indicates the size of
/// the actual encoded data to follow. For example, if a tokenized log of
/// size 24 bytes were to be represented, a buffer of size 25 bytes would
/// be needed to encode this as: [Size(1B) | Data(24B)]. A decoder would
@@ -2786,6 +2918,15 @@ struct LogMessageV2 FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
/// size 24 bytes were to be represented, a buffer of size 26 bytes would
/// be needed to encode this as: [Direction(1B) | Size(1B) | Data(24B)].
///
+ /// * Tokenized nanoapp logs: This log type is specifically for nanoapps with
+ /// tokenized logs enabled. Similar to tokenized logs, the first byte is the
+ /// size of the tokenized log data at the end. The next two bytes is the instance
+ /// ID of the nanoapp which sends this tokenized log message. This instance ID
+ /// will be used to map to the corresponding detokenizer in the log message parser.
+ /// For example, if a nanoapp tokenized log of size 24 bytes were to be sent,
+ /// a buffer of size 27 bytes would be needed to encode this as:
+ /// [Size(1B) | InstanceId (2B) | Data(24B)].
+ ///
/// This pattern repeats until the end of the buffer for multiple log
/// messages. The last byte will always be a null-terminator. There are no
/// padding bytes between these fields. Treat this like a packed struct and be
@@ -3479,6 +3620,90 @@ inline flatbuffers::Offset<DebugConfiguration> CreateDebugConfiguration(
flatbuffers::Offset<DebugConfiguration> CreateDebugConfiguration(flatbuffers::FlatBufferBuilder &_fbb, const DebugConfigurationT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+struct PulseRequestT : public flatbuffers::NativeTable {
+ typedef PulseRequest TableType;
+ PulseRequestT() {
+ }
+};
+
+struct PulseRequest FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef PulseRequestT NativeTableType;
+ typedef PulseRequestBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ verifier.EndTable();
+ }
+ PulseRequestT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(PulseRequestT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<PulseRequest> Pack(flatbuffers::FlatBufferBuilder &_fbb, const PulseRequestT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct PulseRequestBuilder {
+ typedef PulseRequest Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit PulseRequestBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ PulseRequestBuilder &operator=(const PulseRequestBuilder &);
+ flatbuffers::Offset<PulseRequest> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<PulseRequest>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<PulseRequest> CreatePulseRequest(
+ flatbuffers::FlatBufferBuilder &_fbb) {
+ PulseRequestBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+flatbuffers::Offset<PulseRequest> CreatePulseRequest(flatbuffers::FlatBufferBuilder &_fbb, const PulseRequestT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+struct PulseResponseT : public flatbuffers::NativeTable {
+ typedef PulseResponse TableType;
+ PulseResponseT() {
+ }
+};
+
+struct PulseResponse FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef PulseResponseT NativeTableType;
+ typedef PulseResponseBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ verifier.EndTable();
+ }
+ PulseResponseT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(PulseResponseT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<PulseResponse> Pack(flatbuffers::FlatBufferBuilder &_fbb, const PulseResponseT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct PulseResponseBuilder {
+ typedef PulseResponse Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit PulseResponseBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ PulseResponseBuilder &operator=(const PulseResponseBuilder &);
+ flatbuffers::Offset<PulseResponse> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<PulseResponse>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<PulseResponse> CreatePulseResponse(
+ flatbuffers::FlatBufferBuilder &_fbb) {
+ PulseResponseBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+flatbuffers::Offset<PulseResponse> CreatePulseResponse(flatbuffers::FlatBufferBuilder &_fbb, const PulseResponseT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
struct MessageContainerT : public flatbuffers::NativeTable {
typedef MessageContainer TableType;
chre::fbs::ChreMessageUnion message;
@@ -3589,6 +3814,15 @@ struct MessageContainer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const chre::fbs::DebugConfiguration *message_as_DebugConfiguration() const {
return message_type() == chre::fbs::ChreMessage::DebugConfiguration ? static_cast<const chre::fbs::DebugConfiguration *>(message()) : nullptr;
}
+ const chre::fbs::PulseRequest *message_as_PulseRequest() const {
+ return message_type() == chre::fbs::ChreMessage::PulseRequest ? static_cast<const chre::fbs::PulseRequest *>(message()) : nullptr;
+ }
+ const chre::fbs::PulseResponse *message_as_PulseResponse() const {
+ return message_type() == chre::fbs::ChreMessage::PulseResponse ? static_cast<const chre::fbs::PulseResponse *>(message()) : nullptr;
+ }
+ const chre::fbs::NanoappInstanceIdInfo *message_as_NanoappInstanceIdInfo() const {
+ return message_type() == chre::fbs::ChreMessage::NanoappInstanceIdInfo ? static_cast<const chre::fbs::NanoappInstanceIdInfo *>(message()) : nullptr;
+ }
void *mutable_message() {
return GetPointer<void *>(VT_MESSAGE);
}
@@ -3729,6 +3963,18 @@ template<> inline const chre::fbs::DebugConfiguration *MessageContainer::message
return message_as_DebugConfiguration();
}
+template<> inline const chre::fbs::PulseRequest *MessageContainer::message_as<chre::fbs::PulseRequest>() const {
+ return message_as_PulseRequest();
+}
+
+template<> inline const chre::fbs::PulseResponse *MessageContainer::message_as<chre::fbs::PulseResponse>() const {
+ return message_as_PulseResponse();
+}
+
+template<> inline const chre::fbs::NanoappInstanceIdInfo *MessageContainer::message_as<chre::fbs::NanoappInstanceIdInfo>() const {
+ return message_as_NanoappInstanceIdInfo();
+}
+
struct MessageContainerBuilder {
typedef MessageContainer Table;
flatbuffers::FlatBufferBuilder &fbb_;
@@ -4100,6 +4346,35 @@ inline flatbuffers::Offset<LoadNanoappResponse> CreateLoadNanoappResponse(flatbu
_fragment_id);
}
+inline NanoappInstanceIdInfoT *NanoappInstanceIdInfo::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ std::unique_ptr<chre::fbs::NanoappInstanceIdInfoT> _o = std::unique_ptr<chre::fbs::NanoappInstanceIdInfoT>(new NanoappInstanceIdInfoT());
+ UnPackTo(_o.get(), _resolver);
+ return _o.release();
+}
+
+inline void NanoappInstanceIdInfo::UnPackTo(NanoappInstanceIdInfoT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = instance_id(); _o->instance_id = _e; }
+ { auto _e = app_id(); _o->app_id = _e; }
+}
+
+inline flatbuffers::Offset<NanoappInstanceIdInfo> NanoappInstanceIdInfo::Pack(flatbuffers::FlatBufferBuilder &_fbb, const NanoappInstanceIdInfoT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateNanoappInstanceIdInfo(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<NanoappInstanceIdInfo> CreateNanoappInstanceIdInfo(flatbuffers::FlatBufferBuilder &_fbb, const NanoappInstanceIdInfoT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const NanoappInstanceIdInfoT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _instance_id = _o->instance_id;
+ auto _app_id = _o->app_id;
+ return chre::fbs::CreateNanoappInstanceIdInfo(
+ _fbb,
+ _instance_id,
+ _app_id);
+}
+
inline UnloadNanoappRequestT *UnloadNanoappRequest::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
std::unique_ptr<chre::fbs::UnloadNanoappRequestT> _o = std::unique_ptr<chre::fbs::UnloadNanoappRequestT>(new UnloadNanoappRequestT());
UnPackTo(_o.get(), _resolver);
@@ -4661,6 +4936,52 @@ inline flatbuffers::Offset<DebugConfiguration> CreateDebugConfiguration(flatbuff
_health_monitor_failure_crash);
}
+inline PulseRequestT *PulseRequest::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ std::unique_ptr<chre::fbs::PulseRequestT> _o = std::unique_ptr<chre::fbs::PulseRequestT>(new PulseRequestT());
+ UnPackTo(_o.get(), _resolver);
+ return _o.release();
+}
+
+inline void PulseRequest::UnPackTo(PulseRequestT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+}
+
+inline flatbuffers::Offset<PulseRequest> PulseRequest::Pack(flatbuffers::FlatBufferBuilder &_fbb, const PulseRequestT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreatePulseRequest(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<PulseRequest> CreatePulseRequest(flatbuffers::FlatBufferBuilder &_fbb, const PulseRequestT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const PulseRequestT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ return chre::fbs::CreatePulseRequest(
+ _fbb);
+}
+
+inline PulseResponseT *PulseResponse::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ std::unique_ptr<chre::fbs::PulseResponseT> _o = std::unique_ptr<chre::fbs::PulseResponseT>(new PulseResponseT());
+ UnPackTo(_o.get(), _resolver);
+ return _o.release();
+}
+
+inline void PulseResponse::UnPackTo(PulseResponseT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+}
+
+inline flatbuffers::Offset<PulseResponse> PulseResponse::Pack(flatbuffers::FlatBufferBuilder &_fbb, const PulseResponseT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreatePulseResponse(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<PulseResponse> CreatePulseResponse(flatbuffers::FlatBufferBuilder &_fbb, const PulseResponseT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const PulseResponseT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ return chre::fbs::CreatePulseResponse(
+ _fbb);
+}
+
inline MessageContainerT *MessageContainer::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
std::unique_ptr<chre::fbs::MessageContainerT> _o = std::unique_ptr<chre::fbs::MessageContainerT>(new MessageContainerT());
UnPackTo(_o.get(), _resolver);
@@ -4810,6 +5131,18 @@ inline bool VerifyChreMessage(flatbuffers::Verifier &verifier, const void *obj,
auto ptr = reinterpret_cast<const chre::fbs::DebugConfiguration *>(obj);
return verifier.VerifyTable(ptr);
}
+ case ChreMessage::PulseRequest: {
+ auto ptr = reinterpret_cast<const chre::fbs::PulseRequest *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case ChreMessage::PulseResponse: {
+ auto ptr = reinterpret_cast<const chre::fbs::PulseResponse *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case ChreMessage::NanoappInstanceIdInfo: {
+ auto ptr = reinterpret_cast<const chre::fbs::NanoappInstanceIdInfo *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
default: return true;
}
}
@@ -4940,6 +5273,18 @@ inline void *ChreMessageUnion::UnPack(const void *obj, ChreMessage type, const f
auto ptr = reinterpret_cast<const chre::fbs::DebugConfiguration *>(obj);
return ptr->UnPack(resolver);
}
+ case ChreMessage::PulseRequest: {
+ auto ptr = reinterpret_cast<const chre::fbs::PulseRequest *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ case ChreMessage::PulseResponse: {
+ auto ptr = reinterpret_cast<const chre::fbs::PulseResponse *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ case ChreMessage::NanoappInstanceIdInfo: {
+ auto ptr = reinterpret_cast<const chre::fbs::NanoappInstanceIdInfo *>(obj);
+ return ptr->UnPack(resolver);
+ }
default: return nullptr;
}
}
@@ -5058,6 +5403,18 @@ inline flatbuffers::Offset<void> ChreMessageUnion::Pack(flatbuffers::FlatBufferB
auto ptr = reinterpret_cast<const chre::fbs::DebugConfigurationT *>(value);
return CreateDebugConfiguration(_fbb, ptr, _rehasher).Union();
}
+ case ChreMessage::PulseRequest: {
+ auto ptr = reinterpret_cast<const chre::fbs::PulseRequestT *>(value);
+ return CreatePulseRequest(_fbb, ptr, _rehasher).Union();
+ }
+ case ChreMessage::PulseResponse: {
+ auto ptr = reinterpret_cast<const chre::fbs::PulseResponseT *>(value);
+ return CreatePulseResponse(_fbb, ptr, _rehasher).Union();
+ }
+ case ChreMessage::NanoappInstanceIdInfo: {
+ auto ptr = reinterpret_cast<const chre::fbs::NanoappInstanceIdInfoT *>(value);
+ return CreateNanoappInstanceIdInfo(_fbb, ptr, _rehasher).Union();
+ }
default: return 0;
}
}
@@ -5176,6 +5533,18 @@ inline ChreMessageUnion::ChreMessageUnion(const ChreMessageUnion &u) : type(u.ty
value = new chre::fbs::DebugConfigurationT(*reinterpret_cast<chre::fbs::DebugConfigurationT *>(u.value));
break;
}
+ case ChreMessage::PulseRequest: {
+ value = new chre::fbs::PulseRequestT(*reinterpret_cast<chre::fbs::PulseRequestT *>(u.value));
+ break;
+ }
+ case ChreMessage::PulseResponse: {
+ value = new chre::fbs::PulseResponseT(*reinterpret_cast<chre::fbs::PulseResponseT *>(u.value));
+ break;
+ }
+ case ChreMessage::NanoappInstanceIdInfo: {
+ value = new chre::fbs::NanoappInstanceIdInfoT(*reinterpret_cast<chre::fbs::NanoappInstanceIdInfoT *>(u.value));
+ break;
+ }
default:
break;
}
@@ -5323,6 +5692,21 @@ inline void ChreMessageUnion::Reset() {
delete ptr;
break;
}
+ case ChreMessage::PulseRequest: {
+ auto ptr = reinterpret_cast<chre::fbs::PulseRequestT *>(value);
+ delete ptr;
+ break;
+ }
+ case ChreMessage::PulseResponse: {
+ auto ptr = reinterpret_cast<chre::fbs::PulseResponseT *>(value);
+ delete ptr;
+ break;
+ }
+ case ChreMessage::NanoappInstanceIdInfo: {
+ auto ptr = reinterpret_cast<chre::fbs::NanoappInstanceIdInfoT *>(value);
+ delete ptr;
+ break;
+ }
default: break;
}
value = nullptr;
diff --git a/host/common/include/chre_host/hal_client.h b/host/common/include/chre_host/hal_client.h
new file mode 100644
index 00000000..bc6db3bb
--- /dev/null
+++ b/host/common/include/chre_host/hal_client.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHRE_HOST_HAL_CLIENT_H_
+#define CHRE_HOST_HAL_CLIENT_H_
+
+#include <cinttypes>
+#include <memory>
+#include <shared_mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <aidl/android/hardware/contexthub/BnContextHubCallback.h>
+#include <aidl/android/hardware/contexthub/ContextHubMessage.h>
+#include <aidl/android/hardware/contexthub/HostEndpointInfo.h>
+#include <aidl/android/hardware/contexthub/IContextHub.h>
+#include <aidl/android/hardware/contexthub/IContextHubCallback.h>
+#include <aidl/android/hardware/contexthub/NanoappBinary.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "chre_host/log.h"
+#include "host/hal_generic/common/hal_error.h"
+
+namespace android::chre {
+
+using ::aidl::android::hardware::contexthub::AsyncEventType;
+using ::aidl::android::hardware::contexthub::BnContextHubCallback;
+using ::aidl::android::hardware::contexthub::ContextHubInfo;
+using ::aidl::android::hardware::contexthub::ContextHubMessage;
+using ::aidl::android::hardware::contexthub::HostEndpointInfo;
+using ::aidl::android::hardware::contexthub::IContextHub;
+using ::aidl::android::hardware::contexthub::IContextHubCallback;
+using ::aidl::android::hardware::contexthub::IContextHubDefault;
+using ::aidl::android::hardware::contexthub::MessageDeliveryStatus;
+using ::aidl::android::hardware::contexthub::NanoappBinary;
+using ::aidl::android::hardware::contexthub::NanoappInfo;
+using ::aidl::android::hardware::contexthub::NanSessionRequest;
+using ::aidl::android::hardware::contexthub::Setting;
+using ::ndk::ScopedAStatus;
+
+/**
+ * A class exposing CHRE HAL APIs to clients and taking care of binder
+ * (re)connection.
+ *
+ * <p>This class also maintains a set of connected host endpoints, using which
+ * it is enforced that a message can only be sent to/from an endpoint id that is
+ * already connected to HAL.
+ *
+ * <p>When the binder connection to HAL is disconnected HalClient will have a
+ * death recipient re-establish the connection and reconnect the previously
+ * connected endpoints. In a rare case that CHRE also restarts at the same time,
+ * a client should rely on IContextHubCallback.handleContextHubAsyncEvent() to
+ * handle the RESTARTED event which is a signal that CHRE is up running.
+ *
+ * TODO(b/297912356): The name of this class is the same as an internal struct
+ * used by HalClientManager. Consider rename the latter one to avoid confusion
+ *
+ */
+class HalClient {
+ public:
+ static constexpr int32_t kDefaultContextHubId = 0;
+
+ /**
+ * Create a HalClient unique pointer used to communicate with CHRE HAL.
+ *
+ * @param callback a non-null callback.
+ * @param contextHubId context hub id that only 0 is supported at this moment.
+ *
+ * @return null pointer if the creation fails.
+ */
+ static std::unique_ptr<HalClient> create(
+ const std::shared_ptr<IContextHubCallback> &callback,
+ int32_t contextHubId = kDefaultContextHubId);
+
+ ScopedAStatus queryNanoapps() {
+ return callIfConnected(
+ [&]() { return mContextHub->queryNanoapps(mContextHubId); });
+ }
+
+ ScopedAStatus sendMessage(const ContextHubMessage &message);
+
+ ScopedAStatus connectEndpoint(const HostEndpointInfo &hostEndpointInfo);
+
+ ScopedAStatus disconnectEndpoint(char16_t hostEndpointId);
+
+ protected:
+ class HalClientCallback : public BnContextHubCallback {
+ public:
+ explicit HalClientCallback(
+ const std::shared_ptr<IContextHubCallback> &callback,
+ HalClient *halClient)
+ : mCallback(callback), mHalClient(halClient) {}
+
+ ScopedAStatus handleNanoappInfo(
+ const std::vector<NanoappInfo> &appInfo) override {
+ return mCallback->handleNanoappInfo(appInfo);
+ }
+
+ ScopedAStatus handleContextHubMessage(
+ const ContextHubMessage &msg,
+ const std::vector<std::string> &msgContentPerms) override {
+ return mCallback->handleContextHubMessage(msg, msgContentPerms);
+ }
+
+ ScopedAStatus handleContextHubAsyncEvent(AsyncEventType event) override {
+ if (event == AsyncEventType::RESTARTED) {
+ LOGW("CHRE has restarted. Reconnecting endpoints.");
+ tryReconnectEndpoints(mHalClient);
+ }
+ return mCallback->handleContextHubAsyncEvent(event);
+ }
+
+ ScopedAStatus handleTransactionResult(int32_t transactionId,
+ bool success) override {
+ return mCallback->handleTransactionResult(transactionId, success);
+ }
+
+ ScopedAStatus handleNanSessionRequest(
+ const NanSessionRequest &request) override {
+ return mCallback->handleNanSessionRequest(request);
+ }
+
+ ScopedAStatus handleMessageDeliveryStatus(
+ char16_t hostEndPointId,
+ const MessageDeliveryStatus &messageDeliveryStatus) override {
+ return mCallback->handleMessageDeliveryStatus(hostEndPointId,
+ messageDeliveryStatus);
+ }
+
+ ScopedAStatus getUuid(std::array<uint8_t, 16> *outUuid) override {
+ return mCallback->getUuid(outUuid);
+ }
+
+ ScopedAStatus getName(std::string *outName) override {
+ return mCallback->getName(outName);
+ }
+
+ private:
+ std::shared_ptr<IContextHubCallback> mCallback;
+ HalClient *mHalClient;
+ };
+
+ explicit HalClient(const std::shared_ptr<IContextHubCallback> &callback,
+ int32_t contextHubId = kDefaultContextHubId)
+ : mContextHubId(contextHubId) {
+ mCallback = ndk::SharedRefBase::make<HalClientCallback>(callback, this);
+ ABinderProcess_startThreadPool();
+ mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(onHalDisconnected));
+ }
+
+ /**
+ * Initializes the connection to CHRE HAL.
+ */
+ HalError initConnection();
+
+ using HostEndpointId = char16_t;
+
+ const std::string kAidlServiceName =
+ std::string() + IContextHub::descriptor + "/default";
+
+ /** The callback for a disconnected HAL binder connection. */
+ static void onHalDisconnected(void *cookie);
+
+ /** Reconnect previously connected endpoints after CHRE or HAL restarts. */
+ static void tryReconnectEndpoints(HalClient *halClient);
+
+ ScopedAStatus callIfConnected(const std::function<ScopedAStatus()> &func) {
+ std::shared_lock<std::shared_mutex> sharedLock(mConnectionLock);
+ if (mContextHub == nullptr) {
+ return fromHalError(HalError::BINDER_DISCONNECTED);
+ }
+ return func();
+ }
+
+ bool isEndpointConnected(HostEndpointId hostEndpointId) {
+ std::shared_lock<std::shared_mutex> lock(mStateLock);
+ return mConnectedEndpoints.find(hostEndpointId) !=
+ mConnectedEndpoints.end();
+ }
+
+ void insertConnectedEndpoint(const HostEndpointInfo &hostEndpointInfo) {
+ std::lock_guard<std::shared_mutex> lock(mStateLock);
+ mConnectedEndpoints[hostEndpointInfo.hostEndpointId] = hostEndpointInfo;
+ }
+
+ void removeConnectedEndpoint(HostEndpointId hostEndpointId) {
+ std::lock_guard<std::shared_mutex> lock(mStateLock);
+ mConnectedEndpoints.erase(hostEndpointId);
+ }
+
+ void clearConnectedEndpoints() {
+ std::lock_guard<std::shared_mutex> lock(mStateLock);
+ mConnectedEndpoints.clear();
+ }
+
+ static ScopedAStatus fromHalError(HalError errorCode) {
+ return errorCode == HalError::SUCCESS
+ ? ScopedAStatus::ok()
+ : ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(errorCode));
+ }
+
+ // Multi-contextHub is not supported at this moment.
+ int32_t mContextHubId;
+
+ // The lock guarding mConnectedEndpoints.
+ std::shared_mutex mStateLock;
+ std::unordered_map<HostEndpointId, HostEndpointInfo> mConnectedEndpoints{};
+
+ // The lock guarding mContextHub.
+ std::shared_mutex mConnectionLock;
+ std::shared_ptr<IContextHub> mContextHub;
+
+ // Handler of the binder disconnection event with HAL.
+ ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+ std::shared_ptr<HalClientCallback> mCallback;
+};
+
+} // namespace android::chre
+#endif // CHRE_HOST_HAL_CLIENT_H_ \ No newline at end of file
diff --git a/host/common/include/chre_host/host_protocol_host.h b/host/common/include/chre_host/host_protocol_host.h
index 29c1f8be..35f1cedf 100644
--- a/host/common/include/chre_host/host_protocol_host.h
+++ b/host/common/include/chre_host/host_protocol_host.h
@@ -99,6 +99,14 @@ class HostProtocolHost : public ::chre::HostProtocolCommon {
IChreMessageHandlers &handlers);
/**
+ * Encodes a message requesting pulse from CHRE
+ *
+ * @param builder A newly constructed FlatBufferBuilder that will be used to
+ * construct the message
+ */
+ static void encodePulseRequest(flatbuffers::FlatBufferBuilder &builder);
+
+ /**
* Encodes a message requesting hub information from CHRE
*
* @param builder A newly constructed FlatBufferBuilder that will be used to
diff --git a/host/common/include/chre_host/log.h b/host/common/include/chre_host/log.h
index a247e87d..937d368b 100644
--- a/host/common/include/chre_host/log.h
+++ b/host/common/include/chre_host/log.h
@@ -23,25 +23,35 @@
#include <log/log.h>
+namespace android::chre {
+
/**
- * Logs a message to both logcat and stdout. Don't use this directly; prefer one
- * of LOGE, LOGW, etc. to populate the level. Use LOG_PRI directly rather than
- * ALOG to avoid misinterpreting LOG_* macros that may be incorrectly evaluated.
+ * Logs a message to both logcat and stdout/stderr. Don't use this directly;
+ * prefer one of LOGE, LOGW, etc.
*
- * @param level log level to pass to ALOG (LOG_ERROR, LOG_WARN, etc.)
- * @param stream output stream to print to (e.g. stdout)
+ * @param level android log level, e.g., ANDROID_LOG_ERROR
+ * @param stream output stream to print to, e.g., stdout
* @param format printf-style format string
+ * @param func the function name included in the log, e.g., __func__
+ * @param line line number included in the log
*/
-#define CHRE_LOG(level, stream, format, ...) \
- do { \
- LOG_PRI(ANDROID_##level, LOG_TAG, format, ##__VA_ARGS__); \
- fprintf(stream, "%s:%d: " format "\n", __func__, __LINE__, ##__VA_ARGS__); \
- } while (0)
+void outputHostLog(int priority, FILE *stream, const char *format,
+ const char *func, unsigned int line, ...);
+
+} // namespace android::chre
-#define LOGE(format, ...) CHRE_LOG(LOG_ERROR, stderr, format, ##__VA_ARGS__)
-#define LOGW(format, ...) CHRE_LOG(LOG_WARN, stdout, format, ##__VA_ARGS__)
-#define LOGI(format, ...) CHRE_LOG(LOG_INFO, stdout, format, ##__VA_ARGS__)
-#define LOGD(format, ...) CHRE_LOG(LOG_DEBUG, stdout, format, ##__VA_ARGS__)
+#define LOGE(format, ...) \
+ ::android::chre::outputHostLog(ANDROID_LOG_ERROR, stderr, format, __func__, \
+ __LINE__, ##__VA_ARGS__)
+#define LOGW(format, ...) \
+ ::android::chre::outputHostLog(ANDROID_LOG_WARN, stdout, format, __func__, \
+ __LINE__, ##__VA_ARGS__)
+#define LOGI(format, ...) \
+ ::android::chre::outputHostLog(ANDROID_LOG_INFO, stdout, format, __func__, \
+ __LINE__, ##__VA_ARGS__)
+#define LOGD(format, ...) \
+ ::android::chre::outputHostLog(ANDROID_LOG_DEBUG, stdout, format, __func__, \
+ __LINE__, ##__VA_ARGS__)
#if LOG_NDEBUG
__attribute__((format(printf, 1, 2))) inline void chreLogNull(
@@ -49,7 +59,9 @@ __attribute__((format(printf, 1, 2))) inline void chreLogNull(
#define LOGV(format, ...) chreLogNull(format, ##__VA_ARGS__)
#else
-#define LOGV(format, ...) CHRE_LOG(LOG_VERBOSE, stdout, format, ##__VA_ARGS__)
+#define LOGV(format, ...) \
+ ::android::chre::outputHostLog(ANDROID_LOG_VERBOSE, stdout, format, \
+ __func__, __LINE__, ##__VA_ARGS__)
#endif
/**
diff --git a/host/common/include/chre_host/metrics_reporter.h b/host/common/include/chre_host/metrics_reporter.h
new file mode 100644
index 00000000..ea1ddfb5
--- /dev/null
+++ b/host/common/include/chre_host/metrics_reporter.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHRE_HOST_METRICS_REPORTER_H_
+#define CHRE_HOST_METRICS_REPORTER_H_
+
+#include <aidl/android/frameworks/stats/IStats.h>
+#include <chre_atoms_log.h>
+#include <mutex>
+
+namespace android::chre {
+
+class MetricsReporter {
+ public:
+ MetricsReporter() = default;
+ ~MetricsReporter() = default;
+
+ MetricsReporter(const MetricsReporter &) = delete;
+ MetricsReporter &operator=(const MetricsReporter &) = delete;
+
+ /**
+ * Creates and reports CHRE vendor atom and send it to stats_client.
+ *
+ * @param atom the vendor atom to be reported
+ * @return true if the metric was successfully reported, false otherwise.
+ */
+ bool reportMetric(const aidl::android::frameworks::stats::VendorAtom &atom);
+
+ /**
+ * Reports an AP Wakeup caused by a nanoapp.
+ *
+ * @return whether the operation was successful.
+ */
+ bool logApWakeupOccurred(uint64_t nanoappId);
+
+ /**
+ * Reports a nanoapp load failed metric.
+ *
+ * @return whether the operation was successful.
+ */
+ bool logNanoappLoadFailed(
+ uint64_t nanoappId,
+ android::chre::Atoms::ChreHalNanoappLoadFailed::Type type,
+ android::chre::Atoms::ChreHalNanoappLoadFailed::Reason reason);
+
+ /**
+ * Reports a PAL open failed metric.
+ *
+ * @return whether the operation was successful.
+ */
+ bool logPalOpenFailed(
+ android::chre::Atoms::ChrePalOpenFailed::ChrePalType pal,
+ android::chre::Atoms::ChrePalOpenFailed::Type type);
+
+ /**
+ * Reports a event queue snapshot reported metric.
+ *
+ * @return whether the operation was successful.
+ */
+ bool logEventQueueSnapshotReported(int32_t snapshotChreGetTimeMs,
+ int32_t max_event_queue_size,
+ int32_t mean_event_queue_size,
+ int32_t num_dropped_events);
+
+ /**
+ * Called when the binder dies for the stats service.
+ */
+ void onBinderDied();
+
+ private:
+ /**
+ * Connects to the stats service or return nullptr if it cannot connect.
+ * This also adds a binder death handler to the service that will call
+ * onBinderDied on this.
+ *
+ * @return the stats service
+ */
+ std::shared_ptr<aidl::android::frameworks::stats::IStats> getStatsService();
+
+ std::mutex mStatsServiceMutex;
+ std::shared_ptr<aidl::android::frameworks::stats::IStats> mStatsService =
+ nullptr;
+};
+
+} // namespace android::chre
+
+#endif // CHRE_HOST_METRICS_REPORTER_H_ \ No newline at end of file
diff --git a/host/common/include/chre_host/pigweed/hal_channel_output.h b/host/common/include/chre_host/pigweed/hal_channel_output.h
new file mode 100644
index 00000000..f190297b
--- /dev/null
+++ b/host/common/include/chre_host/pigweed/hal_channel_output.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHRE_PIGWEED_HAL_CHANNEL_OUTPUT_H_
+#define CHRE_PIGWEED_HAL_CHANNEL_OUTPUT_H_
+
+#include <cstdint>
+
+#include "chre/util/non_copyable.h"
+#include "chre_host/socket_client.h"
+#include "pw_rpc/channel.h"
+#include "pw_span/span.h"
+
+namespace android::chre {
+
+/**
+ * RPC Channel Output for native vendor processes.
+ */
+class HalChannelOutput : public ::chre::NonCopyable,
+ public pw::rpc::ChannelOutput {
+ public:
+ HalChannelOutput(android::chre::SocketClient &client, uint32_t hostEndpointId,
+ uint64_t serverNanoappId, size_t maxMessageLen)
+ : pw::rpc::ChannelOutput("CHRE"),
+ mServerNanoappId(serverNanoappId),
+ mHostEndpointId(hostEndpointId),
+ mMaxMessageLen(maxMessageLen),
+ mSocketClient(client) {}
+
+ size_t MaximumTransmissionUnit() override;
+
+ pw::Status Send(pw::span<const std::byte> buffer) override;
+
+ private:
+ // Padding used to encode nanoapp messages.
+ static constexpr size_t kFlatBufferPadding = 80;
+
+ const uint64_t mServerNanoappId;
+ const uint32_t mHostEndpointId;
+ const size_t mMaxMessageLen;
+ SocketClient &mSocketClient;
+};
+
+} // namespace android::chre
+
+#endif // CHRE_PIGWEED_HAL_CHANNEL_OUTPUT_H_ \ No newline at end of file
diff --git a/host/common/include/chre_host/pigweed/hal_rpc_client.h b/host/common/include/chre_host/pigweed/hal_rpc_client.h
new file mode 100644
index 00000000..c8cdee60
--- /dev/null
+++ b/host/common/include/chre_host/pigweed/hal_rpc_client.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHRE_PIGWEED_HAL_RPC_CLIENT_H_
+#define CHRE_PIGWEED_HAL_RPC_CLIENT_H_
+
+#include <chrono>
+#include <condition_variable>
+#include <cstdint>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <string_view>
+
+#include <android-base/thread_annotations.h>
+
+#include "chre/util/pigweed/rpc_common.h"
+#include "chre_host/pigweed/hal_channel_output.h"
+
+#include "chre/util/macros.h"
+#include "chre/util/non_copyable.h"
+#include "chre_host/host_protocol_host.h"
+#include "chre_host/log.h"
+#include "chre_host/pigweed/hal_channel_output.h"
+#include "chre_host/socket_client.h"
+#include "pw_rpc/client.h"
+
+namespace android::chre {
+
+/**
+ * RPC client helper to use with native vendor processes.
+ */
+class HalRpcClient : public ::chre::NonCopyable {
+ public:
+ /**
+ * Creates a RPC client helper.
+ *
+ * This method connects to the socket blocks until the initialization is
+ * complete.
+ *
+ # @param appName Name of the app.
+ * @param client A SocketClient that must not be already connected.
+ * @param socketCallbacks The callbacks to call on SocketClient events.
+ * @param hostEndpointId The host endpoint ID for the app.
+ * @param serverNanoappId The ID of the nanoapp providing the service.
+ * @return A pointer to a HalRpcClient. nullptr on error.
+ */
+ static std::unique_ptr<HalRpcClient> createClient(
+ std::string_view appName, SocketClient &client,
+ sp<SocketClient::ICallbacks> socketCallbacks, uint16_t hostEndpointId,
+ uint64_t serverNanoappId);
+
+ ~HalRpcClient() {
+ close();
+ }
+
+ /**
+ * Closes the RPC client and de-allocate resources.
+ *
+ * Note: This method is called from the destructor. However it can also be
+ * called explicitly.
+ */
+ void close();
+
+ /**
+ * Returns a service client.
+ *
+ * NOTE: The template parameter must be set to the Pigweed client type,
+ * i.e. pw::rpc::pw_rpc::nanopb::<ServiceName>::Client
+
+ * @return The service client. It has no value on errors.
+ */
+ template <typename T>
+ std::optional<T> get();
+
+ /**
+ * Returns whether the server nanoapp supports the service.
+ *
+ * Also returns false when the nanoapp is not loaded.
+ *
+ * @return whether the service is published by the server.
+ */
+ bool hasService(uint64_t id, uint32_t version);
+
+ private:
+ /** Timeout for the requests to the daemon */
+ static constexpr auto kRequestTimeout = std::chrono::milliseconds(2000);
+
+ class Callbacks : public SocketClient::ICallbacks,
+ public IChreMessageHandlers {
+ public:
+ Callbacks(HalRpcClient *client,
+ sp<SocketClient::ICallbacks> socketCallbacks)
+ : mClient(client), mSocketCallbacks(socketCallbacks) {}
+
+ /** Socket callbacks. */
+ void onMessageReceived(const void *data, size_t length) override;
+ void onConnected() override;
+ void onConnectionAborted() override;
+ void onDisconnected() override;
+
+ /** Message handlers. */
+ void handleNanoappMessage(
+ const ::chre::fbs::NanoappMessageT &message) override;
+ void handleHubInfoResponse(
+ const ::chre::fbs::HubInfoResponseT &response) override;
+ void handleNanoappListResponse(
+ const ::chre::fbs::NanoappListResponseT &response) override;
+
+ private:
+ HalRpcClient *mClient;
+ sp<SocketClient::ICallbacks> mSocketCallbacks;
+ };
+
+ HalRpcClient(std::string_view appName, SocketClient &client,
+ uint16_t hostEndpointId, uint64_t serverNanoappId)
+ : mServerNanoappId(serverNanoappId),
+ mHostEndpointId(hostEndpointId),
+ mAppName(appName),
+ mSocketClient(client) {}
+
+ /**
+ * Initializes the RPC client helper.
+ *
+ * @param socketCallbacks The callbacks to call on SocketClient events.
+ * @return Whether the initialization was successful.
+ */
+ bool init(sp<SocketClient::ICallbacks> socketCallbacks);
+
+ /** @return the Pigweed RPC channel ID */
+ uint32_t GetChannelId() {
+ return ::chre::kChannelIdHostClient | mHostEndpointId;
+ }
+
+ /**
+ * Notifies CHRE that the host endpoint has connected.
+ *
+ * Needed as the RPC Server helper will retrieve the host endpoint metadata
+ * when servicing a request.
+ */
+ bool notifyEndpointConnected();
+
+ /** Notifies CHRE that the host endpoint has disconnected. */
+ bool notifyEndpointDisconnected();
+
+ /** Query CHRE to retrieve the maximum message length. */
+ bool retrieveMaxMessageLen();
+
+ /** Query CHRE to retrieve the services published by the server nanoapp. */
+ bool retrieveServices();
+
+ const uint64_t mServerNanoappId;
+ const uint16_t mHostEndpointId;
+ const std::string mAppName;
+ SocketClient &mSocketClient;
+ std::unique_ptr<HalChannelOutput> mChannelOutput;
+ pw::rpc::Client mRpcClient;
+ bool mIsChannelOpened = false;
+
+ /** Request Hub Info. */
+ std::mutex mHubInfoMutex;
+ size_t mMaxMessageLen GUARDED_BY(mHubInfoMutex);
+ std::condition_variable mHubInfoCond;
+
+ /** Request Nanoapps. */
+ std::mutex mNanoappMutex;
+ std::vector<::chre::fbs::NanoappRpcServiceT> mServices
+ GUARDED_BY(mNanoappMutex);
+ std::condition_variable mNanoappCond;
+};
+
+template <typename T>
+std::optional<T> HalRpcClient::get() {
+ if (mChannelOutput == nullptr) {
+ LOGE("No channel output");
+ return {};
+ }
+
+ if (!mIsChannelOpened) {
+ mRpcClient.OpenChannel(GetChannelId(), *mChannelOutput);
+ mIsChannelOpened = true;
+ }
+
+ return T(mRpcClient, GetChannelId());
+}
+
+} // namespace android::chre
+
+#endif // CHRE_PIGWEED_HAL_RPC_CLIENT_H_ \ No newline at end of file
diff --git a/host/common/include/chre_host/preloaded_nanoapp_loader.h b/host/common/include/chre_host/preloaded_nanoapp_loader.h
index a605ae74..3a3a2fc0 100644
--- a/host/common/include/chre_host/preloaded_nanoapp_loader.h
+++ b/host/common/include/chre_host/preloaded_nanoapp_loader.h
@@ -18,10 +18,12 @@
#define CHRE_HOST_PRELOADED_NANOAPP_LOADER_H_
#include <android/binder_to_string.h>
+#include <atomic>
#include <cstdint>
#include <mutex>
#include <optional>
#include <string>
+#include <unordered_set>
#include <utility>
#include "chre_connection.h"
@@ -46,7 +48,7 @@ class PreloadedNanoappLoader {
public:
explicit PreloadedNanoappLoader(ChreConnection *connection,
std::string configPath)
- : mConnection(connection), mConfigPath(std::move(configPath)){};
+ : mConnection(connection), mConfigPath(std::move(configPath)) {}
~PreloadedNanoappLoader() = default;
/**
@@ -60,8 +62,14 @@ class PreloadedNanoappLoader {
* ]}
*
* The napp_header and so files will both be used.
+ *
+ * @param selectedNanoappIds only nanoapp ids in this set will be loaded if it
+ * is set. Otherwise the default value means every preloaded nanoapp will be
+ * loaded.
*/
- void loadPreloadedNanoapps();
+ bool loadPreloadedNanoapps(
+ const std::optional<const std::unordered_set<uint64_t>>
+ &selectedNanoappIds = std::nullopt);
/** Callback function to handle the response from CHRE. */
bool onLoadNanoappResponse(const ::chre::fbs::LoadNanoappResponseT &response,
@@ -72,35 +80,28 @@ class PreloadedNanoappLoader {
/** Returns true if the loading is ongoing. */
[[nodiscard]] bool isPreloadOngoing() const {
return mIsPreloadingOngoing;
- };
+ }
private:
+ /** Tracks the transaction state of the ongoing nanoapp loading */
+ struct Transaction {
+ uint32_t transactionId;
+ size_t fragmentId;
+ };
+
/** Timeout value of waiting for the response of a fragmented load */
static constexpr auto kTimeoutInMs = std::chrono::milliseconds(2000);
/**
- * Loads a preloaded nanoapp given a filename.
- *
- * This function allows the transaction to complete before the nanoapp starts
- * so the server can start serving requests as soon as possible.
- *
- * @param directory The directory to load the nanoapp from.
- * @param name The filename of the nanoapp to load.
- * @param transactionId The transaction ID to use when loading the app.
- */
- void loadPreloadedNanoapp(const std::string &directory,
- const std::string &name, uint32_t transactionId);
-
- /**
* Loads a preloaded nanoapp.
*
- * @param header The nanoapp header binary blob.
- * @param nanoapp The nanoapp binary.
+ * @param appHeader The nanoapp header binary blob.
+ * @param nanoappFileName The nanoapp binary file name.
* @param transactionId The transaction ID identifying this load transaction.
* @return true if successful, false otherwise.
*/
- bool loadNanoapp(const std::vector<uint8_t> &header,
- const std::vector<uint8_t> &nanoapp, uint32_t transactionId);
+ bool loadNanoapp(const NanoAppBinaryHeader *appHeader,
+ const std::string &nanoappFileName, uint32_t transactionId);
/**
* Chunks the nanoapp binary into fragments and load each fragment
@@ -123,11 +124,6 @@ class PreloadedNanoappLoader {
[[nodiscard]] bool verifyFragmentLoadResponse(
const ::chre::fbs::LoadNanoappResponseT &response) const;
- /** Tracks the transaction state of the ongoing nanoapp loading */
- struct Transaction {
- uint32_t transactionId;
- size_t fragmentId;
- };
Transaction mPreloadedNanoappPendingTransaction{0, 0};
/** The value of this promise carries the result in the load response. */
@@ -136,7 +132,7 @@ class PreloadedNanoappLoader {
/** The mutex used to guard states change for preloading. */
std::mutex mPreloadedNanoappsMutex;
- bool mIsPreloadingOngoing = false;
+ std::atomic_bool mIsPreloadingOngoing = false;
ChreConnection *mConnection;
std::string mConfigPath;
diff --git a/host/common/include/chre_host/socket_server.h b/host/common/include/chre_host/socket_server.h
index 6a19ecbe..6e5b8404 100644
--- a/host/common/include/chre_host/socket_server.h
+++ b/host/common/include/chre_host/socket_server.h
@@ -28,8 +28,7 @@
#include <android-base/macros.h>
#include <cutils/sockets.h>
-namespace android {
-namespace chre {
+namespace android::chre {
class SocketServer {
public:
@@ -81,7 +80,7 @@ class SocketServer {
*/
bool sendToClientById(const void *data, size_t length, uint16_t clientId);
- void shutdownServer() {
+ static void shutdownServer() {
sSignalReceived = true;
}
@@ -93,8 +92,18 @@ class SocketServer {
static_cast<int>(kMaxActiveClients);
static constexpr size_t kMaxPacketSize = 1024 * 1024;
+ // This is the same value as defined in
+ // host/hal_generic/common/hal_client_id.h. It is redefined here to avoid
+ // adding dependency path at multiple places for such a temporary change,
+ // which will be removed after migrating generic HAL to multiclient HAL.
+ static constexpr uint16_t kMaxHalClientId = 0x1ff;
+
int mSockFd = INVALID_SOCKET;
- uint16_t mNextClientId = 1;
+ // Socket client id and Hal client id are using the same field in the fbs
+ // message. To keep their id range disjoint enables message routing for both
+ // at the same time. There are 0xffff - 0x01ff = 0xfe00 (65024) socket
+ // client ids to use, which should be more than enough.
+ uint16_t mNextClientId = kMaxHalClientId + 1;
// TODO: std::vector-ify this
struct pollfd mPollFds[1 + kMaxActiveClients] = {};
@@ -116,16 +125,19 @@ class SocketServer {
ClientMessageCallback mClientMessageCallback;
void acceptClientConnection();
+
void disconnectClient(int clientSocket);
+
void handleClientData(int clientSocket);
+
bool sendToClientSocket(const void *data, size_t length, int clientSocket,
uint16_t clientId);
+
void serviceSocket();
static std::atomic<bool> sSignalReceived;
};
-} // namespace chre
-} // namespace android
+} // namespace android::chre
#endif // CHRE_HOST_SOCKET_SERVER_H_
diff --git a/host/common/include/chre_host/time_syncer.h b/host/common/include/chre_host/time_syncer.h
index 9518ea25..f73e8ecb 100644
--- a/host/common/include/chre_host/time_syncer.h
+++ b/host/common/include/chre_host/time_syncer.h
@@ -26,11 +26,9 @@ namespace android::chre {
using hardware::contexthub::common::implementation::ChreConnection;
-/** The class synchronizes time between the Context hub and Android. */
-class TimeSyncer {
+/** The functions synchronizing time between the Context hub and Android. */
+class TimeSyncer final {
public:
- explicit TimeSyncer(ChreConnection *connection) : mConnection(connection) {}
-
/**
* Sends time sync message to Context hub and retries numRetries times until
* success.
@@ -40,7 +38,9 @@ class TimeSyncer {
*
* @return true if success, false otherwise.
*/
- bool sendTimeSyncWithRetry(size_t numOfRetries, useconds_t retryDelayUs);
+ static bool sendTimeSyncWithRetry(ChreConnection *connection,
+ size_t numOfRetries,
+ useconds_t retryDelayUs);
/**
* Sends a time sync message to Context hub for once.
@@ -50,10 +50,10 @@ class TimeSyncer {
*
* @return true if success, false otherwise.
*/
- bool sendTimeSync();
+ static bool sendTimeSync(ChreConnection *connection);
private:
- ChreConnection *mConnection;
+ TimeSyncer() = default;
};
} // namespace android::chre
diff --git a/host/common/log.cc b/host/common/log.cc
new file mode 100644
index 00000000..8f3249ff
--- /dev/null
+++ b/host/common/log.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdio>
+
+#include "chre_host/log.h"
+
+namespace android::chre {
+
+void outputHostLog(int priority, FILE *stream, const char *format,
+ const char *func, unsigned int line, ...) {
+ va_list args;
+ va_start(args, line);
+ LOG_PRI_VA(priority, LOG_TAG, format, args);
+ va_end(args);
+ va_start(args, line);
+ fprintf(stream, "%s:%d: ", func, line);
+ vfprintf(stream, format, args);
+ fprintf(stream, "\n");
+ fflush(stream); // flush the buffer to print out the log immediately
+ va_end(args);
+}
+
+} // namespace android::chre \ No newline at end of file
diff --git a/host/common/metrics_reporter.cc b/host/common/metrics_reporter.cc
new file mode 100644
index 00000000..490c80ac
--- /dev/null
+++ b/host/common/metrics_reporter.cc
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "chre_host/metrics_reporter.h"
+
+#include <android/binder_manager.h>
+#include <chre_atoms_log.h>
+#include <chre_host/log.h>
+#include <limits>
+#include <mutex>
+
+namespace android::chre {
+
+using ::aidl::android::frameworks::stats::IStats;
+using ::aidl::android::frameworks::stats::VendorAtom;
+using ::aidl::android::frameworks::stats::VendorAtomValue;
+using ::android::chre::Atoms::CHRE_AP_WAKE_UP_OCCURRED;
+using ::android::chre::Atoms::CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED;
+using ::android::chre::Atoms::CHRE_HAL_NANOAPP_LOAD_FAILED;
+using ::android::chre::Atoms::CHRE_PAL_OPEN_FAILED;
+using ::android::chre::Atoms::ChreHalNanoappLoadFailed;
+using ::android::chre::Atoms::ChrePalOpenFailed;
+
+std::shared_ptr<IStats> MetricsReporter::getStatsService() {
+ const std::string statsServiceName =
+ std::string(IStats::descriptor).append("/default");
+ if (!AServiceManager_isDeclared(statsServiceName.c_str())) {
+ LOGE("Stats service is not declared.");
+ return nullptr;
+ }
+
+ ndk::SpAIBinder statsServiceBinder =
+ ndk::SpAIBinder(AServiceManager_waitForService(statsServiceName.c_str()));
+ if (statsServiceBinder.get() == nullptr) {
+ LOGE("Failed to get the IStats service binder");
+ return nullptr;
+ }
+
+ binder_status_t status = AIBinder_linkToDeath(
+ statsServiceBinder.get(), AIBinder_DeathRecipient_new([](void *cookie) {
+ MetricsReporter *metricsReporter =
+ static_cast<MetricsReporter *>(cookie);
+ metricsReporter->onBinderDied();
+ }),
+ this);
+ if (status != STATUS_OK) {
+ LOGE("Failed to link to death the stats service binder");
+ return nullptr;
+ }
+
+ std::shared_ptr<IStats> statsService = IStats::fromBinder(statsServiceBinder);
+ if (statsService == nullptr) {
+ LOGE("Failed to get IStats service");
+ return nullptr;
+ }
+ return statsService;
+}
+
+bool MetricsReporter::reportMetric(const VendorAtom &atom) {
+ ndk::ScopedAStatus ret;
+ {
+ std::lock_guard<std::mutex> lock(mStatsServiceMutex);
+ if (mStatsService == nullptr) {
+ mStatsService = getStatsService();
+ if (mStatsService == nullptr) {
+ return false;
+ }
+ }
+
+ ret = mStatsService->reportVendorAtom(atom);
+ }
+
+ if (!ret.isOk()) {
+ LOGE("Failed to report vendor atom");
+ }
+ return ret.isOk();
+}
+
+bool MetricsReporter::logApWakeupOccurred(uint64_t nanoappId) {
+ std::vector<VendorAtomValue> values(1);
+ values[0].set<VendorAtomValue::longValue>(nanoappId);
+
+ const VendorAtom atom{
+ .atomId = CHRE_AP_WAKE_UP_OCCURRED,
+ .values{std::move(values)},
+ };
+
+ return reportMetric(atom);
+}
+
+bool MetricsReporter::logNanoappLoadFailed(
+ uint64_t nanoappId, ChreHalNanoappLoadFailed::Type type,
+ ChreHalNanoappLoadFailed::Reason reason) {
+ std::vector<VendorAtomValue> values(3);
+ values[0].set<VendorAtomValue::longValue>(nanoappId);
+ values[1].set<VendorAtomValue::intValue>(type);
+ values[2].set<VendorAtomValue::intValue>(reason);
+
+ const VendorAtom atom{
+ .atomId = CHRE_HAL_NANOAPP_LOAD_FAILED,
+ .values{std::move(values)},
+ };
+
+ return reportMetric(atom);
+}
+
+bool MetricsReporter::logPalOpenFailed(ChrePalOpenFailed::ChrePalType pal,
+ ChrePalOpenFailed::Type type) {
+ std::vector<VendorAtomValue> values(2);
+ values[0].set<VendorAtomValue::intValue>(pal);
+ values[1].set<VendorAtomValue::intValue>(type);
+
+ const VendorAtom atom{
+ .atomId = CHRE_PAL_OPEN_FAILED,
+ .values{std::move(values)},
+ };
+
+ return reportMetric(atom);
+}
+
+bool MetricsReporter::logEventQueueSnapshotReported(
+ int32_t snapshotChreGetTimeMs, int32_t maxEventQueueSize,
+ int32_t meanEventQueueSize, int32_t numDroppedEvents) {
+ std::vector<VendorAtomValue> values(6);
+ values[0].set<VendorAtomValue::intValue>(snapshotChreGetTimeMs);
+ values[1].set<VendorAtomValue::intValue>(maxEventQueueSize);
+ values[2].set<VendorAtomValue::intValue>(meanEventQueueSize);
+ values[3].set<VendorAtomValue::intValue>(numDroppedEvents);
+
+ // TODO(b/298459533): Implement these two values
+ // Last two values are not currently populated and will be implemented
+ // later. To avoid confusion of the interpretation, we use UINT32_MAX
+ // as a placeholder value.
+ values[4].set<VendorAtomValue::longValue>(
+ std::numeric_limits<int64_t>::max());
+ values[5].set<VendorAtomValue::longValue>(
+ std::numeric_limits<int64_t>::max());
+
+ const VendorAtom atom{
+ .atomId = CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED,
+ .values{std::move(values)},
+ };
+
+ return reportMetric(atom);
+}
+
+void MetricsReporter::onBinderDied() {
+ LOGI("MetricsReporter: stats service died - reconnecting");
+
+ std::lock_guard<std::mutex> lock(mStatsServiceMutex);
+ mStatsService.reset();
+ mStatsService = getStatsService();
+}
+
+} // namespace android::chre
diff --git a/host/common/pigweed/hal_channel_output.cc b/host/common/pigweed/hal_channel_output.cc
new file mode 100644
index 00000000..f61d719e
--- /dev/null
+++ b/host/common/pigweed/hal_channel_output.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "chre_host/pigweed/hal_channel_output.h"
+
+#include <cstdint>
+
+#include "chre/event.h"
+#include "chre/util/pigweed/rpc_common.h"
+#include "chre_host/host_protocol_host.h"
+#include "chre_host/log.h"
+#include "chre_host/socket_client.h"
+#include "pw_rpc/channel.h"
+#include "pw_span/span.h"
+
+namespace android::chre {
+
+using ::flatbuffers::FlatBufferBuilder;
+
+size_t HalChannelOutput::MaximumTransmissionUnit() {
+ return mMaxMessageLen > kFlatBufferPadding
+ ? mMaxMessageLen - kFlatBufferPadding
+ : 0;
+}
+
+pw::Status HalChannelOutput::Send(pw::span<const std::byte> buffer) {
+ if (buffer.size() > 0) {
+ FlatBufferBuilder builder(buffer.size() + kFlatBufferPadding);
+
+ HostProtocolHost::encodeNanoappMessage(
+ builder, mServerNanoappId, CHRE_MESSAGE_TYPE_RPC, mHostEndpointId,
+ buffer.data(), buffer.size());
+
+ if (!mSocketClient.sendMessage(builder.GetBufferPointer(),
+ builder.GetSize())) {
+ LOGE("Failed to send message");
+ return PW_STATUS_UNKNOWN;
+ }
+ }
+
+ return PW_STATUS_OK;
+}
+
+} // namespace android::chre \ No newline at end of file
diff --git a/host/common/pigweed/hal_rpc_client.cc b/host/common/pigweed/hal_rpc_client.cc
new file mode 100644
index 00000000..d9a91468
--- /dev/null
+++ b/host/common/pigweed/hal_rpc_client.cc
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "chre_host/pigweed/hal_rpc_client.h"
+
+#include <cstdint>
+#include <memory>
+
+#include "chre/event.h"
+#include "chre/util/pigweed/rpc_common.h"
+#include "chre_host/host_protocol_host.h"
+#include "chre_host/log.h"
+#include "chre_host/pigweed/hal_channel_output.h"
+
+namespace android::chre {
+
+using ::chre::fbs::HubInfoResponseT;
+using ::chre::fbs::NanoappListEntryT;
+using ::chre::fbs::NanoappListResponseT;
+using ::chre::fbs::NanoappMessageT;
+using ::chre::fbs::NanoappRpcServiceT;
+using ::flatbuffers::FlatBufferBuilder;
+
+std::unique_ptr<HalRpcClient> HalRpcClient::createClient(
+ std::string_view appName, SocketClient &client,
+ sp<SocketClient::ICallbacks> socketCallbacks, uint16_t hostEndpointId,
+ uint64_t serverNanoappId) {
+ auto rpcClient = std::unique_ptr<HalRpcClient>(
+ new HalRpcClient(appName, client, hostEndpointId, serverNanoappId));
+
+ if (!rpcClient->init(socketCallbacks)) {
+ return nullptr;
+ }
+
+ return rpcClient;
+}
+
+bool HalRpcClient::hasService(uint64_t id, uint32_t version) {
+ std::lock_guard lock(mNanoappMutex);
+ for (const NanoappRpcServiceT &service : mServices) {
+ if (service.id == id && service.version == version) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void HalRpcClient::close() {
+ if (mIsChannelOpened) {
+ mRpcClient.CloseChannel(GetChannelId());
+ mIsChannelOpened = false;
+ }
+ if (mSocketClient.isConnected()) {
+ notifyEndpointDisconnected();
+ mSocketClient.disconnect();
+ }
+}
+
+// Private methods
+
+bool HalRpcClient::init(sp<SocketClient::ICallbacks> socketCallbacks) {
+ if (mSocketClient.isConnected()) {
+ LOGE("Already connected to socket");
+ return false;
+ }
+
+ auto callbacks = sp<Callbacks>::make(this, socketCallbacks);
+
+ if (!mSocketClient.connect("chre", callbacks)) {
+ LOGE("Couldn't connect to socket");
+ return false;
+ }
+
+ bool success = true;
+
+ if (!notifyEndpointConnected()) {
+ LOGE("Failed to notify connection");
+ success = false;
+ } else if (!retrieveMaxMessageLen()) {
+ LOGE("Failed to retrieve the max message length");
+ success = false;
+ } else if (!retrieveServices()) {
+ LOGE("Failed to retrieve the services");
+ success = false;
+ }
+
+ if (!success) {
+ mSocketClient.disconnect();
+ return false;
+ }
+
+ {
+ std::lock_guard lock(mHubInfoMutex);
+ mChannelOutput = std::make_unique<HalChannelOutput>(
+ mSocketClient, mHostEndpointId, mServerNanoappId, mMaxMessageLen);
+ }
+
+ return true;
+}
+
+bool HalRpcClient::notifyEndpointConnected() {
+ FlatBufferBuilder builder(64);
+ HostProtocolHost::encodeHostEndpointConnected(
+ builder, mHostEndpointId, CHRE_HOST_ENDPOINT_TYPE_NATIVE, mAppName,
+ /* attributionTag= */ "");
+ return mSocketClient.sendMessage(builder.GetBufferPointer(),
+ builder.GetSize());
+}
+
+bool HalRpcClient::notifyEndpointDisconnected() {
+ FlatBufferBuilder builder(64);
+ HostProtocolHost::encodeHostEndpointDisconnected(builder, mHostEndpointId);
+ return mSocketClient.sendMessage(builder.GetBufferPointer(),
+ builder.GetSize());
+}
+
+bool HalRpcClient::retrieveMaxMessageLen() {
+ FlatBufferBuilder builder(64);
+ HostProtocolHost::encodeHubInfoRequest(builder);
+ if (!mSocketClient.sendMessage(builder.GetBufferPointer(),
+ builder.GetSize())) {
+ return false;
+ }
+
+ std::unique_lock lock(mHubInfoMutex);
+ std::cv_status status = mHubInfoCond.wait_for(lock, kRequestTimeout);
+
+ return status != std::cv_status::timeout;
+}
+
+bool HalRpcClient::retrieveServices() {
+ FlatBufferBuilder builder(64);
+ HostProtocolHost::encodeNanoappListRequest(builder);
+
+ if (!mSocketClient.sendMessage(builder.GetBufferPointer(),
+ builder.GetSize())) {
+ return false;
+ }
+
+ std::unique_lock lock(mNanoappMutex);
+ std::cv_status status = mNanoappCond.wait_for(lock, kRequestTimeout);
+
+ return status != std::cv_status::timeout;
+}
+
+// Socket callbacks.
+
+void HalRpcClient::Callbacks::onMessageReceived(const void *data,
+ size_t length) {
+ if (!android::chre::HostProtocolHost::decodeMessageFromChre(data, length,
+ *this)) {
+ LOGE("Failed to decode message");
+ }
+ mSocketCallbacks->onMessageReceived(data, length);
+}
+
+void HalRpcClient::Callbacks::onConnected() {
+ mSocketCallbacks->onConnected();
+}
+
+void HalRpcClient::Callbacks::onConnectionAborted() {
+ mSocketCallbacks->onConnectionAborted();
+}
+
+void HalRpcClient::Callbacks::onDisconnected() {
+ // Close connections on CHRE reset.
+ mClient->close();
+ mSocketCallbacks->onDisconnected();
+}
+
+// Message handlers.
+
+void HalRpcClient::Callbacks::handleNanoappMessage(
+ const NanoappMessageT &message) {
+ if (message.message_type == CHRE_MESSAGE_TYPE_RPC) {
+ pw::span packet(reinterpret_cast<const std::byte *>(message.message.data()),
+ message.message.size());
+
+ if (message.app_id == mClient->mServerNanoappId) {
+ pw::Status status = mClient->mRpcClient.ProcessPacket(packet);
+ if (status != pw::OkStatus()) {
+ LOGE("Failed to process the packet");
+ }
+ }
+ }
+}
+
+void HalRpcClient::Callbacks::handleHubInfoResponse(
+ const HubInfoResponseT &response) {
+ {
+ std::lock_guard lock(mClient->mHubInfoMutex);
+ mClient->mMaxMessageLen = response.max_msg_len;
+ }
+ mClient->mHubInfoCond.notify_all();
+}
+
+void HalRpcClient::Callbacks::handleNanoappListResponse(
+ const NanoappListResponseT &response) {
+ for (const std::unique_ptr<NanoappListEntryT> &nanoapp : response.nanoapps) {
+ if (nanoapp->app_id == mClient->mServerNanoappId) {
+ std::lock_guard lock(mClient->mNanoappMutex);
+ mClient->mServices.clear();
+ mClient->mServices.reserve(nanoapp->rpc_services.size());
+ for (const std::unique_ptr<NanoappRpcServiceT> &service :
+ nanoapp->rpc_services) {
+ mClient->mServices.push_back(*service);
+ }
+ }
+ }
+
+ mClient->mNanoappCond.notify_all();
+}
+
+} // namespace android::chre \ No newline at end of file
diff --git a/host/common/preloaded_nanoapp_loader.cc b/host/common/preloaded_nanoapp_loader.cc
index b6fb892b..6739d5d2 100644
--- a/host/common/preloaded_nanoapp_loader.cc
+++ b/host/common/preloaded_nanoapp_loader.cc
@@ -28,82 +28,108 @@ namespace android::chre {
using android::chre::readFileContents;
using android::hardware::contexthub::common::implementation::kHalId;
+namespace {
+
+bool getNanoappHeaderFromFile(const char *headerFileName,
+ std::vector<uint8_t> &headerBuffer) {
+ if (!readFileContents(headerFileName, headerBuffer)) {
+ LOGE("Failed to read header file for nanoapp %s", headerFileName);
+ return false;
+ }
+ if (headerBuffer.size() != sizeof(NanoAppBinaryHeader)) {
+ LOGE("Nanoapp binary's header size is incorrect");
+ return false;
+ }
+ return true;
+}
+
+inline bool shouldSkipNanoapp(
+ std::optional<const std::unordered_set<uint64_t>> selectedNanoappIds,
+ uint64_t appId) {
+ return selectedNanoappIds.has_value() &&
+ selectedNanoappIds->find(appId) == selectedNanoappIds->end();
+}
+} // namespace
+
void PreloadedNanoappLoader::getPreloadedNanoappIds(
std::vector<uint64_t> &out_preloadedNanoappIds) {
std::vector<std::string> nanoappNames;
std::string directory;
out_preloadedNanoappIds.clear();
- bool success =
- getPreloadedNanoappsFromConfigFile(mConfigPath, directory, nanoappNames);
- if (!success) {
+ if (!getPreloadedNanoappsFromConfigFile(mConfigPath, directory,
+ nanoappNames)) {
LOGE("Failed to parse preloaded nanoapps config file");
}
for (const std::string &nanoappName : nanoappNames) {
- std::string headerFile = directory + "/" + nanoappName + ".napp_header";
+ std::string headerFileName = directory + "/" + nanoappName + ".napp_header";
std::vector<uint8_t> headerBuffer;
- if (!readFileContents(headerFile.c_str(), headerBuffer)) {
- LOGE("Cannot read header file: %s", headerFile.c_str());
- continue;
- }
- if (headerBuffer.size() != sizeof(NanoAppBinaryHeader)) {
- LOGE("Header size mismatch");
+ if (!getNanoappHeaderFromFile(headerFileName.c_str(), headerBuffer)) {
+ LOGE("Failed to parse the nanoapp header for %s", headerFileName.c_str());
continue;
}
- const auto *appHeader =
+ auto header =
reinterpret_cast<const NanoAppBinaryHeader *>(headerBuffer.data());
- out_preloadedNanoappIds.emplace_back(appHeader->appId);
+ out_preloadedNanoappIds.emplace_back(header->appId);
}
}
-void PreloadedNanoappLoader::loadPreloadedNanoapps() {
+bool PreloadedNanoappLoader::loadPreloadedNanoapps(
+ const std::optional<const std::unordered_set<uint64_t>>
+ &selectedNanoappIds) {
std::string directory;
std::vector<std::string> nanoapps;
-
- bool success =
- getPreloadedNanoappsFromConfigFile(mConfigPath, directory, nanoapps);
- if (!success) {
+ if (!getPreloadedNanoappsFromConfigFile(mConfigPath, directory, nanoapps)) {
LOGE("Failed to load any preloaded nanoapp");
- } else {
- mIsPreloadingOngoing = true;
- for (uint32_t i = 0; i < nanoapps.size(); ++i) {
- loadPreloadedNanoapp(directory, nanoapps[i], i);
- }
- mIsPreloadingOngoing = false;
+ return false;
}
-}
-
-void PreloadedNanoappLoader::loadPreloadedNanoapp(const std::string &directory,
- const std::string &name,
- uint32_t transactionId) {
- std::vector<uint8_t> headerBuffer;
- std::vector<uint8_t> nanoappBuffer;
-
- std::string headerFilename = directory + "/" + name + ".napp_header";
- std::string nanoappFilename = directory + "/" + name + ".so";
-
- if (!readFileContents(headerFilename.c_str(), headerBuffer) ||
- !readFileContents(nanoappFilename.c_str(), nanoappBuffer) ||
- !loadNanoapp(headerBuffer, nanoappBuffer, transactionId)) {
- LOGE("Failed to load nanoapp: '%s'", name.c_str());
+ if (mIsPreloadingOngoing.exchange(true)) {
+ LOGE("Preloading is ongoing. A new request shouldn't happen.");
+ return false;
+ }
+ bool success = true;
+ for (uint32_t i = 0; i < nanoapps.size(); ++i) {
+ std::string headerFilename = directory + "/" + nanoapps[i] + ".napp_header";
+ std::string nanoappFilename = directory + "/" + nanoapps[i] + ".so";
+ // parse the header
+ std::vector<uint8_t> headerBuffer;
+ if (!getNanoappHeaderFromFile(headerFilename.c_str(), headerBuffer)) {
+ LOGE("Failed to parse the nanoapp header for %s",
+ nanoappFilename.c_str());
+ success = false;
+ continue;
+ }
+ const auto header =
+ reinterpret_cast<const NanoAppBinaryHeader *>(headerBuffer.data());
+ // check if the app should be skipped
+ if (shouldSkipNanoapp(selectedNanoappIds, header->appId)) {
+ LOGI("Loading of %s is skipped.", headerFilename.c_str());
+ continue;
+ }
+ // load the binary
+ if (!loadNanoapp(header, nanoappFilename, i)) {
+ success = false;
+ }
}
+ mIsPreloadingOngoing.store(false);
+ return success;
}
-bool PreloadedNanoappLoader::loadNanoapp(const std::vector<uint8_t> &header,
- const std::vector<uint8_t> &nanoapp,
+bool PreloadedNanoappLoader::loadNanoapp(const NanoAppBinaryHeader *appHeader,
+ const std::string &nanoappFileName,
uint32_t transactionId) {
- if (header.size() != sizeof(NanoAppBinaryHeader)) {
- LOGE("Nanoapp binary's header size is incorrect");
+ // parse the binary
+ std::vector<uint8_t> nanoappBuffer;
+ if (!readFileContents(nanoappFileName.c_str(), nanoappBuffer)) {
+ LOGE("Unable to read %s.", nanoappFileName.c_str());
return false;
}
- const auto *appHeader =
- reinterpret_cast<const NanoAppBinaryHeader *>(header.data());
-
// Build the target API version from major and minor.
uint32_t targetApiVersion = (appHeader->targetChreApiMajorVersion << 24) |
(appHeader->targetChreApiMinorVersion << 16);
return sendFragmentedLoadAndWaitForEachResponse(
appHeader->appId, appHeader->appVersion, appHeader->flags,
- targetApiVersion, nanoapp.data(), nanoapp.size(), transactionId);
+ targetApiVersion, nanoappBuffer.data(), nanoappBuffer.size(),
+ transactionId);
}
bool PreloadedNanoappLoader::sendFragmentedLoadAndWaitForEachResponse(
diff --git a/host/common/socket_client.cc b/host/common/socket_client.cc
index a8c18d9c..cf172073 100644
--- a/host/common/socket_client.cc
+++ b/host/common/socket_client.cc
@@ -177,6 +177,10 @@ void SocketClient::receiveThread() {
ssize_t bytesReceived = recv(mSockFd, buffer, sizeof(buffer), 0);
if (bytesReceived < 0) {
LOG_ERROR("Exiting RX thread", errno);
+ if (!mGracefulShutdown) {
+ LOGI("Force onDisconnected");
+ mCallbacks->onDisconnected();
+ }
break;
} else if (bytesReceived == 0) {
if (!mGracefulShutdown) {
diff --git a/host/common/socket_server.cc b/host/common/socket_server.cc
index e5403a23..1c2681a6 100644
--- a/host/common/socket_server.cc
+++ b/host/common/socket_server.cc
@@ -19,6 +19,7 @@
#include <poll.h>
#include <cassert>
+#include <cerrno>
#include <cinttypes>
#include <csignal>
#include <cstdlib>
@@ -172,6 +173,9 @@ void SocketServer::handleClientData(int clientSocket) {
if (packetSize < 0) {
LOGE("Couldn't get packet from client %" PRIu16 ": %s", clientId,
strerror(errno));
+ if (ENOTCONN == errno) {
+ disconnectClient(clientSocket);
+ }
} else if (packetSize == 0) {
LOGI("Client %" PRIu16 " disconnected", clientId);
disconnectClient(clientSocket);
diff --git a/host/common/test/chre_test_client.cc b/host/common/test/chre_test_client.cc
index 57da705d..397c66c0 100644
--- a/host/common/test/chre_test_client.cc
+++ b/host/common/test/chre_test_client.cc
@@ -14,26 +14,29 @@
* limitations under the License.
*/
-#include "chre/util/nanoapp/app_id.h"
-#include "chre/util/system/napp_header_utils.h"
-#include "chre_host/file_stream.h"
-#include "chre_host/host_protocol_host.h"
-#include "chre_host/log.h"
-#include "chre_host/napp_header.h"
-#include "chre_host/socket_client.h"
-
#include <inttypes.h>
#include <sys/socket.h>
#include <sys/types.h>
+#include <chrono>
+#include <condition_variable>
#include <fstream>
#include <future>
+#include <mutex>
#include <sstream>
#include <thread>
#include <cutils/sockets.h>
#include <utils/StrongPointer.h>
+#include "chre/util/nanoapp/app_id.h"
+#include "chre/util/system/napp_header_utils.h"
+#include "chre_host/file_stream.h"
+#include "chre_host/host_protocol_host.h"
+#include "chre_host/log.h"
+#include "chre_host/napp_header.h"
+#include "chre_host/socket_client.h"
+
/**
* @file
* A test utility that connects to the CHRE daemon that runs on the apps
@@ -47,6 +50,7 @@
*/
using android::sp;
+using android::chre::FragmentedLoadRequest;
using android::chre::FragmentedLoadTransaction;
using android::chre::getStringFromByteVector;
using android::chre::HostProtocolHost;
@@ -62,15 +66,34 @@ namespace fbs = ::chre::fbs;
namespace {
-//! The host endpoint we use when sending; set to CHRE_HOST_ENDPOINT_UNSPECIFIED
-//! Other clients below the HAL may use a value above 0x8000 to enable unicast
-//! messaging (currently requires internal coordination to avoid conflict;
-//! in the future these should be assigned by the daemon).
-constexpr uint16_t kHostEndpoint = 0xfffe;
+//! The host endpoint we use when sending; Clients may use a value above
+//! 0x8000 to enable unicast messaging (currently requires internal coordination
+//! to avoid conflict).
+constexpr uint16_t kHostEndpoint = 0x8002;
constexpr uint32_t kDefaultAppVersion = 1;
constexpr uint32_t kDefaultApiVersion = 0x01000000;
+// Timeout for loading a nanoapp fragment.
+static constexpr auto kFragmentTimeout = std::chrono::milliseconds(2000);
+
+enum class LoadingStatus {
+ kLoading,
+ kSuccess,
+ kError,
+};
+
+// State of a nanoapp fragment.
+struct FragmentStatus {
+ size_t id;
+ LoadingStatus loadStatus;
+};
+
+// State of the current nanoapp fragment.
+std::mutex gFragmentMutex;
+std::condition_variable gFragmentCondVar;
+FragmentStatus gFragmentStatus;
+
class SocketCallbacks : public SocketClient::ICallbacks,
public IChreMessageHandlers {
public:
@@ -127,8 +150,21 @@ class SocketCallbacks : public SocketClient::ICallbacks,
void handleLoadNanoappResponse(
const fbs::LoadNanoappResponseT &response) override {
- LOGI("Got load nanoapp response, transaction ID 0x%" PRIx32 " result %d",
- response.transaction_id, response.success);
+ LOGI("Got load nanoapp response, transaction ID 0x%" PRIx32
+ " fragment %" PRIx32 " result %d",
+ response.transaction_id, response.fragment_id, response.success);
+
+ {
+ std::lock_guard lock(gFragmentMutex);
+ if (response.fragment_id != gFragmentStatus.id) {
+ gFragmentStatus.loadStatus = LoadingStatus::kError;
+ } else {
+ gFragmentStatus.loadStatus =
+ response.success ? LoadingStatus::kSuccess : LoadingStatus::kError;
+ }
+ }
+
+ gFragmentCondVar.notify_all();
}
void handleUnloadNanoappResponse(
@@ -187,20 +223,48 @@ void sendMessageToNanoapp(SocketClient &client) {
void sendNanoappLoad(SocketClient &client, uint64_t appId, uint32_t appVersion,
uint32_t apiVersion, uint32_t appFlags,
const std::vector<uint8_t> &binary) {
- // Perform loading with 1 fragment for simplicity
- FlatBufferBuilder builder(binary.size() + 128);
FragmentedLoadTransaction transaction = FragmentedLoadTransaction(
- 1 /* transactionId */, appId, appVersion, appFlags, apiVersion, binary,
- binary.size() /* fragmentSize */);
- HostProtocolHost::encodeFragmentedLoadNanoappRequest(
- builder, transaction.getNextRequest());
-
- LOGI("Sending load nanoapp request (%" PRIu32
- " bytes total w/%zu bytes of "
- "payload)",
- builder.GetSize(), binary.size());
- if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
- LOGE("Failed to send message");
+ 1 /* transactionId */, appId, appVersion, appFlags, apiVersion, binary);
+
+ bool success = true;
+ while (!transaction.isComplete()) {
+ const FragmentedLoadRequest &request = transaction.getNextRequest();
+ LOGI("Loading nanoapp fragment %zu", request.fragmentId);
+
+ FlatBufferBuilder builder(request.binary.size() + 128);
+ HostProtocolHost::encodeFragmentedLoadNanoappRequest(builder, request);
+
+ std::unique_lock lock(gFragmentMutex);
+ gFragmentStatus = {.id = request.fragmentId,
+ .loadStatus = LoadingStatus::kLoading};
+ lock.unlock();
+
+ if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
+ LOGE("Failed to send fragment");
+ success = false;
+ break;
+ }
+
+ lock.lock();
+ std::cv_status status = gFragmentCondVar.wait_for(lock, kFragmentTimeout);
+
+ if (status == std::cv_status::timeout) {
+ success = false;
+ LOGE("Timeout loading the fragment");
+ break;
+ }
+
+ if (gFragmentStatus.loadStatus != LoadingStatus::kSuccess) {
+ LOGE("Error loading the fragment");
+ success = false;
+ break;
+ }
+ }
+
+ if (success) {
+ LOGI("Nanoapp loaded successfully");
+ } else {
+ LOGE("Error loading the nanoapp");
}
}
diff --git a/host/common/test/chre_test_rpc.cc b/host/common/test/chre_test_rpc.cc
new file mode 100644
index 00000000..64ad98c7
--- /dev/null
+++ b/host/common/test/chre_test_rpc.cc
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include <utils/StrongPointer.h>
+#include <chrono>
+#include <cstdint>
+#include <future>
+#include <thread>
+
+#include "chre/util/nanoapp/app_id.h"
+#include "chre_host/host_protocol_host.h"
+#include "chre_host/log.h"
+#include "chre_host/pigweed/hal_rpc_client.h"
+#include "chre_host/socket_client.h"
+#include "rpc_world.pb.h"
+#include "rpc_world.rpc.pb.h"
+
+/**
+ * @file
+ * Test RPC by calling a service provided by the rpc_world nanoapp.
+ *
+ * Usage:
+ * 1. Compile and push the rpc_world nanoapp to the device.
+ *
+ * 2. Load the nanoapp:
+ * adb shell chre_test_client load_with_header \
+ * /vendor/etc/chre/rpc_world.napp_header \
+ * /vendor/etc/chre/rpc_world.so
+ *
+ * 3. Build this test and push it to the device:
+ * m chre_test_rpc
+ * adb push \
+ * out/target/product/<product>/vendor/bin/chre_test_rpc \
+ * /vendor/bin/chre_test_rpc
+ *
+ * 4. Launch the test:
+ * adb shell chre_test_rpc
+ */
+
+namespace {
+
+using ::android::sp;
+using ::android::chre::HalRpcClient;
+using ::android::chre::HostProtocolHost;
+using ::android::chre::IChreMessageHandlers;
+using ::android::chre::SocketClient;
+using ::flatbuffers::FlatBufferBuilder;
+
+// Aliased for consistency with the way these symbols are referenced in
+// CHRE-side code
+namespace fbs = ::chre::fbs;
+
+constexpr uint16_t kHostEndpoint = 0x8006;
+
+constexpr uint32_t kRequestNumber = 10;
+std::promise<uint32_t> gResponsePromise;
+
+class SocketCallbacks : public SocketClient::ICallbacks,
+ public IChreMessageHandlers {
+ public:
+ void onMessageReceived(const void *data, size_t length) override {
+ if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
+ LOGE("Failed to decode message");
+ }
+ }
+
+ void handleNanoappListResponse(
+ const fbs::NanoappListResponseT &response) override {
+ LOGI("Got nanoapp list response with %zu apps", response.nanoapps.size());
+ }
+};
+
+} // namespace
+
+void incrementResponse(const chre_rpc_NumberMessage &response,
+ pw::Status status) {
+ if (status.ok()) {
+ gResponsePromise.set_value(response.number);
+ } else {
+ LOGE("Increment failed with status %d", static_cast<int>(status.code()));
+ }
+}
+
+int main(int argc, char *argv[]) {
+ UNUSED_VAR(argc);
+ UNUSED_VAR(argv);
+
+ SocketClient socketClient;
+
+ auto callbacks = sp<SocketCallbacks>::make();
+
+ std::unique_ptr<HalRpcClient> rpcClient =
+ HalRpcClient::createClient("chre_test_rpc", socketClient, callbacks,
+ kHostEndpoint, chre::kRpcWorldAppId);
+
+ if (rpcClient == nullptr) {
+ LOGE("Failed to create the RPC client");
+ return -1;
+ }
+
+ if (!rpcClient->hasService(/* id= */ 0xca8f7150a3f05847,
+ /* version= */ 0x01020034)) {
+ LOGE("RpcWorld service not found");
+ return -1;
+ }
+
+ auto client =
+ rpcClient->get<chre::rpc::pw_rpc::nanopb::RpcWorldService::Client>();
+
+ chre_rpc_NumberMessage incrementRequest;
+ incrementRequest.number = kRequestNumber;
+
+ pw::rpc::NanopbUnaryReceiver<chre_rpc_NumberMessage> call =
+ client->Increment(incrementRequest, incrementResponse);
+
+ if (!call.active()) {
+ LOGE("Failed to call the service");
+ return -1;
+ }
+
+ std::future<uint32_t> response = gResponsePromise.get_future();
+
+ if (response.wait_for(std::chrono::seconds(2)) != std::future_status::ready) {
+ LOGE("No response received from RPC");
+ } else {
+ const uint32_t value = response.get();
+ LOGI("The RPC service says %" PRIu32 " + 1 = %" PRIu32, kRequestNumber,
+ value);
+ }
+
+ rpcClient->close();
+
+ return 0;
+}
diff --git a/host/common/test/power_test/chre_power_test_client.cc b/host/common/test/power_test/chre_power_test_client.cc
index 344944dc..1251e998 100644
--- a/host/common/test/power_test/chre_power_test_client.cc
+++ b/host/common/test/power_test/chre_power_test_client.cc
@@ -145,7 +145,10 @@ namespace ptest = ::chre::power_test;
namespace {
-constexpr uint16_t kHostEndpoint = 0xfffd;
+//! The host endpoint we use when sending; Clients may use a value above
+//! 0x8000 to enable unicast messaging (currently requires internal coordination
+//! to avoid conflict).
+constexpr uint16_t kHostEndpoint = 0x8003;
constexpr uint64_t kPowerTestAppId = 0x012345678900000f;
constexpr uint64_t kPowerTestTcmAppId = 0x0123456789000010;
diff --git a/host/common/time_syncer.cc b/host/common/time_syncer.cc
index e6d27929..41028b99 100644
--- a/host/common/time_syncer.cc
+++ b/host/common/time_syncer.cc
@@ -20,33 +20,33 @@
namespace android::chre {
// TODO(b/247124878): Can we add a static assert to make sure these functions
-// are not called when mConnection->isTimeSyncNeeded() returns false?
-bool TimeSyncer::sendTimeSync() {
- if (!mConnection->isTimeSyncNeeded()) {
+// are not called when connection->isTimeSyncNeeded() returns false?
+bool TimeSyncer::sendTimeSync(ChreConnection *connection) {
+ if (!connection->isTimeSyncNeeded()) {
LOGW("Platform doesn't require time sync. Ignore the request.");
return true;
}
int64_t timeOffsetUs = 0;
- if (!mConnection->getTimeOffset(&timeOffsetUs)) {
+ if (!connection->getTimeOffset(&timeOffsetUs)) {
LOGE("Failed to get time offset.");
return false;
}
flatbuffers::FlatBufferBuilder builder(64);
// clientId doesn't matter for time sync request so the default id is used.
HostProtocolHost::encodeTimeSyncMessage(builder, timeOffsetUs);
- return mConnection->sendMessage(builder.GetBufferPointer(),
- builder.GetSize());
+ return connection->sendMessage(builder.GetBufferPointer(), builder.GetSize());
}
-bool TimeSyncer::sendTimeSyncWithRetry(size_t numOfRetries,
+bool TimeSyncer::sendTimeSyncWithRetry(ChreConnection *connection,
+ size_t numOfRetries,
useconds_t retryDelayUs) {
- if (!mConnection->isTimeSyncNeeded()) {
+ if (!connection->isTimeSyncNeeded()) {
LOGW("Platform doesn't require time sync. Ignore the request.");
return true;
}
bool success = false;
while (!success && (numOfRetries-- > 0)) {
- success = sendTimeSync();
+ success = sendTimeSync(connection);
if (!success) {
usleep(retryDelayUs);
}
diff --git a/host/hal_generic/Android.bp b/host/hal_generic/Android.bp
index caef5284..7b85a82a 100644
--- a/host/hal_generic/Android.bp
+++ b/host/hal_generic/Android.bp
@@ -27,22 +27,31 @@ package {
cc_binary {
name: "android.hardware.contexthub-service.generic",
- defaults: ["hidl_defaults"],
+ defaults: ["chre_aidl_hal_generic_defaults"],
vendor: true,
relative_install_path: "hw",
+ srcs: [":hal_aidl_generic_srcs", "aidl/service.cc"],
+ init_rc: ["aidl/android.hardware.contexthub-service.generic.rc"],
+ vintf_fragments: ["aidl/android.hardware.contexthub-service.generic.xml"],
+ visibility: ["//visibility:public"],
+}
+
+filegroup {
+ name: "hal_aidl_generic_srcs",
srcs: [
"aidl/generic_context_hub_aidl.cc",
- "aidl/service.cc",
"common/hal_chre_socket_connection.cc",
"common/permissions_util.cc",
],
+}
+
+cc_defaults {
+ name: "chre_aidl_hal_generic_defaults",
+ vendor: true,
include_dirs: [
+ "system/chre/host/hal_generic/common/",
"system/chre/util/include",
],
- local_include_dirs: [
- "common/",
- ],
- init_rc: ["aidl/android.hardware.contexthub-service.generic.rc"],
cflags: [
"-Wall",
"-Werror",
@@ -50,6 +59,9 @@ cc_binary {
"-DCHRE_HAL_SOCKET_METRICS_ENABLED",
"-DCHRE_IS_HOST_BUILD",
],
+ header_libs: [
+ "chre_api",
+ ],
shared_libs: [
"android.frameworks.stats-V1-ndk",
"libcutils",
@@ -59,17 +71,24 @@ cc_binary {
"libutils",
"libbase",
"libbinder_ndk",
- "android.hardware.contexthub-V2-ndk",
+ "android.hardware.contexthub-V3-ndk",
"chremetrics-cpp",
"chre_atoms_log",
- ],
- header_libs: [
- "chre_api",
+ "chre_metrics_reporter",
+ "server_configurable_flags",
],
static_libs: [
"chre_client",
"chre_config_util",
"event_logger",
+ "chre_flags_c_lib",
+ ],
+}
+
+cc_library_headers {
+ name: "chre_aidl_hal_generic",
+ vendor: true,
+ export_include_dirs: [
+ "aidl",
],
- vintf_fragments: ["aidl/android.hardware.contexthub-service.generic.xml"],
}
diff --git a/host/hal_generic/aidl/android.hardware.contexthub-service.generic.xml b/host/hal_generic/aidl/android.hardware.contexthub-service.generic.xml
index 930f6721..2f8ddc8e 100644
--- a/host/hal_generic/aidl/android.hardware.contexthub-service.generic.xml
+++ b/host/hal_generic/aidl/android.hardware.contexthub-service.generic.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.contexthub</name>
- <version>2</version>
+ <version>3</version>
<interface>
<name>IContextHub</name>
<instance>default</instance>
diff --git a/host/hal_generic/aidl/generic_context_hub_aidl.cc b/host/hal_generic/aidl/generic_context_hub_aidl.cc
index dae0d6f4..16c5c3c7 100644
--- a/host/hal_generic/aidl/generic_context_hub_aidl.cc
+++ b/host/hal_generic/aidl/generic_context_hub_aidl.cc
@@ -51,6 +51,7 @@ constexpr uint32_t kDefaultHubId = 0;
constexpr char kPreloadedNanoappsConfigPath[] =
"/vendor/etc/chre/preloaded_nanoapps.json";
constexpr std::chrono::duration kTestModeTimeout = std::chrono::seconds(10);
+constexpr uint16_t kMaxValidHostEndPointId = 0x7fff;
/*
* The starting transaction ID for internal transactions. We choose
@@ -124,6 +125,9 @@ ScopedAStatus ContextHub::getContextHubs(
hub.supportedPermissions = kSupportedPermissions;
+ // TODO(b/312417087): Implement reliable message support
+ hub.supportsReliableMessages = false;
+
out_contextHubInfos->push_back(hub);
}
@@ -296,6 +300,13 @@ ScopedAStatus ContextHub::setTestMode(bool enable) {
return enable ? enableTestMode() : disableTestMode();
}
+ScopedAStatus ContextHub::sendMessageDeliveryStatusToHub(
+ int32_t /* contextHubId */,
+ const MessageDeliveryStatus & /* messageDeliveryStatus */) {
+ // TODO(b/312417087): Implement reliable message support
+ return ndk::ScopedAStatus::ok();
+}
+
ScopedAStatus ContextHub::onHostEndpointConnected(
const HostEndpointInfo &in_info) {
std::lock_guard<std::mutex> lock(mConnectedHostEndpointsMutex);
@@ -345,6 +356,11 @@ ScopedAStatus ContextHub::onNanSessionStateChanged(
void ContextHub::onNanoappMessage(const ::chre::fbs::NanoappMessageT &message) {
std::lock_guard<std::mutex> lock(mCallbackMutex);
if (mCallback != nullptr) {
+ if (message.host_endpoint > kMaxValidHostEndPointId &&
+ message.host_endpoint != CHRE_HOST_ENDPOINT_BROADCAST) {
+ return;
+ }
+
mEventLogger.logMessageFromNanoapp(message);
ContextHubMessage outMessage;
outMessage.nanoappId = message.app_id;
diff --git a/host/hal_generic/aidl/generic_context_hub_aidl.h b/host/hal_generic/aidl/generic_context_hub_aidl.h
index 9c12c16c..024cb1e3 100644
--- a/host/hal_generic/aidl/generic_context_hub_aidl.h
+++ b/host/hal_generic/aidl/generic_context_hub_aidl.h
@@ -79,6 +79,9 @@ class ContextHub : public BnContextHub,
::ndk::ScopedAStatus sendMessageToHub(
int32_t contextHubId, const ContextHubMessage &message) override;
::ndk::ScopedAStatus setTestMode(bool enable) override;
+ ::ndk::ScopedAStatus sendMessageDeliveryStatusToHub(
+ int32_t contextHubId,
+ const MessageDeliveryStatus &messageDeliveryStatus) override;
::ndk::ScopedAStatus onHostEndpointConnected(
const HostEndpointInfo &in_info) override;
::ndk::ScopedAStatus onHostEndpointDisconnected(
diff --git a/host/hal_generic/common/hal_chre_socket_connection.cc b/host/hal_generic/common/hal_chre_socket_connection.cc
index b113e44f..432a36ef 100644
--- a/host/hal_generic/common/hal_chre_socket_connection.cc
+++ b/host/hal_generic/common/hal_chre_socket_connection.cc
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// TODO(b/298459533): remove_ap_wakeup_metric_report_limit ramp up -> remove old
+// code
+
#define LOG_TAG "ContextHubHal"
#define LOG_NDEBUG 1
@@ -22,8 +25,13 @@
#include <log/log.h>
#ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
+// TODO(b/298459533): Remove these when the flag_log_nanoapp_load_metrics flag
+// is cleaned up
#include <aidl/android/frameworks/stats/IStats.h>
#include <android/binder_manager.h>
+#include <android_chre_flags.h>
+// TODO(b/298459533): Remove end
+
#include <chre_atoms_log.h>
#include <utils/SystemClock.h>
#endif // CHRE_HAL_SOCKET_METRICS_ENABLED
@@ -34,15 +42,25 @@ namespace contexthub {
namespace common {
namespace implementation {
-using chre::FragmentedLoadRequest;
-using chre::FragmentedLoadTransaction;
-using chre::HostProtocolHost;
-using flatbuffers::FlatBufferBuilder;
+using ::android::chre::FragmentedLoadRequest;
+using ::android::chre::FragmentedLoadTransaction;
+using ::android::chre::HostProtocolHost;
+using ::flatbuffers::FlatBufferBuilder;
#ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
+// TODO(b/298459533): Remove these when the flag_log_nanoapp_load_metrics flag
+// is cleaned up
using ::aidl::android::frameworks::stats::IStats;
using ::aidl::android::frameworks::stats::VendorAtom;
using ::aidl::android::frameworks::stats::VendorAtomValue;
+using ::android::chre::Atoms::CHRE_AP_WAKE_UP_OCCURRED;
+using ::android::chre::Atoms::CHRE_HAL_NANOAPP_LOAD_FAILED;
+using ::android::chre::flags::flag_log_nanoapp_load_metrics;
+using ::android::chre::flags::remove_ap_wakeup_metric_report_limit;
+// TODO(b/298459533): Remove end
+
+using ::android::chre::MetricsReporter;
+using ::android::chre::Atoms::ChreHalNanoappLoadFailed;
#endif // CHRE_HAL_SOCKET_METRICS_ENABLED
HalChreSocketConnection::HalChreSocketConnection(
@@ -182,7 +200,9 @@ HalChreSocketConnection::SocketCallbacks::SocketCallbacks(
HalChreSocketConnection &parent, IChreSocketCallback *callback)
: mParent(parent), mCallback(callback) {
#ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
- mLastClearedTimestamp = elapsedRealtime();
+ if (!remove_ap_wakeup_metric_report_limit()) {
+ mLastClearedTimestamp = elapsedRealtime();
+ }
#endif // CHRE_HAL_SOCKET_METRICS_ENABLED
}
@@ -217,25 +237,35 @@ void HalChreSocketConnection::SocketCallbacks::handleNanoappMessage(
// check and update the 24hour timer
std::lock_guard<std::mutex> lock(mNanoappWokeApCountMutex);
long nanoappId = message.app_id;
- long timeElapsed = elapsedRealtime() - mLastClearedTimestamp;
- if (timeElapsed > kOneDayinMillis) {
- mNanoappWokeUpCount = 0;
- mLastClearedTimestamp = elapsedRealtime();
+
+ if (!remove_ap_wakeup_metric_report_limit()) {
+ long timeElapsed = elapsedRealtime() - mLastClearedTimestamp;
+ if (timeElapsed > kOneDayinMillis) {
+ mNanoappWokeUpCount = 0;
+ mLastClearedTimestamp = elapsedRealtime();
+ }
+
+ mNanoappWokeUpCount++;
}
- // update and report the AP woke up metric
- mNanoappWokeUpCount++;
- if (mNanoappWokeUpCount < kMaxDailyReportedApWakeUp) {
- // create and report the vendor atom
- std::vector<VendorAtomValue> values(1);
- values[0].set<VendorAtomValue::longValue>(nanoappId);
+ if (remove_ap_wakeup_metric_report_limit() ||
+ mNanoappWokeUpCount < kMaxDailyReportedApWakeUp) {
+ if (flag_log_nanoapp_load_metrics()) {
+ if (!mParent.mMetricsReporter.logApWakeupOccurred(nanoappId)) {
+ ALOGE("Could not log AP Wakeup metric");
+ }
+ } else {
+ // create and report the vendor atom
+ std::vector<VendorAtomValue> values(1);
+ values[0].set<VendorAtomValue::longValue>(nanoappId);
- const VendorAtom atom{
- .atomId = chre::Atoms::CHRE_AP_WAKE_UP_OCCURRED,
- .values{std::move(values)},
- };
+ const VendorAtom atom{
+ .atomId = CHRE_AP_WAKE_UP_OCCURRED,
+ .values{std::move(values)},
+ };
- mParent.reportMetric(atom);
+ mParent.reportMetric(atom);
+ }
}
}
#endif // CHRE_HAL_SOCKET_METRICS_ENABLED
@@ -293,6 +323,19 @@ void HalChreSocketConnection::SocketCallbacks::handleLoadNanoappResponse(
}
} else {
success = response.success;
+
+#ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
+ if (!success) {
+ if (flag_log_nanoapp_load_metrics()) {
+ if (!mParent.mMetricsReporter.logNanoappLoadFailed(
+ transaction.getNanoappId(),
+ ChreHalNanoappLoadFailed::TYPE_DYNAMIC,
+ ChreHalNanoappLoadFailed::REASON_ERROR_GENERIC)) {
+ ALOGE("Could not log the nanoapp load failed metric");
+ }
+ }
+ }
+#endif // CHRE_HAL_SOCKET_METRICS_ENABLED
}
if (!continueLoadRequest) {
@@ -347,19 +390,27 @@ bool HalChreSocketConnection::sendFragmentedLoadNanoAppRequest(
request.fragmentId);
#ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
- // create and report the vendor atom
- std::vector<VendorAtomValue> values(3);
- values[0].set<VendorAtomValue::longValue>(request.appId);
- values[1].set<VendorAtomValue::intValue>(
- chre::Atoms::ChreHalNanoappLoadFailed::TYPE_DYNAMIC);
- values[2].set<VendorAtomValue::intValue>(
- chre::Atoms::ChreHalNanoappLoadFailed::REASON_ERROR_GENERIC);
-
- const VendorAtom atom{
- .atomId = chre::Atoms::CHRE_HAL_NANOAPP_LOAD_FAILED,
- .values{std::move(values)},
- };
- reportMetric(atom);
+ if (flag_log_nanoapp_load_metrics()) {
+ if (!mMetricsReporter.logNanoappLoadFailed(
+ request.appId, ChreHalNanoappLoadFailed::TYPE_DYNAMIC,
+ ChreHalNanoappLoadFailed::REASON_CONNECTION_ERROR)) {
+ ALOGE("Could not log the nanoapp load failed metric");
+ }
+ } else {
+ // create and report the vendor atom
+ std::vector<VendorAtomValue> values(3);
+ values[0].set<VendorAtomValue::longValue>(request.appId);
+ values[1].set<VendorAtomValue::intValue>(
+ ChreHalNanoappLoadFailed::TYPE_DYNAMIC);
+ values[2].set<VendorAtomValue::intValue>(
+ ChreHalNanoappLoadFailed::REASON_ERROR_GENERIC);
+
+ const VendorAtom atom{
+ .atomId = CHRE_HAL_NANOAPP_LOAD_FAILED,
+ .values{std::move(values)},
+ };
+ reportMetric(atom);
+ }
#endif // CHRE_HAL_SOCKET_METRICS_ENABLED
} else {
@@ -371,6 +422,8 @@ bool HalChreSocketConnection::sendFragmentedLoadNanoAppRequest(
}
#ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
+// TODO(b/298459533): Remove this the flag_log_nanoapp_load_metrics flag is
+// cleaned up
void HalChreSocketConnection::reportMetric(const VendorAtom atom) {
const std::string statsServiceName =
std::string(IStats::descriptor).append("/default");
@@ -391,6 +444,7 @@ void HalChreSocketConnection::reportMetric(const VendorAtom atom) {
ALOGE("Failed to report vendor atom");
}
}
+// TODO(b/298459533): Remove end
#endif // CHRE_HAL_SOCKET_METRICS_ENABLED
} // namespace implementation
diff --git a/host/hal_generic/common/hal_chre_socket_connection.h b/host/hal_generic/common/hal_chre_socket_connection.h
index b3bb294c..417638c6 100644
--- a/host/hal_generic/common/hal_chre_socket_connection.h
+++ b/host/hal_generic/common/hal_chre_socket_connection.h
@@ -26,7 +26,9 @@
#ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
#include <aidl/android/frameworks/stats/IStats.h>
-#endif // CHRE_HAL_SOCKET_METRICS_ENABLED
+
+#include "chre_host/metrics_reporter.h"
+#endif // CHRE_HAL_SOCKET_METRICS_ENABLED
namespace android {
namespace hardware {
@@ -182,6 +184,10 @@ class HalChreSocketConnection {
std::optional<chre::FragmentedLoadTransaction> mPendingLoadTransaction;
std::mutex mPendingLoadTransactionMutex;
+#ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
+ android::chre::MetricsReporter mMetricsReporter;
+#endif // CHRE_HAL_SOCKET_METRICS_ENABLED
+
/**
* Checks to see if a load response matches the currently pending
* fragmented load transaction. mPendingLoadTransactionMutex must
@@ -206,14 +212,17 @@ class HalChreSocketConnection {
bool sendFragmentedLoadNanoAppRequest(
chre::FragmentedLoadTransaction &transaction);
+#ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
+ // TODO(b/298459533): Remove this when the flag_log_nanoapp_load_metrics flag
+ // is cleaned up
/**
* Create and report CHRE vendor atom and send it to stats_client
*
* @param atom the vendor atom to be reported
*/
-#ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
void reportMetric(const aidl::android::frameworks::stats::VendorAtom atom);
#endif // CHRE_HAL_SOCKET_METRICS_ENABLED
+ // TODO(b/298459533): Remove end
};
} // namespace implementation
diff --git a/host/hal_generic/common/hal_client_id.h b/host/hal_generic/common/hal_client_id.h
index fb6e2a5b..778a59d0 100644
--- a/host/hal_generic/common/hal_client_id.h
+++ b/host/hal_generic/common/hal_client_id.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_HARDWARE_CONTEXTHUB_COMMON_HAL_CLIENT_ID_H_
#define ANDROID_HARDWARE_CONTEXTHUB_COMMON_HAL_CLIENT_ID_H_
+#include <cstdint>
#include <limits>
namespace android::hardware::contexthub::common::implementation {
@@ -29,9 +30,6 @@ constexpr HalClientId kMaxHalClientId = 0x1ff;
/** Max number of HAL clients supported. */
constexpr uint16_t kMaxNumOfHalClients = kMaxHalClientId - 1;
-/** The default HAL client id indicating the id is not assigned. */
-constexpr HalClientId kDefaultHalClientId = 0;
-
/**
* The HAL client id indicating the message is actually sent to the HAL itself.
*/
diff --git a/host/hal_generic/common/hal_client_manager.cc b/host/hal_generic/common/hal_client_manager.cc
index 39ce4c9b..4658c837 100644
--- a/host/hal_generic/common/hal_client_manager.cc
+++ b/host/hal_generic/common/hal_client_manager.cc
@@ -14,197 +14,246 @@
* limitations under the License.
*/
#include "hal_client_manager.h"
+
+#include <fstream>
+
#include <aidl/android/hardware/contexthub/AsyncEventType.h>
#include <android-base/strings.h>
+#include <android_chre_flags.h>
#include <json/json.h>
#include <utils/SystemClock.h>
-#include <fstream>
namespace android::hardware::contexthub::common::implementation {
-using aidl::android::hardware::contexthub::AsyncEventType;
-using aidl::android::hardware::contexthub::ContextHubMessage;
-using aidl::android::hardware::contexthub::HostEndpointInfo;
-using aidl::android::hardware::contexthub::IContextHubCallback;
+using ::aidl::android::hardware::contexthub::AsyncEventType;
+using ::aidl::android::hardware::contexthub::ContextHubMessage;
+using ::aidl::android::hardware::contexthub::HostEndpointInfo;
+using ::aidl::android::hardware::contexthub::IContextHubCallback;
+using ::android::chre::flags::context_hub_callback_uuid_enabled;
+
+using HalClient = HalClientManager::HalClient;
namespace {
-bool getClientMappingsFromFile(const char *filePath, Json::Value &mappings) {
+bool getClientMappingsFromFile(const std::string &filePath,
+ Json::Value &mappings) {
std::fstream file(filePath);
Json::CharReaderBuilder builder;
return file.good() &&
Json::parseFromStream(builder, file, &mappings, /* errs= */ nullptr);
}
+
+std::string getUuid(const std::shared_ptr<IContextHubCallback> &callback) {
+ std::array<uint8_t, 16> uuidBytes{};
+ callback->getUuid(&uuidBytes);
+ std::ostringstream oStringStream;
+ char buffer[3]{};
+ for (const uint8_t &byte : uuidBytes) {
+ snprintf(buffer, sizeof(buffer), "%02x", static_cast<int>(byte));
+ oStringStream << buffer;
+ }
+ return oStringStream.str();
+}
+
+std::string getName(const std::shared_ptr<IContextHubCallback> &callback) {
+ std::string name;
+ callback->getName(&name);
+ return name;
+}
+
+bool isCallbackV3Enabled(const std::shared_ptr<IContextHubCallback> &callback) {
+ int32_t callbackVersion;
+ callback->getInterfaceVersion(&callbackVersion);
+ return callbackVersion >= 3 && context_hub_callback_uuid_enabled();
+}
+
} // namespace
-std::optional<HalClientId> HalClientManager::createClientIdLocked(
- const std::string &processName) {
- if (mPIdsToClientIds.size() > kMaxNumOfHalClients ||
- mNextClientId > kMaxHalClientId) {
- LOGE("Too many HAL clients registered which should never happen.");
- return std::nullopt;
+HalClient *HalClientManager::getClientByField(
+ const std::function<bool(const HalClient &client)> &fieldMatcher) {
+ for (HalClient &client : mClients) {
+ if (fieldMatcher(client)) {
+ return &client;
+ }
+ }
+ return nullptr;
+}
+
+HalClient *HalClientManager::getClientByClientIdLocked(HalClientId clientId) {
+ return getClientByField([&clientId](const HalClient &client) {
+ return client.clientId == clientId;
+ });
+}
+
+HalClient *HalClientManager::getClientByUuidLocked(const std::string &uuid) {
+ return getClientByField(
+ [&uuid](const HalClient &client) { return client.uuid == uuid; });
+}
+
+HalClient *HalClientManager::getClientByProcessIdLocked(pid_t pid) {
+ return getClientByField(
+ [&pid](const HalClient &client) { return client.pid == pid; });
+}
+
+bool HalClientManager::updateNextClientIdLocked() {
+ std::unordered_set<HalClientId> usedClientIds{};
+ for (const HalClient &client : mClients) {
+ usedClientIds.insert(client.clientId);
+ }
+ for (int i = 0; i < kMaxNumOfHalClients; i++) {
+ mNextClientId = (mNextClientId + 1) % kMaxHalClientId;
+ if (mNextClientId != ::chre::kHostClientIdUnspecified &&
+ mReservedClientIds.find(mNextClientId) == mReservedClientIds.end() &&
+ usedClientIds.find(mNextClientId) == usedClientIds.end()) {
+ // Found a client id that is not reserved nor used.
+ return true;
+ }
+ }
+ LOGE("Unable to find the next available client id");
+ mNextClientId = ::chre::kHostClientIdUnspecified;
+ return false;
+}
+
+bool HalClientManager::createClientLocked(
+ const std::string &uuid, pid_t pid,
+ const std::shared_ptr<IContextHubCallback> &callback,
+ void *deathRecipientCookie) {
+ if (mClients.size() > kMaxNumOfHalClients ||
+ mNextClientId == ::chre::kHostClientIdUnspecified) {
+ LOGE("Too many HAL clients (%zu) registered which should never happen.",
+ mClients.size());
+ return false;
}
- if (mProcessNamesToClientIds.find(processName) !=
- mProcessNamesToClientIds.end()) {
- return mProcessNamesToClientIds[processName];
+ std::string name{"undefined"};
+ if (isCallbackV3Enabled(callback)) {
+ name = getName(callback);
}
+ mClients.emplace_back(uuid, name, mNextClientId, pid, callback,
+ deathRecipientCookie);
// Update the json list with the new mapping
- mProcessNamesToClientIds.emplace(processName, mNextClientId);
Json::Value mappings;
- for (const auto &[name, clientId] : mProcessNamesToClientIds) {
+ for (const auto &client : mClients) {
Json::Value mapping;
- mapping[kJsonProcessName] = name;
- mapping[kJsonClientId] = clientId;
+ mapping[kJsonUuid] = client.uuid;
+ mapping[kJsonName] = client.name;
+ mapping[kJsonClientId] = client.clientId;
mappings.append(mapping);
}
// write to the file; Create the file if it doesn't exist
Json::StreamWriterBuilder factory;
std::unique_ptr<Json::StreamWriter> const writer(factory.newStreamWriter());
- std::ofstream fileStream(kClientMappingFilePath);
+ std::ofstream fileStream(mClientMappingFilePath);
writer->write(mappings, &fileStream);
fileStream << std::endl;
- return {mNextClientId++};
+ updateNextClientIdLocked();
+ return true;
}
-HalClientId HalClientManager::getClientId() {
- pid_t pid = AIBinder_getCallingPid();
+HalClientId HalClientManager::getClientId(pid_t pid) {
const std::lock_guard<std::mutex> lock(mLock);
- if (isKnownPIdLocked(pid)) {
- return mPIdsToClientIds[pid];
+ const HalClient *client = getClientByProcessIdLocked(pid);
+ if (client == nullptr) {
+ LOGE("Failed to find the client id for pid %d", pid);
+ return ::chre::kHostClientIdUnspecified;
}
- LOGE("Failed to find the client id for pid %d", pid);
- return kDefaultHalClientId;
+ return client->clientId;
}
std::shared_ptr<IContextHubCallback> HalClientManager::getCallback(
HalClientId clientId) {
const std::lock_guard<std::mutex> lock(mLock);
- if (isAllocatedClientIdLocked(clientId)) {
- return mClientIdsToClientInfo.at(clientId).callback;
+ const HalClient *client = getClientByClientIdLocked(clientId);
+ if (client == nullptr) {
+ LOGE("Failed to find the callback for the client id %" PRIu16, clientId);
+ return nullptr;
}
- LOGE("Failed to find the callback for the client id %" PRIu16, clientId);
- return nullptr;
+ return client->callback;
}
bool HalClientManager::registerCallback(
- const std::shared_ptr<IContextHubCallback> &callback,
- const ndk::ScopedAIBinder_DeathRecipient &deathRecipient,
+ pid_t pid, const std::shared_ptr<IContextHubCallback> &callback,
void *deathRecipientCookie) {
- pid_t pid = AIBinder_getCallingPid();
const std::lock_guard<std::mutex> lock(mLock);
- if (AIBinder_linkToDeath(callback->asBinder().get(), deathRecipient.get(),
- deathRecipientCookie) != STATUS_OK) {
- LOGE("Failed to link client binder to death recipient.");
- return false;
- }
- if (isKnownPIdLocked(pid)) {
+ HalClient *client = getClientByProcessIdLocked(pid);
+ if (client != nullptr) {
LOGW("The pid %d has already registered. Overriding its callback.", pid);
- return overrideCallbackLocked(pid, callback, deathRecipient,
- deathRecipientCookie);
- }
- std::string processName = getProcessName(pid);
- std::optional<HalClientId> clientIdOptional =
- createClientIdLocked(processName);
- if (clientIdOptional == std::nullopt) {
- LOGE("Failed to generate a valid client id for process %s",
- processName.c_str());
- return false;
- }
- HalClientId clientId = clientIdOptional.value();
- if (mClientIdsToClientInfo.find(clientId) != mClientIdsToClientInfo.end()) {
- LOGE("Process %s already has a connection to HAL.", processName.c_str());
- return false;
+ if (!mDeadClientUnlinker(client->callback, client->deathRecipientCookie)) {
+ LOGE("Unable to unlink the old callback for pid %d", pid);
+ return false;
+ }
+ client->callback.reset();
+ client->callback = callback;
+ client->deathRecipientCookie = deathRecipientCookie;
+ return true;
}
- mPIdsToClientIds[pid] = clientId;
- mClientIdsToClientInfo.emplace(clientId,
- HalClientInfo(callback, deathRecipientCookie));
- if (mFrameworkServiceClientId == kDefaultHalClientId &&
- processName == kSystemServerName) {
- mFrameworkServiceClientId = clientId;
+
+ std::string uuid;
+ if (isCallbackV3Enabled(callback)) {
+ uuid = getUuid(callback);
+ } else {
+ uuid = getUuidLocked();
}
- return true;
-}
-bool HalClientManager::overrideCallbackLocked(
- pid_t pid, const std::shared_ptr<IContextHubCallback> &callback,
- const ndk::ScopedAIBinder_DeathRecipient &deathRecipient,
- void *deathRecipientCookie) {
- LOGI("Overriding the callback for pid %d", pid);
- HalClientInfo &clientInfo =
- mClientIdsToClientInfo.at(mPIdsToClientIds.at(pid));
- if (AIBinder_unlinkToDeath(clientInfo.callback->asBinder().get(),
- deathRecipient.get(),
- clientInfo.deathRecipientCookie) != STATUS_OK) {
- LOGE("Unable to unlink the old callback for pid %d", pid);
- return false;
+ client = getClientByUuidLocked(uuid);
+ if (client != nullptr) {
+ if (client->pid != HalClient::PID_UNSET) {
+ // A client is trying to connect to HAL from a different process. But the
+ // previous connection is still active because otherwise the pid will be
+ // cleared in handleClientDeath().
+ LOGE("Client (uuid=%s) already has a connection to HAL.", uuid.c_str());
+ return false;
+ }
+ // For a known client the previous assigned clientId will be reused.
+ client->reset(/* processId= */ pid,
+ /* contextHubCallback= */ callback,
+ /* cookie= */ deathRecipientCookie);
+ return true;
}
- clientInfo.callback.reset();
- clientInfo.callback = callback;
- clientInfo.deathRecipientCookie = deathRecipientCookie;
- return true;
+ return createClientLocked(uuid, pid, callback, deathRecipientCookie);
}
-void HalClientManager::handleClientDeath(
- pid_t pid, const ndk::ScopedAIBinder_DeathRecipient &deathRecipient) {
+void HalClientManager::handleClientDeath(pid_t pid) {
const std::lock_guard<std::mutex> lock(mLock);
- if (!isKnownPIdLocked(pid)) {
+ HalClient *client = getClientByProcessIdLocked(pid);
+ if (client == nullptr) {
LOGE("Failed to locate the dead pid %d", pid);
return;
}
- HalClientId clientId = mPIdsToClientIds[pid];
- mPIdsToClientIds.erase(mPIdsToClientIds.find(pid));
- if (!isAllocatedClientIdLocked(clientId)) {
- LOGE("Failed to locate the dead client id %" PRIu16, clientId);
- return;
- }
- for (const auto &[procName, id] : mProcessNamesToClientIds) {
- if (id == clientId && procName == kSystemServerName) {
- LOGE("System server is disconnected");
- mIsFirstClient = true;
- }
- }
-
- HalClientInfo &clientInfo = mClientIdsToClientInfo.at(clientId);
- if (AIBinder_unlinkToDeath(clientInfo.callback->asBinder().get(),
- deathRecipient.get(),
- clientInfo.deathRecipientCookie) != STATUS_OK) {
+ if (!mDeadClientUnlinker(client->callback, client->deathRecipientCookie)) {
LOGE("Unable to unlink the old callback for pid %d in death handler", pid);
}
- clientInfo.callback.reset();
+ client->reset(/* processId= */ HalClient::PID_UNSET,
+ /* contextHubCallback= */ nullptr, /* cookie= */ nullptr);
+
if (mPendingLoadTransaction.has_value() &&
- mPendingLoadTransaction->clientId == clientId) {
+ mPendingLoadTransaction->clientId == client->clientId) {
mPendingLoadTransaction.reset();
}
if (mPendingUnloadTransaction.has_value() &&
- mPendingUnloadTransaction->clientId == clientId) {
+ mPendingUnloadTransaction->clientId == client->clientId) {
mPendingLoadTransaction.reset();
}
- mClientIdsToClientInfo.erase(clientId);
- if (mFrameworkServiceClientId == clientId) {
- mFrameworkServiceClientId = kDefaultHalClientId;
- }
LOGI("Process %" PRIu32 " is disconnected from HAL.", pid);
}
bool HalClientManager::registerPendingLoadTransaction(
- std::unique_ptr<chre::FragmentedLoadTransaction> transaction) {
+ pid_t pid, std::unique_ptr<chre::FragmentedLoadTransaction> transaction) {
if (transaction->isComplete()) {
LOGW("No need to register a completed load transaction.");
return false;
}
- pid_t pid = AIBinder_getCallingPid();
const std::lock_guard<std::mutex> lock(mLock);
- if (!isKnownPIdLocked(pid)) {
+ const HalClient *client = getClientByProcessIdLocked(pid);
+ if (client == nullptr) {
LOGE("Unknown HAL client when registering its pending load transaction.");
return false;
}
- auto clientId = mPIdsToClientIds[pid];
- if (!isNewTransactionAllowedLocked(clientId)) {
+ if (!isNewTransactionAllowedLocked(client->clientId)) {
return false;
}
mPendingLoadTransaction.emplace(
- clientId, /* registeredTimeMs= */ android::elapsedRealtime(),
+ client->clientId, /* registeredTimeMs= */ android::elapsedRealtime(),
/* currentFragmentId= */ 0, std::move(transaction));
return true;
}
@@ -228,19 +277,18 @@ HalClientManager::getNextFragmentedLoadRequest() {
}
bool HalClientManager::registerPendingUnloadTransaction(
- uint32_t transactionId) {
- pid_t pid = AIBinder_getCallingPid();
+ pid_t pid, uint32_t transactionId) {
const std::lock_guard<std::mutex> lock(mLock);
- if (!isKnownPIdLocked(pid)) {
+ const HalClient *client = getClientByProcessIdLocked(pid);
+ if (client == nullptr) {
LOGE("Unknown HAL client when registering its pending unload transaction.");
return false;
}
- auto clientId = mPIdsToClientIds[pid];
- if (!isNewTransactionAllowedLocked(clientId)) {
+ if (!isNewTransactionAllowedLocked(client->clientId)) {
return false;
}
mPendingUnloadTransaction.emplace(
- clientId, transactionId,
+ client->clientId, transactionId,
/* registeredTimeMs= */ android::elapsedRealtime());
return true;
}
@@ -293,79 +341,94 @@ bool HalClientManager::isNewTransactionAllowedLocked(HalClientId clientId) {
return true;
}
-bool HalClientManager::registerEndpointId(const HostEndpointId &endpointId) {
- pid_t pid = AIBinder_getCallingPid();
+bool HalClientManager::registerEndpointId(pid_t pid,
+ const HostEndpointId &endpointId) {
const std::lock_guard<std::mutex> lock(mLock);
- if (!isKnownPIdLocked(pid)) {
+ HalClient *client = getClientByProcessIdLocked(pid);
+ if (client == nullptr) {
LOGE(
"Unknown HAL client (pid %d). Register the callback before registering "
"an endpoint.",
pid);
return false;
}
- HalClientId clientId = mPIdsToClientIds[pid];
- if (!isValidEndpointId(clientId, endpointId)) {
+ if (!isValidEndpointId(client, endpointId)) {
LOGE("Endpoint id %" PRIu16 " from process %d is out of range.", endpointId,
pid);
return false;
}
- if (mClientIdsToClientInfo[clientId].endpointIds.find(endpointId) !=
- mClientIdsToClientInfo[clientId].endpointIds.end()) {
+ if (client->endpointIds.find(endpointId) != client->endpointIds.end()) {
LOGW("The endpoint %" PRIu16 " is already connected.", endpointId);
return false;
}
- mClientIdsToClientInfo[clientId].endpointIds.insert(endpointId);
+ client->endpointIds.insert(endpointId);
LOGI("Endpoint id %" PRIu16 " is connected to client %" PRIu16, endpointId,
- clientId);
+ client->clientId);
return true;
}
-bool HalClientManager::removeEndpointId(const HostEndpointId &endpointId) {
- pid_t pid = AIBinder_getCallingPid();
+bool HalClientManager::removeEndpointId(pid_t pid,
+ const HostEndpointId &endpointId) {
const std::lock_guard<std::mutex> lock(mLock);
- if (!isKnownPIdLocked(pid)) {
+ HalClient *client = getClientByProcessIdLocked(pid);
+ if (client == nullptr) {
LOGE(
"Unknown HAL client (pid %d). A callback should have been registered "
"before removing an endpoint.",
pid);
return false;
}
- HalClientId clientId = mPIdsToClientIds[pid];
- if (!isValidEndpointId(clientId, endpointId)) {
+ if (!isValidEndpointId(client, endpointId)) {
LOGE("Endpoint id %" PRIu16 " from process %d is out of range.", endpointId,
pid);
return false;
}
- if (mClientIdsToClientInfo[clientId].endpointIds.find(endpointId) ==
- mClientIdsToClientInfo[clientId].endpointIds.end()) {
+ if (client->endpointIds.find(endpointId) == client->endpointIds.end()) {
LOGW("The endpoint %" PRIu16 " is not connected.", endpointId);
return false;
}
- mClientIdsToClientInfo[clientId].endpointIds.erase(endpointId);
+ client->endpointIds.erase(endpointId);
LOGI("Endpoint id %" PRIu16 " is removed from client %" PRIu16, endpointId,
- clientId);
+ client->clientId);
return true;
}
std::shared_ptr<IContextHubCallback> HalClientManager::getCallbackForEndpoint(
- const HostEndpointId &endpointId) {
+ const HostEndpointId mutatedEndpointId) {
const std::lock_guard<std::mutex> lock(mLock);
- HalClientId clientId = getClientIdFromEndpointId(endpointId);
- if (!isAllocatedClientIdLocked(clientId)) {
+ HalClient *client;
+ if (mutatedEndpointId & kVendorEndpointIdBitMask) {
+ HalClientId clientId =
+ mutatedEndpointId >> kNumOfBitsForEndpointId & kMaxHalClientId;
+ client = getClientByClientIdLocked(clientId);
+ } else {
+ client = getClientByUuidLocked(kSystemServerUuid);
+ }
+
+ HostEndpointId originalEndpointId =
+ convertToOriginalEndpointId(mutatedEndpointId);
+ if (client == nullptr) {
LOGE("Unknown endpoint id %" PRIu16 ". Please register the callback first.",
- endpointId);
+ originalEndpointId);
return nullptr;
}
- return mClientIdsToClientInfo[clientId].callback;
+ if (client->endpointIds.find(originalEndpointId) ==
+ client->endpointIds.end()) {
+ LOGW(
+ "Received a message from CHRE for an unknown or disconnected endpoint "
+ "id %" PRIu16,
+ originalEndpointId);
+ }
+ return client->callback;
}
void HalClientManager::sendMessageForAllCallbacks(
const ContextHubMessage &message,
const std::vector<std::string> &messageParams) {
const std::lock_guard<std::mutex> lock(mLock);
- for (const auto &[_, clientInfo] : mClientIdsToClientInfo) {
- if (clientInfo.callback != nullptr) {
- clientInfo.callback->handleContextHubMessage(message, messageParams);
+ for (const auto &client : mClients) {
+ if (client.callback != nullptr) {
+ client.callback->handleContextHubMessage(message, messageParams);
}
}
}
@@ -373,30 +436,26 @@ void HalClientManager::sendMessageForAllCallbacks(
const std::unordered_set<HostEndpointId>
*HalClientManager::getAllConnectedEndpoints(pid_t pid) {
const std::lock_guard<std::mutex> lock(mLock);
- if (!isKnownPIdLocked(pid)) {
+ const HalClient *client = getClientByProcessIdLocked(pid);
+ if (client == nullptr) {
LOGE("Unknown HAL client with pid %d", pid);
return nullptr;
}
- HalClientId clientId = mPIdsToClientIds[pid];
- if (mClientIdsToClientInfo.find(clientId) == mClientIdsToClientInfo.end()) {
- LOGE("Can't find any information for client id %" PRIu16, clientId);
- return nullptr;
- }
- return &mClientIdsToClientInfo[clientId].endpointIds;
+ return &(client->endpointIds);
}
bool HalClientManager::mutateEndpointIdFromHostIfNeeded(
- const pid_t &pid, HostEndpointId &endpointId) {
+ pid_t pid, HostEndpointId &endpointId) {
const std::lock_guard<std::mutex> lock(mLock);
- if (!isKnownPIdLocked(pid)) {
+ const HalClient *client = getClientByProcessIdLocked(pid);
+ if (client == nullptr) {
LOGE("Unknown HAL client with pid %d", pid);
return false;
}
// no need to mutate client id for framework service
- if (mPIdsToClientIds[pid] != mFrameworkServiceClientId) {
- HalClientId clientId = mPIdsToClientIds[pid];
+ if (client->uuid != kSystemServerUuid) {
endpointId = kVendorEndpointIdBitMask |
- clientId << kNumOfBitsForEndpointId | endpointId;
+ client->clientId << kNumOfBitsForEndpointId | endpointId;
}
return true;
}
@@ -409,31 +468,35 @@ HostEndpointId HalClientManager::convertToOriginalEndpointId(
return endpointId;
}
-HalClientManager::HalClientManager() {
+HalClientManager::HalClientManager(
+ DeadClientUnlinker deadClientUnlinker,
+ const std::string &clientIdMappingFilePath,
+ const std::unordered_set<HalClientId> &reservedClientIds) {
+ mDeadClientUnlinker = std::move(deadClientUnlinker);
+ mClientMappingFilePath = clientIdMappingFilePath;
+ mReservedClientIds = reservedClientIds;
// Parses the file to construct a mapping from process names to client ids.
Json::Value mappings;
- if (!getClientMappingsFromFile(kClientMappingFilePath, mappings)) {
+ if (!getClientMappingsFromFile(mClientMappingFilePath, mappings)) {
// TODO(b/247124878): When the device was firstly booted up the file doesn't
// exist which is expected. Consider to create a default file to avoid
// confusions.
- LOGW("Unable to find and read %s.", kClientMappingFilePath);
- return;
- }
- for (int i = 0; i < mappings.size(); i++) {
- Json::Value mapping = mappings[i];
- if (!mapping.isMember(kJsonClientId) ||
- !mapping.isMember(kJsonProcessName)) {
- LOGE("Unable to find expected key name for the entry %d", i);
- continue;
- }
- std::string processName = mapping[kJsonProcessName].asString();
- auto clientId = static_cast<HalClientId>(mapping[kJsonClientId].asUInt());
- mProcessNamesToClientIds[processName] = clientId;
- // mNextClientId should always hold the next available client id
- if (mNextClientId <= clientId) {
- mNextClientId = clientId + 1;
+ LOGW("Unable to find and read %s.", mClientMappingFilePath.c_str());
+ } else {
+ for (int i = 0; i < mappings.size(); i++) {
+ Json::Value mapping = mappings[i];
+ if (!mapping.isMember(kJsonClientId) || !mapping.isMember(kJsonUuid) ||
+ !mapping.isMember(kJsonName)) {
+ LOGE("Unable to find expected key name for the entry %d", i);
+ continue;
+ }
+ std::string uuid = mapping[kJsonUuid].asString();
+ std::string name = mapping[kJsonName].asString();
+ auto clientId = static_cast<HalClientId>(mapping[kJsonClientId].asUInt());
+ mClients.emplace_back(uuid, name, clientId);
}
}
+ updateNextClientIdLocked();
}
bool HalClientManager::isPendingLoadTransactionMatchedLocked(
@@ -490,15 +553,14 @@ void HalClientManager::handleChreRestart() {
const std::lock_guard<std::mutex> lock(mLock);
mPendingLoadTransaction.reset();
mPendingUnloadTransaction.reset();
- for (auto &[_, clientInfo] : mClientIdsToClientInfo) {
- clientInfo.endpointIds.clear();
+ for (HalClient &client : mClients) {
+ client.endpointIds.clear();
}
}
// Incurs callbacks without holding the lock to avoid deadlocks.
- for (auto &[_, clientInfo] : mClientIdsToClientInfo) {
- if (clientInfo.callback != nullptr) {
- clientInfo.callback->handleContextHubAsyncEvent(
- AsyncEventType::RESTARTED);
+ for (const HalClient &client : mClients) {
+ if (client.callback != nullptr) {
+ client.callback->handleContextHubAsyncEvent(AsyncEventType::RESTARTED);
}
}
}
diff --git a/host/hal_generic/common/hal_client_manager.h b/host/hal_generic/common/hal_client_manager.h
index 66ca8594..80f20896 100644
--- a/host/hal_generic/common/hal_client_manager.h
+++ b/host/hal_generic/common/hal_client_manager.h
@@ -16,17 +16,21 @@
#ifndef ANDROID_HARDWARE_CONTEXTHUB_COMMON_HAL_CLIENT_MANAGER_H_
#define ANDROID_HARDWARE_CONTEXTHUB_COMMON_HAL_CLIENT_MANAGER_H_
-#include <aidl/android/hardware/contexthub/ContextHubMessage.h>
-#include <aidl/android/hardware/contexthub/IContextHub.h>
-#include <aidl/android/hardware/contexthub/IContextHubCallback.h>
-#include <chre_host/fragmented_load_transaction.h>
-#include <chre_host/preloaded_nanoapp_loader.h>
+#include "chre/platform/shared/host_protocol_common.h"
+#include "chre_host/fragmented_load_transaction.h"
+#include "chre_host/log.h"
+#include "chre_host/preloaded_nanoapp_loader.h"
+#include "hal_client_id.h"
+
#include <sys/types.h>
#include <cstddef>
#include <unordered_map>
#include <unordered_set>
-#include "chre_host/log.h"
-#include "hal_client_id.h"
+#include <utility>
+
+#include <aidl/android/hardware/contexthub/ContextHubMessage.h>
+#include <aidl/android/hardware/contexthub/IContextHub.h>
+#include <aidl/android/hardware/contexthub/IContextHubCallback.h>
using aidl::android::hardware::contexthub::ContextHubMessage;
using aidl::android::hardware::contexthub::HostEndpointInfo;
@@ -42,16 +46,21 @@ namespace android::hardware::contexthub::common::implementation {
* A HAL client is defined as a user calling the IContextHub API. The main
* purpose of this class are:
* - to assign a unique HalClientId identifying each client;
- * - to maintain a mapping between client ids and HalClientInfos;
- * - to maintain a mapping between client ids and their endpoint ids.
+ * - to maintain a mapping between a HAL client and its states defined in
+ * HalClient;
+ * - to track the ongoing load/unload transactions
*
- * There are two types of ids HalClientManager will track, host endpoint id and
- * client id. A host endpoint id, which is defined at
- * hardware/interfaces/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl,
- * identifies a host app that communicates with a HAL client. A client id
- * identifies a HAL client, which is the layer beneath the host apps, such as
- * ContextHubService. Multiple apps with different host endpoint IDs can have
- * the same client ID.
+ * There are 3 types of ids HalClientManager will track: client uuid, HAL client
+ * id and host endpoint id.
+ * - A uuid uniquely identifies a client when it registers its callback.
+ * After a callback is registered, a HAL client id is created and will be
+ * used to identify the client in the following API calls from/to it
+ * - A client id identifies a HAL client, which is the layer beneath the host
+ * apps, such as ContextHubService. Multiple apps with different host
+ * endpoint IDs can have the same client ID.
+ * - A host endpoint id, which is defined at
+ * hardware/interfaces/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl,
+ * identifies a host app that communicates with a HAL client.
*
* For a host endpoint connected to ContextHubService, its endpoint id is kept
*in the form below during the communication with CHRE.
@@ -77,7 +86,57 @@ namespace android::hardware::contexthub::common::implementation {
*/
class HalClientManager {
public:
- HalClientManager();
+ struct HalClient {
+ static constexpr pid_t PID_UNSET = 0;
+
+ explicit HalClient(const std::string &uuid, const std::string &name,
+ const HalClientId clientId)
+ : HalClient(uuid, name, clientId, /* pid= */ PID_UNSET,
+ /* callback= */ nullptr,
+ /* deathRecipientCookie= */ nullptr) {}
+
+ explicit HalClient(std::string uuid, std::string name,
+ const HalClientId clientId, pid_t pid,
+ const std::shared_ptr<IContextHubCallback> &callback,
+ void *deathRecipientCookie)
+ : uuid{std::move(uuid)},
+ name{std::move(name)},
+ clientId{clientId},
+ pid{pid},
+ callback{callback},
+ deathRecipientCookie{deathRecipientCookie} {}
+
+ /** Resets the client's fields except uuid and clientId. */
+ void reset(pid_t processId,
+ const std::shared_ptr<IContextHubCallback> &contextHubCallback,
+ void *cookie) {
+ pid = processId;
+ callback = contextHubCallback;
+ deathRecipientCookie = cookie;
+ endpointIds.clear();
+ }
+
+ const std::string uuid;
+ std::string name;
+ const HalClientId clientId;
+ pid_t pid{};
+ std::shared_ptr<IContextHubCallback> callback{};
+ // cookie is used by the death recipient's linked callback
+ void *deathRecipientCookie{};
+ std::unordered_set<HostEndpointId> endpointIds{};
+ };
+
+ // The endpoint id is from a vendor client if the highest bit is set to 1.
+ static constexpr HostEndpointId kVendorEndpointIdBitMask = 0x8000;
+ static constexpr uint8_t kNumOfBitsForEndpointId = 6;
+
+ using DeadClientUnlinker = std::function<bool(
+ const std::shared_ptr<IContextHubCallback> &callback, void *cookie)>;
+
+ explicit HalClientManager(
+ DeadClientUnlinker deadClientUnlinker,
+ const std::string &clientIdMappingFilePath,
+ const std::unordered_set<HalClientId> &reservedClientIds = {});
virtual ~HalClientManager() = default;
/** Disable copy constructor and copy assignment to avoid duplicates. */
@@ -87,14 +146,16 @@ class HalClientManager {
/**
* Gets the client id allocated to the current HAL client.
*
- * The current HAL client is identified by its process id, which is retrieved
- * by calling AIBinder_getCallingPid(). If the process doesn't have any client
- * id assigned, HalClientManager will create one mapped to its process id.
+ * The current HAL client is identified by its process id. If the process
+ * doesn't have any client id assigned, HalClientManager will create one
+ * mapped to its process id.
+ *
+ * @param pid process id of the current client
*
- * @return client id assigned to the calling process, or kDefaultHalClientId
- * if the process id is not found.
+ * @return client id assigned to the calling process, or
+ * ::chre::kHostClientIdUnspecified if the process id is not found.
*/
- HalClientId getClientId();
+ HalClientId getClientId(pid_t pid);
/**
* Gets the callback for the current HAL client identified by the clientId.
@@ -109,16 +170,15 @@ class HalClientManager {
* client id. @p deathRecipient and @p deathRecipientCookie are used to unlink
* the previous registered callback for the same client, if any.
*
+ * @param pid process id of the current client
* @param callback a function incurred to handle the client death event.
- * @param deathRecipient a handle on the death notification.
* @param deathRecipientCookie the data used by the callback.
*
* @return true if success, otherwise false.
*/
- bool registerCallback(
- const std::shared_ptr<IContextHubCallback> &callback,
- const ndk::ScopedAIBinder_DeathRecipient &deathRecipient,
- void *deathRecipientCookie);
+ bool registerCallback(pid_t pid,
+ const std::shared_ptr<IContextHubCallback> &callback,
+ void *deathRecipientCookie);
/**
* Registers a FragmentedLoadTransaction for the current HAL client.
@@ -126,10 +186,13 @@ class HalClientManager {
* At this moment only one active transaction, either load or unload, is
* supported.
*
+ * @param pid process id of the current client
+ * @param transaction the transaction being registered
+ *
* @return true if success, otherwise false.
*/
bool registerPendingLoadTransaction(
- std::unique_ptr<FragmentedLoadTransaction> transaction);
+ pid_t pid, std::unique_ptr<chre::FragmentedLoadTransaction> transaction);
/**
* Returns true if the load transaction matches the arguments provided.
@@ -166,9 +229,12 @@ class HalClientManager {
* At this moment only one active transaction, either load or unload, is
* supported.
*
+ * @param pid process id of the current client
+ * @param transaction the transaction being registered
+ *
* @return true if success, otherwise false.
*/
- bool registerPendingUnloadTransaction(uint32_t transactionId);
+ bool registerPendingUnloadTransaction(pid_t pid, uint32_t transactionId);
/**
* Clears the pending unload transaction.
@@ -188,31 +254,39 @@ class HalClientManager {
/**
* Registers an endpoint id when it is connected to HAL.
*
+ * @param pid process id of the current HAL client
+ * @param endpointId the endpointId being registered
+ *
* @return true if success, otherwise false.
*/
- bool registerEndpointId(const HostEndpointId &endpointId);
+ bool registerEndpointId(pid_t pid, const HostEndpointId &endpointId);
/**
* Removes an endpoint id when it is disconnected to HAL.
*
+ * @param pid process id of the current HAL client
+ * @param endpointId the endpointId being registered
+ *
* @return true if success, otherwise false.
*/
- bool removeEndpointId(const HostEndpointId &endpointId);
+ bool removeEndpointId(pid_t pid, const HostEndpointId &endpointId);
/**
* Mutates the endpoint id if the hal client is not the framework service.
*
+ * @param pid process id of the current HAL client
+ * @param endpointId the endpointId being registered
+ *
* @return true if success, otherwise false.
*/
- bool mutateEndpointIdFromHostIfNeeded(const pid_t &pid,
- HostEndpointId &endpointId);
+ bool mutateEndpointIdFromHostIfNeeded(pid_t pid, HostEndpointId &endpointId);
/** Returns the original endpoint id sent by the host client. */
static HostEndpointId convertToOriginalEndpointId(
const HostEndpointId &endpointId);
/**
- * Gets all the connected endpoints for the client identified by the pid.
+ * Gets all the connected endpoints for the client identified by the @p pid.
*
* @return the pointer to the endpoint id set if the client is identifiable,
* otherwise nullptr.
@@ -225,45 +299,28 @@ class HalClientManager {
const std::vector<std::string> &messageParams);
std::shared_ptr<IContextHubCallback> getCallbackForEndpoint(
- const HostEndpointId &endpointId);
+ HostEndpointId mutatedEndpointId);
/**
* Handles the client death event.
*
* @param pid of the client that loses the binder connection to the HAL.
- * @param deathRecipient to be unlinked with the client's callback
*/
- void handleClientDeath(
- pid_t pid, const ndk::ScopedAIBinder_DeathRecipient &deathRecipient);
+ void handleClientDeath(pid_t pid);
/** Handles CHRE restart event. */
void handleChreRestart();
protected:
- static constexpr char kSystemServerName[] = "system_server";
- static constexpr char kClientMappingFilePath[] =
- "/data/vendor/chre/chre_hal_clients.json";
+ static constexpr char kSystemServerUuid[] =
+ "9a17008d6bf1445a90116d21bd985b6c";
+ static constexpr char kVendorClientUuid[] = "vendor-client";
static constexpr char kJsonClientId[] = "ClientId";
- static constexpr char kJsonProcessName[] = "ProcessName";
+ static constexpr char kJsonUuid[] = "uuid";
+ static constexpr char kJsonName[] = "name";
static constexpr int64_t kTransactionTimeoutThresholdMs = 5000; // 5 seconds
- static constexpr uint8_t kNumOfBitsForEndpointId = 6;
static constexpr HostEndpointId kMaxVendorEndpointId =
(1 << kNumOfBitsForEndpointId) - 1;
- // The endpoint id is from a vendor client if the highest bit is set to 1.
- static constexpr HostEndpointId kVendorEndpointIdBitMask = 0x8000;
-
- struct HalClientInfo {
- explicit HalClientInfo(const std::shared_ptr<IContextHubCallback> &callback,
- void *cookie) {
- this->callback = callback;
- this->deathRecipientCookie = cookie;
- }
- HalClientInfo() = default;
- std::shared_ptr<IContextHubCallback> callback;
- // cookie is used by the death recipient's linked callback
- void *deathRecipientCookie{};
- std::unordered_set<HostEndpointId> endpointIds{};
- };
struct PendingTransaction {
PendingTransaction(HalClientId clientId, uint32_t transactionId,
@@ -310,10 +367,17 @@ class HalClientManager {
*
* mLock must be held when this function is called.
*
- * @param processName the process name of the client
*/
- virtual std::optional<HalClientId> createClientIdLocked(
- const std::string &processName);
+ bool createClientLocked(const std::string &uuid, pid_t pid,
+ const std::shared_ptr<IContextHubCallback> &callback,
+ void *deathRecipientCookie);
+
+ /**
+ * Update @p mNextClientId to be the next available one.
+ *
+ * @return true if success, otherwise false.
+ */
+ bool updateNextClientIdLocked();
/**
* Returns true if @p clientId and @p transactionId match the
@@ -355,84 +419,48 @@ class HalClientManager {
*/
bool isNewTransactionAllowedLocked(HalClientId clientId);
- /**
- * Returns true if the clientId is being used.
- *
- * mLock must be held when this function is called.
- */
- inline bool isAllocatedClientIdLocked(HalClientId clientId) {
- return mClientIdsToClientInfo.find(clientId) !=
- mClientIdsToClientInfo.end();
+ /** Returns true if the endpoint id is within the accepted range. */
+ [[nodiscard]] static inline bool isValidEndpointId(
+ const HalClient *client, const HostEndpointId &endpointId) {
+ return client->uuid == kSystemServerUuid ||
+ endpointId <= kMaxVendorEndpointId;
}
- /**
- * Returns true if the pid is being used to identify a client.
- *
- * mLock must be held when this function is called.
- */
- inline bool isKnownPIdLocked(pid_t pid) {
- return mPIdsToClientIds.find(pid) != mPIdsToClientIds.end();
+ // TODO(b/290375569): isSystemServerConnectedLocked() and getUuidLocked() are
+ // temporary solutions to get a pseudo-uuid. Remove these two functions when
+ // flag context_hub_callback_uuid_enabled is ramped up.
+ inline bool isSystemServerConnectedLocked() {
+ HalClient *client = getClientByUuidLocked(kSystemServerUuid);
+ return client != nullptr && client->pid != 0;
}
-
- /** Returns true if the endpoint id is within the accepted range. */
- [[nodiscard]] inline bool isValidEndpointId(
- const HalClientId &clientId, const HostEndpointId &endpointId) const {
- if (clientId != mFrameworkServiceClientId) {
- return endpointId <= kMaxVendorEndpointId;
- }
- return true;
+ inline std::string getUuidLocked() {
+ return isSystemServerConnectedLocked() ? kVendorClientUuid
+ : kSystemServerUuid;
}
- /**
- * Overrides the old callback registered with the client.
- *
- * @return true if success, otherwise false
- */
- bool overrideCallbackLocked(
- pid_t pid, const std::shared_ptr<IContextHubCallback> &callback,
- const ndk::ScopedAIBinder_DeathRecipient &deathRecipient,
- void *deathRecipientCookie);
+ HalClient *getClientByField(
+ const std::function<bool(const HalClient &client)> &fieldMatcher);
- /**
- * Extracts the client id from the endpoint id.
- *
- * @param endpointId the endpoint id received from CHRE, before any conversion
- */
- [[nodiscard]] inline HalClientId getClientIdFromEndpointId(
- const HostEndpointId &endpointId) const {
- if (endpointId & kVendorEndpointIdBitMask) {
- return endpointId >> kNumOfBitsForEndpointId & kMaxHalClientId;
- }
- return mFrameworkServiceClientId;
- }
+ HalClient *getClientByClientIdLocked(HalClientId clientId);
- std::string getProcessName(pid_t /*pid*/) {
- // TODO(b/274597758): this is a temporary solution that should be updated
- // after b/274597758 is resolved.
- if (mIsFirstClient) {
- mIsFirstClient = false;
- return kSystemServerName;
- }
- return "the_vendor_client";
- }
+ HalClient *getClientByUuidLocked(const std::string &uuid);
+
+ HalClient *getClientByProcessIdLocked(pid_t pid);
- bool mIsFirstClient = true;
+ DeadClientUnlinker mDeadClientUnlinker{};
+
+ std::string mClientMappingFilePath;
// next available client id
- HalClientId mNextClientId = kDefaultHalClientId + 1;
- // framework service client id
- HalClientId mFrameworkServiceClientId = kDefaultHalClientId;
+ HalClientId mNextClientId = ::chre::kHostClientIdUnspecified;
+
+ // reserved client ids that will not be used
+ std::unordered_set<HalClientId> mReservedClientIds;
// The lock guarding the access to clients' states and pending transactions
std::mutex mLock;
- // Map from process name to client id which stays consistent with the file
- // stored at kClientMappingFilePath
- std::unordered_map<std::string, HalClientId> mProcessNamesToClientIds{};
- // Map from pids to client ids
- std::unordered_map<pid_t, HalClientId> mPIdsToClientIds{};
- // Map from client ids to ClientInfos
- std::unordered_map<HalClientId, HalClientInfo> mClientIdsToClientInfo{};
+ std::vector<HalClient> mClients;
// States tracking pending transactions
std::optional<PendingLoadTransaction> mPendingLoadTransaction = std::nullopt;
diff --git a/host/hal_generic/common/hal_error.h b/host/hal_generic/common/hal_error.h
new file mode 100644
index 00000000..8dc437a9
--- /dev/null
+++ b/host/hal_generic/common/hal_error.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHRE_HOST_HAL_ERROR_H_
+#define CHRE_HOST_HAL_ERROR_H_
+
+#include <cinttypes>
+
+namespace android::chre {
+
+enum class HalError {
+ SUCCESS = 0,
+
+ // Hal service errors
+ OPERATION_FAILED = -1,
+ INVALID_RESULT = -2,
+ INVALID_ARGUMENT = -3,
+
+ // Hal client errors
+ BINDER_CONNECTION_FAILED = -100,
+ BINDER_DISCONNECTED = -101,
+ NULL_CONTEXT_HUB_FROM_BINDER = -102,
+ LINK_DEATH_RECIPIENT_FAILED = -103,
+ CALLBACK_REGISTRATION_FAILED = -104,
+ UNEXPECTED_ENDPOINT_STATE = -105,
+};
+
+} // namespace android::chre
+#endif // CHRE_HOST_HAL_ERROR_H_ \ No newline at end of file
diff --git a/host/hal_generic/common/multi_client_context_hub_base.cc b/host/hal_generic/common/multi_client_context_hub_base.cc
index 950c09fb..0c257c36 100644
--- a/host/hal_generic/common/multi_client_context_hub_base.cc
+++ b/host/hal_generic/common/multi_client_context_hub_base.cc
@@ -15,14 +15,15 @@
*/
#include "multi_client_context_hub_base.h"
+
#include <chre/platform/shared/host_protocol_common.h>
#include <chre_host/generated/host_messages_generated.h>
#include <chre_host/log.h>
#include "chre/event.h"
#include "chre_host/config_util.h"
-#include "chre_host/file_stream.h"
#include "chre_host/fragmented_load_transaction.h"
#include "chre_host/host_protocol_host.h"
+#include "hal_error.h"
#include "permissions_util.h"
namespace android::hardware::contexthub::common::implementation {
@@ -37,12 +38,8 @@ constexpr uint32_t kDefaultHubId = 0;
// timeout for calling getContextHubs(), which is synchronous
constexpr auto kHubInfoQueryTimeout = std::chrono::seconds(5);
-
-enum class HalErrorCode : int32_t {
- OPERATION_FAILED = -1,
- INVALID_RESULT = -2,
- INVALID_ARGUMENT = -3,
-};
+// timeout for enable/disable test mode, which is synchronous
+constexpr std::chrono::duration ktestModeTimeOut = std::chrono::seconds(5);
bool isValidContextHubId(uint32_t hubId) {
if (hubId != kDefaultHubId) {
@@ -89,16 +86,34 @@ inline constexpr uint16_t extractChrePatchVersion(uint32_t chreVersion) {
}
// functions that help to generate ScopedAStatus from different values.
-inline ScopedAStatus fromServiceError(HalErrorCode errorCode) {
+inline ScopedAStatus fromServiceError(HalError errorCode) {
return ScopedAStatus::fromServiceSpecificError(
static_cast<int32_t>(errorCode));
}
inline ScopedAStatus fromResult(bool result) {
return result ? ScopedAStatus::ok()
- : fromServiceError(HalErrorCode::OPERATION_FAILED);
+ : fromServiceError(HalError::OPERATION_FAILED);
}
} // anonymous namespace
+MultiClientContextHubBase::MultiClientContextHubBase() {
+ mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(onClientDied));
+ AIBinder_DeathRecipient_setOnUnlinked(
+ mDeathRecipient.get(), /*onUnlinked= */ [](void *cookie) {
+ LOGI("Callback is unlinked. Releasing the death recipient cookie.");
+ delete static_cast<HalDeathRecipientCookie *>(cookie);
+ });
+ mDeadClientUnlinker =
+ [&deathRecipient = mDeathRecipient](
+ const std::shared_ptr<IContextHubCallback> &callback,
+ void *deathRecipientCookie) {
+ return AIBinder_unlinkToDeath(callback->asBinder().get(),
+ deathRecipient.get(),
+ deathRecipientCookie) == STATUS_OK;
+ };
+}
+
ScopedAStatus MultiClientContextHubBase::getContextHubs(
std::vector<ContextHubInfo> *contextHubInfos) {
std::unique_lock<std::mutex> lock(mHubInfoMutex);
@@ -108,7 +123,7 @@ ScopedAStatus MultiClientContextHubBase::getContextHubs(
HostProtocolHost::encodeHubInfoRequest(builder);
if (!mConnection->sendMessage(builder)) {
LOGE("Failed to send a message to CHRE to get context hub info.");
- return fromServiceError(HalErrorCode::OPERATION_FAILED);
+ return fromServiceError(HalError::OPERATION_FAILED);
}
mHubInfoCondition.wait_for(lock, kHubInfoQueryTimeout,
[this]() { return mContextHubInfo != nullptr; });
@@ -119,7 +134,7 @@ ScopedAStatus MultiClientContextHubBase::getContextHubs(
}
LOGE("Unable to get a valid context hub info for PID %d",
AIBinder_getCallingPid());
- return fromServiceError(HalErrorCode::INVALID_RESULT);
+ return fromServiceError(HalError::INVALID_RESULT);
}
ScopedAStatus MultiClientContextHubBase::loadNanoapp(
@@ -135,20 +150,25 @@ ScopedAStatus MultiClientContextHubBase::loadNanoapp(
transactionId, appBinary.nanoappId, appBinary.nanoappVersion,
appBinary.flags, targetApiVersion, appBinary.customBinary,
mConnection->getLoadFragmentSizeBytes());
+ pid_t pid = AIBinder_getCallingPid();
if (!mHalClientManager->registerPendingLoadTransaction(
- std::move(transaction))) {
+ pid, std::move(transaction))) {
return fromResult(false);
}
- auto clientId = mHalClientManager->getClientId();
+ auto clientId = mHalClientManager->getClientId(pid);
auto request = mHalClientManager->getNextFragmentedLoadRequest();
if (request.has_value() &&
sendFragmentedLoadRequest(clientId, request.value())) {
+ mEventLogger.logNanoappLoad(appBinary, /* success= */ true);
return ScopedAStatus::ok();
}
LOGE("Failed to send the first load request for nanoapp 0x%" PRIx64,
appBinary.nanoappId);
mHalClientManager->resetPendingLoadTransaction();
+ // TODO(b/284481035): The result should be logged after the async response is
+ // received.
+ mEventLogger.logNanoappLoad(appBinary, /* success= */ false);
return fromResult(false);
}
@@ -168,10 +188,12 @@ ScopedAStatus MultiClientContextHubBase::unloadNanoapp(int32_t contextHubId,
if (!isValidContextHubId(contextHubId)) {
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- if (!mHalClientManager->registerPendingUnloadTransaction(transactionId)) {
+ pid_t pid = AIBinder_getCallingPid();
+ if (!mHalClientManager->registerPendingUnloadTransaction(pid,
+ transactionId)) {
return fromResult(false);
}
- HalClientId clientId = mHalClientManager->getClientId();
+ HalClientId clientId = mHalClientManager->getClientId(pid);
flatbuffers::FlatBufferBuilder builder(64);
HostProtocolHost::encodeUnloadNanoappRequest(
builder, transactionId, appId, /* allowSystemNanoappUnload= */ false);
@@ -182,6 +204,9 @@ ScopedAStatus MultiClientContextHubBase::unloadNanoapp(int32_t contextHubId,
if (!result) {
mHalClientManager->resetPendingUnloadTransaction(clientId, transactionId);
}
+ // TODO(b/284481035): The result should be logged after the async response is
+ // received.
+ mEventLogger.logNanoappUnload(appId, result);
return fromResult(result);
}
@@ -255,9 +280,9 @@ ScopedAStatus MultiClientContextHubBase::queryNanoapps(int32_t contextHubId) {
}
flatbuffers::FlatBufferBuilder builder(64);
HostProtocolHost::encodeNanoappListRequest(builder);
- HostProtocolHost::mutateHostClientId(builder.GetBufferPointer(),
- builder.GetSize(),
- mHalClientManager->getClientId());
+ HostProtocolHost::mutateHostClientId(
+ builder.GetBufferPointer(), builder.GetSize(),
+ mHalClientManager->getClientId(AIBinder_getCallingPid()));
return fromResult(mConnection->sendMessage(builder));
}
@@ -291,14 +316,20 @@ ScopedAStatus MultiClientContextHubBase::registerCallback(
LOGE("Callback of context hub HAL must not be null");
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- // If everything is successful cookie will be released by the callback of
- // binder unlinking (callback overridden).
- auto *cookie = new HalDeathRecipientCookie(this, AIBinder_getCallingPid());
- if (!mHalClientManager->registerCallback(callback, mDeathRecipient, cookie)) {
- LOGE("Unable to register the callback");
+ pid_t pid = AIBinder_getCallingPid();
+ auto *cookie = new HalDeathRecipientCookie(this, pid);
+ if (AIBinder_linkToDeath(callback->asBinder().get(), mDeathRecipient.get(),
+ cookie) != STATUS_OK) {
+ LOGE("Failed to link a client binder (pid=%d) to the death recipient", pid);
delete cookie;
return fromResult(false);
}
+ // If AIBinder_linkToDeath is successful the cookie will be released by the
+ // callback of binder unlinking (callback overridden).
+ if (!mHalClientManager->registerCallback(pid, callback, cookie)) {
+ LOGE("Unable to register a client (pid=%d) callback", pid);
+ return fromResult(false);
+ }
return ScopedAStatus::ok();
}
@@ -316,7 +347,9 @@ ScopedAStatus MultiClientContextHubBase::sendMessageToHub(
HostProtocolHost::encodeNanoappMessage(
builder, message.nanoappId, message.messageType, hostEndpointId,
message.messageBody.data(), message.messageBody.size());
- return fromResult(mConnection->sendMessage(builder));
+ bool success = mConnection->sendMessage(builder);
+ mEventLogger.logMessageToNanoapp(message, success);
+ return fromResult(success);
}
ScopedAStatus MultiClientContextHubBase::onHostEndpointConnected(
@@ -334,14 +367,14 @@ ScopedAStatus MultiClientContextHubBase::onHostEndpointConnected(
break;
default:
LOGE("Unsupported host endpoint type %" PRIu32, info.type);
- return fromServiceError(HalErrorCode::INVALID_ARGUMENT);
+ return fromServiceError(HalError::INVALID_ARGUMENT);
}
uint16_t endpointId = info.hostEndpointId;
- if (!mHalClientManager->registerEndpointId(info.hostEndpointId) ||
- !mHalClientManager->mutateEndpointIdFromHostIfNeeded(
- AIBinder_getCallingPid(), endpointId)) {
- return fromServiceError(HalErrorCode::INVALID_ARGUMENT);
+ pid_t pid = AIBinder_getCallingPid();
+ if (!mHalClientManager->registerEndpointId(pid, info.hostEndpointId) ||
+ !mHalClientManager->mutateEndpointIdFromHostIfNeeded(pid, endpointId)) {
+ return fromServiceError(HalError::INVALID_ARGUMENT);
}
flatbuffers::FlatBufferBuilder builder(64);
HostProtocolHost::encodeHostEndpointConnected(
@@ -353,10 +386,11 @@ ScopedAStatus MultiClientContextHubBase::onHostEndpointConnected(
ScopedAStatus MultiClientContextHubBase::onHostEndpointDisconnected(
char16_t in_hostEndpointId) {
HostEndpointId hostEndpointId = in_hostEndpointId;
+ pid_t pid = AIBinder_getCallingPid();
bool isSuccessful = false;
- if (mHalClientManager->removeEndpointId(hostEndpointId) &&
- mHalClientManager->mutateEndpointIdFromHostIfNeeded(
- AIBinder_getCallingPid(), hostEndpointId)) {
+ if (mHalClientManager->removeEndpointId(pid, hostEndpointId) &&
+ mHalClientManager->mutateEndpointIdFromHostIfNeeded(pid,
+ hostEndpointId)) {
flatbuffers::FlatBufferBuilder builder(64);
HostProtocolHost::encodeHostEndpointDisconnected(builder, hostEndpointId);
isSuccessful = mConnection->sendMessage(builder);
@@ -373,9 +407,65 @@ ScopedAStatus MultiClientContextHubBase::onNanSessionStateChanged(
return ndk::ScopedAStatus::ok();
}
-ScopedAStatus MultiClientContextHubBase::setTestMode(bool /*enable*/) {
- // To be implemented.
- return ScopedAStatus::ok();
+ScopedAStatus MultiClientContextHubBase::setTestMode(bool enable) {
+ return fromResult(enable ? enableTestMode() : disableTestMode());
+}
+
+ScopedAStatus MultiClientContextHubBase::sendMessageDeliveryStatusToHub(
+ int32_t /* contextHubId */,
+ const MessageDeliveryStatus & /* messageDeliveryStatus */) {
+ // TODO(b/312417087): Implement reliable message support - transaction status
+ return ndk::ScopedAStatus::ok();
+}
+
+bool MultiClientContextHubBase::enableTestMode() {
+ std::unique_lock<std::mutex> lock(mTestModeMutex);
+ if (mIsTestModeEnabled) {
+ return true;
+ }
+ mTestModeNanoapps.reset();
+ if (!queryNanoapps(kDefaultHubId).isOk()) {
+ LOGE("Failed to get a list of loaded nanoapps.");
+ mTestModeNanoapps.emplace();
+ return false;
+ }
+ mEnableTestModeCv.wait_for(lock, ktestModeTimeOut,
+ [&]() { return mTestModeNanoapps.has_value(); });
+ for (const auto &appId : *mTestModeNanoapps) {
+ if (!unloadNanoapp(kDefaultHubId, appId, mTestModeTransactionId).isOk()) {
+ LOGE("Failed to unload nanoapp 0x%" PRIx64 " to enable the test mode.",
+ appId);
+ return false;
+ }
+ mTestModeSyncUnloadResult.reset();
+ mEnableTestModeCv.wait_for(lock, ktestModeTimeOut, [&]() {
+ return mTestModeSyncUnloadResult.has_value();
+ });
+ if (!*mTestModeSyncUnloadResult) {
+ LOGE("Failed to unload nanoapp 0x%" PRIx64 " to enable the test mode.",
+ appId);
+ return false;
+ }
+ }
+ mIsTestModeEnabled = true;
+ return true;
+}
+
+bool MultiClientContextHubBase::disableTestMode() {
+ std::unique_lock<std::mutex> lock(mTestModeMutex);
+ if (!mIsTestModeEnabled) {
+ return true;
+ }
+ if (mTestModeNanoapps.has_value() && !mTestModeNanoapps->empty()) {
+ if (!mPreloadedNanoappLoader->loadPreloadedNanoapps(*mTestModeNanoapps)) {
+ LOGE("Failed to reload the nanoapps to disable the test mode.");
+ return false;
+ }
+ }
+ mTestModeNanoapps.emplace();
+ mTestModeTransactionId = static_cast<int32_t>(kDefaultTestModeTransactionId);
+ mIsTestModeEnabled = false;
+ return true;
}
void MultiClientContextHubBase::handleMessageFromChre(
@@ -402,6 +492,14 @@ void MultiClientContextHubBase::handleMessageFromChre(
onNanoappLoadResponse(*message.AsLoadNanoappResponse(), clientId);
break;
}
+ case fbs::ChreMessage::TimeSyncRequest: {
+ if (mConnection->isTimeSyncNeeded()) {
+ TimeSyncer::sendTimeSync(mConnection.get());
+ } else {
+ LOGW("Received an unexpected time sync request from CHRE.");
+ }
+ break;
+ }
case fbs::ChreMessage::UnloadNanoappResponse: {
onNanoappUnloadResponse(*message.AsUnloadNanoappResponse(), clientId);
break;
@@ -410,6 +508,14 @@ void MultiClientContextHubBase::handleMessageFromChre(
onNanoappMessage(*message.AsNanoappMessage());
break;
}
+ case fbs::ChreMessage::DebugDumpData: {
+ onDebugDumpData(*message.AsDebugDumpData());
+ break;
+ }
+ case fbs::ChreMessage::DebugDumpResponse: {
+ onDebugDumpComplete(*message.AsDebugDumpResponse());
+ break;
+ }
default:
LOGW("Got unexpected message type %" PRIu8,
static_cast<uint8_t>(message.type));
@@ -432,9 +538,32 @@ void MultiClientContextHubBase::handleHubInfoResponse(
mContextHubInfo->chreApiMinorVersion = extractChreApiMinorVersion(version);
mContextHubInfo->chrePatchVersion = extractChrePatchVersion(version);
mContextHubInfo->supportedPermissions = kSupportedPermissions;
+
+ // TODO(b/312417087): Implement reliable message support
+ mContextHubInfo->supportsReliableMessages = false;
mHubInfoCondition.notify_all();
}
+void MultiClientContextHubBase::onDebugDumpData(
+ const ::chre::fbs::DebugDumpDataT &data) {
+ auto str = std::string(reinterpret_cast<const char *>(data.debug_str.data()),
+ data.debug_str.size());
+ debugDumpAppend(str);
+}
+
+void MultiClientContextHubBase::onDebugDumpComplete(
+ const ::chre::fbs::DebugDumpResponseT &response) {
+ if (!response.success) {
+ LOGE("Dumping debug information fails");
+ }
+ if (checkDebugFd()) {
+ const std::string &dump = mEventLogger.dump();
+ writeToDebugFile(dump.c_str());
+ writeToDebugFile("\n-- End of CHRE/ASH debug info --\n");
+ }
+ debugDumpComplete();
+}
+
void MultiClientContextHubBase::onNanoappListResponse(
const fbs::NanoappListResponseT &response, HalClientId clientId) {
std::shared_ptr<IContextHubCallback> callback =
@@ -463,6 +592,17 @@ void MultiClientContextHubBase::onNanoappListResponse(
appInfo.rpcServices = rpcServices;
appInfoList.push_back(appInfo);
}
+ {
+ std::unique_lock<std::mutex> lock(mTestModeMutex);
+ if (!mTestModeNanoapps.has_value()) {
+ mTestModeNanoapps.emplace();
+ for (const auto &appInfo : appInfoList) {
+ mTestModeNanoapps->insert(appInfo.nanoappId);
+ }
+ mEnableTestModeCv.notify_all();
+ }
+ }
+
callback->handleNanoappInfo(appInfoList);
}
@@ -517,6 +657,14 @@ void MultiClientContextHubBase::onNanoappUnloadResponse(
const fbs::UnloadNanoappResponseT &response, HalClientId clientId) {
if (mHalClientManager->resetPendingUnloadTransaction(
clientId, response.transaction_id)) {
+ {
+ std::unique_lock<std::mutex> lock(mTestModeMutex);
+ if (response.transaction_id == mTestModeTransactionId) {
+ mTestModeSyncUnloadResult.emplace(response.success);
+ mEnableTestModeCv.notify_all();
+ return;
+ }
+ }
if (auto callback = mHalClientManager->getCallback(clientId);
callback != nullptr) {
callback->handleTransactionResult(response.transaction_id,
@@ -527,6 +675,7 @@ void MultiClientContextHubBase::onNanoappUnloadResponse(
void MultiClientContextHubBase::onNanoappMessage(
const ::chre::fbs::NanoappMessageT &message) {
+ mEventLogger.logMessageFromNanoapp(message);
ContextHubMessage outMessage;
outMessage.nanoappId = message.app_id;
outMessage.hostEndPoint = message.host_endpoint;
@@ -567,11 +716,32 @@ void MultiClientContextHubBase::handleClientDeath(pid_t clientPid) {
mConnection->sendMessage(builder);
}
}
- mHalClientManager->handleClientDeath(clientPid, mDeathRecipient);
+ mHalClientManager->handleClientDeath(clientPid);
}
void MultiClientContextHubBase::onChreRestarted() {
mIsWifiAvailable.reset();
+ mEventLogger.logContextHubRestart();
mHalClientManager->handleChreRestart();
}
+
+binder_status_t MultiClientContextHubBase::dump(int fd,
+ const char ** /* args */,
+ uint32_t /* numArgs */) {
+ // debugDumpStart waits for the dump to finish before returning.
+ debugDumpStart(fd);
+ return STATUS_OK;
+}
+
+bool MultiClientContextHubBase::requestDebugDump() {
+ flatbuffers::FlatBufferBuilder builder;
+ HostProtocolHost::encodeDebugDumpRequest(builder);
+ return mConnection->sendMessage(builder);
+}
+
+void MultiClientContextHubBase::writeToDebugFile(const char *str) {
+ if (!::android::base::WriteStringToFd(std::string(str), getDebugFd())) {
+ LOGW("Failed to write %zu bytes to debug dump fd", strlen(str));
+ }
+}
} // namespace android::hardware::contexthub::common::implementation
diff --git a/host/hal_generic/common/multi_client_context_hub_base.h b/host/hal_generic/common/multi_client_context_hub_base.h
index 8fa00e54..7d92e71e 100644
--- a/host/hal_generic/common/multi_client_context_hub_base.h
+++ b/host/hal_generic/common/multi_client_context_hub_base.h
@@ -17,16 +17,15 @@
#ifndef ANDROID_HARDWARE_CONTEXTHUB_COMMON_MULTICLIENTS_HAL_BASE_H_
#define ANDROID_HARDWARE_CONTEXTHUB_COMMON_MULTICLIENTS_HAL_BASE_H_
-#ifndef LOG_TAG
-#define LOG_TAG "CHRE.HAL"
-#endif
-
#include <aidl/android/hardware/contexthub/BnContextHub.h>
#include <chre_host/generated/host_messages_generated.h>
#include "chre_connection_callback.h"
#include "chre_host/napp_header.h"
#include "chre_host/preloaded_nanoapp_loader.h"
+#include "chre_host/time_syncer.h"
+#include "debug_dump_helper.h"
+#include "event_logger.h"
#include "hal_client_id.h"
#include "hal_client_manager.h"
@@ -37,29 +36,22 @@ using namespace android::chre;
using ::ndk::ScopedAStatus;
/**
- * The base class of multiclients HAL.
+ * The base class of multiclient HAL.
*
* A subclass should initiate mConnection, mHalClientManager and
* mPreloadedNanoappLoader in its constructor.
- *
- * TODO(b/247124878): A few things are pending:
- * - Some APIs of IContextHub are not implemented yet;
- * - onHostEndpointConnected/Disconnected now returns an error if the endpoint
- * id is illegal or already connected/disconnected. The doc of
- * IContextHub.aidl should be updated accordingly.
- * - registerCallback() can fail if mHalClientManager sees an error during
- * registration. The doc of IContextHub.aidl should be updated accordingly.
- * - Involve EventLogger to log API calls;
- * - extends DebugDumpHelper to ease debugging
*/
class MultiClientContextHubBase
: public BnContextHub,
public ::android::hardware::contexthub::common::implementation::
- ChreConnectionCallback {
+ ChreConnectionCallback,
+ public ::android::hardware::contexthub::DebugDumpHelper {
public:
/** The entry point of death recipient for a disconnected client. */
static void onClientDied(void *cookie);
+ MultiClientContextHubBase();
+
// functions implementing IContextHub
ScopedAStatus getContextHubs(
std::vector<ContextHubInfo> *contextHubInfos) override;
@@ -86,12 +78,20 @@ class MultiClientContextHubBase
ScopedAStatus onNanSessionStateChanged(
const NanSessionStateUpdate &in_update) override;
ScopedAStatus setTestMode(bool enable) override;
+ ScopedAStatus sendMessageDeliveryStatusToHub(
+ int32_t contextHubId,
+ const MessageDeliveryStatus &messageDeliveryStatus) override;
// The callback function implementing ChreConnectionCallback
void handleMessageFromChre(const unsigned char *messageBuffer,
size_t messageLen) override;
void onChreRestarted() override;
+ // The functions for dumping debug information
+ binder_status_t dump(int fd, const char **args, uint32_t numArgs) override;
+ bool requestDebugDump() override;
+ void writeToDebugFile(const char *str) override;
+
protected:
// The data needed by the death client to clear states of a client.
struct HalDeathRecipientCookie {
@@ -102,7 +102,15 @@ class MultiClientContextHubBase
this->clientPid = pid;
}
};
- MultiClientContextHubBase() = default;
+
+ static constexpr uint32_t kDefaultTestModeTransactionId = 0x80000000;
+
+ void tryTimeSync(size_t numOfRetries, useconds_t retryDelayUs) {
+ if (mConnection->isTimeSyncNeeded()) {
+ TimeSyncer::sendTimeSyncWithRetry(mConnection.get(), numOfRetries,
+ retryDelayUs);
+ }
+ }
bool sendFragmentedLoadRequest(HalClientId clientId,
FragmentedLoadRequest &fragmentedLoadRequest);
@@ -117,14 +125,21 @@ class MultiClientContextHubBase
const ::chre::fbs::UnloadNanoappResponseT &response,
HalClientId clientId);
void onNanoappMessage(const ::chre::fbs::NanoappMessageT &message);
-
+ void onDebugDumpData(const ::chre::fbs::DebugDumpDataT &data);
+ void onDebugDumpComplete(
+ const ::chre::fbs::DebugDumpResponseT & /* response */);
void handleClientDeath(pid_t pid);
+ bool enableTestMode();
+ bool disableTestMode();
+
inline bool isSettingEnabled(Setting setting) {
return mSettingEnabled.find(setting) != mSettingEnabled.end() &&
mSettingEnabled[setting];
}
+ HalClientManager::DeadClientUnlinker mDeadClientUnlinker;
+
// HAL is the unique owner of the communication channel to CHRE.
std::unique_ptr<ChreConnection> mConnection{};
@@ -151,6 +166,18 @@ class MultiClientContextHubBase
// A mutex to synchronize access to the list of preloaded nanoapp IDs.
std::mutex mPreloadedNanoappIdsMutex;
std::optional<std::vector<uint64_t>> mPreloadedNanoappIds{};
+
+ // test mode settings
+ std::mutex mTestModeMutex;
+ std::condition_variable mEnableTestModeCv;
+ bool mIsTestModeEnabled = false;
+ std::optional<bool> mTestModeSyncUnloadResult = std::nullopt;
+ std::optional<std::unordered_set<uint64_t>> mTestModeNanoapps =
+ std::unordered_set<uint64_t>{};
+ int32_t mTestModeTransactionId =
+ static_cast<int32_t>(kDefaultTestModeTransactionId);
+
+ EventLogger mEventLogger;
};
} // namespace android::hardware::contexthub::common::implementation
#endif // ANDROID_HARDWARE_CONTEXTHUB_COMMON_MULTICLIENTS_HAL_BASE_H_
diff --git a/host/test/hal_generic/common/hal_client_manager_test.cc b/host/test/hal_generic/common/hal_client_manager_test.cc
new file mode 100644
index 00000000..b8e7a5f9
--- /dev/null
+++ b/host/test/hal_generic/common/hal_client_manager_test.cc
@@ -0,0 +1,552 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <array>
+#include <chrono>
+#include <cstdlib>
+#include <fstream>
+#include <thread>
+
+#include <json/json.h>
+
+#include <aidl/android/hardware/contexthub/BnContextHubCallback.h>
+#include <aidl/android/hardware/contexthub/IContextHub.h>
+#include <aidl/android/hardware/contexthub/NanoappBinary.h>
+#include "chre/platform/shared/host_protocol_common.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "hal_client_manager.h"
+
+namespace android::hardware::contexthub::common::implementation {
+
+namespace {
+using aidl::android::hardware::contexthub::AsyncEventType;
+using aidl::android::hardware::contexthub::BnContextHubCallback;
+using aidl::android::hardware::contexthub::ContextHubMessage;
+using aidl::android::hardware::contexthub::MessageDeliveryStatus;
+using aidl::android::hardware::contexthub::NanoappInfo;
+using aidl::android::hardware::contexthub::NanSessionRequest;
+
+using ndk::ScopedAStatus;
+
+using ::testing::_;
+using ::testing::ByMove;
+using ::testing::IsEmpty;
+using ::testing::Return;
+using ::testing::SizeIs;
+using ::testing::UnorderedElementsAre;
+
+using HalClient = HalClientManager::HalClient;
+
+constexpr pid_t kSystemServerPid = 1000;
+// The uuid assigned to ContextHubService
+const std::string kSystemServerUuid = "9a17008d6bf1445a90116d21bd985b6c";
+
+constexpr pid_t kVendorPid = 1001;
+const std::string kVendorUuid = "6e406b36cf4f4c0d8183db3708f45d8f";
+
+const std::string kClientIdMappingFilePath = "./chre_hal_clients.json";
+const std::string kClientName = "HalClientManagerTest";
+
+class ContextHubCallbackForTest : public BnContextHubCallback {
+ public:
+ explicit ContextHubCallbackForTest(const std::string &uuid) {
+ assert(uuid.length() == 32); // 2 digits for one bytes x 16 bytes
+ for (int i = 0; i < 16; i++) {
+ mUuid[i] = strtol(uuid.substr(i * 2, 2).c_str(), /* end_ptr= */ nullptr,
+ /* base= */ 16);
+ }
+ ON_CALL(*this, handleContextHubAsyncEvent(_))
+ .WillByDefault(Return(ByMove(ScopedAStatus::ok())));
+ }
+ ScopedAStatus handleNanoappInfo(
+ const std::vector<NanoappInfo> & /*appInfo*/) override {
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus handleContextHubMessage(
+ const ContextHubMessage & /*message*/,
+ const std::vector<std::string> & /*msgContentPerms*/) override {
+ return ScopedAStatus::ok();
+ }
+
+ MOCK_METHOD(ScopedAStatus, handleContextHubAsyncEvent, (AsyncEventType event),
+ (override));
+
+ // Called after loading/unloading a nanoapp.
+ ScopedAStatus handleTransactionResult(int32_t /*transactionId*/,
+ bool /*success*/) override {
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus handleNanSessionRequest(
+ const NanSessionRequest & /* request */) override {
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus handleMessageDeliveryStatus(
+ char16_t /* hostEndPointId */,
+ const MessageDeliveryStatus & /* messageDeliveryStatus */) override {
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus getUuid(std::array<uint8_t, 16> *out_uuid) override {
+ *out_uuid = mUuid;
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus getName(std::string *out_name) override {
+ *out_name = kClientName;
+ return ScopedAStatus::ok();
+ }
+
+ private:
+ const std::string kClientName = "HalClientManagerUnitTest";
+ std::array<uint8_t, 16> mUuid{};
+};
+
+class HalClientManagerForTest : public HalClientManager {
+ public:
+ HalClientManagerForTest(
+ DeadClientUnlinker deadClientUnlinker,
+ const std::string &clientIdMappingFilePath,
+ const std::unordered_set<HalClientId> &reservedClientIds = {})
+ : HalClientManager(std::move(deadClientUnlinker), clientIdMappingFilePath,
+ reservedClientIds) {}
+
+ const std::vector<HalClient> getClients() {
+ return mClients;
+ }
+
+ bool createClientForTest(const std::string &uuid, pid_t pid) {
+ // No need to hold the lock during a unit test which is single-threaded
+ std::shared_ptr<ContextHubCallbackForTest> callback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+ return createClientLocked(uuid, pid, callback,
+ /* deathRecipientCookie= */ nullptr);
+ }
+
+ HalClientId getNextClientId() {
+ return mNextClientId;
+ }
+
+ static int64_t getTransactionTimeoutSeconds() {
+ return kTransactionTimeoutThresholdMs / 1000;
+ }
+
+ static const char *getClientIdTag() {
+ return kJsonClientId;
+ }
+
+ static const char *getUuidTag() {
+ return kJsonUuid;
+ }
+
+ static const char *getNameTag() {
+ return kJsonName;
+ }
+};
+
+class HalClientManagerTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ // Clears out the mapping file content
+ std::ofstream file(kClientIdMappingFilePath);
+ ASSERT_TRUE(file.good());
+ }
+ void TearDown() override {}
+};
+
+auto mockDeadClientUnlinker =
+ [](const std::shared_ptr<IContextHubCallback> & /*callback*/,
+ void * /*deathRecipientCookie*/) { return true; };
+
+std::unique_ptr<FragmentedLoadTransaction> createLoadTransaction(
+ uint32_t transactionId) {
+ uint64_t appId = 0x476f6f676cabcdef;
+ uint32_t appVersion = 2;
+ uint32_t appFlags = 3;
+ uint32_t targetApiVersion = 4;
+ std::vector<uint8_t> binary = {0xf0, 0xf1};
+ return std::make_unique<FragmentedLoadTransaction>(
+ transactionId, appId, appVersion, appFlags, targetApiVersion, binary,
+ /* fragmentSize= */ 2048);
+}
+
+TEST_F(HalClientManagerTest, ClientIdMappingFile) {
+ HalClientId systemClientId = 100;
+ {
+ // Write systemClientId into the mapping file
+ Json::Value mappings;
+ Json::Value mapping;
+ mapping[HalClientManagerForTest::getClientIdTag()] = systemClientId;
+ mapping[HalClientManagerForTest::getUuidTag()] = kSystemServerUuid;
+ mapping[HalClientManagerForTest::getNameTag()] = kClientName;
+ mappings.append(mapping);
+ Json::StreamWriterBuilder factory;
+ std::unique_ptr<Json::StreamWriter> const writer(factory.newStreamWriter());
+ std::ofstream fileStream(kClientIdMappingFilePath);
+ writer->write(mappings, &fileStream);
+ fileStream << std::endl;
+ }
+
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ std::shared_ptr<ContextHubCallbackForTest> callback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+ EXPECT_TRUE(
+ halClientManager->registerCallback(kSystemServerPid, callback,
+ /* deathRecipientCookie= */ nullptr));
+
+ std::vector<HalClient> clients = halClientManager->getClients();
+ const HalClient &client = clients.front();
+ EXPECT_THAT(clients, SizeIs(1));
+ EXPECT_THAT(client.endpointIds, IsEmpty());
+ EXPECT_EQ(client.callback, callback);
+ EXPECT_EQ(client.uuid, kSystemServerUuid);
+ EXPECT_EQ(client.pid, kSystemServerPid);
+ // The client id allocated should be the one specified in the mapping file
+ EXPECT_EQ(client.clientId, systemClientId);
+}
+
+TEST_F(HalClientManagerTest, CallbackRegistryBasic) {
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ std::shared_ptr<ContextHubCallbackForTest> callback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+
+ EXPECT_TRUE(
+ halClientManager->registerCallback(kSystemServerPid, callback,
+ /* deathRecipientCookie= */ nullptr));
+
+ std::vector<HalClient> clients = halClientManager->getClients();
+ const HalClient &client = clients.front();
+
+ EXPECT_THAT(clients, SizeIs(1));
+ EXPECT_THAT(client.endpointIds, IsEmpty());
+ EXPECT_EQ(client.callback, callback);
+ EXPECT_EQ(client.uuid, kSystemServerUuid);
+ EXPECT_EQ(client.pid, kSystemServerPid);
+ EXPECT_NE(client.clientId, ::chre::kHostClientIdUnspecified);
+}
+
+TEST_F(HalClientManagerTest, CallbackRegistryTwiceFromSameClient) {
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ std::shared_ptr<ContextHubCallbackForTest> callbackA =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+ std::shared_ptr<ContextHubCallbackForTest> callbackB =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+
+ EXPECT_TRUE(
+ halClientManager->registerCallback(kSystemServerPid, callbackA,
+ /* deathRecipientCookie= */ nullptr));
+ EXPECT_THAT(halClientManager->getClients(), SizeIs(1));
+ EXPECT_EQ(halClientManager->getClients().front().callback, callbackA);
+ // Same client can override its callback
+ EXPECT_TRUE(
+ halClientManager->registerCallback(kSystemServerPid, callbackB,
+ /* deathRecipientCookie= */ nullptr));
+ EXPECT_THAT(halClientManager->getClients(), SizeIs(1));
+ EXPECT_EQ(halClientManager->getClients().front().callback, callbackB);
+}
+
+TEST_F(HalClientManagerTest, CallbackRetrievalByEndpoint) {
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ std::shared_ptr<ContextHubCallbackForTest> systemCallback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+ std::shared_ptr<ContextHubCallbackForTest> vendorCallback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(kVendorUuid);
+ uint16_t vendorEndpointId = 1;
+ uint16_t systemServerEndpointId = 1;
+
+ // Register the callbacks and endpoint ids
+ EXPECT_TRUE(halClientManager->registerCallback(
+ kSystemServerPid, systemCallback, /* deathRecipientCookie= */ nullptr));
+ EXPECT_TRUE(halClientManager->registerEndpointId(kSystemServerPid,
+ systemServerEndpointId));
+ EXPECT_TRUE(halClientManager->registerCallback(
+ kVendorPid, vendorCallback, /* deathRecipientCookie= */ nullptr));
+ EXPECT_TRUE(
+ halClientManager->registerEndpointId(kVendorPid, vendorEndpointId));
+
+ // Though endpoint ids have the same value, they should be mutated before
+ // getting sent to CHRE and mapped to different callbacks
+ EXPECT_TRUE(halClientManager->mutateEndpointIdFromHostIfNeeded(
+ kVendorPid, vendorEndpointId));
+ EXPECT_TRUE(halClientManager->mutateEndpointIdFromHostIfNeeded(
+ kSystemServerPid, systemServerEndpointId));
+ EXPECT_EQ(halClientManager->getCallbackForEndpoint(vendorEndpointId),
+ vendorCallback);
+ EXPECT_EQ(halClientManager->getCallbackForEndpoint(systemServerEndpointId),
+ systemCallback);
+}
+
+TEST_F(HalClientManagerTest, ClientCreation) {
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ int uuid = 1;
+ int pid = 1;
+ for (int i = 0; i < kMaxNumOfHalClients; i++, uuid++, pid++) {
+ EXPECT_TRUE(
+ halClientManager->createClientForTest(std::to_string(uuid), pid));
+ }
+ // if max number of clients are reached no more client can be created
+ EXPECT_FALSE(
+ halClientManager->createClientForTest(std::to_string(uuid), pid));
+ // mNextClientId is reset to ::chre::kHostClientIdUnspecified when new client
+ // is not accepted
+ EXPECT_EQ(halClientManager->getNextClientId(),
+ ::chre::kHostClientIdUnspecified);
+}
+
+TEST_F(HalClientManagerTest, ClientCreationWithReservedClientId) {
+ std::unordered_set<HalClientId> reservedClientIds{
+ ::chre::kHostClientIdUnspecified + 1, 64};
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath, reservedClientIds);
+ int uuid = 1;
+ int pid = 1;
+ for (int i = 0; i < kMaxNumOfHalClients - reservedClientIds.size();
+ i++, uuid++, pid++) {
+ EXPECT_TRUE(
+ halClientManager->createClientForTest(std::to_string(uuid), pid));
+ }
+ // if max number of clients are reached no more client can be created
+ EXPECT_FALSE(
+ halClientManager->createClientForTest(std::to_string(uuid), pid));
+ // mNextClientId is reset to ::chre::kHostClientIdUnspecified when new client
+ // is not accepted
+ EXPECT_EQ(halClientManager->getNextClientId(),
+ ::chre::kHostClientIdUnspecified);
+ // Verify that every reserved client id is not used:
+ for (const HalClient &client : halClientManager->getClients()) {
+ EXPECT_EQ(reservedClientIds.find(client.clientId), reservedClientIds.end());
+ }
+}
+
+TEST_F(HalClientManagerTest, TransactionRegistryAndOverridden) {
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ std::shared_ptr<ContextHubCallbackForTest> callback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+ EXPECT_TRUE(halClientManager->registerCallback(
+ kSystemServerPid, callback, /* deathRecipientCookie= */ nullptr));
+
+ EXPECT_TRUE(halClientManager->registerPendingLoadTransaction(
+ kSystemServerPid, createLoadTransaction(/* transactionId= */ 1)));
+
+ // Immediate transaction overridden is not allowed as each transaction is
+ // given a certain amount of time to finish
+ EXPECT_FALSE(halClientManager->registerPendingLoadTransaction(
+ kSystemServerPid, createLoadTransaction(/* transactionId= */ 2)));
+
+ // Wait until the transaction is timed out to override it
+ std::this_thread::sleep_for(std::chrono::seconds(
+ HalClientManagerForTest::getTransactionTimeoutSeconds()));
+ EXPECT_TRUE(halClientManager->registerPendingLoadTransaction(
+ kSystemServerPid, createLoadTransaction(/* transactionId= */ 3)));
+}
+
+TEST_F(HalClientManagerTest, TransactionRegistryLoadAndUnload) {
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ std::shared_ptr<ContextHubCallbackForTest> callback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+ EXPECT_TRUE(halClientManager->registerCallback(
+ kSystemServerPid, callback, /* deathRecipientCookie= */ nullptr));
+
+ EXPECT_TRUE(halClientManager->registerPendingUnloadTransaction(
+ kSystemServerPid, /* transactionId= */ 1));
+
+ // Load and unload transaction can't coexist because unloading a nanoapp that
+ // is being loaded can cause problems.
+ EXPECT_FALSE(halClientManager->registerPendingLoadTransaction(
+ kSystemServerPid, createLoadTransaction(/* transactionId= */ 2)));
+
+ // Clears out the pending unload transaction to register a new one.
+ halClientManager->resetPendingUnloadTransaction(
+ halClientManager->getClientId(kSystemServerPid), /* transactionId= */ 1);
+ EXPECT_TRUE(halClientManager->registerPendingLoadTransaction(
+ kSystemServerPid, createLoadTransaction(/* transactionId= */ 2)));
+}
+
+TEST_F(HalClientManagerTest, EndpointRegistry) {
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ std::shared_ptr<ContextHubCallbackForTest> systemCallback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+ std::shared_ptr<ContextHubCallbackForTest> vendorCallback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(kVendorUuid);
+
+ halClientManager->registerCallback(kSystemServerPid, systemCallback,
+ /* deathRecipientCookie= */ nullptr);
+ halClientManager->registerCallback(kVendorPid, vendorCallback,
+ /* deathRecipientCookie= */ nullptr);
+
+ std::vector<HalClient> clients = halClientManager->getClients();
+ EXPECT_THAT(clients, SizeIs(2));
+ // only system server can register endpoint ids > 63.
+
+ EXPECT_TRUE(halClientManager->registerEndpointId(kSystemServerPid,
+ /* endpointId= */ 64));
+ EXPECT_TRUE(halClientManager->registerEndpointId(kVendorPid,
+ /*endpointId= */ 63));
+ EXPECT_FALSE(halClientManager->registerEndpointId(kVendorPid,
+ /* endpointId= */ 64));
+}
+
+TEST_F(HalClientManagerTest, EndpointIdMutationForVendorClient) {
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ std::shared_ptr<ContextHubCallbackForTest> vendorCallback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(kVendorUuid);
+ std::shared_ptr<ContextHubCallbackForTest> systemCallback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+ const uint16_t originalEndpointId = 10; // 0b1010;
+ uint16_t mutatedEndpointId = originalEndpointId;
+
+ // Register the system callback
+ EXPECT_TRUE(halClientManager->registerCallback(
+ kSystemServerPid, systemCallback, /* deathRecipientCookie= */ nullptr));
+ // Register the vendor callback
+ EXPECT_TRUE(halClientManager->registerCallback(
+ kVendorPid, vendorCallback, /* deathRecipientCookie= */ nullptr));
+
+ // Mutate endpoint id from host to CHRE
+ EXPECT_TRUE(halClientManager->mutateEndpointIdFromHostIfNeeded(
+ kVendorPid, mutatedEndpointId));
+ HalClientId clientId = halClientManager->getClientId(kVendorPid);
+ EXPECT_EQ(mutatedEndpointId, 0x8000 | clientId << 6 | originalEndpointId);
+
+ // Mutate endpoint id from CHRE to Host
+ EXPECT_EQ(halClientManager->convertToOriginalEndpointId(mutatedEndpointId),
+ originalEndpointId);
+}
+
+TEST_F(HalClientManagerTest, EndpointIdMutationForSystemServer) {
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ std::shared_ptr<ContextHubCallbackForTest> callback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+ const uint16_t originalEndpointId = 100;
+ uint16_t mutatedEndpointId = originalEndpointId;
+
+ // Register the callback
+ EXPECT_TRUE(halClientManager->registerCallback(
+ kSystemServerPid, callback, /* deathRecipientCookie= */ nullptr));
+
+ // Endpoint id from the system server shouldn't be mutated
+ EXPECT_TRUE(halClientManager->mutateEndpointIdFromHostIfNeeded(
+ kSystemServerPid, mutatedEndpointId));
+ EXPECT_EQ(mutatedEndpointId, originalEndpointId);
+ EXPECT_EQ(halClientManager->convertToOriginalEndpointId(mutatedEndpointId),
+ originalEndpointId);
+}
+
+TEST_F(HalClientManagerTest, EndpointIdUnknownFromChre) {
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ std::shared_ptr<ContextHubCallbackForTest> vendorCallback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(kVendorUuid);
+ std::shared_ptr<ContextHubCallbackForTest> systemCallback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+ const HostEndpointId originalEndpointId = 0x10; // unregistered endpoint id
+ HostEndpointId mutatedEndpointId = originalEndpointId;
+
+ // Register the callback
+ EXPECT_TRUE(halClientManager->registerCallback(
+ kSystemServerPid, systemCallback, /* deathRecipientCookie= */ nullptr));
+ EXPECT_TRUE(halClientManager->registerCallback(
+ kVendorPid, vendorCallback, /* deathRecipientCookie= */ nullptr));
+
+ // As long as a client's callback is registered, hal_client_manager won't
+ // block message exchanged from/to the client even if the endpoint id is
+ // not registered. The enforcement of endpoint id registration is done on the
+ // client side (contextHubService, library, etc.).
+ EXPECT_TRUE(halClientManager->mutateEndpointIdFromHostIfNeeded(
+ kVendorPid, mutatedEndpointId));
+ EXPECT_NE(mutatedEndpointId, originalEndpointId);
+ EXPECT_EQ(halClientManager->convertToOriginalEndpointId(mutatedEndpointId),
+ originalEndpointId);
+ EXPECT_EQ(halClientManager->getCallbackForEndpoint(mutatedEndpointId),
+ vendorCallback);
+}
+
+TEST_F(HalClientManagerTest, handleDeathClient) {
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ std::shared_ptr<ContextHubCallbackForTest> callback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+ halClientManager->registerCallback(kSystemServerPid, callback,
+ /* deathRecipientCookie= */ nullptr);
+ halClientManager->registerEndpointId(kSystemServerPid, /* endpointId= */ 10);
+
+ halClientManager->handleClientDeath(kSystemServerPid);
+
+ const std::vector<HalClient> &clients = halClientManager->getClients();
+ EXPECT_THAT(clients, SizeIs(1));
+ const HalClient &client = clients.front();
+ EXPECT_EQ(client.callback, nullptr);
+ EXPECT_EQ(client.pid, HalClient::PID_UNSET);
+ EXPECT_EQ(client.uuid, kSystemServerUuid);
+ EXPECT_NE(client.clientId, ::chre::kHostClientIdUnspecified);
+ EXPECT_THAT(client.endpointIds, IsEmpty());
+}
+
+TEST_F(HalClientManagerTest, handleChreRestartForConnectedClientsOnly) {
+ auto halClientManager = std::make_unique<HalClientManagerForTest>(
+ mockDeadClientUnlinker, kClientIdMappingFilePath);
+ std::shared_ptr<ContextHubCallbackForTest> vendorCallback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(kVendorUuid);
+ std::shared_ptr<ContextHubCallbackForTest> systemCallback =
+ ContextHubCallbackForTest::make<ContextHubCallbackForTest>(
+ kSystemServerUuid);
+ // Register the system callback
+ EXPECT_TRUE(halClientManager->registerCallback(
+ kSystemServerPid, systemCallback, /* deathRecipientCookie= */ nullptr));
+ // Register the vendor callback
+ EXPECT_TRUE(halClientManager->registerCallback(
+ kVendorPid, vendorCallback, /* deathRecipientCookie= */ nullptr));
+
+ // Only connected clients' handleContextHubAsyncEvent should be called.
+ EXPECT_CALL(*systemCallback,
+ handleContextHubAsyncEvent(AsyncEventType::RESTARTED));
+ EXPECT_CALL(*vendorCallback,
+ handleContextHubAsyncEvent(AsyncEventType::RESTARTED))
+ .Times(0);
+
+ // Disconnect the vendor client and handle CHRE restart for the system server
+ halClientManager->handleClientDeath(kVendorPid);
+ halClientManager->handleChreRestart();
+}
+
+} // namespace
+} // namespace android::hardware::contexthub::common::implementation
diff --git a/host/test/hal_generic/common/hal_client_test.cc b/host/test/hal_generic/common/hal_client_test.cc
new file mode 100644
index 00000000..eac5bd84
--- /dev/null
+++ b/host/test/hal_generic/common/hal_client_test.cc
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "chre_host/hal_client.h"
+#include "host/hal_generic/common/hal_error.h"
+
+#include <unordered_set>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include <aidl/android/hardware/contexthub/IContextHub.h>
+
+namespace android::chre {
+
+namespace {
+using ::aidl::android::hardware::contexthub::ContextHubMessage;
+using ::aidl::android::hardware::contexthub::HostEndpointInfo;
+using ::aidl::android::hardware::contexthub::IContextHub;
+using ::aidl::android::hardware::contexthub::IContextHubCallbackDefault;
+using ::aidl::android::hardware::contexthub::IContextHubDefault;
+
+using ::ndk::ScopedAStatus;
+
+using ::testing::_;
+using ::testing::ByMove;
+using ::testing::Field;
+using ::testing::IsEmpty;
+using ::testing::Return;
+using ::testing::UnorderedElementsAre;
+
+using HostEndpointId = char16_t;
+constexpr HostEndpointId kEndpointId = 0x10;
+
+class HalClientForTest : public HalClient {
+ public:
+ HalClientForTest(const std::shared_ptr<IContextHub> &contextHub,
+ const std::vector<HostEndpointId> &connectedEndpoints,
+ const std::shared_ptr<IContextHubCallback> &callback =
+ ndk::SharedRefBase::make<IContextHubCallbackDefault>())
+ : HalClient(callback) {
+ mContextHub = contextHub;
+ for (const HostEndpointId &endpointId : connectedEndpoints) {
+ mConnectedEndpoints[endpointId] = {.hostEndpointId = endpointId};
+ }
+ }
+
+ std::unordered_set<HostEndpointId> getConnectedEndpointIds() {
+ std::unordered_set<HostEndpointId> result{};
+ for (const auto &[endpointId, unusedEndpointInfo] : mConnectedEndpoints) {
+ result.insert(endpointId);
+ }
+ return result;
+ }
+
+ HalClientCallback *getClientCallback() {
+ return mCallback.get();
+ }
+};
+
+class MockContextHub : public IContextHubDefault {
+ public:
+ MOCK_METHOD(ScopedAStatus, onHostEndpointConnected,
+ (const HostEndpointInfo &info), (override));
+ MOCK_METHOD(ScopedAStatus, onHostEndpointDisconnected,
+ (HostEndpointId endpointId), (override));
+ MOCK_METHOD(ScopedAStatus, queryNanoapps, (int32_t icontextHubId),
+ (override));
+ MOCK_METHOD(ScopedAStatus, sendMessageToHub,
+ (int32_t contextHubId, const ContextHubMessage &message),
+ (override));
+};
+
+} // namespace
+
+TEST(HalClientTest, EndpointConnectionBasic) {
+ auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
+ const HostEndpointInfo kInfo = {
+ .hostEndpointId = kEndpointId,
+ .type = HostEndpointInfo::Type::NATIVE,
+ .packageName = "HalClientTest",
+ .attributionTag{},
+ };
+
+ auto halClient = std::make_unique<HalClientForTest>(
+ mockContextHub, std::vector<HostEndpointId>{});
+ EXPECT_THAT(halClient->getConnectedEndpointIds(), IsEmpty());
+
+ EXPECT_CALL(*mockContextHub,
+ onHostEndpointConnected(
+ Field(&HostEndpointInfo::hostEndpointId, kEndpointId)))
+ .WillOnce(Return(ScopedAStatus::ok()));
+
+ halClient->connectEndpoint(kInfo);
+ EXPECT_THAT(halClient->getConnectedEndpointIds(),
+ UnorderedElementsAre(kEndpointId));
+}
+
+TEST(HalClientTest, EndpointConnectionMultipleRequests) {
+ auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
+ const HostEndpointInfo kInfo = {
+ .hostEndpointId = kEndpointId,
+ .type = HostEndpointInfo::Type::NATIVE,
+ .packageName = "HalClientTest",
+ .attributionTag{},
+ };
+
+ auto halClient = std::make_unique<HalClientForTest>(
+ mockContextHub, std::vector<HostEndpointId>{});
+ EXPECT_THAT(halClient->getConnectedEndpointIds(), IsEmpty());
+
+ // multiple requests are tolerated
+ EXPECT_CALL(*mockContextHub,
+ onHostEndpointConnected(
+ Field(&HostEndpointInfo::hostEndpointId, kEndpointId)))
+ .WillOnce(Return(ScopedAStatus::ok()))
+ .WillOnce(Return(ScopedAStatus::ok()));
+
+ halClient->connectEndpoint(kInfo);
+ halClient->connectEndpoint(kInfo);
+
+ EXPECT_THAT(halClient->getConnectedEndpointIds(),
+ UnorderedElementsAre(kEndpointId));
+}
+
+TEST(HalClientTest, EndpointDisconnectionBasic) {
+ auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
+ auto halClient = std::make_unique<HalClientForTest>(
+ mockContextHub, std::vector<HostEndpointId>{kEndpointId});
+
+ EXPECT_THAT(halClient->getConnectedEndpointIds(),
+ UnorderedElementsAre(kEndpointId));
+
+ EXPECT_CALL(*mockContextHub, onHostEndpointDisconnected(kEndpointId))
+ .WillOnce(Return(ScopedAStatus::ok()));
+ halClient->disconnectEndpoint(kEndpointId);
+
+ EXPECT_THAT(halClient->getConnectedEndpointIds(), IsEmpty());
+}
+
+TEST(HalClientTest, EndpointDisconnectionMultipleRequest) {
+ auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
+ auto halClient = std::make_unique<HalClientForTest>(
+ mockContextHub, std::vector<HostEndpointId>{kEndpointId});
+ EXPECT_THAT(halClient->getConnectedEndpointIds(),
+ UnorderedElementsAre(kEndpointId));
+
+ EXPECT_CALL(*mockContextHub, onHostEndpointDisconnected(kEndpointId))
+ .WillOnce(Return(ScopedAStatus::ok()))
+ .WillOnce(Return(ScopedAStatus::ok()));
+
+ halClient->disconnectEndpoint(kEndpointId);
+ halClient->disconnectEndpoint(kEndpointId);
+
+ EXPECT_THAT(halClient->getConnectedEndpointIds(), IsEmpty());
+}
+
+TEST(HalClientTest, SendMessageBasic) {
+ auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
+ const ContextHubMessage contextHubMessage = {
+ .nanoappId = 0xbeef,
+ .hostEndPoint = kEndpointId,
+ .messageBody = {},
+ .permissions = {},
+ };
+ auto halClient = std::make_unique<HalClientForTest>(
+ mockContextHub, std::vector<HostEndpointId>{kEndpointId});
+
+ EXPECT_CALL(*mockContextHub, sendMessageToHub(_, _))
+ .WillOnce(Return(ScopedAStatus::ok()));
+ halClient->sendMessage(contextHubMessage);
+}
+
+TEST(HalClientTest, QueryNanoapp) {
+ auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
+ auto halClient = std::make_unique<HalClientForTest>(
+ mockContextHub, std::vector<HostEndpointId>{});
+
+ EXPECT_CALL(*mockContextHub, queryNanoapps(HalClient::kDefaultContextHubId));
+ halClient->queryNanoapps();
+}
+
+TEST(HalClientTest, HandleChreRestart) {
+ auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
+
+ auto halClient = std::make_unique<HalClientForTest>(
+ mockContextHub,
+ std::vector<HostEndpointId>{kEndpointId, kEndpointId + 1});
+
+ EXPECT_CALL(*mockContextHub, onHostEndpointConnected(
+ Field(&HostEndpointInfo::hostEndpointId, _)))
+ .WillOnce(Return(ScopedAStatus::ok()))
+ .WillOnce(Return(ScopedAStatus::ok()));
+
+ halClient->getClientCallback()->handleContextHubAsyncEvent(
+ AsyncEventType::RESTARTED);
+ EXPECT_THAT(halClient->getConnectedEndpointIds(),
+ UnorderedElementsAre(kEndpointId, kEndpointId + 1));
+}
+} // namespace android::chre
diff --git a/host/tinysys/hal/Android.bp b/host/tinysys/hal/Android.bp
index 0550da16..5dde4af0 100644
--- a/host/tinysys/hal/Android.bp
+++ b/host/tinysys/hal/Android.bp
@@ -33,7 +33,7 @@ cc_binary {
"tinysys_chre_connection.cc",
"tinysys_context_hub.cc",
":st_hal_lpma_handler",
- ":contexthub_generic_aidl_hal_core",
+ ":contexthub_hal_core",
],
include_dirs: [
"system/chre/util/include/",
@@ -53,7 +53,7 @@ cc_binary {
],
shared_libs: [
"android.media.soundtrigger.types-V1-ndk",
- "android.hardware.contexthub-V2-ndk",
+ "android.hardware.contexthub-V3-ndk",
"android.hardware.soundtrigger3-V1-ndk",
"libcutils",
"liblog",
@@ -62,6 +62,7 @@ cc_binary {
"libbinder_ndk",
"libpower",
"libjsoncpp",
+ "server_configurable_flags",
],
header_libs: [
"chre_api",
@@ -70,6 +71,7 @@ cc_binary {
],
static_libs: [
"chre_client",
+ "chre_flags_c_lib",
"event_logger",
"pw_varint",
"pw_detokenizer",
diff --git a/host/tinysys/hal/android.hardware.contexthub-service.tinysys.xml b/host/tinysys/hal/android.hardware.contexthub-service.tinysys.xml
index 54d4592e..db2e2d7c 100644
--- a/host/tinysys/hal/android.hardware.contexthub-service.tinysys.xml
+++ b/host/tinysys/hal/android.hardware.contexthub-service.tinysys.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.contexthub</name>
- <version>2</version>
+ <version>3</version>
<fqname>IContextHub/default</fqname>
</hal>
</manifest>
diff --git a/host/tinysys/hal/tinysys_chre_connection.cc b/host/tinysys/hal/tinysys_chre_connection.cc
index 3be581ce..c560d7ba 100644
--- a/host/tinysys/hal/tinysys_chre_connection.cc
+++ b/host/tinysys/hal/tinysys_chre_connection.cc
@@ -21,6 +21,7 @@
#include <hardware_legacy/power.h>
#include <sys/ioctl.h>
+#include <utils/SystemClock.h>
#include <cerrno>
#include <thread>
@@ -131,10 +132,13 @@ bool TinysysChreConnection::init() {
chreNextState);
}
if (chreCurrentState == SCP_CHRE_STOP && chreNextState == SCP_CHRE_START) {
- // TODO(b/277128368): We should have an explicit indication from CHRE for
- // restart recovery.
- LOGW("SCP restarted. Give it 5s for recovery before notifying clients");
- std::this_thread::sleep_for(std::chrono::milliseconds(5000));
+ int64_t startTime = ::android::elapsedRealtime();
+ // Though usually CHRE is recovered within 1s after SCP is up, in a corner
+ // case it can go beyond 5s. Wait for 10s to cover more extreme cases.
+ chreConnection->waitChreBackOnline(
+ /* timeoutMs= */ std::chrono::milliseconds(10000));
+ LOGW("SCP restarted! CHRE recover time: %" PRIu64 "ms.",
+ ::android::elapsedRealtime() - startTime);
chreConnection->getCallback()->onChreRestarted();
}
chreCurrentState = chreNextState;
@@ -206,6 +210,10 @@ void TinysysChreConnection::handleMessageFromChre(
chreConnection->getLpmaHandler()->enable(/* enabled= */ false);
break;
}
+ case fbs::ChreMessage::PulseResponse: {
+ chreConnection->notifyChreBackOnline();
+ break;
+ }
case fbs::ChreMessage::MetricLog:
case fbs::ChreMessage::NanConfigurationRequest:
case fbs::ChreMessage::TimeSyncRequest:
diff --git a/host/tinysys/hal/tinysys_chre_connection.h b/host/tinysys/hal/tinysys_chre_connection.h
index e42b0c49..32974e0e 100644
--- a/host/tinysys/hal/tinysys_chre_connection.h
+++ b/host/tinysys/hal/tinysys_chre_connection.h
@@ -20,6 +20,7 @@
#include "chre_connection.h"
#include "chre_connection_callback.h"
#include "chre_host/fragmented_load_transaction.h"
+#include "chre_host/host_protocol_host.h"
#include "chre_host/log.h"
#include "chre_host/log_message_parser.h"
#include "chre_host/st_hal_lpma_handler.h"
@@ -35,6 +36,7 @@ using ::android::chre::StHalLpmaHandler;
namespace aidl::android::hardware::contexthub {
using namespace ::android::hardware::contexthub::common::implementation;
+using ::android::chre::HostProtocolHost;
/** A class handling message transmission between context hub HAL and CHRE. */
// TODO(b/267188769): We should add comments explaining how IPI works.
@@ -67,6 +69,27 @@ class TinysysChreConnection : public ChreConnection {
bool sendMessage(void *data, size_t length) override;
+ void waitChreBackOnline(std::chrono::milliseconds timeoutMs) {
+ flatbuffers::FlatBufferBuilder builder(48);
+ HostProtocolHost::encodePulseRequest(builder);
+
+ std::unique_lock<std::mutex> lock(mChrePulseMutex);
+ // reset mIsChreRecovered before sending a PulseRequest message
+ mIsChreBackOnline = false;
+ sendMessage(builder.GetBufferPointer(), builder.GetSize());
+ mChrePulseCondition.wait_for(
+ lock, timeoutMs,
+ [&isChreBackOnline = mIsChreBackOnline] { return isChreBackOnline; });
+ }
+
+ void notifyChreBackOnline() {
+ {
+ std::unique_lock<std::mutex> lock(mChrePulseMutex);
+ mIsChreBackOnline = true;
+ }
+ mChrePulseCondition.notify_all();
+ }
+
inline ChreConnectionCallback *getCallback() {
return mCallback;
}
@@ -191,6 +214,12 @@ class TinysysChreConnection : public ChreConnection {
// For messages sent to CHRE
SynchronousMessageQueue mQueue;
+
+ // Mutex and CV are used to get PulseResponse from CHRE synchronously.
+ std::mutex mChrePulseMutex;
+ std::condition_variable mChrePulseCondition;
+ bool mIsChreBackOnline =
+ false; // set to true after CHRE recovers from a restart
};
} // namespace aidl::android::hardware::contexthub
diff --git a/host/tinysys/hal/tinysys_context_hub.cc b/host/tinysys/hal/tinysys_context_hub.cc
index 2f54aba7..2e290c69 100644
--- a/host/tinysys/hal/tinysys_context_hub.cc
+++ b/host/tinysys/hal/tinysys_context_hub.cc
@@ -18,28 +18,21 @@
namespace aidl::android::hardware::contexthub {
TinysysContextHub::TinysysContextHub() {
- mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
- AIBinder_DeathRecipient_new(onClientDied));
- AIBinder_DeathRecipient_setOnUnlinked(
- mDeathRecipient.get(), [](void *cookie) {
- LOGI("Callback is unlinked. Releasing the death recipient cookie.");
- delete static_cast<HalDeathRecipientCookie *>(cookie);
- });
mConnection = std::make_unique<TinysysChreConnection>(this);
- mHalClientManager = std::make_unique<HalClientManager>();
+ mHalClientManager = std::make_unique<HalClientManager>(
+ mDeadClientUnlinker, kClientIdMappingFilePath);
mPreloadedNanoappLoader = std::make_unique<PreloadedNanoappLoader>(
mConnection.get(), kPreloadedNanoappsConfigPath);
if (mConnection->init()) {
- if (!kPreloadedNanoappsConfigPath.empty()) {
- mPreloadedNanoappLoader->loadPreloadedNanoapps();
- }
+ mPreloadedNanoappLoader->loadPreloadedNanoapps();
+ } else {
+ LOGE("Failed to initialize the connection to CHRE. Restart.");
+ exit(-1);
}
}
void TinysysContextHub::onChreRestarted() {
- if (!kPreloadedNanoappsConfigPath.empty()) {
- mPreloadedNanoappLoader->loadPreloadedNanoapps();
- }
+ mPreloadedNanoappLoader->loadPreloadedNanoapps();
MultiClientContextHubBase::onChreRestarted();
}
} // namespace aidl::android::hardware::contexthub \ No newline at end of file
diff --git a/host/tinysys/hal/tinysys_context_hub.h b/host/tinysys/hal/tinysys_context_hub.h
index 4be2d933..2fbf1bb2 100644
--- a/host/tinysys/hal/tinysys_context_hub.h
+++ b/host/tinysys/hal/tinysys_context_hub.h
@@ -36,6 +36,8 @@ class TinysysContextHub : public MultiClientContextHubBase {
void onChreRestarted() override;
const std::string kPreloadedNanoappsConfigPath =
"/vendor/etc/chre/preloaded_nanoapps.json";
+ const std::string kClientIdMappingFilePath =
+ "/data/vendor/chre/chre_hal_clients.json";
};
} // namespace aidl::android::hardware::contexthub
#endif // ANDROID_HARDWARE_CONTEXTHUB_AIDL_CONTEXTHUB_H
diff --git a/java/test/audio_concurrency/Android.bp b/java/test/audio_concurrency/Android.bp
index 462f7216..064e3760 100644
--- a/java/test/audio_concurrency/Android.bp
+++ b/java/test/audio_concurrency/Android.bp
@@ -33,5 +33,5 @@ java_library {
"chre-test-utils",
],
- sdk_version: "system_current",
+ sdk_version: "test_current",
}
diff --git a/java/test/audio_concurrency/src/com/google/android/chre/test/audioconcurrency/ContextHubAudioConcurrencyTestExecutor.java b/java/test/audio_concurrency/src/com/google/android/chre/test/audioconcurrency/ContextHubAudioConcurrencyTestExecutor.java
index b5345869..b2aae5ec 100644
--- a/java/test/audio_concurrency/src/com/google/android/chre/test/audioconcurrency/ContextHubAudioConcurrencyTestExecutor.java
+++ b/java/test/audio_concurrency/src/com/google/android/chre/test/audioconcurrency/ContextHubAudioConcurrencyTestExecutor.java
@@ -25,6 +25,8 @@ import android.hardware.location.NanoAppMessage;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
import android.util.Log;
import com.google.android.chre.nanoapp.proto.ChreAudioConcurrencyTest;
@@ -65,6 +67,8 @@ public class ContextHubAudioConcurrencyTestExecutor extends ContextHubClientCall
private boolean mInitialized = false;
+ private boolean mVerifyAudioGaps = false;
+
private final AtomicBoolean mChreAudioEnabled = new AtomicBoolean(false);
private final AtomicReference<ChreTestCommon.TestResult> mTestResult = new AtomicReference<>();
@@ -132,21 +136,24 @@ public class ContextHubAudioConcurrencyTestExecutor extends ContextHubClientCall
Assert.assertFalse("init() must not be invoked when already initialized", mInitialized);
ChreTestUtil.loadNanoAppAssertSuccess(mContextHubManager, mContextHubInfo, mNanoAppBinary);
+ mVerifyAudioGaps = shouldVerifyAudioGaps();
mInitialized = true;
}
/**
* Runs the test.
*/
- public void run() {
+ public void run() throws InterruptedException {
// Send a message to the nanoapp to enable CHRE audio
mCountDownLatch = new CountDownLatch(1);
- sendTestCommandMessage(ChreAudioConcurrencyTest.TestCommand.Step.ENABLE_AUDIO);
- try {
- mCountDownLatch.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Assert.fail(e.getMessage());
+ if (mVerifyAudioGaps) {
+ sendTestCommandMessage(
+ ChreAudioConcurrencyTest.TestCommand.Step.ENABLE_AUDIO_WITH_GAP_VERIFICATION);
+ } else {
+ sendTestCommandMessage(ChreAudioConcurrencyTest.TestCommand.Step.ENABLE_AUDIO);
}
+ boolean success = mCountDownLatch.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ Assert.assertTrue("Timeout waiting for signal: ENABLE_AUDIO", success);
Assert.assertTrue("Failed to enable CHRE audio",
mChreAudioEnabled.get() || mTestResult.get() != null);
@@ -155,11 +162,8 @@ public class ContextHubAudioConcurrencyTestExecutor extends ContextHubClientCall
// Send a message to the nanoapp to verify that CHRE audio resumes
mCountDownLatch = new CountDownLatch(1);
sendTestCommandMessage(ChreAudioConcurrencyTest.TestCommand.Step.VERIFY_AUDIO_RESUME);
- try {
- mCountDownLatch.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Assert.fail(e.getMessage());
- }
+ success = mCountDownLatch.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ Assert.assertTrue("Timeout waiting for signal: VERIFY_AUDIO_RESUME", success);
if (mTestResult.get() == null) {
Assert.fail("No test result received");
@@ -231,4 +235,14 @@ public class ContextHubAudioConcurrencyTestExecutor extends ContextHubClientCall
mCountDownLatch.countDown();
}
}
+
+ /**
+ * Returns whether we should verify audio gaps. This is only supported on devices
+ * that are currently running Android U or later and were shipped with Android U
+ * or later.
+ */
+ private boolean shouldVerifyAudioGaps() {
+ return VERSION.SDK_INT >= VERSION_CODES.UPSIDE_DOWN_CAKE &&
+ VERSION.DEVICE_INITIAL_SDK_INT >= VERSION_CODES.UPSIDE_DOWN_CAKE;
+ }
}
diff --git a/java/test/ble_concurrency/src/com/google/android/chre/test/bleconcurrency/ContextHubBleConcurrencyTestExecutor.java b/java/test/ble_concurrency/src/com/google/android/chre/test/bleconcurrency/ContextHubBleConcurrencyTestExecutor.java
index b961f64d..cd1db4d9 100644
--- a/java/test/ble_concurrency/src/com/google/android/chre/test/bleconcurrency/ContextHubBleConcurrencyTestExecutor.java
+++ b/java/test/ble_concurrency/src/com/google/android/chre/test/bleconcurrency/ContextHubBleConcurrencyTestExecutor.java
@@ -16,85 +16,18 @@
package com.google.android.chre.test.bleconcurrency;
-import static com.google.common.truth.Truth.assertThat;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.le.BluetoothLeScanner;
-import android.bluetooth.le.ScanCallback;
-import android.bluetooth.le.ScanFilter;
-import android.bluetooth.le.ScanRecord;
-import android.bluetooth.le.ScanResult;
-import android.bluetooth.le.ScanSettings;
import android.hardware.location.NanoAppBinary;
-import com.google.android.chre.test.chqts.ContextHubChreApiTestExecutor;
-import com.google.android.utils.chre.ChreApiTestUtil;
-import com.google.common.collect.ImmutableList;
-import com.google.protobuf.ByteString;
-
-import org.junit.Assert;
-
-import java.util.HexFormat;
-import java.util.List;
-
-import dev.chre.rpc.proto.ChreApiTest;
+import com.google.android.chre.test.chqts.ContextHubBleTestExecutor;
/**
* A class that can execute the CHRE BLE concurrency test.
*/
-public class ContextHubBleConcurrencyTestExecutor extends ContextHubChreApiTestExecutor {
+public class ContextHubBleConcurrencyTestExecutor extends ContextHubBleTestExecutor {
private static final String TAG = "ContextHubBleConcurrencyTestExecutor";
- /**
- * The delay to report results in milliseconds.
- */
- private static final int REPORT_DELAY_MS = 0;
-
- /**
- * The RSSI threshold for the BLE scan filter.
- */
- private static final int RSSI_THRESHOLD = -128;
-
- /**
- * The advertisement type for service data.
- */
- private static final int CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16 = 0x16;
-
- /**
- * CHRE BLE capabilities and filter capabilities.
- */
- private static final int CHRE_BLE_CAPABILITIES_SCAN = 1 << 0;
- private static final int CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA = 1 << 7;
-
- private BluetoothLeScanner mBluetoothLeScanner = null;
-
- private final ScanCallback mScanCallback = new ScanCallback() {
- @Override
- public void onBatchScanResults(List<ScanResult> results) {
- // do nothing
- }
-
- @Override
- public void onScanFailed(int errorCode) {
- Assert.fail("Failed to start a BLE scan on the host");
- }
-
- @Override
- public void onScanResult(int callbackType, ScanResult result) {
- // do nothing
- }
- };
-
public ContextHubBleConcurrencyTestExecutor(NanoAppBinary nanoapp) {
super(nanoapp);
-
- BluetoothManager bluetoothManager = mContext.getSystemService(BluetoothManager.class);
- assertThat(bluetoothManager).isNotNull();
- BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
- if (bluetoothAdapter != null) {
- mBluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
- }
}
/**
@@ -109,143 +42,6 @@ public class ContextHubBleConcurrencyTestExecutor extends ContextHubChreApiTestE
}
/**
- * Generates a BLE scan filter that filters only for the known Google beacons:
- * Google Eddystone and Nearby Fastpair.
- */
- private static ChreApiTest.ChreBleScanFilter getDefaultScanFilter() {
- ChreApiTest.ChreBleGenericFilter eddystoneFilter =
- ChreApiTest.ChreBleGenericFilter.newBuilder()
- .setType(CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16)
- .setLength(2)
- .setData(ByteString.copyFrom(HexFormat.of().parseHex("AAFE")))
- .setMask(ByteString.copyFrom(HexFormat.of().parseHex("FFFF")))
- .build();
- ChreApiTest.ChreBleGenericFilter nearbyFastpairFilter =
- ChreApiTest.ChreBleGenericFilter.newBuilder()
- .setType(CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16)
- .setLength(2)
- .setData(ByteString.copyFrom(HexFormat.of().parseHex("2CFE")))
- .setMask(ByteString.copyFrom(HexFormat.of().parseHex("FFFF")))
- .build();
-
- return ChreApiTest.ChreBleScanFilter.newBuilder()
- .setRssiThreshold(RSSI_THRESHOLD)
- .setScanFilterCount(2)
- .addScanFilters(eddystoneFilter)
- .addScanFilters(nearbyFastpairFilter)
- .build();
- }
-
- /**
- * Generates a BLE scan filter that filters only for the known Google beacons:
- * Google Eddystone and Nearby Fastpair. We specify the filter data in (little-endian) LE
- * here as the CHRE code will take BE input and transform it to LE.
- */
- private static List<ScanFilter> getDefaultScanFilterHost() {
- assertThat(CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16)
- .isEqualTo(ScanRecord.DATA_TYPE_SERVICE_DATA_16_BIT);
-
- ScanFilter scanFilter = new ScanFilter.Builder()
- .setAdvertisingDataTypeWithData(
- ScanRecord.DATA_TYPE_SERVICE_DATA_16_BIT,
- ByteString.copyFrom(HexFormat.of().parseHex("AAFE")).toByteArray(),
- ByteString.copyFrom(HexFormat.of().parseHex("FFFF")).toByteArray())
- .build();
- ScanFilter scanFilter2 = new ScanFilter.Builder()
- .setAdvertisingDataTypeWithData(
- ScanRecord.DATA_TYPE_SERVICE_DATA_16_BIT,
- ByteString.copyFrom(HexFormat.of().parseHex("2CFE")).toByteArray(),
- ByteString.copyFrom(HexFormat.of().parseHex("FFFF")).toByteArray())
- .build();
-
- return ImmutableList.of(scanFilter, scanFilter2);
- }
-
- /**
- * Starts a BLE scan and asserts it was started successfully in a synchronous manner.
- * This waits for the event to be received and returns the status in the event.
- *
- * @param scanFilter The scan filter.
- */
- private void chreBleStartScanSync(ChreApiTest.ChreBleScanFilter scanFilter) throws Exception {
- ChreApiTest.ChreBleStartScanAsyncInput.Builder inputBuilder =
- ChreApiTest.ChreBleStartScanAsyncInput.newBuilder()
- .setMode(ChreApiTest.ChreBleScanMode.CHRE_BLE_SCAN_MODE_FOREGROUND)
- .setReportDelayMs(REPORT_DELAY_MS)
- .setHasFilter(scanFilter != null);
- if (scanFilter != null) {
- inputBuilder.setFilter(scanFilter);
- }
-
- ChreApiTestUtil util = new ChreApiTestUtil();
- List<ChreApiTest.GeneralSyncMessage> response =
- util.callServerStreamingRpcMethodSync(getRpcClient(),
- "chre.rpc.ChreApiTestService.ChreBleStartScanSync",
- inputBuilder.build());
- assertThat(response).isNotEmpty();
- for (ChreApiTest.GeneralSyncMessage status: response) {
- assertThat(status.getStatus()).isTrue();
- }
- }
-
- /**
- * Stops a BLE scan and asserts it was started successfully in a synchronous manner.
- * This waits for the event to be received and returns the status in the event.
- */
- private void chreBleStopScanSync() throws Exception {
- ChreApiTestUtil util = new ChreApiTestUtil();
- List<ChreApiTest.GeneralSyncMessage> response =
- util.callServerStreamingRpcMethodSync(getRpcClient(),
- "chre.rpc.ChreApiTestService.ChreBleStopScanSync");
- assertThat(response).isNotEmpty();
- for (ChreApiTest.GeneralSyncMessage status: response) {
- assertThat(status.getStatus()).isTrue();
- }
- }
-
- /**
- * Returns true if the required BLE capabilities and filter capabilities exist,
- * otherwise returns false.
- */
- private boolean doesNecessaryBleCapabilitiesExist() throws Exception {
- if (mBluetoothLeScanner == null) {
- return false;
- }
-
- ChreApiTest.Capabilities capabilitiesResponse =
- ChreApiTestUtil.callUnaryRpcMethodSync(getRpcClient(),
- "chre.rpc.ChreApiTestService.ChreBleGetCapabilities");
- int capabilities = capabilitiesResponse.getCapabilities();
- if ((capabilities & CHRE_BLE_CAPABILITIES_SCAN) != 0) {
- ChreApiTest.Capabilities filterCapabilitiesResponse =
- ChreApiTestUtil.callUnaryRpcMethodSync(getRpcClient(),
- "chre.rpc.ChreApiTestService.ChreBleGetFilterCapabilities");
- int filterCapabilities = filterCapabilitiesResponse.getCapabilities();
- return (filterCapabilities & CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA) != 0;
- }
- return false;
- }
-
- /**
- * Starts a BLE scan on the host side with known Google beacon filters.
- */
- private void startBleScanOnHost() {
- ScanSettings scanSettings = new ScanSettings.Builder()
- .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
- .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
- .build();
- mBluetoothLeScanner.startScan(getDefaultScanFilterHost(),
- scanSettings, mScanCallback);
- }
-
- /**
- * Stops a BLE scan on the host side.
- */
- private void stopBleScanOnHost() {
- mBluetoothLeScanner.stopScan(mScanCallback);
- }
-
- /**
* Tests with the host starting scanning first.
*/
private void testHostScanFirst() throws Exception {
diff --git a/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubBleTestExecutor.java b/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubBleTestExecutor.java
new file mode 100644
index 00000000..cdb0e98d
--- /dev/null
+++ b/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubBleTestExecutor.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.chre.test.chqts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertisingSet;
+import android.bluetooth.le.AdvertisingSetCallback;
+import android.bluetooth.le.AdvertisingSetParameters;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanRecord;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.hardware.location.NanoAppBinary;
+import android.os.ParcelUuid;
+
+import com.google.android.utils.chre.ChreApiTestUtil;
+import com.google.common.collect.ImmutableList;
+import com.google.protobuf.ByteString;
+
+import org.junit.Assert;
+
+import java.util.HexFormat;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import dev.chre.rpc.proto.ChreApiTest;
+
+/**
+ * A class that contains common BLE functionality using the CHRE API Test nanoapp.
+ */
+public class ContextHubBleTestExecutor extends ContextHubChreApiTestExecutor {
+ private static final String TAG = "ContextHubBleTestExecutor";
+
+ /**
+ * The Base UUID is used for calculating 128-bit UUIDs from "short UUIDs" (16- and 32-bit).
+ *
+ * @see {https://www.bluetooth.com/specifications/assigned-numbers/service-discovery}
+ */
+ public static final UUID BASE_UUID = UUID.fromString("00000000-0000-1000-8000-00805F9B34FB");
+
+ /**
+ * Used for UUID conversion. This is the bit index where the 16-bit UUID is inserted.
+ */
+ private static final int BIT_INDEX_OF_16_BIT_UUID = 32;
+
+ /**
+ * The ID for the Google Eddystone beacon.
+ */
+ public static final UUID EDDYSTONE_UUID = to128BitUuid((short) 0xFEAA);
+
+ /**
+ * The delay to report results in milliseconds.
+ */
+ private static final int REPORT_DELAY_MS = 0;
+
+ /**
+ * The RSSI threshold for the BLE scan filter.
+ */
+ private static final int RSSI_THRESHOLD = -128;
+
+ /**
+ * The advertisement type for service data.
+ */
+ public static final int CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16 = 0x16;
+
+ /**
+ * The BLE advertisement event ID.
+ */
+ public static final int CHRE_EVENT_BLE_ADVERTISEMENT = 0x0350 + 1;
+
+ /**
+ * CHRE BLE capabilities and filter capabilities.
+ */
+ public static final int CHRE_BLE_CAPABILITIES_SCAN = 1 << 0;
+ public static final int CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA = 1 << 7;
+
+ private BluetoothAdapter mBluetoothAdapter = null;
+ private BluetoothLeAdvertiser mBluetoothLeAdvertiser = null;
+ private BluetoothLeScanner mBluetoothLeScanner = null;
+
+ /**
+ * The signal for advertising start.
+ */
+ private CountDownLatch mAdvertisingStartLatch = new CountDownLatch(1);
+
+ /**
+ * The signal for advertising stop.
+ */
+ private CountDownLatch mAdvertisingStopLatch = new CountDownLatch(1);
+
+ /**
+ * Indicates whether the device is advertising or not.
+ */
+ private AtomicBoolean mIsAdvertising = new AtomicBoolean();
+
+ /**
+ * Callback for BLE scans.
+ */
+ private final ScanCallback mScanCallback = new ScanCallback() {
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ // do nothing
+ }
+
+ @Override
+ public void onScanFailed(int errorCode) {
+ Assert.fail("Failed to start a BLE scan on the host");
+ }
+
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ // do nothing
+ }
+ };
+
+ /**
+ * The BLE advertising callback. It updates the mIsAdvertising state
+ * and notifies any waiting threads that the state of advertising
+ * has changed.
+ */
+ private AdvertisingSetCallback mAdvertisingSetCallback = new AdvertisingSetCallback() {
+ @Override
+ public void onAdvertisingSetStarted(AdvertisingSet advertisingSet,
+ int txPower, int status) {
+ mIsAdvertising.set(true);
+ mAdvertisingStartLatch.countDown();
+ }
+
+ @Override
+ public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {
+ // do nothing
+ }
+
+ @Override
+ public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) {
+ // do nothing
+ }
+
+ @Override
+ public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
+ mIsAdvertising.set(false);
+ mAdvertisingStopLatch.countDown();
+ }
+ };
+
+ public ContextHubBleTestExecutor(NanoAppBinary nanoapp) {
+ super(nanoapp);
+
+ BluetoothManager bluetoothManager = mContext.getSystemService(BluetoothManager.class);
+ assertThat(bluetoothManager).isNotNull();
+ mBluetoothAdapter = bluetoothManager.getAdapter();
+ if (mBluetoothAdapter != null) {
+ mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
+ mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
+ }
+ }
+
+ /**
+ * Generates a BLE scan filter that filters only for the known Google beacons:
+ * Google Eddystone and Nearby Fastpair.
+ *
+ * @param useEddystone if true, filter for Google Eddystone.
+ * @param useNearbyFastpair if true, filter for Nearby Fastpair.
+ */
+ public static ChreApiTest.ChreBleScanFilter getDefaultScanFilter(boolean useEddystone,
+ boolean useNearbyFastpair) {
+ ChreApiTest.ChreBleScanFilter.Builder builder =
+ ChreApiTest.ChreBleScanFilter.newBuilder()
+ .setRssiThreshold(RSSI_THRESHOLD);
+
+ if (useEddystone) {
+ ChreApiTest.ChreBleGenericFilter eddystoneFilter =
+ ChreApiTest.ChreBleGenericFilter.newBuilder()
+ .setType(CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16)
+ .setLength(2)
+ .setData(ByteString.copyFrom(HexFormat.of().parseHex("AAFE")))
+ .setMask(ByteString.copyFrom(HexFormat.of().parseHex("FFFF")))
+ .build();
+ builder = builder.addScanFilters(eddystoneFilter);
+ }
+
+ if (useNearbyFastpair) {
+ ChreApiTest.ChreBleGenericFilter nearbyFastpairFilter =
+ ChreApiTest.ChreBleGenericFilter.newBuilder()
+ .setType(CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16)
+ .setLength(2)
+ .setData(ByteString.copyFrom(HexFormat.of().parseHex("2CFE")))
+ .setMask(ByteString.copyFrom(HexFormat.of().parseHex("FFFF")))
+ .build();
+ builder = builder.addScanFilters(nearbyFastpairFilter);
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Generates a BLE scan filter that filters only for the known Google beacons:
+ * Google Eddystone and Nearby Fastpair.
+ */
+ public static ChreApiTest.ChreBleScanFilter getDefaultScanFilter() {
+ return getDefaultScanFilter(true /* useEddystone */, true /* useNearbyFastpair */);
+ }
+
+ /**
+ * Generates a BLE scan filter that filters only for Google Eddystone.
+ */
+ public static ChreApiTest.ChreBleScanFilter getGoogleEddystoneScanFilter() {
+ return getDefaultScanFilter(true /* useEddystone */, false /* useNearbyFastpair */);
+ }
+
+ /**
+ * Generates a BLE scan filter that filters only for the known Google beacons:
+ * Google Eddystone and Nearby Fastpair. We specify the filter data in (little-endian) LE
+ * here as the CHRE code will take BE input and transform it to LE.
+ */
+ public static List<ScanFilter> getDefaultScanFilterHost() {
+ assertThat(CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16)
+ .isEqualTo(ScanRecord.DATA_TYPE_SERVICE_DATA_16_BIT);
+
+ ScanFilter scanFilter = new ScanFilter.Builder()
+ .setAdvertisingDataTypeWithData(
+ ScanRecord.DATA_TYPE_SERVICE_DATA_16_BIT,
+ ByteString.copyFrom(HexFormat.of().parseHex("AAFE")).toByteArray(),
+ ByteString.copyFrom(HexFormat.of().parseHex("FFFF")).toByteArray())
+ .build();
+ ScanFilter scanFilter2 = new ScanFilter.Builder()
+ .setAdvertisingDataTypeWithData(
+ ScanRecord.DATA_TYPE_SERVICE_DATA_16_BIT,
+ ByteString.copyFrom(HexFormat.of().parseHex("2CFE")).toByteArray(),
+ ByteString.copyFrom(HexFormat.of().parseHex("FFFF")).toByteArray())
+ .build();
+
+ return ImmutableList.of(scanFilter, scanFilter2);
+ }
+
+ /**
+ * Starts a BLE scan and asserts it was started successfully in a synchronous manner.
+ * This waits for the event to be received and returns the status in the event.
+ *
+ * @param scanFilter The scan filter.
+ */
+ public void chreBleStartScanSync(ChreApiTest.ChreBleScanFilter scanFilter) throws Exception {
+ ChreApiTest.ChreBleStartScanAsyncInput.Builder inputBuilder =
+ ChreApiTest.ChreBleStartScanAsyncInput.newBuilder()
+ .setMode(ChreApiTest.ChreBleScanMode.CHRE_BLE_SCAN_MODE_FOREGROUND)
+ .setReportDelayMs(REPORT_DELAY_MS)
+ .setHasFilter(scanFilter != null);
+ if (scanFilter != null) {
+ inputBuilder.setFilter(scanFilter);
+ }
+
+ ChreApiTestUtil util = new ChreApiTestUtil();
+ List<ChreApiTest.GeneralSyncMessage> response =
+ util.callServerStreamingRpcMethodSync(getRpcClient(),
+ "chre.rpc.ChreApiTestService.ChreBleStartScanSync",
+ inputBuilder.build());
+ assertThat(response).isNotEmpty();
+ for (ChreApiTest.GeneralSyncMessage status: response) {
+ assertThat(status.getStatus()).isTrue();
+ }
+ }
+
+ /**
+ * Stops a BLE scan and asserts it was started successfully in a synchronous manner.
+ * This waits for the event to be received and returns the status in the event.
+ */
+ public void chreBleStopScanSync() throws Exception {
+ ChreApiTestUtil util = new ChreApiTestUtil();
+ List<ChreApiTest.GeneralSyncMessage> response =
+ util.callServerStreamingRpcMethodSync(getRpcClient(),
+ "chre.rpc.ChreApiTestService.ChreBleStopScanSync");
+ assertThat(response).isNotEmpty();
+ for (ChreApiTest.GeneralSyncMessage status: response) {
+ assertThat(status.getStatus()).isTrue();
+ }
+ }
+
+ /**
+ * Returns true if the required BLE capabilities and filter capabilities exist,
+ * otherwise returns false.
+ */
+ public boolean doesNecessaryBleCapabilitiesExist() throws Exception {
+ if (mBluetoothLeScanner == null) {
+ return false;
+ }
+
+ ChreApiTest.Capabilities capabilitiesResponse =
+ ChreApiTestUtil.callUnaryRpcMethodSync(getRpcClient(),
+ "chre.rpc.ChreApiTestService.ChreBleGetCapabilities");
+ int capabilities = capabilitiesResponse.getCapabilities();
+ if ((capabilities & CHRE_BLE_CAPABILITIES_SCAN) != 0) {
+ ChreApiTest.Capabilities filterCapabilitiesResponse =
+ ChreApiTestUtil.callUnaryRpcMethodSync(getRpcClient(),
+ "chre.rpc.ChreApiTestService.ChreBleGetFilterCapabilities");
+ int filterCapabilities = filterCapabilitiesResponse.getCapabilities();
+ return (filterCapabilities & CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA) != 0;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the required BLE capabilities and filter capabilities exist
+ * on the AP, otherwise returns false.
+ */
+ public boolean doesNecessaryBleCapabilitiesExistOnTheAP() throws Exception {
+ return mBluetoothLeAdvertiser != null;
+ }
+
+ /**
+ * Starts a BLE scan on the host side with known Google beacon filters.
+ */
+ public void startBleScanOnHost() {
+ ScanSettings scanSettings = new ScanSettings.Builder()
+ .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
+ .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+ .build();
+ mBluetoothLeScanner.startScan(getDefaultScanFilterHost(),
+ scanSettings, mScanCallback);
+ }
+
+ /**
+ * Stops a BLE scan on the host side.
+ */
+ public void stopBleScanOnHost() {
+ mBluetoothLeScanner.stopScan(mScanCallback);
+ }
+
+ /**
+ * Starts broadcasting the Google Eddystone beacon from the AP.
+ */
+ public void startBleAdvertisingGoogleEddystone() throws InterruptedException {
+ if (mIsAdvertising.get()) {
+ return;
+ }
+
+ AdvertisingSetParameters parameters = (new AdvertisingSetParameters.Builder())
+ .setLegacyMode(true)
+ .setConnectable(false)
+ .setInterval(AdvertisingSetParameters.INTERVAL_HIGH)
+ .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_HIGH)
+ .build();
+
+ AdvertiseData data = new AdvertiseData.Builder()
+ .addServiceData(new ParcelUuid(EDDYSTONE_UUID), new byte[] {0})
+ .setIncludeDeviceName(false)
+ .setIncludeTxPowerLevel(true)
+ .build();
+
+ mBluetoothLeAdvertiser.startAdvertisingSet(parameters, data,
+ null, null, null, mAdvertisingSetCallback);
+ mAdvertisingStartLatch.await();
+ assertThat(mIsAdvertising.get()).isTrue();
+ }
+
+ /**
+ * Stops advertising Google Eddystone from the AP.
+ */
+ public void stopBleAdvertisingGoogleEddystone() throws InterruptedException {
+ if (!mIsAdvertising.get()) {
+ return;
+ }
+
+ mBluetoothLeAdvertiser.stopAdvertisingSet(mAdvertisingSetCallback);
+ mAdvertisingStopLatch.await();
+ assertThat(mIsAdvertising.get()).isFalse();
+ }
+
+ /**
+ * Converts short UUID to 128 bit UUID.
+ */
+ private static UUID to128BitUuid(short shortUuid) {
+ return new UUID(
+ ((shortUuid & 0xFFFFL) << BIT_INDEX_OF_16_BIT_UUID)
+ | BASE_UUID.getMostSignificantBits(),
+ BASE_UUID.getLeastSignificantBits());
+ }
+}
diff --git a/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubChreApiTestExecutor.java b/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubChreApiTestExecutor.java
index 28b363f0..b3c23366 100644
--- a/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubChreApiTestExecutor.java
+++ b/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubChreApiTestExecutor.java
@@ -42,7 +42,6 @@ import dev.pigweed.pw_rpc.Service;
*/
public class ContextHubChreApiTestExecutor extends ContextHubClientCallback {
private final List<NanoAppBinary> mNanoAppBinaries;
- private final List<Long> mNanoAppIds = new ArrayList<Long>();
private final ContextHubClient mContextHubClient;
private final AtomicBoolean mChreReset = new AtomicBoolean(false);
protected final Context mContext = InstrumentationRegistry.getTargetContext();
@@ -64,7 +63,6 @@ public class ContextHubChreApiTestExecutor extends ContextHubClientCallback {
mContextHubClient = mContextHubManager.createClient(mContextHub, this);
for (NanoAppBinary nanoapp: nanoapps) {
- mNanoAppIds.add(nanoapp.getNanoAppId());
Service chreApiService = ChreApiTestUtil.getChreApiService();
mRpcClients.add(new ChreRpcClient(
mContextHubManager, mContextHub, nanoapp.getNanoAppId(),
@@ -79,7 +77,6 @@ public class ContextHubChreApiTestExecutor extends ContextHubClientCallback {
/** Should be invoked before run() is invoked to set up the test, e.g. in a @Before method. */
public void init() {
- mContextHubManager.enableTestMode();
for (NanoAppBinary nanoapp: mNanoAppBinaries) {
ChreTestUtil.loadNanoAppAssertSuccess(mContextHubManager, mContextHub, nanoapp);
}
@@ -91,10 +88,10 @@ public class ContextHubChreApiTestExecutor extends ContextHubClientCallback {
Assert.fail("CHRE reset during the test");
}
- for (Long nanoappId: mNanoAppIds) {
- ChreTestUtil.unloadNanoAppAssertSuccess(mContextHubManager, mContextHub, nanoappId);
+ for (NanoAppBinary nanoapp: mNanoAppBinaries) {
+ ChreTestUtil.unloadNanoAppAssertSuccess(mContextHubManager, mContextHub,
+ nanoapp.getNanoAppId());
}
- mContextHubManager.disableTestMode();
mContextHubClient.close();
}
diff --git a/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubGeneralTestExecutor.java b/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubGeneralTestExecutor.java
index 10680f2c..355d0ced 100644
--- a/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubGeneralTestExecutor.java
+++ b/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubGeneralTestExecutor.java
@@ -15,6 +15,12 @@
*/
package com.google.android.chre.test.chqts;
+import android.app.Instrumentation;
+import android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.hardware.location.ContextHubClient;
import android.hardware.location.ContextHubClientCallback;
import android.hardware.location.ContextHubInfo;
@@ -25,6 +31,7 @@ import android.hardware.location.NanoAppMessage;
import android.util.Log;
import com.google.android.utils.chre.ChreTestUtil;
+import com.google.android.utils.chre.SettingsUtil;
import org.junit.Assert;
@@ -74,6 +81,28 @@ public abstract class ContextHubGeneralTestExecutor extends ContextHubClientCall
private long mThreadId;
+ private final Instrumentation mInstrumentation =
+ androidx.test.platform.app.InstrumentationRegistry.getInstrumentation();
+
+ private final Context mContext = mInstrumentation.getTargetContext();
+
+ private final SettingsUtil mSettingsUtil;
+
+ private boolean mInitialBluetoothEnabled = false;
+
+ public static class BluetoothUpdateListener {
+ public CountDownLatch mBluetoothLatch = new CountDownLatch(1);
+
+ public BroadcastReceiver mBluetoothUpdateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
+ mBluetoothLatch.countDown();
+ }
+ }
+ };
+ }
+
/**
* A container class to describe a general_test nanoapp.
*/
@@ -145,6 +174,7 @@ public abstract class ContextHubGeneralTestExecutor extends ContextHubClientCall
for (GeneralTestNanoApp test : mGeneralTestNanoAppList) {
mNanoAppIdSet.add(test.getNanoAppBinary().getNanoAppId());
}
+ mSettingsUtil = new SettingsUtil(mContext);
}
@Override
@@ -200,6 +230,9 @@ public abstract class ContextHubGeneralTestExecutor extends ContextHubClientCall
mContextHubClient = mContextHubManager.createClient(mContextHubInfo, this);
for (GeneralTestNanoApp test : mGeneralTestNanoAppList) {
+ if (test.getTestName() == ContextHubTestConstants.TestNames.BASIC_BLE_TEST) {
+ handleBleTestSetup();
+ }
if (test.loadAtInit()) {
ChreTestUtil.loadNanoAppAssertSuccess(mContextHubManager, mContextHubInfo,
test.getNanoAppBinary());
@@ -209,10 +242,33 @@ public abstract class ContextHubGeneralTestExecutor extends ContextHubClientCall
mErrorString.set(null);
}
+ private void handleBleTestSetup() {
+ mInitialBluetoothEnabled = mSettingsUtil.isBluetoothEnabled();
+ Log.i(TAG, "Initial bluetooth setting enabled: " + mInitialBluetoothEnabled);
+ if (mInitialBluetoothEnabled) {
+ return;
+ }
+ BluetoothUpdateListener bluetoothUpdateListener = new BluetoothUpdateListener();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+ mContext.registerReceiver(bluetoothUpdateListener.mBluetoothUpdateReceiver, filter);
+ mSettingsUtil.setBluetooth(true /* enable */);
+ try {
+ bluetoothUpdateListener.mBluetoothLatch.await(10, TimeUnit.SECONDS);
+ Assert.assertTrue(mSettingsUtil.isBluetoothEnabled());
+ Log.i(TAG, "Bluetooth enabled successfully");
+ // Wait a few seconds to ensure setting is propagated to CHRE path
+ // TODO(b/302018530): Remove Thread.sleep calls for CHRE settings propagation
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
/**
* Run the test.
*/
- public void run(long timeoutSeconds) {
+ public void run(long timeoutSeconds) throws InterruptedException {
mThreadId = Thread.currentThread().getId();
for (GeneralTestNanoApp test : mGeneralTestNanoAppList) {
@@ -222,13 +278,7 @@ public abstract class ContextHubGeneralTestExecutor extends ContextHubClientCall
}
}
- boolean success = false;
- try {
- success = mCountDownLatch.await(timeoutSeconds, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Assert.fail(e.getMessage());
- }
-
+ boolean success = mCountDownLatch.await(timeoutSeconds, TimeUnit.SECONDS);
Assert.assertTrue("Test timed out", success);
}
@@ -248,6 +298,10 @@ public abstract class ContextHubGeneralTestExecutor extends ContextHubClientCall
// TODO: If the nanoapp aborted (i.e. test failed), wait for CHRE reset or nanoapp abort
// callback, and otherwise assert unload success.
for (GeneralTestNanoApp test : mGeneralTestNanoAppList) {
+ if (test.getTestName() == ContextHubTestConstants.TestNames.BASIC_BLE_TEST
+ && !mInitialBluetoothEnabled) {
+ mSettingsUtil.setBluetooth(mInitialBluetoothEnabled);
+ }
ChreTestUtil.unloadNanoApp(mContextHubManager, mContextHubInfo,
test.getNanoAppBinary().getNanoAppId());
}
diff --git a/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubHostEndpointInfoTestExecutor.java b/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubHostEndpointInfoTestExecutor.java
index 7290ab89..2843cb4d 100644
--- a/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubHostEndpointInfoTestExecutor.java
+++ b/java/test/chqts/src/com/google/android/chre/test/chqts/ContextHubHostEndpointInfoTestExecutor.java
@@ -19,30 +19,43 @@ package com.google.android.chre.test.chqts;
import android.hardware.location.ContextHubClient;
import android.hardware.location.NanoAppBinary;
+import androidx.annotation.NonNull;
+
import com.google.android.utils.chre.ChreApiTestUtil;
import org.junit.Assert;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
import dev.chre.rpc.proto.ChreApiTest;
/**
* Test to ensure CHRE HostEndpoint related API works as expected.
*/
public class ContextHubHostEndpointInfoTestExecutor extends ContextHubChreApiTestExecutor {
+ private static final int HOST_ENDPOINT_NOTIFICATION_TYPE_DISCONNECT = 0;
+ private static final int CHRE_HOST_ENDPOINT_NOTIFICATION_EVENT = 0x0008;
+
public ContextHubHostEndpointInfoTestExecutor(NanoAppBinary nanoapp) {
super(nanoapp);
}
/**
- * Validates if the host endpoint info stored in ChreApiTest Nanoapp is as expected.
+ * Validates if the host endpoint info stored in ChreApiTest Nanoapp is as
+ * expected.
*
- * @param id the host endpoint id of the host endpoint.
- * @param success true if we are expecting to retrieve host endpoint info by this id, otherwise
- * false.
+ * @param id the host endpoint id of the host endpoint.
+ * @param success true if we are expecting to retrieve host endpoint info by
+ * this id, otherwise false.
*/
private void validateHostEndpointInfoById(int id, boolean success) throws Exception {
ChreApiTest.ChreGetHostEndpointInfoInput input =
- ChreApiTest.ChreGetHostEndpointInfoInput.newBuilder().setHostEndpointId(id).build();
+ ChreApiTest.ChreGetHostEndpointInfoInput.newBuilder()
+ .setHostEndpointId(id)
+ .build();
ChreApiTest.ChreGetHostEndpointInfoOutput response =
ChreApiTestUtil.callUnaryRpcMethodSync(
getRpcClient(), "chre.rpc.ChreApiTestService.ChreGetHostEndpointInfo",
@@ -84,25 +97,31 @@ public class ContextHubHostEndpointInfoTestExecutor extends ContextHubChreApiTes
* Validates if the nanoapp received a proper host endpoint notification disconnection event.
*
* @param id host endpoint id for the most recent disconnected host endpoint.
+ * @param events host endpoint notification events received by the nanoapp.
*/
- private void validateLatestHostEndpointNotification(int id) throws Exception {
- // TODO(b/274791978): Deprecate this once we can capture event in test mode.
- ChreApiTest.RetrieveLatestDisconnectedHostEndpointEventOutput response =
- ChreApiTestUtil.callUnaryRpcMethodSync(
- getRpcClient(),
- "chre.rpc.ChreApiTestService.RetrieveLatestDisconnectedHostEndpointEvent");
+ private void validateChreHostEndpointNotification(int id,
+ @NonNull List<ChreApiTest.GeneralEventsMessage> events) throws Exception {
+ Objects.requireNonNull(events);
Assert.assertEquals(
"Should have exactly receive 1 host endpoint notification",
- 1,
- response.getDisconnectedCount());
- Assert.assertEquals("Host endpoint Id mismatch", response.getHostEndpointId(), id);
+ 1, events.size());
+ ChreApiTest.ChreHostEndpointNotification hostEndpointNotification =
+ events.get(0).getChreHostEndpointNotification();
+ Assert.assertTrue(events.get(0).getStatus());
+ Assert.assertEquals("Host endpoint Id mismatch", id,
+ hostEndpointNotification.getHostEndpointId());
+
+ Assert.assertEquals("Not receive HOST_ENDPOINT_NOTIFICATION_TYPE_DISCONNECT",
+ HOST_ENDPOINT_NOTIFICATION_TYPE_DISCONNECT,
+ hostEndpointNotification.getNotificationType());
}
/**
* Asks the test nanoapp to configure host endpoint notification.
*
* @param hostEndpointId which host endpoint to get notification.
- * @param enable true to enable host endpoint notification, false to disable.
+ * @param enable true to enable host endpoint notification, false to
+ * disable.
*/
private void configureHostEndpointNotification(int hostEndpointId, boolean enable)
throws Exception {
@@ -127,8 +146,15 @@ public class ContextHubHostEndpointInfoTestExecutor extends ContextHubChreApiTes
ContextHubClient client = mContextHubManager.createClient(mContextHub, this);
int clientHostEndpointId = client.getId();
configureHostEndpointNotification(clientHostEndpointId, true);
+ Future<List<ChreApiTest.GeneralEventsMessage>> eventsFuture = new ChreApiTestUtil()
+ .gatherEvents(mRpcClients.get(0),
+ CHRE_HOST_ENDPOINT_NOTIFICATION_EVENT,
+ /* eventCount= */ 1,
+ ChreApiTestUtil.RPC_TIMEOUT_IN_NS);
client.close();
- Thread.sleep(1000);
- validateLatestHostEndpointNotification(clientHostEndpointId);
+ List<ChreApiTest.GeneralEventsMessage> events =
+ eventsFuture.get(2 * ChreApiTestUtil.RPC_TIMEOUT_IN_NS,
+ TimeUnit.NANOSECONDS);
+ validateChreHostEndpointNotification(clientHostEndpointId, events);
}
}
diff --git a/java/test/chqts/src/com/google/android/chre/test/chqts/multidevice/ContextHubMultiDeviceBleBeaconTestExecutor.java b/java/test/chqts/src/com/google/android/chre/test/chqts/multidevice/ContextHubMultiDeviceBleBeaconTestExecutor.java
new file mode 100644
index 00000000..19f04915
--- /dev/null
+++ b/java/test/chqts/src/com/google/android/chre/test/chqts/multidevice/ContextHubMultiDeviceBleBeaconTestExecutor.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.chre.test.chqts.multidevice;
+
+import android.hardware.location.NanoAppBinary;
+
+import com.google.android.chre.test.chqts.ContextHubBleTestExecutor;
+import com.google.android.utils.chre.ChreApiTestUtil;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Future;
+
+import dev.chre.rpc.proto.ChreApiTest;
+
+public class ContextHubMultiDeviceBleBeaconTestExecutor extends ContextHubBleTestExecutor {
+ private static final int NUM_EVENTS_TO_GATHER = 10;
+
+ private static final long TIMEOUT_IN_S = 30;
+
+ private static final long TIMEOUT_IN_NS = TIMEOUT_IN_S * 1000000000L;
+
+ public ContextHubMultiDeviceBleBeaconTestExecutor(NanoAppBinary nanoapp) {
+ super(nanoapp);
+ }
+
+ /**
+ * Gathers BLE advertisement events from the nanoapp for TIMEOUT_IN_NS or up to
+ * NUM_EVENTS_TO_GATHER events. This function returns true if all
+ * chreBleAdvertisingReport's contain advertisments for Google Eddystone and
+ * there is at least one advertisement, otherwise it returns false.
+ */
+ public boolean gatherAndVerifyChreBleAdvertisementsForGoogleEddystone() throws Exception {
+ Future<List<ChreApiTest.GeneralEventsMessage>> eventsFuture =
+ new ChreApiTestUtil().gatherEvents(
+ mRpcClients.get(0),
+ Arrays.asList(CHRE_EVENT_BLE_ADVERTISEMENT),
+ NUM_EVENTS_TO_GATHER,
+ TIMEOUT_IN_NS);
+
+ List<ChreApiTest.GeneralEventsMessage> events = eventsFuture.get();
+ if (events == null) {
+ return false;
+ }
+
+ boolean foundGoogleEddystoneBleAdvertisement = false;
+ for (ChreApiTest.GeneralEventsMessage event: events) {
+ if (!event.hasChreBleAdvertisementEvent()) {
+ continue;
+ }
+
+ ChreApiTest.ChreBleAdvertisementEvent bleAdvertisementEvent =
+ event.getChreBleAdvertisementEvent();
+ for (int i = 0; i < bleAdvertisementEvent.getReportsCount(); ++i) {
+ ChreApiTest.ChreBleAdvertisingReport report = bleAdvertisementEvent.getReports(i);
+ byte[] data = report.getData().toByteArray();
+ if (data == null || data.length < 2) {
+ continue;
+ }
+
+ if (!searchForGoogleEddystoneAdvertisement(data)) {
+ return false;
+ }
+ foundGoogleEddystoneBleAdvertisement = true;
+ }
+ }
+ return foundGoogleEddystoneBleAdvertisement;
+ }
+
+ /**
+ * Starts a BLE scan with the Google Eddystone filter.
+ */
+ public void chreBleStartScanSyncWithGoogleEddystoneFilter() throws Exception {
+ chreBleStartScanSync(getGoogleEddystoneScanFilter());
+ }
+
+ /**
+ * Returns true if the data contains an advertisement for Google Eddystone,
+ * otherwise returns false.
+ */
+ private boolean searchForGoogleEddystoneAdvertisement(byte[] data) {
+ if (data.length < 2) {
+ return false;
+ }
+
+ for (int j = 0; j < data.length - 1; ++j) {
+ if (Byte.compare(data[j], (byte) 0xAA) == 0
+ && Byte.compare(data[j + 1], (byte) 0xFE) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/java/test/chre_concurrency/src/com/google/android/chre/test/chreconcurrency/ContextHubChreConcurrencyTestExecutor.java b/java/test/chre_concurrency/src/com/google/android/chre/test/chreconcurrency/ContextHubChreConcurrencyTestExecutor.java
index 46101794..81460af7 100644
--- a/java/test/chre_concurrency/src/com/google/android/chre/test/chreconcurrency/ContextHubChreConcurrencyTestExecutor.java
+++ b/java/test/chre_concurrency/src/com/google/android/chre/test/chreconcurrency/ContextHubChreConcurrencyTestExecutor.java
@@ -56,12 +56,18 @@ public class ContextHubChreConcurrencyTestExecutor extends ContextHubChreApiTest
private static final long TIMEOUT_IN_NS = 5000000000L;
/**
- * The multiplier used to allow for jitter in the timestamps of the samples. This is
+ * The multiplier used to allow for jitter in the intervals of the samples. This is
* multiplied against the requested interval between samples to produce the final interval
* that is compared with the real interval between samples. This allows for 5% of jitter.
*/
private static final double JITTER_MULTIPLIER = 1.05;
+ /**
+ * The sum of the intervals in ns and timestamp count. Used to calculate the average interval.
+ */
+ private double mIntervalSumNs = 0;
+ private int mTimestampCount = 0;
+
public ContextHubChreConcurrencyTestExecutor(NanoAppBinary nanoapp, NanoAppBinary nanoapp2) {
super(Arrays.asList(nanoapp, nanoapp2));
}
@@ -203,19 +209,30 @@ public class ContextHubChreConcurrencyTestExecutor extends ContextHubChreApiTest
List<ChreApiTest.GeneralEventsMessage> events,
long requestedIntervalNs) {
assertThat(events).isNotNull();
+
Long lastReadingTimestamp = null;
+ mIntervalSumNs = 0;
+ mTimestampCount = 0;
for (ChreApiTest.GeneralEventsMessage event: events) {
Assert.assertTrue(event.getStatus());
if (event.hasChreSensorThreeAxisData()) {
lastReadingTimestamp = handleChreSensorThreeAxisData(event, requestedIntervalNs,
lastReadingTimestamp, accelerometerHandle);
} else if (event.hasChreSensorSamplingStatusEvent()) {
+ // The interval will change due to the sampling status event.
+ // Assert the past data was good and continue with fresh data.
+ assertAverageIntervalIsLessThanOrEqualToTheRequestedInterval(requestedIntervalNs);
+
+ mIntervalSumNs = 0;
+ mTimestampCount = 0;
requestedIntervalNs = handleChreSensorSamplingStatusEvent(event,
requestedIntervalNs, accelerometerHandle);
} else {
Assert.fail("Event does not contain any requested data.");
}
}
+
+ assertAverageIntervalIsLessThanOrEqualToTheRequestedInterval(requestedIntervalNs);
}
/**
@@ -231,8 +248,8 @@ public class ContextHubChreConcurrencyTestExecutor extends ContextHubChreApiTest
long requestedIntervalNs, Long lastReadingTimestamp, int accelerometerHandle) {
ChreApiTest.ChreSensorThreeAxisData data = event.getChreSensorThreeAxisData();
Assert.assertEquals(data.getHeader().getSensorHandle(), accelerometerHandle);
-
assertThat(data.getReadingsCount()).isGreaterThan(0);
+
for (int i = 0; i < data.getReadingsCount(); ++i) {
ChreApiTest.ChreSensorThreeAxisSampleData sampleData = data.getReadings(i);
@@ -243,11 +260,8 @@ public class ContextHubChreConcurrencyTestExecutor extends ContextHubChreApiTest
? data.getHeader().getBaseTimestamp()
: lastReadingTimestamp) + sampleData.getTimestampDelta();
if (lastReadingTimestamp != null) {
- Assert.assertTrue("Invalid timestamp between samples: interval: "
- + (readingTimestamp - lastReadingTimestamp)
- + ", requestedIntervalNs: " + requestedIntervalNs,
- readingTimestamp <= requestedIntervalNs * JITTER_MULTIPLIER
- + lastReadingTimestamp);
+ mIntervalSumNs += readingTimestamp - lastReadingTimestamp;
+ ++mTimestampCount;
}
lastReadingTimestamp = readingTimestamp;
}
@@ -271,4 +285,22 @@ public class ContextHubChreConcurrencyTestExecutor extends ContextHubChreApiTest
ChreApiTest.ChreSensorSamplingStatus samplingStatus = samplingStatusEvent.getStatus();
return samplingStatus.getEnabled() ? samplingStatus.getInterval() : requestedIntervalNs;
}
+
+ /**
+ * Asserts that the average interval is less than the requested interval (both in ns),
+ * accounting for jitter.
+ *
+ * @param requestedIntervalNs the requested interval in ns.
+ */
+ private void assertAverageIntervalIsLessThanOrEqualToTheRequestedInterval(
+ long requestedIntervalNs) {
+ if (mTimestampCount <= 0) {
+ return;
+ }
+
+ double averageIntervalNs = mIntervalSumNs / mTimestampCount;
+ Assert.assertTrue("Invalid average timestamp between samples: averageIntervalNs: "
+ + averageIntervalNs + ", requestedIntervalNs: " + requestedIntervalNs,
+ averageIntervalNs <= requestedIntervalNs * JITTER_MULTIPLIER);
+ }
}
diff --git a/java/test/cross_validation/Android.bp b/java/test/cross_validation/Android.bp
index e56416cf..0d3a2d1e 100644
--- a/java/test/cross_validation/Android.bp
+++ b/java/test/cross_validation/Android.bp
@@ -35,5 +35,5 @@ java_library {
"guava",
],
- sdk_version: "system_current",
+ sdk_version: "test_current",
}
diff --git a/java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorBase.java b/java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorBase.java
index 5028b9bf..c5641274 100644
--- a/java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorBase.java
+++ b/java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorBase.java
@@ -24,6 +24,8 @@ import android.hardware.location.ContextHubTransaction;
import android.hardware.location.NanoAppBinary;
import android.hardware.location.NanoAppMessage;
import android.hardware.location.NanoAppState;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
import android.util.Log;
import com.google.android.utils.chre.ChreTestUtil;
@@ -101,7 +103,7 @@ abstract class ChreCrossValidatorBase {
* @param samplingDurationInMs The amount of time in milliseconds to collect samples from AP and
* CHRE.
*/
- public abstract void validate() throws AssertionError;
+ public abstract void validate() throws AssertionError, InterruptedException;
/**
* Clean up resources allocated for cross validation. Subclasses should override this method and
@@ -122,6 +124,13 @@ abstract class ChreCrossValidatorBase {
* with data received.
*/
private void unloadAllNanoApps() {
+ // We only need to unload all nanoapps when the device has version < U, so the
+ // tests remain the same on those devices. On newer devices, test mode will
+ // handle this.
+ if (VERSION.SDK_INT >= VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ return;
+ }
+
List<NanoAppState> nanoAppStateList =
ChreTestUtil.queryNanoAppsAssertSuccess(mContextHubManager, mContextHubInfo);
diff --git a/java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorSensor.java b/java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorSensor.java
index d53f4080..f6a43214 100644
--- a/java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorSensor.java
+++ b/java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorSensor.java
@@ -150,7 +150,7 @@ public class ChreCrossValidatorSensor
}
@Override
- public void validate() throws AssertionError {
+ public void validate() throws AssertionError, InterruptedException {
HashSet<Integer> testedSensorIndices = new HashSet<>();
for (int i = 0; i < mSensorList.size(); i++) {
mApDatapointsQueue.clear();
@@ -453,12 +453,9 @@ public class ChreCrossValidatorSensor
* @param samplingDurationInMs The amount of time to wait for AP and CHRE to collected data in
* ms.
*/
- private void waitForDataSampling() throws AssertionError {
- try {
- mAwaitDataLatch.await(getAwaitDataTimeoutInMs(), TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- Assert.fail("await data latch interrupted");
- }
+ private void waitForDataSampling() throws AssertionError, InterruptedException {
+ mAwaitDataLatch.await(getAwaitDataTimeoutInMs(), TimeUnit.MILLISECONDS);
+
if (mErrorStr.get() != null) {
Assert.fail(mErrorStr.get());
}
@@ -543,21 +540,15 @@ public class ChreCrossValidatorSensor
/**
* Verify the CHRE sensor being evaluated is present on this device.
*/
- private void verifyChreSensorIsPresent() {
+ private void verifyChreSensorIsPresent() throws InterruptedException {
mCollectingData.set(true);
sendMessageToNanoApp(makeInfoCommandMessage());
waitForInfoResponse();
mCollectingData.set(false);
}
- private void waitForInfoResponse() {
- boolean success = false;
- try {
- success = mAwaitDataLatch.await(INFO_RESPONSE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- Assert.fail("await data latch interrupted");
- }
-
+ private void waitForInfoResponse() throws InterruptedException {
+ boolean success = mAwaitDataLatch.await(INFO_RESPONSE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (!success) {
Assert.fail("Timed out waiting for sensor info response");
}
diff --git a/java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorWifi.java b/java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorWifi.java
index 812fe3a0..e9f9f92c 100644
--- a/java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorWifi.java
+++ b/java/test/cross_validation/src/com/google/android/chre/test/crossvalidator/ChreCrossValidatorWifi.java
@@ -41,6 +41,7 @@ import org.junit.Assert;
import org.junit.Assume;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -104,7 +105,7 @@ public class ChreCrossValidatorWifi extends ChreCrossValidatorBase {
context.registerReceiver(mWifiScanReceiver, intentFilter);
}
- @Override public void validate() throws AssertionError {
+ @Override public void validate() throws AssertionError, InterruptedException {
mCollectingData.set(true);
sendStepStartMessage(Step.CAPABILITIES);
waitForMessageFromNanoapp();
@@ -183,12 +184,10 @@ public class ChreCrossValidatorWifi extends ChreCrossValidatorBase {
/**
* Wait for a messaage from the nanoapp.
*/
- private void waitForMessageFromNanoapp() {
- try {
- mAwaitDataLatch.await(AWAIT_STEP_RESULT_MESSAGE_TIMEOUT_SEC, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Assert.fail("Interrupted while awaiting " + getCurrentStepName() + " step");
- }
+ private void waitForMessageFromNanoapp() throws InterruptedException {
+ boolean success =
+ mAwaitDataLatch.await(AWAIT_STEP_RESULT_MESSAGE_TIMEOUT_SEC, TimeUnit.SECONDS);
+ Assert.assertTrue("Timeout waiting for signal: wait for message from nanoapp", success);
mAwaitDataLatch = new CountDownLatch(1);
Assert.assertTrue("Timed out while waiting for step result in " + getCurrentStepName()
+ " step", mDidReceiveNanoAppMessage.get());
@@ -207,18 +206,31 @@ public class ChreCrossValidatorWifi extends ChreCrossValidatorBase {
&& (capabilities.getWifiCapabilities() & WIFI_CAPABILITIES_ON_DEMAND_SCAN) != 0;
}
- private void waitForApScanResults() {
- try {
- mAwaitApWifiSetupScan.await(AWAIT_WIFI_SCAN_RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Assert.fail("Interrupted while awaiting ap wifi scan result");
- }
+ private void waitForApScanResults() throws InterruptedException {
+ boolean success =
+ mAwaitApWifiSetupScan.await(AWAIT_WIFI_SCAN_RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
+ Assert.assertTrue("Timeout waiting for signal: wait for ap scan results", success);
Assert.assertTrue("AP wifi scan result failed asynchronously", mApWifiScanSuccess.get());
}
private void sendWifiScanResultsToChre() {
List<ScanResult> results = mWifiManager.getScanResults();
Assert.assertTrue("No wifi scan results returned from AP", !results.isEmpty());
+
+ // CHRE does not currently support 6 GHz results, so filter these results from the list
+ int logsRemoved = 0;
+ Iterator<ScanResult> iter = results.iterator();
+ while (iter.hasNext()) {
+ ScanResult current = iter.next();
+ if (current.getBand() == ScanResult.WIFI_BAND_6_GHZ) {
+ iter.remove();
+ logsRemoved++;
+ }
+ }
+ if (logsRemoved > 0) {
+ Log.i(TAG, "Filtering out 6 GHz band scan result for CHRE, total=" + logsRemoved);
+ }
+
for (int i = 0; i < results.size(); i++) {
sendMessageToNanoApp(makeWifiScanResultMessage(results.get(i), results.size(), i));
}
diff --git a/java/test/permissions/Android.bp b/java/test/permissions/Android.bp
index 6dd10bfc..c6860814 100644
--- a/java/test/permissions/Android.bp
+++ b/java/test/permissions/Android.bp
@@ -34,5 +34,5 @@ java_library {
"chre-test-utils",
],
- sdk_version: "system_current",
+ sdk_version: "test_current",
}
diff --git a/java/test/rpc_service/Android.bp b/java/test/rpc_service/Android.bp
index 2403d7a9..c848681e 100644
--- a/java/test/rpc_service/Android.bp
+++ b/java/test/rpc_service/Android.bp
@@ -35,5 +35,5 @@ java_library {
"pw_rpc_java_client",
],
- sdk_version: "system_current",
+ sdk_version: "test_current",
}
diff --git a/java/test/rpc_service/src/com/google/android/chre/test/rpc_service/ContextHubRpcServiceTestExecutor.java b/java/test/rpc_service/src/com/google/android/chre/test/rpc_service/ContextHubRpcServiceTestExecutor.java
index b6da0f1b..78b1a1aa 100644
--- a/java/test/rpc_service/src/com/google/android/chre/test/rpc_service/ContextHubRpcServiceTestExecutor.java
+++ b/java/test/rpc_service/src/com/google/android/chre/test/rpc_service/ContextHubRpcServiceTestExecutor.java
@@ -129,7 +129,6 @@ public class ContextHubRpcServiceTestExecutor extends ContextHubClientCallback {
};
IntentFilter filter = new IntentFilter(ACTION);
- mContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
Intent intent = new Intent(ACTION).setPackage(mContext.getPackageName());
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
@@ -138,6 +137,7 @@ public class ContextHubRpcServiceTestExecutor extends ContextHubClientCallback {
pendingIntent, mNanoAppId);
mRpcClient = new ChreRpcClient(contextHubClient, mNanoAppId, List.of(mEchoService));
+ mContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
invokeRpc(mRpcClient);
diff --git a/java/test/settings/Android.bp b/java/test/settings/Android.bp
index f26ff7f2..15976d21 100644
--- a/java/test/settings/Android.bp
+++ b/java/test/settings/Android.bp
@@ -32,5 +32,5 @@ java_library {
"chre-test-utils",
],
- sdk_version: "system_current",
+ sdk_version: "test_current",
}
diff --git a/java/test/settings/src/com/google/android/chre/test/setting/ContextHubBleSettingsTestExecutor.java b/java/test/settings/src/com/google/android/chre/test/setting/ContextHubBleSettingsTestExecutor.java
index 4ada672e..e91785dd 100644
--- a/java/test/settings/src/com/google/android/chre/test/setting/ContextHubBleSettingsTestExecutor.java
+++ b/java/test/settings/src/com/google/android/chre/test/setting/ContextHubBleSettingsTestExecutor.java
@@ -16,8 +16,6 @@
package com.google.android.chre.test.setting;
-import static android.Manifest.permission.BLUETOOTH_CONNECT;
-
import android.app.Instrumentation;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
@@ -88,7 +86,7 @@ public class ContextHubBleSettingsTestExecutor {
/**
* Should be called in a @Before method.
*/
- public void setUp() {
+ public void setUp() throws InterruptedException {
mInitialBluetoothEnabled = mSettingsUtil.isBluetoothEnabled();
mInitialBluetoothScanningEnabled = mSettingsUtil.isBluetoothScanningAlwaysEnabled();
mInitialAirplaneMode = mSettingsUtil.isAirplaneModeOn();
@@ -99,7 +97,7 @@ public class ContextHubBleSettingsTestExecutor {
mExecutor.init();
}
- public void runBleScanningTest() {
+ public void runBleScanningTest() throws InterruptedException {
runBleScanningTest(false /* enableBluetooth */, false /* enableBluetoothScanning */);
runBleScanningTest(true /* enableBluetooth */, false /* enableBluetoothScanning */);
runBleScanningTest(false /* enableBluetooth */, true /* enableBluetoothScanning */);
@@ -109,7 +107,7 @@ public class ContextHubBleSettingsTestExecutor {
/**
* Should be called in an @After method.
*/
- public void tearDown() {
+ public void tearDown() throws InterruptedException {
mExecutor.deinit();
mSettingsUtil.setBluetooth(mInitialBluetoothEnabled);
mSettingsUtil.setBluetoothScanningSettings(mInitialBluetoothScanningEnabled);
@@ -122,6 +120,12 @@ public class ContextHubBleSettingsTestExecutor {
* @param enableBluetoothScanning if true, enable BLE scanning; false, otherwise
*/
private void setBluetoothSettings(boolean enable, boolean enableBluetoothScanning) {
+ // Check if already in the desired state
+ if ((enable == mSettingsUtil.isBluetoothEnabled())
+ && (enableBluetoothScanning == mSettingsUtil.isBluetoothScanningAlwaysEnabled())) {
+ return;
+ }
+
int state = BluetoothAdapter.STATE_OFF;
if (enable) {
state = BluetoothAdapter.STATE_ON;
@@ -142,11 +146,11 @@ public class ContextHubBleSettingsTestExecutor {
Assert.assertTrue(bluetoothManager != null);
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
Assert.assertTrue(bluetoothAdapter != null);
- mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
Assert.assertTrue(bluetoothAdapter.enableBLE());
}
try {
- bluetoothUpdateListener.mBluetoothLatch.await(10, TimeUnit.SECONDS);
+ boolean success = bluetoothUpdateListener.mBluetoothLatch.await(10, TimeUnit.SECONDS);
+ Assert.assertTrue("Timeout waiting for signal: bluetooth update listener", success);
Assert.assertTrue(enable == mSettingsUtil.isBluetoothEnabled());
Assert.assertTrue(enableBluetoothScanning
== mSettingsUtil.isBluetoothScanningAlwaysEnabled());
@@ -167,7 +171,7 @@ public class ContextHubBleSettingsTestExecutor {
* @param enableBluetoothScanning if bluetooth scanning is always enabled
*/
private void runBleScanningTest(boolean enableBluetooth,
- boolean enableBluetoothScanning) {
+ boolean enableBluetoothScanning) throws InterruptedException {
setBluetoothSettings(enableBluetooth, enableBluetoothScanning);
boolean enableFeature = enableBluetooth || enableBluetoothScanning;
diff --git a/java/test/settings/src/com/google/android/chre/test/setting/ContextHubGnssSettingsTestExecutor.java b/java/test/settings/src/com/google/android/chre/test/setting/ContextHubGnssSettingsTestExecutor.java
index 8b49dadb..e99fed1b 100644
--- a/java/test/settings/src/com/google/android/chre/test/setting/ContextHubGnssSettingsTestExecutor.java
+++ b/java/test/settings/src/com/google/android/chre/test/setting/ContextHubGnssSettingsTestExecutor.java
@@ -48,12 +48,12 @@ public class ContextHubGnssSettingsTestExecutor {
mExecutor.init();
}
- public void runGnssLocationTest() {
+ public void runGnssLocationTest() throws InterruptedException {
runTest(ChreSettingsTest.TestCommand.Feature.GNSS_LOCATION, false /* enableFeature */);
runTest(ChreSettingsTest.TestCommand.Feature.GNSS_LOCATION, true /* enableFeature */);
}
- public void runGnssMeasurementTest() {
+ public void runGnssMeasurementTest() throws InterruptedException {
runTest(ChreSettingsTest.TestCommand.Feature.GNSS_MEASUREMENT, false /* enableFeature */);
runTest(ChreSettingsTest.TestCommand.Feature.GNSS_MEASUREMENT, true /* enableFeature */);
}
@@ -61,7 +61,7 @@ public class ContextHubGnssSettingsTestExecutor {
/**
* Should be called in an @After method.
*/
- public void tearDown() {
+ public void tearDown() throws InterruptedException {
mExecutor.deinit();
mSettingsUtil.setLocationMode(mInitialLocationEnabled, 30 /* timeoutSeconds */);
}
@@ -71,7 +71,8 @@ public class ContextHubGnssSettingsTestExecutor {
* @param feature The GNSS feature to test.
* @param enableFeature True for enable.
*/
- private void runTest(ChreSettingsTest.TestCommand.Feature feature, boolean enableFeature) {
+ private void runTest(ChreSettingsTest.TestCommand.Feature feature, boolean enableFeature)
+ throws InterruptedException {
mSettingsUtil.setLocationMode(enableFeature, 30 /* timeoutSeconds */);
ChreSettingsTest.TestCommand.State state = enableFeature
diff --git a/java/test/settings/src/com/google/android/chre/test/setting/ContextHubMicDisableSettingsTestExecutor.java b/java/test/settings/src/com/google/android/chre/test/setting/ContextHubMicDisableSettingsTestExecutor.java
index 8d8c4e9e..c17dd318 100644
--- a/java/test/settings/src/com/google/android/chre/test/setting/ContextHubMicDisableSettingsTestExecutor.java
+++ b/java/test/settings/src/com/google/android/chre/test/setting/ContextHubMicDisableSettingsTestExecutor.java
@@ -50,7 +50,7 @@ public class ContextHubMicDisableSettingsTestExecutor {
mExecutor.init();
}
- public void runMicDisableSettingsTest() {
+ public void runMicDisableSettingsTest() throws InterruptedException {
setMicrophoneDisableSetting(false /* disableAccess */);
runTest(ChreSettingsTest.TestCommand.Feature.AUDIO, false /* enableFeature */);
@@ -87,7 +87,8 @@ public class ContextHubMicDisableSettingsTestExecutor {
* @param feature The feature to test.
* @param enableFeature True for enable.
*/
- private void runTest(ChreSettingsTest.TestCommand.Feature feature, boolean enableFeature) {
+ private void runTest(ChreSettingsTest.TestCommand.Feature feature, boolean enableFeature)
+ throws InterruptedException {
ChreSettingsTest.TestCommand.State state = enableFeature
? ChreSettingsTest.TestCommand.State.ENABLED
: ChreSettingsTest.TestCommand.State.DISABLED;
diff --git a/java/test/settings/src/com/google/android/chre/test/setting/ContextHubSettingsTestExecutor.java b/java/test/settings/src/com/google/android/chre/test/setting/ContextHubSettingsTestExecutor.java
index 78a2f1bb..5c9a2173 100644
--- a/java/test/settings/src/com/google/android/chre/test/setting/ContextHubSettingsTestExecutor.java
+++ b/java/test/settings/src/com/google/android/chre/test/setting/ContextHubSettingsTestExecutor.java
@@ -138,7 +138,8 @@ public class ContextHubSettingsTestExecutor extends ContextHubClientCallback {
*
* @param feature The feature to set the test up for.
*/
- public void setupTestAssertSuccess(ChreSettingsTest.TestCommand.Feature feature) {
+ public void setupTestAssertSuccess(ChreSettingsTest.TestCommand.Feature feature)
+ throws InterruptedException {
mTestResult.set(null);
mTestSetupComplete.set(false);
mCountDownLatch = new CountDownLatch(1);
@@ -155,12 +156,8 @@ public class ContextHubSettingsTestExecutor extends ContextHubClientCallback {
Assert.fail("Failed to send message: result = " + result);
}
- try {
- mCountDownLatch.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Assert.fail(e.getMessage());
- }
-
+ boolean success = mCountDownLatch.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ Assert.assertTrue("Timeout waiting for signal: test setup", success);
Assert.assertTrue(
"Failed to set up test", mTestSetupComplete.get() || mTestResult.get() != null);
}
@@ -173,7 +170,7 @@ public class ContextHubSettingsTestExecutor extends ContextHubClientCallback {
*/
public void startTestAssertSuccess(
ChreSettingsTest.TestCommand.Feature feature,
- ChreSettingsTest.TestCommand.State state) {
+ ChreSettingsTest.TestCommand.State state) throws InterruptedException {
mTestResult.set(null);
mCountDownLatch = new CountDownLatch(1);
@@ -188,11 +185,8 @@ public class ContextHubSettingsTestExecutor extends ContextHubClientCallback {
Assert.fail("Failed to send message: result = " + result);
}
- try {
- mCountDownLatch.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Assert.fail(e.getMessage());
- }
+ boolean success = mCountDownLatch.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ Assert.assertTrue("Timeout waiting for signal: wait for test", success);
if (mTestResult.get() == null) {
Assert.fail("No test result received");
diff --git a/java/test/settings/src/com/google/android/chre/test/setting/ContextHubWifiSettingsTestExecutor.java b/java/test/settings/src/com/google/android/chre/test/setting/ContextHubWifiSettingsTestExecutor.java
index 50d740dd..0cc477b4 100644
--- a/java/test/settings/src/com/google/android/chre/test/setting/ContextHubWifiSettingsTestExecutor.java
+++ b/java/test/settings/src/com/google/android/chre/test/setting/ContextHubWifiSettingsTestExecutor.java
@@ -95,12 +95,12 @@ public class ContextHubWifiSettingsTestExecutor {
mExecutor.init();
}
- public void runWifiScanningTest() {
+ public void runWifiScanningTest() throws InterruptedException {
runWifiScanningTest(false /* enableFeature */);
runWifiScanningTest(true /* enableFeature */);
}
- public void runWifiRangingTest() {
+ public void runWifiRangingTest() throws InterruptedException {
runWifiRangingTest(false /* enableFeature */);
runWifiRangingTest(true /* enableFeature */);
}
@@ -108,7 +108,7 @@ public class ContextHubWifiSettingsTestExecutor {
/**
* Should be called in an @After method.
*/
- public void tearDown() {
+ public void tearDown() throws InterruptedException {
mExecutor.deinit();
mSettingsUtil.setWifi(mInitialWifiEnabled);
mSettingsUtil.setWifiScanningSettings(mInitialWifiScanningAlwaysEnabled);
@@ -119,7 +119,7 @@ public class ContextHubWifiSettingsTestExecutor {
* Sets the WiFi scanning settings on the device.
* @param enable true to enable WiFi settings, false to disable it.
*/
- private void setWifiSettings(boolean enable) {
+ private void setWifiSettings(boolean enable) throws InterruptedException {
WifiUpdateListener wifiUpdateListener = new WifiUpdateListener(enable);
mContext.registerReceiver(
wifiUpdateListener.mWifiUpdateReceiver,
@@ -128,14 +128,11 @@ public class ContextHubWifiSettingsTestExecutor {
mSettingsUtil.setWifiScanningSettings(enable);
mSettingsUtil.setWifi(enable);
- try {
- wifiUpdateListener.mWifiLatch.await(30, TimeUnit.SECONDS);
+ boolean success = wifiUpdateListener.mWifiLatch.await(30, TimeUnit.SECONDS);
+ Assert.assertTrue("Timeout waiting for signal: set wifi settings", success);
- // Wait a few seconds to ensure setting is propagated to CHRE path
- Thread.sleep(10000);
- } catch (InterruptedException e) {
- Assert.fail(e.getMessage());
- }
+ // Wait a few seconds to ensure setting is propagated to CHRE path
+ Thread.sleep(10000);
mContext.unregisterReceiver(wifiUpdateListener.mWifiUpdateReceiver);
}
@@ -144,7 +141,7 @@ public class ContextHubWifiSettingsTestExecutor {
* Helper function to run the test.
* @param enableFeature True for enable.
*/
- private void runWifiScanningTest(boolean enableFeature) {
+ private void runWifiScanningTest(boolean enableFeature) throws InterruptedException {
setWifiSettings(enableFeature);
ChreSettingsTest.TestCommand.State state = enableFeature
@@ -158,7 +155,7 @@ public class ContextHubWifiSettingsTestExecutor {
* Helper function to run the test.
* @param enableFeature True for enable.
*/
- private void runWifiRangingTest(boolean enableFeature) {
+ private void runWifiRangingTest(boolean enableFeature) throws InterruptedException {
if (!mSettingsUtil.isWifiEnabled() || !mSettingsUtil.isWifiScanningAlwaysEnabled()) {
setWifiSettings(true /* enable */);
}
diff --git a/java/test/settings/src/com/google/android/chre/test/setting/ContextHubWwanSettingsTestExecutor.java b/java/test/settings/src/com/google/android/chre/test/setting/ContextHubWwanSettingsTestExecutor.java
index e6d82e70..c7f726fc 100644
--- a/java/test/settings/src/com/google/android/chre/test/setting/ContextHubWwanSettingsTestExecutor.java
+++ b/java/test/settings/src/com/google/android/chre/test/setting/ContextHubWwanSettingsTestExecutor.java
@@ -51,7 +51,7 @@ public class ContextHubWwanSettingsTestExecutor {
mExecutor.init();
}
- public void runWwanTest() {
+ public void runWwanTest() throws InterruptedException {
runTest(false /* enableFeature */);
runTest(true /* enableFeature */);
}
@@ -59,7 +59,7 @@ public class ContextHubWwanSettingsTestExecutor {
/**
* Should be called in an @After method.
*/
- public void tearDown() {
+ public void tearDown() throws InterruptedException {
mExecutor.deinit();
mSettingsUtil.setAirplaneMode(mInitialAirplaneMode);
}
@@ -68,7 +68,7 @@ public class ContextHubWwanSettingsTestExecutor {
* Helper function to run the test.
* @param enableFeature True for enable.
*/
- private void runTest(boolean enableFeature) {
+ private void runTest(boolean enableFeature) throws InterruptedException {
boolean airplaneModeExpected = !enableFeature;
mSettingsUtil.setAirplaneMode(airplaneModeExpected);
diff --git a/java/test/stress/Android.bp b/java/test/stress/Android.bp
index c0c2cc84..cf3ccf4d 100644
--- a/java/test/stress/Android.bp
+++ b/java/test/stress/Android.bp
@@ -33,5 +33,5 @@ java_library {
"chre-test-utils",
],
- sdk_version: "system_current",
+ sdk_version: "test_current",
}
diff --git a/java/test/stress/src/com/google/android/chre/test/stress/ContextHubStressTestExecutor.java b/java/test/stress/src/com/google/android/chre/test/stress/ContextHubStressTestExecutor.java
index 378640a8..a907a000 100644
--- a/java/test/stress/src/com/google/android/chre/test/stress/ContextHubStressTestExecutor.java
+++ b/java/test/stress/src/com/google/android/chre/test/stress/ContextHubStressTestExecutor.java
@@ -175,7 +175,7 @@ public class ContextHubStressTestExecutor extends ContextHubClientCallback {
* @param timeout The amount of time to run the stress test.
* @param unit The unit for timeout.
*/
- public void runStressTest(long timeout, TimeUnit unit) {
+ public void runStressTest(long timeout, TimeUnit unit) throws InterruptedException {
ChreStressTest.TestCommand.Feature[] features = {
ChreStressTest.TestCommand.Feature.WIFI_ON_DEMAND_SCAN,
ChreStressTest.TestCommand.Feature.GNSS_LOCATION,
@@ -194,11 +194,8 @@ public class ContextHubStressTestExecutor extends ContextHubClientCallback {
}
if (!mLoadAndStartOnly) {
- try {
- mCountDownLatch.await(timeout, unit);
- } catch (InterruptedException e) {
- Assert.fail(e.getMessage());
- }
+ boolean success = mCountDownLatch.await(timeout, unit);
+ Assert.assertTrue("Timeout waiting for signal", success);
checkTestFailure();
@@ -233,7 +230,7 @@ public class ContextHubStressTestExecutor extends ContextHubClientCallback {
* 4. Keep the nanoapp loaded, and then run this test.
* 5. Unload the nanoapp after this test ends.
*/
- public void runWifiScanMonitorRestartTest() {
+ public void runWifiScanMonitorRestartTest() throws InterruptedException {
// Since the host connection may have reset, inform the nanoapp about this event.
NanoAppMessage message = NanoAppMessage.createMessageToNanoApp(
mNanoAppId, ChreStressTest.MessageType.TEST_HOST_RESTARTED_VALUE,
@@ -246,11 +243,8 @@ public class ContextHubStressTestExecutor extends ContextHubClientCallback {
new byte[0]);
sendMessageToNanoApp(message);
- try {
- mCountDownLatch.await(30, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Assert.fail(e.getMessage());
- }
+ boolean success = mCountDownLatch.await(30, TimeUnit.SECONDS);
+ Assert.assertTrue("Timeout waiting for signal: wifi scan monitor restart test", success);
if ((mCapabilities.getWifi() & WIFI_CAPABILITIES_SCAN_MONITORING) != 0) {
WifiManager manager =
@@ -262,11 +256,8 @@ public class ContextHubStressTestExecutor extends ContextHubClientCallback {
mCountDownLatch = new CountDownLatch(1);
Assert.assertTrue(manager.startScan());
- try {
- mCountDownLatch.await(30, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Assert.fail(e.getMessage());
- }
+ success = mCountDownLatch.await(30, TimeUnit.SECONDS);
+ Assert.assertTrue("Timeout waiting for signal: trigger scan monitor", success);
Assert.assertTrue(mWifiScanMonitorTriggered.get());
checkTestFailure();
}
diff --git a/java/test/utils/Android.bp b/java/test/utils/Android.bp
index ca474dfb..adca53e3 100644
--- a/java/test/utils/Android.bp
+++ b/java/test/utils/Android.bp
@@ -28,11 +28,12 @@ java_library {
static_libs: [
"androidx.test.rules",
- "truth",
"chre_api_test_proto_java_lite",
"chre_pigweed_utils",
+ "compatibility-device-util-axt",
"pw_rpc_java_client",
+ "truth",
],
- sdk_version: "system_current",
+ sdk_version: "test_current",
}
diff --git a/java/test/utils/src/com/google/android/utils/chre/ChreApiTestUtil.java b/java/test/utils/src/com/google/android/utils/chre/ChreApiTestUtil.java
index 7a0be9e6..d30d3ed3 100644
--- a/java/test/utils/src/com/google/android/utils/chre/ChreApiTestUtil.java
+++ b/java/test/utils/src/com/google/android/utils/chre/ChreApiTestUtil.java
@@ -19,6 +19,7 @@ package com.google.android.utils.chre;
import androidx.annotation.NonNull;
import com.google.android.chre.utils.pigweed.ChreRpcClient;
+import com.google.protobuf.Empty;
import com.google.protobuf.MessageLite;
import java.util.ArrayList;
@@ -55,6 +56,11 @@ public class ChreApiTestUtil {
public static final int RPC_TIMEOUT_IN_MS = RPC_TIMEOUT_IN_SECONDS * 1000;
/**
+ * The default timeout for an RPC call in nanosecond.
+ */
+ public static final long RPC_TIMEOUT_IN_NS = RPC_TIMEOUT_IN_SECONDS * 1000000000L;
+
+ /**
* The number of threads for the executor that executes the futures.
* We need at least 2 here. One to process the RPCs for server streaming
* and one to process events (which has server streaming as a dependent).
@@ -140,7 +146,7 @@ public class ChreApiTestUtil {
/**
* Calls a server streaming RPC method with RPC_TIMEOUT_IN_SECONDS seconds of
- * timeout with a void request.
+ * timeout with an empty request.
*
* @param <ResponseType> the type of the response (proto generated type).
* @param rpcClient the RPC client.
@@ -155,7 +161,7 @@ public class ChreApiTestUtil {
Objects.requireNonNull(rpcClient);
Objects.requireNonNull(method);
- ChreApiTest.Void request = ChreApiTest.Void.newBuilder().build();
+ Empty request = Empty.newBuilder().build();
return callServerStreamingRpcMethodSync(rpcClient, method, request);
}
@@ -266,7 +272,7 @@ public class ChreApiTestUtil {
}
/**
- * Calls an RPC method with RPC_TIMEOUT_IN_SECONDS seconds of timeout with a void request.
+ * Calls an RPC method with RPC_TIMEOUT_IN_SECONDS seconds of timeout with an empty request.
*
* @param <ResponseType> the type of the response (proto generated type).
* @param rpcClient the RPC client.
@@ -280,7 +286,7 @@ public class ChreApiTestUtil {
Objects.requireNonNull(rpcClient);
Objects.requireNonNull(method);
- ChreApiTest.Void request = ChreApiTest.Void.newBuilder().build();
+ Empty request = Empty.newBuilder().build();
return callUnaryRpcMethodSync(rpcClient, method, request);
}
@@ -303,7 +309,6 @@ public class ChreApiTestUtil {
ChreApiTest.GatherEventsInput input = ChreApiTest.GatherEventsInput.newBuilder()
.addAllEventTypes(eventTypes)
- .setEventTypeCount(eventTypes.size())
.setEventCount(eventCount)
.setTimeoutInNs(timeoutInNs)
.build();
@@ -385,69 +390,56 @@ public class ChreApiTestUtil {
return new Service("chre.rpc.ChreApiTestService",
Service.unaryMethod(
"ChreBleGetCapabilities",
- ChreApiTest.Void.class,
- ChreApiTest.Capabilities.class),
+ Empty.parser(),
+ ChreApiTest.Capabilities.parser()),
Service.unaryMethod(
"ChreBleGetFilterCapabilities",
- ChreApiTest.Void.class,
- ChreApiTest.Capabilities.class),
- Service.unaryMethod(
- "ChreBleStartScanAsync",
- ChreApiTest.ChreBleStartScanAsyncInput.class,
- ChreApiTest.Status.class),
+ Empty.parser(),
+ ChreApiTest.Capabilities.parser()),
Service.serverStreamingMethod(
"ChreBleStartScanSync",
- ChreApiTest.ChreBleStartScanAsyncInput.class,
- ChreApiTest.GeneralSyncMessage.class),
- Service.unaryMethod(
- "ChreBleStopScanAsync",
- ChreApiTest.Void.class,
- ChreApiTest.Status.class),
+ ChreApiTest.ChreBleStartScanAsyncInput.parser(),
+ ChreApiTest.GeneralSyncMessage.parser()),
Service.serverStreamingMethod(
"ChreBleStopScanSync",
- ChreApiTest.Void.class,
- ChreApiTest.GeneralSyncMessage.class),
+ Empty.parser(),
+ ChreApiTest.GeneralSyncMessage.parser()),
Service.unaryMethod(
"ChreSensorFindDefault",
- ChreApiTest.ChreSensorFindDefaultInput.class,
- ChreApiTest.ChreSensorFindDefaultOutput.class),
+ ChreApiTest.ChreSensorFindDefaultInput.parser(),
+ ChreApiTest.ChreSensorFindDefaultOutput.parser()),
Service.unaryMethod(
"ChreGetSensorInfo",
- ChreApiTest.ChreHandleInput.class,
- ChreApiTest.ChreGetSensorInfoOutput.class),
+ ChreApiTest.ChreHandleInput.parser(),
+ ChreApiTest.ChreGetSensorInfoOutput.parser()),
Service.unaryMethod(
"ChreGetSensorSamplingStatus",
- ChreApiTest.ChreHandleInput.class,
- ChreApiTest.ChreGetSensorSamplingStatusOutput.class),
+ ChreApiTest.ChreHandleInput.parser(),
+ ChreApiTest.ChreGetSensorSamplingStatusOutput.parser()),
Service.unaryMethod(
"ChreSensorConfigure",
- ChreApiTest.ChreSensorConfigureInput.class,
- ChreApiTest.Status.class),
+ ChreApiTest.ChreSensorConfigureInput.parser(),
+ ChreApiTest.Status.parser()),
Service.unaryMethod(
"ChreSensorConfigureModeOnly",
- ChreApiTest.ChreSensorConfigureModeOnlyInput.class,
- ChreApiTest.Status.class),
+ ChreApiTest.ChreSensorConfigureModeOnlyInput.parser(),
+ ChreApiTest.Status.parser()),
Service.unaryMethod(
"ChreAudioGetSource",
- ChreApiTest.ChreHandleInput.class,
- ChreApiTest.ChreAudioGetSourceOutput.class),
+ ChreApiTest.ChreHandleInput.parser(),
+ ChreApiTest.ChreAudioGetSourceOutput.parser()),
Service.unaryMethod(
"ChreConfigureHostEndpointNotifications",
- ChreApiTest.ChreConfigureHostEndpointNotificationsInput.class,
- ChreApiTest.Status.class),
- Service.unaryMethod(
- "RetrieveLatestDisconnectedHostEndpointEvent",
- ChreApiTest.Void.class,
- ChreApiTest.RetrieveLatestDisconnectedHostEndpointEventOutput
- .class),
+ ChreApiTest.ChreConfigureHostEndpointNotificationsInput.parser(),
+ ChreApiTest.Status.parser()),
Service.unaryMethod(
"ChreGetHostEndpointInfo",
- ChreApiTest.ChreGetHostEndpointInfoInput.class,
- ChreApiTest.ChreGetHostEndpointInfoOutput.class),
+ ChreApiTest.ChreGetHostEndpointInfoInput.parser(),
+ ChreApiTest.ChreGetHostEndpointInfoOutput.parser()),
Service.serverStreamingMethod(
"GatherEvents",
- ChreApiTest.GatherEventsInput.class,
- ChreApiTest.GeneralEventsMessage.class));
+ ChreApiTest.GatherEventsInput.parser(),
+ ChreApiTest.GeneralEventsMessage.parser()));
}
/**
diff --git a/java/test/utils/src/com/google/android/utils/chre/ContextHubHostTestUtil.java b/java/test/utils/src/com/google/android/utils/chre/ContextHubHostTestUtil.java
new file mode 100644
index 00000000..ba1b8a00
--- /dev/null
+++ b/java/test/utils/src/com/google/android/utils/chre/ContextHubHostTestUtil.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.utils.chre;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.location.ContextHubInfo;
+import android.hardware.location.ContextHubManager;
+import android.hardware.location.NanoAppBinary;
+import android.os.Build;
+import android.os.Bundle;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A class that defines various utility functions to be used by Context Hub host tests.
+ */
+public class ContextHubHostTestUtil {
+ /**
+ * The names of the dynamic configs corresponding to each test suite.
+ */
+ public static final String[] DEVICE_DYNAMIC_CONFIG_NAMES =
+ new String[] {"GtsGmscoreHostTestCases", "GtsLocationContextMultiDeviceTestCases"};
+
+ public static String multiDeviceExternalNanoappPath = null;
+
+ /**
+ * Returns the path to the directory containing the nanoapp binaries.
+ * It is the external path if passed in, otherwise the relative path
+ * to the assets directory of the context of the calling app.
+ *
+ * @param context the Context to find the asset resources
+ * @param hubInfo the ContextHubInfo describing the hub
+ * @return the path to the nanoapps
+ */
+ public static String getNanoAppBinaryPath(Context context, ContextHubInfo hubInfo) {
+ String path = getExternalNanoAppPath();
+
+ // Only check for bundled nanoapps if the test is not in debug mode
+ if (path == null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ path = getNanoAppBinaryPathFromPlatformId(hubInfo.getChrePlatformId());
+ } else {
+ path = getNanoAppBinaryPathFromHubName(hubInfo.getName());
+ }
+
+ boolean haveNanoApps = false;
+ try {
+ haveNanoApps = context.getAssets().list(path).length > 0;
+ } catch (IOException e) {
+ Assert.fail("IOException while getting asset list at " + path);
+ }
+
+ // We anticipate this failure case (ContextHubInfo being of an unknown
+ // platform for us) much more than the case of knowing about a platform
+ // but not having a specific nanoapp built for it. So we separate
+ // out this error check to help the user debug this case more easily.
+ Assert.assertTrue("None of the test nanoapps are available on the platform: " + path,
+ haveNanoApps);
+ }
+ return path;
+ }
+
+ /**
+ * Waits on a CountDownLatch or assert if it timed out or was interrupted.
+ *
+ * @param latch the CountDownLatch
+ * @param timeout the timeout duration
+ * @param unit the timeout unit
+ * @param timeoutErrorMessage the message to display on timeout assert
+ */
+ public static void awaitCountDownLatchAssertOnFailure(
+ CountDownLatch latch, long timeout, TimeUnit unit, String timeoutErrorMessage)
+ throws InterruptedException {
+ boolean result = latch.await(timeout, unit);
+ Assert.assertTrue(timeoutErrorMessage, result);
+ }
+
+ /**
+ * Creates a NanoAppBinary object from the nanoapp filename.
+ *
+ * @param hub the hub to create the binary for
+ * @param filename the filename of the nanoapp
+ * @return the NanoAppBinary object
+ */
+ public static NanoAppBinary createNanoAppBinary(ContextHubInfo hub, String filename) {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ String fullName = getNanoAppBinaryPath(context, hub) + "/" + filename;
+
+ InputStream stream = getNanoAppInputStream(context, fullName);
+ byte[] binary = null;
+ try {
+ binary = new byte[stream.available()];
+ stream.read(binary);
+ } catch (IOException e) {
+ Assert.fail("IOException while reading binary for " + fullName + ": " + e.getMessage());
+ }
+
+ return new NanoAppBinary(binary);
+ }
+
+ /**
+ * Read the nanoapp to an InputStream object.
+ *
+ * @param context the Context to find the asset resources
+ * @param fullName the fullName of the nanoapp
+ * @return the InputStream of the nanoapp
+ */
+ public static InputStream getNanoAppInputStream(Context context, String fullName) {
+ InputStream inputStream = null;
+ try {
+ inputStream = (getExternalNanoAppPath() == null)
+ ? context.getAssets().open(fullName) :
+ new FileInputStream(new File(fullName));
+ } catch (IOException e) {
+ Assert.fail("Could not find asset " + fullName + ": "
+ + e.toString());
+ }
+ return inputStream;
+ }
+
+ /**
+ * Converts a list of integers to a byte array.
+ *
+ * @param intArray the integer values
+ * @return the byte[] array containing the integer values in byte order
+ */
+ public static byte[] intArrayToByteArray(int[] intArray) {
+ ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES * intArray.length);
+ for (int i = 0; i < intArray.length; i++) {
+ buffer.putInt(intArray[i]);
+ }
+
+ return buffer.array();
+ }
+
+ /**
+ * Determines if the device under test is in the allowlist to run CHQTS.
+ *
+ * The device-side test currently skips the test only if the Context Hub
+ * Service does not exist, but the Android framework currently exposes it unconditionally.
+ * This method should be used to skip the test if the test device is not in the allowlist and
+ * no Context Hub exists in order to avoid false positive failures. In the future, the framework
+ * should be modified to only expose the service if CHRE is supported on the device. This hack
+ * should then only be used on Android version that do not have that capability.
+ *
+ * @return true if the device is in the allowlist, false otherwise
+ */
+ public static boolean deviceInAllowlist() {
+ DynamicConfigDeviceSide deviceDynamicConfig = getDynamicConfig();
+ List<String> configValues = deviceDynamicConfig.getValues("chre_device_whitelist");
+ Assert.assertTrue("Could not find device allowlist from dynamic config",
+ configValues != null);
+
+ String deviceName = Build.DEVICE;
+ for (String element : configValues) {
+ if (element.equals(deviceName)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Determines if the device under test is in the denylist to NOT run CHQTS.
+ *
+ * The denylist is structured as "device,platform_id,max_chre_version", and characterizes
+ * if a device should skip running CHQTS. For platform_id, and max_chre_version, "*" denotes
+ * "matches everything".
+ *
+ * @return true if the device is in the denylist, false otherwise
+ */
+ public static boolean deviceInDenylist() {
+ DynamicConfigDeviceSide deviceDynamicConfig = getDynamicConfig();
+ List<String> configValues = deviceDynamicConfig.getValues("chre_device_blacklist");
+ Assert.assertTrue("Could not find device denylist from dynamic config",
+ configValues != null);
+
+ String deviceName = Build.DEVICE;
+ for (String element : configValues) {
+ String[] delimited = element.split(",");
+ if (delimited.length != 0 && delimited[0].equals(deviceName)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the path of the nanoapps for a CHRE implementation using the platform ID.
+ *
+ * The dynamic configuration file for GtsGmscoreHostTestCases defines the key
+ * 'chre_platform_id_nanoapp_dir_pairs', whose value is a list of strings of the form
+ * '{platformId},{assetDirectoryName}', where platformId is one defined by the Context Hub
+ * and is returned by ContextHubInfo.getChrePlatformId().
+ *
+ * @param platformId the platform ID of the hub
+ * @return the path to the nanoapps
+ */
+ private static String getNanoAppBinaryPathFromPlatformId(long platformId) {
+ DynamicConfigDeviceSide deviceDynamicConfig = getDynamicConfig();
+ List<String> configValues =
+ deviceDynamicConfig.getValues("chre_platform_id_nanoapp_dir_pairs");
+ Assert.assertTrue("Could not find nanoapp asset list from dynamic config",
+ configValues != null);
+
+ String platformIdHexString = Long.toHexString(platformId);
+ String path = null;
+ for (String element : configValues) {
+ String[] delimited = element.split(",");
+ if (delimited.length == 2 && delimited[0].equals(platformIdHexString)) {
+ path = delimited[1];
+ break;
+ }
+ }
+
+ Assert.assertTrue("Could not find known asset directory for hub with platform ID = 0x"
+ + platformIdHexString, path != null);
+ return path;
+ }
+
+ /**
+ * Returns the path for nanoapps of a CHRE implementation using the Context Hub name.
+ *
+ * The dynamic configuration file for GtsGmscoreHostTestCases defines the key
+ * 'chre_hubname_nanoapp_dir_pairs', whose value is a list of strings of the form
+ * '{hubName},{assetDirectoryName}', where hubName is one defined by the Context Hub
+ * and is returned by ContextHubInfo.getName(). This method should be used instead of
+ * getNanoAppBinaryPathFromPlatformId() prior to Android P.
+ *
+ * @param contextHubName the name of the hub
+ * @return the path to the nanoapps
+ */
+ private static String getNanoAppBinaryPathFromHubName(String contextHubName) {
+ DynamicConfigDeviceSide deviceDynamicConfig = getDynamicConfig();
+ List<String> configValues =
+ deviceDynamicConfig.getValues("chre_hubname_nanoapp_dir_pairs");
+ Assert.assertTrue("Could not find nanoapp asset list from dynamic config",
+ configValues != null);
+
+ String path = null;
+ for (String element : configValues) {
+ String[] delimited = element.split(",");
+ if (delimited.length == 2 && delimited[0].equals(contextHubName)) {
+ path = delimited[1];
+ break;
+ }
+ }
+
+ Assert.assertTrue("Could not find known asset directory for hub " + contextHubName,
+ path != null);
+ return path;
+ }
+
+ /**
+ * @return the device side dynamic config for GtsGmscoreHostTestCases or
+ * GtsLocationContextMultiDeviceTestCases
+ */
+ private static DynamicConfigDeviceSide getDynamicConfig() {
+ DynamicConfigDeviceSide deviceDynamicConfig = null;
+ for (String deviceDynamicConfigName: DEVICE_DYNAMIC_CONFIG_NAMES) {
+ try {
+ deviceDynamicConfig = new DynamicConfigDeviceSide(deviceDynamicConfigName);
+ } catch (XmlPullParserException e) {
+ Assert.fail(e.getMessage());
+ } catch (IOException e) {
+ // Not found - try again
+ }
+ }
+
+ if (deviceDynamicConfig == null) {
+ Assert.fail("Could not get the device dynamic config.");
+ }
+ return deviceDynamicConfig;
+ }
+
+ /**
+ * Returns the path to external nanoapps. This method should be used to debug the test
+ * with custom unbundled nanoapps, and must not be used in actual certification.
+ *
+ * @return external nanoapp path, null if no externalNanoAppPath passed in
+ */
+ public static String getExternalNanoAppPath() {
+ if (multiDeviceExternalNanoappPath != null) {
+ return multiDeviceExternalNanoappPath;
+ }
+
+ Bundle extras = InstrumentationRegistry.getArguments();
+ return (extras == null) ? null : extras.getString("externalNanoAppPath");
+ }
+
+ /**
+ * Runs various checks to decide if the platform should run CHQTS.
+ *
+ * @param context The context at which the test should run.
+ * @param manager The ContextHubManager on this app.
+ */
+ public static void checkDeviceShouldRunTest(Context context, ContextHubManager manager) {
+ boolean supportsContextHub;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ supportsContextHub =
+ context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_CONTEXT_HUB);
+ Assert.assertTrue("ContextHubManager must be null if feature is not supported.",
+ supportsContextHub || manager == null);
+ } else {
+ supportsContextHub = (manager != null);
+ }
+ Assume.assumeTrue("Device does not support Context Hub, skipping test", supportsContextHub);
+
+ int numContextHubs;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ numContextHubs = manager.getContextHubs().size();
+ } else {
+ int[] handles = manager.getContextHubHandles();
+ Assert.assertNotNull(handles);
+ numContextHubs = handles.length;
+ }
+
+ // Only use allowlist logic on builds that do not require the Context Hub feature flag.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ // Use allowlist on platforms that reports no Context Hubs to prevent false positive
+ // failures on devices that do not actually support CHRE.
+ Assume.assumeTrue(
+ "Device not in allowlist and does not have Context Hub, skipping test",
+ numContextHubs != 0 || deviceInAllowlist());
+ }
+
+ // Use a denylist on platforms that should not run CHQTS.
+ Assume.assumeTrue("Device is in denylist, skipping test", !deviceInDenylist());
+ }
+}
diff --git a/java/test/utils/src/com/google/android/utils/chre/ContextHubServiceTestHelper.java b/java/test/utils/src/com/google/android/utils/chre/ContextHubServiceTestHelper.java
index 1c0731a1..18623a0b 100644
--- a/java/test/utils/src/com/google/android/utils/chre/ContextHubServiceTestHelper.java
+++ b/java/test/utils/src/com/google/android/utils/chre/ContextHubServiceTestHelper.java
@@ -26,6 +26,8 @@ import android.hardware.location.ContextHubManager;
import android.hardware.location.ContextHubTransaction;
import android.hardware.location.NanoAppBinary;
import android.hardware.location.NanoAppState;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
import java.util.HashMap;
import java.util.List;
@@ -65,8 +67,14 @@ public class ContextHubServiceTestHelper {
public void initAndUnloadAllNanoApps() throws InterruptedException, TimeoutException {
init();
- // Unload all nanoapps to ensure test starts at a clean state.
- unloadAllNanoApps();
+
+ // We only need to unload all nanoapps when the device has version < U, so the
+ // tests remain the same on those devices. On newer devices, test mode will
+ // handle this.
+ if (VERSION.SDK_INT < VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ // Unload all nanoapps to ensure test starts at a clean state.
+ unloadAllNanoApps();
+ }
}
public void deinit() {
diff --git a/java/test/utils/src/com/google/android/utils/chre/SettingsUtil.java b/java/test/utils/src/com/google/android/utils/chre/SettingsUtil.java
index 98a2ace6..54401ac4 100644
--- a/java/test/utils/src/com/google/android/utils/chre/SettingsUtil.java
+++ b/java/test/utils/src/com/google/android/utils/chre/SettingsUtil.java
@@ -116,7 +116,7 @@ public class SettingsUtil {
* @param enable True to enable location, false to disable it.
* @param timeoutSeconds The maximum amount of time in seconds to wait.
*/
- public void setLocationMode(boolean enable, long timeoutSeconds) {
+ public void setLocationMode(boolean enable, long timeoutSeconds) throws InterruptedException {
if (isLocationEnabled() != enable) {
LocationUpdateListener listener = new LocationUpdateListener();
@@ -125,14 +125,11 @@ public class SettingsUtil {
new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
mLocationManager.setLocationEnabledForUser(enable, UserHandle.CURRENT);
- try {
- listener.mLocationLatch.await(timeoutSeconds, TimeUnit.SECONDS);
+ boolean success = listener.mLocationLatch.await(timeoutSeconds, TimeUnit.SECONDS);
+ Assert.assertTrue("Timeout waiting for signal: set location mode", success);
- // Wait 1 additional second to make sure setting gets propagated to CHRE
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- Assert.fail("InterruptedException while waiting for location update");
- }
+ // Wait 1 additional second to make sure setting gets propagated to CHRE
+ Thread.sleep(1000);
Assert.assertTrue(isLocationEnabled() == enable);
@@ -172,7 +169,7 @@ public class SettingsUtil {
public boolean isBluetoothEnabled() {
String out = ChreTestUtil.executeShellCommand(
mInstrumentation, "settings get global bluetooth_on");
- return ChreTestUtil.convertToIntegerOrFail(out) > 0;
+ return ChreTestUtil.convertToIntegerOrFail(out) == 1;
}
/**
@@ -190,7 +187,7 @@ public class SettingsUtil {
* Sets the airplane mode on the device.
* @param enable True to enable airplane mode, false to disable it.
*/
- public void setAirplaneMode(boolean enable) {
+ public void setAirplaneMode(boolean enable) throws InterruptedException {
if (isAirplaneModeOn() != enable) {
AirplaneModeListener listener = new AirplaneModeListener();
mContext.registerReceiver(
@@ -201,13 +198,10 @@ public class SettingsUtil {
ChreTestUtil.executeShellCommand(
mInstrumentation, "cmd connectivity airplane-mode " + value);
- try {
- listener.mAirplaneModeLatch.await(10, TimeUnit.SECONDS);
- // Wait 1 additional second to make sure setting gets propagated to CHRE
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- Assert.fail(e.getMessage());
- }
+ boolean success = listener.mAirplaneModeLatch.await(10, TimeUnit.SECONDS);
+ Assert.assertTrue("Timeout waiting for signal: set airplane mode", success);
+ // Wait 1 additional second to make sure setting gets propagated to CHRE
+ Thread.sleep(1000);
Assert.assertTrue(isAirplaneModeOn() == enable);
mContext.unregisterReceiver(listener.mAirplaneModeReceiver);
}
diff --git a/java/utils/pigweed/Android.bp b/java/utils/pigweed/Android.bp
index e7b15724..66d7d16d 100644
--- a/java/utils/pigweed/Android.bp
+++ b/java/utils/pigweed/Android.bp
@@ -27,7 +27,6 @@ java_library {
srcs: ["src/**/*.java"],
static_libs: [
- "androidx.annotation_annotation",
"guava",
"pw_rpc_java_client",
],
diff --git a/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreCallbackHandler.java b/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreCallbackHandler.java
index b84ebad4..291ebf7d 100644
--- a/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreCallbackHandler.java
+++ b/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreCallbackHandler.java
@@ -22,9 +22,6 @@ import android.hardware.location.ContextHubClient;
import android.hardware.location.ContextHubClientCallback;
import android.hardware.location.NanoAppMessage;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
import java.util.Objects;
import dev.pigweed.pw_rpc.Client;
@@ -35,16 +32,17 @@ import dev.pigweed.pw_rpc.Client;
*/
public class ChreCallbackHandler extends ContextHubClientCallback {
private final long mNanoappId;
- @Nullable
+ // Nullable.
private final ContextHubClientCallback mCallback;
private Client mRpcClient;
private ChreChannelOutput mChannelOutput;
/**
* @param nanoappId ID of the RPC Server nanoapp
- * @param callback The callbacks receiving messages and life-cycle events from nanoapps
+ * @param callback The callbacks receiving messages and life-cycle events from nanoapps,
+ * nullable.
*/
- public ChreCallbackHandler(long nanoappId, @Nullable ContextHubClientCallback callback) {
+ public ChreCallbackHandler(long nanoappId, ContextHubClientCallback callback) {
mNanoappId = nanoappId;
mCallback = callback;
}
@@ -52,10 +50,10 @@ public class ChreCallbackHandler extends ContextHubClientCallback {
/**
* Completes the initialization.
*
- * @param rpcClient The Pigweed RPC client
- * @param channelOutput The ChannelOutput used by Pigweed
+ * @param rpcClient The Pigweed RPC client, non null
+ * @param channelOutput The ChannelOutput used by Pigweed, non null
*/
- public void lateInit(@NonNull Client rpcClient, @NonNull ChreChannelOutput channelOutput) {
+ public void lateInit(Client rpcClient, ChreChannelOutput channelOutput) {
mRpcClient = Objects.requireNonNull(rpcClient);
mChannelOutput = Objects.requireNonNull(channelOutput);
}
diff --git a/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreChannelOutput.java b/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreChannelOutput.java
index 43440b59..1e79693b 100644
--- a/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreChannelOutput.java
+++ b/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreChannelOutput.java
@@ -30,10 +30,9 @@ import dev.pigweed.pw_rpc.ChannelOutputException;
*/
public class ChreChannelOutput implements Channel.Output {
/**
- * Random value chosen not too close to max value to try to avoid conflicts with other messages
- * in case pw rpc isn't the only way the client chooses to communicate.
+ * Message type to use for RPC messages.
*/
- public static final int PW_RPC_CHRE_MESSAGE_TYPE = Integer.MAX_VALUE - 10;
+ public static final int CHRE_MESSAGE_TYPE_RPC = 0x7FFFFFF5;
// 1 denotes that a host endpoint is the client that created the channel.
private static final int CHANNEL_ID_HOST_CLIENT = (1 << 16);
@@ -55,7 +54,7 @@ public class ChreChannelOutput implements Channel.Output {
@Override
public void send(byte[] packet) throws ChannelOutputException {
NanoAppMessage message = NanoAppMessage.createMessageToNanoApp(mNanoappId,
- PW_RPC_CHRE_MESSAGE_TYPE, packet);
+ CHRE_MESSAGE_TYPE_RPC, packet);
if (mAuthDenied.get()
|| ContextHubTransaction.RESULT_SUCCESS != mClient.sendMessageToNanoApp(message)) {
throw new ChannelOutputException();
diff --git a/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreIntentHandler.java b/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreIntentHandler.java
index bec78fc8..91cdcf28 100644
--- a/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreIntentHandler.java
+++ b/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreIntentHandler.java
@@ -23,8 +23,6 @@ import android.hardware.location.ContextHubIntentEvent;
import android.hardware.location.ContextHubManager;
import android.util.Log;
-import androidx.annotation.NonNull;
-
import java.util.Objects;
import dev.pigweed.pw_rpc.Client;
@@ -38,13 +36,13 @@ public class ChreIntentHandler {
/**
* Handles CHRE intents.
*
- * @param intent the intent.
+ * @param intent the intent, non null
* @param nanoappId ID of the RPC Server nanoapp
- * @param rpcClient The Pigweed RPC client
- * @param channelOutput The ChannelOutput used by Pigweed
+ * @param rpcClient The Pigweed RPC client, non null
+ * @param channelOutput The ChannelOutput used by Pigweed, non null
*/
- public static void handle(@NonNull Intent intent, long nanoappId, @NonNull Client rpcClient,
- @NonNull ChreChannelOutput channelOutput) {
+ public static void handle(Intent intent, long nanoappId, Client rpcClient,
+ ChreChannelOutput channelOutput) {
Objects.requireNonNull(intent);
Objects.requireNonNull(rpcClient);
Objects.requireNonNull(channelOutput);
diff --git a/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreRpcClient.java b/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreRpcClient.java
index 0ba98ed5..205482ee 100644
--- a/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreRpcClient.java
+++ b/java/utils/pigweed/src/com/google/android/chre/utils/pigweed/ChreRpcClient.java
@@ -23,9 +23,6 @@ import android.hardware.location.ContextHubManager;
import android.hardware.location.NanoAppRpcService;
import android.hardware.location.NanoAppState;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
import java.util.List;
import java.util.Objects;
@@ -40,14 +37,15 @@ import dev.pigweed.pw_rpc.Service;
* See https://g3doc.corp.google.com/location/lbs/contexthub/g3doc/nanoapps/pw_rpc_host.md
*/
public class ChreRpcClient {
- @NonNull
+
+ // Non null.
private final Client mRpcClient;
- @NonNull
+ // Non null.
private final Channel mChannel;
- @NonNull
+ // Non null.
private final ChreChannelOutput mChannelOutput;
private final long mServerNanoappId;
- @NonNull
+ // Non null.
private final ContextHubClient mContextHubClient;
private ChreIntentHandler mIntentHandler;
@@ -56,14 +54,16 @@ public class ChreRpcClient {
*
* Use this constructor for persistent clients using callbacks.
*
- * @param manager The context manager used to create a client
+ * @param manager The context manager used to create a client, non null
+ * @param info Context hub info, non null
* @param serverNanoappId The ID of the RPC server nanoapp
- * @param services The list of services provided by the server
- * @param callback The callbacks receiving messages and life-cycle events from nanoapps
+ * @param services The list of services provided by the server, non null
+ * @param callback The callbacks receiving messages and life-cycle events from nanoapps,
+ * nullable
*/
- public ChreRpcClient(@NonNull ContextHubManager manager, @NonNull ContextHubInfo info,
- long serverNanoappId, @NonNull List<Service> services,
- @Nullable ContextHubClientCallback callback) {
+ public ChreRpcClient(ContextHubManager manager, ContextHubInfo info,
+ long serverNanoappId, List<Service> services,
+ ContextHubClientCallback callback) {
Objects.requireNonNull(manager);
Objects.requireNonNull(info);
Objects.requireNonNull(services);
@@ -83,12 +83,12 @@ public class ChreRpcClient {
*
* handleIntent() must be called with any CHRE intent received by the BroadcastReceiver.
*
- * @param contextHubClient The context hub client providing the RPC server nanoapp
+ * @param contextHubClient The context hub client providing the RPC server nanoapp, non null
* @param serverNanoappId The ID of the RPC server nanoapp
- * @param services The list of services provided by the server
+ * @param services The list of services provided by the server, non null
*/
- public ChreRpcClient(@NonNull ContextHubClient contextHubClient, long serverNanoappId,
- @NonNull List<Service> services) {
+ public ChreRpcClient(ContextHubClient contextHubClient, long serverNanoappId,
+ List<Service> services) {
mContextHubClient = Objects.requireNonNull(contextHubClient);
Objects.requireNonNull(services);
mServerNanoappId = serverNanoappId;
@@ -124,9 +124,9 @@ public class ChreRpcClient {
/**
* Handles CHRE intents.
*
- * @param intent The CHRE intent.
+ * @param intent The CHRE intent, non null
*/
- public void handleIntent(@NonNull Intent intent) {
+ public void handleIntent(Intent intent) {
ChreIntentHandler.handle(intent, mServerNanoappId, mRpcClient, mChannelOutput);
}
diff --git a/pal/include/chre/pal/ble.h b/pal/include/chre/pal/ble.h
index 4f27535e..aa1cb90d 100644
--- a/pal/include/chre/pal/ble.h
+++ b/pal/include/chre/pal/ble.h
@@ -46,9 +46,19 @@ extern "C" {
#define CHRE_PAL_BLE_API_V1_8 CHRE_PAL_CREATE_API_VERSION(1, 8)
/**
+ * Introduced alongside CHRE API v1.8, adds flush() API.
+ */
+#define CHRE_PAL_BLE_API_V1_9 CHRE_PAL_CREATE_API_VERSION(1, 9)
+
+/**
+ * Introduced alongside CHRE API v1.9, add broadcaster address filter.
+ */
+#define CHRE_PAL_BLE_API_V1_10 CHRE_PAL_CREATE_API_VERSION(1, 10)
+
+/**
* The version of the CHRE BLE PAL defined in this header file.
*/
-#define CHRE_PAL_BLE_API_CURRENT_VERSION CHRE_PAL_BLE_API_V1_8
+#define CHRE_PAL_BLE_API_CURRENT_VERSION CHRE_PAL_BLE_API_V1_10
/**
* The maximum amount of time allowed to elapse between the call to
@@ -123,6 +133,18 @@ struct chrePalBleCallbacks {
void (*readRssiCallback)(uint8_t errorCode, uint16_t handle, int8_t rssi);
/**
+ * Callback used to inform CHRE of a completed flush event.
+ *
+ * @param errorCode An error code from enum chreError, with CHRE_ERROR_NONE
+ * indicating a successful response.
+ *
+ * @see chrePalBleApi.flush
+ *
+ * @since v1.9
+ */
+ void (*flushCallback)(uint8_t errorCode);
+
+ /**
* Sends a BT snoop log to the CHRE daemon.
*
* @param isTxToBtController True if the direction of the BT snoop log is Tx
@@ -202,7 +224,7 @@ struct chrePalBleApi {
* @see chreBleStartScanAsync()
*/
bool (*startScan)(enum chreBleScanMode mode, uint32_t reportDelayMs,
- const struct chreBleScanFilter *filter);
+ const struct chreBleScanFilterV1_9 *filter);
/**
* Stops Bluetooth LE (BLE) scanning.
*
@@ -243,6 +265,17 @@ struct chrePalBleApi {
* @since v1.8
*/
bool (*readRssi)(uint16_t connectionHandle);
+
+ /**
+ * Initiates a flush operation where all batched advertisement events will be
+ * immediately processed.
+ *
+ * @return true if the request was accepted, in which case a subsequent call
+ * to flushCallback() will be used to indicate the result of the operation.
+ *
+ * @since v1.9
+ */
+ bool (*flush)();
};
/**
diff --git a/pal/tests/src/audio_pal_impl_test.cc b/pal/tests/src/audio_pal_impl_test.cc
index 1b3c3068..daf8e1e0 100644
--- a/pal/tests/src/audio_pal_impl_test.cc
+++ b/pal/tests/src/audio_pal_impl_test.cc
@@ -125,8 +125,7 @@ TEST_F(PalAudioTest, GetDataEvent) {
LockGuard<Mutex> lock(gCallbacks->mMutex);
EXPECT_TRUE(mApi->requestAudioDataEvent(0 /*handle*/, 1000 /*numSamples*/,
100 /*eventDelaysNs*/));
- gCallbacks->mCondVarDataEvents.wait_for(
- gCallbacks->mMutex, Nanoseconds(25 * kOneMillisecondInNanoseconds));
+ gCallbacks->mCondVarDataEvents.wait(gCallbacks->mMutex);
ASSERT_TRUE(gCallbacks->mDataEvent.has_value());
struct chreAudioDataEvent *event = gCallbacks->mDataEvent.value();
EXPECT_EQ(event->handle, 0);
diff --git a/pal/tests/src/ble_pal_impl_test.cc b/pal/tests/src/ble_pal_impl_test.cc
index 0d08a879..8c53aebd 100644
--- a/pal/tests/src/ble_pal_impl_test.cc
+++ b/pal/tests/src/ble_pal_impl_test.cc
@@ -35,6 +35,7 @@ namespace {
using ::chre::ConditionVariable;
using ::chre::createBleScanFilterForKnownBeacons;
+using ::chre::createBleScanFilterForKnownBeaconsV1_9;
using ::chre::FixedSizeVector;
using ::chre::gChrePalSystemApi;
using ::chre::LockGuard;
@@ -53,6 +54,10 @@ constexpr uint32_t kBleBatchDurationMs = 0;
class Callbacks {
public:
+ Callbacks() = delete;
+
+ explicit Callbacks(const struct chrePalBleApi *api) : mApi(api) {}
+
void requestStateResync() {}
void scanStatusChangeCallback(bool enabled, uint8_t errorCode) {
@@ -71,6 +76,8 @@ class Callbacks {
if (mEventData.full()) {
mCondVarEvents.notify_one();
}
+ } else {
+ mApi->releaseAdvertisingEvent(event);
}
}
@@ -83,6 +90,9 @@ class Callbacks {
Mutex mMutex;
ConditionVariable mCondVarStatus;
ConditionVariable mCondVarEvents;
+
+ //! CHRE PAL implementation API.
+ const struct chrePalBleApi *mApi;
};
UniquePtr<Callbacks> gCallbacks = nullptr;
@@ -108,10 +118,10 @@ void advertisingEventCallback(struct chreBleAdvertisementEvent *event) {
class PalBleTest : public testing::Test {
protected:
void SetUp() override {
- gCallbacks = MakeUnique<Callbacks>();
chre::TaskManagerSingleton::deinit();
chre::TaskManagerSingleton::init();
mApi = chrePalBleGetApi(CHRE_PAL_BLE_API_CURRENT_VERSION);
+ gCallbacks = MakeUnique<Callbacks>(mApi);
ASSERT_NE(mApi, nullptr);
EXPECT_EQ(mApi->moduleVersion, CHRE_PAL_BLE_API_CURRENT_VERSION);
ASSERT_TRUE(mApi->open(&gChrePalSystemApi, &mPalCallbacks));
@@ -168,19 +178,21 @@ TEST_F(PalBleTest, Capabilities) {
// advertising BLE beacons with service data for either the Google eddystone
// or fastpair UUIDs.
TEST_F(PalBleTest, FilteredScan) {
- struct chreBleScanFilter filter;
+ struct chreBleScanFilterV1_9 filterV1_9;
chreBleGenericFilter uuidFilters[kNumScanFilters];
- createBleScanFilterForKnownBeacons(filter, uuidFilters, kNumScanFilters);
+ createBleScanFilterForKnownBeaconsV1_9(filterV1_9, uuidFilters,
+ kNumScanFilters);
+
+ LockGuard<Mutex> lock(gCallbacks->mMutex);
EXPECT_TRUE(mApi->startScan(CHRE_BLE_SCAN_MODE_BACKGROUND,
- kBleBatchDurationMs, &filter));
+ kBleBatchDurationMs, &filterV1_9));
- LockGuard<Mutex> lock(gCallbacks->mMutex);
+ EXPECT_TRUE(mApi->startScan(CHRE_BLE_SCAN_MODE_AGGRESSIVE,
+ kBleBatchDurationMs, &filterV1_9));
gCallbacks->mCondVarStatus.wait_for(gCallbacks->mMutex, kBleStatusTimeoutNs);
- EXPECT_TRUE(gCallbacks->mEnabled.has_value());
- if (gCallbacks->mEnabled.has_value()) {
- EXPECT_TRUE(gCallbacks->mEnabled.value());
- }
+ ASSERT_TRUE(gCallbacks->mEnabled.has_value());
+ EXPECT_TRUE(gCallbacks->mEnabled.value());
gCallbacks->mCondVarEvents.wait_for(gCallbacks->mMutex, kBleEventTimeoutNs);
EXPECT_TRUE(gCallbacks->mEventData.full());
diff --git a/pal/tests/src/sensor_pal_impl_test.cc b/pal/tests/src/sensor_pal_impl_test.cc
index f76c6174..6b0aefa2 100644
--- a/pal/tests/src/sensor_pal_impl_test.cc
+++ b/pal/tests/src/sensor_pal_impl_test.cc
@@ -183,6 +183,8 @@ TEST_F(PalSensorTest, EnableAContinuousSensor) {
ASSERT_TRUE(gCallbacks->mStatus.has_value());
EXPECT_TRUE(gCallbacks->mStatus.value()->enabled);
gApi->releaseSamplingStatusEvent(gCallbacks->mStatus.value());
+ gCallbacks->mStatus.reset();
+ gCallbacks->mStatusSensorIndex.reset();
gCallbacks->mCondVarEvents.wait_for(
gCallbacks->mMutex,
@@ -197,6 +199,22 @@ TEST_F(PalSensorTest, EnableAContinuousSensor) {
EXPECT_EQ(threeAxisData->header.readingCount, 1);
gApi->releaseSensorDataEvent(data);
}
+ // Need to unlock this mutex because the following disable sensor request
+ // needs it.
+ gCallbacks->mMutex.unlock();
+
+ EXPECT_TRUE(gApi->configureSensor(
+ 0 /* sensorInfoIndex */, CHRE_SENSOR_CONFIGURE_MODE_DONE,
+ kOneMillisecondInNanoseconds /* intervalNs */, 0 /* latencyNs */));
+ gCallbacks->mMutex.lock();
+ gCallbacks->mCondVarStatus.wait_for(
+ gCallbacks->mMutex,
+ Nanoseconds(kTimeoutMultiplier * kOneMillisecondInNanoseconds));
+ ASSERT_TRUE(gCallbacks->mStatusSensorIndex.has_value());
+ ASSERT_TRUE(gCallbacks->mStatus.has_value());
+ gApi->releaseSamplingStatusEvent(gCallbacks->mStatus.value());
+ gCallbacks->mStatus.reset();
+ gCallbacks->mStatusSensorIndex.reset();
}
TEST_F(PalSensorTest, DisableAContinuousSensor) {
@@ -208,11 +226,13 @@ TEST_F(PalSensorTest, DisableAContinuousSensor) {
gCallbacks->mCondVarStatus.wait_for(
gCallbacks->mMutex,
Nanoseconds(kTimeoutMultiplier * kOneMillisecondInNanoseconds));
- EXPECT_TRUE(gCallbacks->mStatusSensorIndex.has_value());
+ ASSERT_TRUE(gCallbacks->mStatusSensorIndex.has_value());
EXPECT_EQ(gCallbacks->mStatusSensorIndex.value(), 0);
- EXPECT_TRUE(gCallbacks->mStatus.has_value());
+ ASSERT_TRUE(gCallbacks->mStatus.has_value());
EXPECT_FALSE(gCallbacks->mStatus.value()->enabled);
gApi->releaseSamplingStatusEvent(gCallbacks->mStatus.value());
+ gCallbacks->mStatus.reset();
+ gCallbacks->mStatusSensorIndex.reset();
}
-} // namespace \ No newline at end of file
+} // namespace
diff --git a/platform/exynos/host_link.cc b/platform/exynos/host_link.cc
index 3e03bec3..480e022c 100644
--- a/platform/exynos/host_link.cc
+++ b/platform/exynos/host_link.cc
@@ -139,6 +139,8 @@ void HostMessageHandlers::handleNanoappListRequest(uint16_t hostClientId) {
// TODO(b/230134803): Implement this.
}
+void HostMessageHandlers::handlePulseRequest() {}
+
void HostMessageHandlers::sendFragmentResponse(uint16_t hostClientId,
uint32_t transactionId,
uint32_t fragmentId,
diff --git a/platform/include/chre/platform/assert.h b/platform/include/chre/platform/assert.h
index 218dd48a..be83a360 100644
--- a/platform/include/chre/platform/assert.h
+++ b/platform/include/chre/platform/assert.h
@@ -21,19 +21,26 @@
/**
* @file
- * Defines the CHRE_ASSERT and CHRE_ASSERT_LOG macros for CHRE platforms.
- * Platforms must supply an implementation for assertCondition or use the shared
- * implementation.
+ * Includes the platform-specific header file that supplies an assertion macro.
+ * The platform header must supply the following symbol as a macro or free
+ * function:
+ *
+ * CHRE_ASSERT(scalar expression)
+ *
+ * Where expression will be checked to be false (ie: compares equal to zero) and
+ * terminate the program if found to be the case.
*/
-#if defined(CHRE_ASSERTIONS_ENABLED)
+#if defined(CHRE_ASSERTIONS_ENABLED) && defined(CHRE_ASSERTIONS_DISABLED)
+#error "CHRE_ASSERT is both enabled and disabled!"
-#define CHRE_ASSERT(condition) \
- do { \
- if (!(condition)) { \
- chreDoAssert(CHRE_FILENAME, __LINE__); \
- } \
- } while (0)
+#elif defined(CHRE_ASSERTIONS_ENABLED)
+
+#include "chre/target_platform/assert.h"
+
+#ifndef CHRE_ASSERT
+#error "CHRE_ASSERT must be defined by the target platform's assert.h"
+#endif // CHRE_ASSERT
#elif defined(CHRE_ASSERTIONS_DISABLED)
@@ -81,20 +88,4 @@
#define CHRE_ASSERT_IF_NOT_TEST(condition) CHRE_ASSERT(condition)
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Performs assertion while logging the filename and line provided.
- *
- * @param filename The filename containing the assertion being fired.
- * @param line The line that contains the assertion being fired.
- */
-void chreDoAssert(const char *filename, size_t line);
-
-#ifdef __cplusplus
-}
-#endif
-
#endif // CHRE_PLATFORM_ASSERT_H_
diff --git a/platform/include/chre/platform/atomic.h b/platform/include/chre/platform/atomic.h
index 7688c499..445feb90 100644
--- a/platform/include/chre/platform/atomic.h
+++ b/platform/include/chre/platform/atomic.h
@@ -53,7 +53,7 @@ class AtomicBool : public AtomicBoolBase, public NonCopyable {
*/
operator bool() const {
return load();
- };
+ }
/**
* Atomically loads the current value of the atomic object.
diff --git a/platform/include/chre/platform/fatal_error.h b/platform/include/chre/platform/fatal_error.h
index 0c301db0..f272eba8 100644
--- a/platform/include/chre/platform/fatal_error.h
+++ b/platform/include/chre/platform/fatal_error.h
@@ -40,6 +40,9 @@
do { \
LOGE(fmt, ##__VA_ARGS__); \
FATAL_ERROR_QUIT(); \
+ while (1) { \
+ /* never return */ \
+ } \
} while (0)
/**
diff --git a/platform/include/chre/platform/platform_ble.h b/platform/include/chre/platform/platform_ble.h
index 3f9b56ad..fdb495f0 100644
--- a/platform/include/chre/platform/platform_ble.h
+++ b/platform/include/chre/platform/platform_ble.h
@@ -69,7 +69,7 @@ class PlatformBle : public PlatformBleBase {
* @return true if scan was successfully enabled.
*/
bool startScanAsync(chreBleScanMode mode, uint32_t reportDelayMs,
- const struct chreBleScanFilter *filter);
+ const struct chreBleScanFilterV1_9 *filter);
/**
* End a BLE scan asynchronously. The result is delivered through a
@@ -105,6 +105,17 @@ class PlatformBle : public PlatformBleBase {
* @since v1.8
*/
bool readRssiAsync(uint16_t connectionHandle);
+
+ /**
+ * Initiates a flush operation where all batched advertisement events will be
+ * immediately processed.
+ *
+ * @return true if the request was accepted, in which case a subsequent call
+ * to flushCallback() will be used to indicate the result of the operation.
+ *
+ * @since v1.9
+ */
+ bool flushAsync();
};
} // namespace chre
diff --git a/platform/include/chre/platform/tracing.h b/platform/include/chre/platform/tracing.h
index fc94deb4..7a5559be 100644
--- a/platform/include/chre/platform/tracing.h
+++ b/platform/include/chre/platform/tracing.h
@@ -19,36 +19,90 @@
#include <cstdint>
-/**
- * @file
- * Tracing support for CHRE.
- * Platforms must supply an implementation of the trace functions.
- */
+// Needs to be a number because it's used in STRINGIFY and as a number.
+#define CHRE_TRACE_STR_BUFFER_SIZE 11
+// Strings are placed into a buffer in the form:
+// {<1-byte str len>, str chars...}.
+// So the max string size is always one less than the total string buffer size.
+#define CHRE_TRACE_MAX_STRING_SIZE CHRE_TRACE_STR_BUFFER_SIZE - 1
-namespace chre {
-/**
- * Registers a nanoapp instance with the tracing infrastructure.
- *
- * @param instanceId instance ID of the nanoapp.
- * @param name name of the nanoapp.
- */
-void traceRegisterNanoapp(uint16_t instanceId, const char *name);
+// TODO(b/301497381): See if netstruct lib would be more useful here
+// Field values defined by python struct docs:
+// https://docs.python.org/3/library/struct.html.
+#define TRACE_BOOL "?"
+#define TRACE_U8 "B"
+#define TRACE_U16 "H"
+#define TRACE_U32 "L"
+#define TRACE_U64 "Q"
+#define TRACE_I8 "b"
+#define TRACE_I16 "h"
+#define TRACE_I32 "l"
+#define TRACE_I64 "q"
+#define TRACE_C "c"
+#define TRACE_S STRINGIFY(CHRE_TRACE_STR_BUFFER_SIZE) "p"
-/**
- * Marks the start of the nanoappHandleEvent function.
- *
- * @param instanceId instance ID of the nanoapp.
- * @param eventType event being handled.
- */
-void traceNanoappHandleEventStart(uint16_t instanceId, uint16_t eventType);
+// Check to make sure pointer size macro is defined.
+#ifndef __SIZEOF_POINTER__
+#error "__SIZEOF_POINTER__ macro not defined - unsupported toolchain being used"
+#else
+static_assert(sizeof(void *) == __SIZEOF_POINTER__,
+ "Size of pointer does not match __SIZEOF_POINTER__ macro");
+#endif
+
+// Check the predefined pointer size to use the most accurate size
+#if __SIZEOF_POINTER__ == 8
+#define TRACE_PTR TRACE_U64
+#elif __SIZEOF_POINTER__ == 4
+#define TRACE_PTR TRACE_U32
+#else
+#error "Pointer size is of unsupported size"
+#endif // __SIZEOF_POINTER__ == 8 || __SIZEOF_POINTER__ == 4
+
+#ifdef CHRE_TRACING_ENABLED
+
+#include "chre/target_platform/tracing.h"
/**
- * Marks the end of the nanoappHandleEvent function.
- *
- * @param instanceId instance ID of the nanoapp.
+ * All tracing macros to be used in CHRE
*/
-void traceNanoappHandleEventEnd(uint16_t instanceId);
+#ifndef CHRE_TRACE_INSTANT
+#error "CHRE_TRACE_INSTANT must be defined by chre/target_platform/tracing.h"
+#endif
+
+#ifndef CHRE_TRACE_START
+#error "CHRE_TRACE_START must be defined by chre/target_platform/tracing.h"
+#endif
+
+#ifndef CHRE_TRACE_END
+#error "CHRE_TRACE_END must be defined by chre/target_platform/tracing.h"
+#endif
+
+#ifndef CHRE_TRACE_INSTANT_DATA
+#error \
+ "CHRE_TRACE_INSTANT_DATA must be defined by chre/target_platform/tracing.h"
+#endif
+
+#ifndef CHRE_TRACE_START_DATA
+#error "CHRE_TRACE_START_DATA must be defined by chre/target_platform/tracing.h"
+#endif
+
+#ifndef CHRE_TRACE_END_DATA
+#error "CHRE_TRACE_END_DATA must be defined by chre/target_platform/tracing.h"
+#endif
+
+#else // CHRE_TRACING_ENABLED
+
+#include "chre/util/macros.h"
+
+inline void chreTraceUnusedParams(...) {}
+
+#define CHRE_TRACE_INSTANT(...) chreTraceUnusedParams(__VA_ARGS__)
+#define CHRE_TRACE_START(...) chreTraceUnusedParams(__VA_ARGS__)
+#define CHRE_TRACE_END(...) chreTraceUnusedParams(__VA_ARGS__)
+#define CHRE_TRACE_INSTANT_DATA(...) chreTraceUnusedParams(__VA_ARGS__)
+#define CHRE_TRACE_START_DATA(...) chreTraceUnusedParams(__VA_ARGS__)
+#define CHRE_TRACE_END_DATA(...) chreTraceUnusedParams(__VA_ARGS__)
-} // namespace chre
+#endif // CHRE_TRACING_ENABLED
#endif // CHRE_PLATFORM_TRACING_H_
diff --git a/platform/linux/include/chre/platform/linux/task_util/task.h b/platform/linux/include/chre/platform/linux/task_util/task.h
index 858cfb74..698df3b5 100644
--- a/platform/linux/include/chre/platform/linux/task_util/task.h
+++ b/platform/linux/include/chre/platform/linux/task_util/task.h
@@ -28,7 +28,7 @@ namespace task_manager_internal {
/**
* Represents a task to execute (a function to call) that can be executed once
- * or repeatedly with interval: repeatInterval in milliseconds until
+ * or repeatedly with interval: intervalOrDelay in nanoseconds until
* cancel() is called.
*
* Note: The Task class is not thread-safe nor synchronized properly. It is
@@ -51,12 +51,14 @@ class Task {
* Construct a new Task object.
*
* @param func the function to execute.
- * @param repeatInterval the interval in which to repeat execution in
- * milliseconds.
+ * @param intervalOrDelay the interval in which to repeat execution or the
+ * delay for a one-shot Task.
* @param id the unique ID for use with the Task Manager.
+ * @param isOneShot if true, the task should only be executed once
+ * after a delay of intervalOrDelay.
*/
- Task(const TaskFunction &func, std::chrono::milliseconds repeatInterval,
- uint32_t id);
+ Task(const TaskFunction &func, std::chrono::nanoseconds intervalOrDelay,
+ uint32_t id, bool isOneShot = false);
/**
* Construct a new Task object.
@@ -68,8 +70,8 @@ class Task {
/**
* Assignment operator.
*
- * @param rhs rhs arg.
- * @return this.
+ * @param rhs rhs arg.
+ * @return this.
*/
Task &operator=(const Task &rhs);
@@ -101,8 +103,8 @@ class Task {
/**
* Returns true if the task has executed at least once, false if otherwise.
*
- * @return true if the task has executed at least once.
- * @return false if the task has not executed at least once.
+ * @return true if the task has executed at least once.
+ * @return false if the task has not executed at least once.
*/
inline bool hasExecuted() const {
return mHasExecuted;
@@ -112,8 +114,8 @@ class Task {
* Returns true if the task is ready to execute (time now is >= task
* timestamp).
*
- * @return true the task can be executed.
- * @return false do not yet execute the task.
+ * @return true the task can be executed.
+ * @return false do not yet execute the task.
*/
inline bool isReadyToExecute() const {
return mExecutionTimestamp <= std::chrono::steady_clock::now();
@@ -121,10 +123,10 @@ class Task {
/**
* Returns true if the task is a repeating task - if it has has a
- * repeatInterval > 0.
+ * intervalOrDelay > 0.
*
- * @return true if the task is a repeating task.
- * @return false otherwise.
+ * @return true if the task is a repeating task.
+ * @return false otherwise.
*/
inline bool isRepeating() const {
return mRepeatInterval.count() > 0;
@@ -158,7 +160,7 @@ class Task {
/**
* The amount of time to wait in between repeating the task.
*/
- std::chrono::milliseconds mRepeatInterval;
+ std::chrono::nanoseconds mRepeatInterval;
/**
* The function to execute.
diff --git a/platform/linux/include/chre/platform/linux/task_util/task_manager.h b/platform/linux/include/chre/platform/linux/task_util/task_manager.h
index 9710c39c..ad322216 100644
--- a/platform/linux/include/chre/platform/linux/task_util/task_manager.h
+++ b/platform/linux/include/chre/platform/linux/task_util/task_manager.h
@@ -51,24 +51,29 @@ class TaskManager : public NonCopyable {
/**
* Adds a task to the queue for execution. The manager calls the function func
- * during execution. If repeatInterval > 0, the task will repeat every
- * repeatInterval milliseconds. If repeatInterval == 0, the task will be
- * executed only once.
+ * during execution. If intervalOrDelay > 0 and isOneShot is false, the task
+ * will repeat every intervalOrDelay nanoseconds. If intervalOrDelay is > 0
+ * and isOneShot is true, the task will be executed only once after a delay of
+ * intervalOrDelay. If intervalOrDelay == 0, the task will be executed only
+ * once with no delay.
*
* @param func the function to call.
- * @param repeatInterval the interval to repeat.
+ * @param intervalOrDelay the interval to repeat.
+ * @param isOneShot if true, the task should be executed only
+ * once with a delay of intervalOrDelay.
* @return the ID of the Task object or an empty
* Optional<> when there is an error.
*/
std::optional<uint32_t> addTask(
const Task::TaskFunction &func,
- std::chrono::milliseconds repeatInterval = std::chrono::milliseconds(0));
+ std::chrono::nanoseconds intervalOrDelay = std::chrono::nanoseconds(0),
+ bool isOneShot = false);
/**
* Cancels the task with the taskId.
*
- * @param taskId the ID of the task.
- * @return bool success.
+ * @param taskId the ID of the task.
+ * @return bool success.
*/
bool cancelTask(uint32_t taskId);
diff --git a/platform/linux/include/chre/target_platform/assert.h b/platform/linux/include/chre/target_platform/assert.h
new file mode 100644
index 00000000..76f2450f
--- /dev/null
+++ b/platform/linux/include/chre/target_platform/assert.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PLATFORM_LINUX_INCLUDE_CHRE_TARGET_PLATFORM_ASSERT_H
+#define PLATFORM_LINUX_INCLUDE_CHRE_TARGET_PLATFORM_ASSERT_H
+
+#include "chre/platform/shared/assert_func.h"
+
+#endif // PLATFORM_LINUX_INCLUDE_CHRE_TARGET_PLATFORM_ASSERT_H
diff --git a/platform/linux/pal_audio.cc b/platform/linux/pal_audio.cc
index 3664c0d3..5816232c 100644
--- a/platform/linux/pal_audio.cc
+++ b/platform/linux/pal_audio.cc
@@ -31,7 +31,7 @@
*/
namespace {
-using chre::TaskManagerSingleton;
+using ::chre::TaskManagerSingleton;
const struct chrePalSystemApi *gSystemApi = nullptr;
const struct chrePalAudioCallbacks *gCallbacks = nullptr;
@@ -45,6 +45,7 @@ bool gIsHandle0Enabled = false;
void stopHandle0Task() {
if (gHandle0TaskId.has_value()) {
TaskManagerSingleton::get()->cancelTask(gHandle0TaskId.value());
+ gHandle0TaskId.reset();
}
}
@@ -80,9 +81,6 @@ void sendHandle0Events(uint32_t numSamples) {
static_cast<const uint8_t *>(chre::memoryAlloc(numSamples));
gCallbacks->audioDataEventCallback(data.release());
-
- // Cancel the task so this is only run once with a delay.
- TaskManagerSingleton::get()->cancelTask(gHandle0TaskId.value());
}
bool chrePalAudioApiRequestAudioDataEvent(uint32_t handle, uint32_t numSamples,
@@ -96,8 +94,7 @@ bool chrePalAudioApiRequestAudioDataEvent(uint32_t handle, uint32_t numSamples,
gIsHandle0Enabled = true;
gHandle0TaskId = TaskManagerSingleton::get()->addTask(
[numSamples]() { sendHandle0Events(numSamples); },
- std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::nanoseconds(eventDelayNs)));
+ std::chrono::nanoseconds(eventDelayNs), true /*isOneShot*/);
if (!gHandle0TaskId.has_value()) {
return false;
}
diff --git a/platform/linux/pal_ble.cc b/platform/linux/pal_ble.cc
index bb4b144f..341caea6 100644
--- a/platform/linux/pal_ble.cc
+++ b/platform/linux/pal_ble.cc
@@ -24,23 +24,30 @@
#include <chrono>
#include <optional>
+#include <vector>
/**
* A simulated implementation of the BLE PAL for the linux platform.
*/
namespace {
-using chre::TaskManagerSingleton;
+using ::chre::TaskManagerSingleton;
const struct chrePalSystemApi *gSystemApi = nullptr;
const struct chrePalBleCallbacks *gCallbacks = nullptr;
bool gBleEnabled = false;
bool gDelayScanStart = false;
-std::chrono::milliseconds gScanInterval(1400);
+
+std::mutex gBatchMutex;
+std::vector<struct chreBleAdvertisementEvent *> gBatchedAdEvents;
+std::chrono::time_point<std::chrono::steady_clock> gLastAdDataTimestamp;
+std::optional<uint32_t> gReportDelayMs;
+std::chrono::nanoseconds gScanInterval = std::chrono::milliseconds(1400);
// Tasks for startScan, sendAdReportEvents, and stopScan.
std::optional<uint32_t> gBleAdReportEventTaskId;
+std::optional<uint32_t> gBleFlushTaskId;
void updateScanInterval(chreBleScanMode mode) {
gScanInterval = std::chrono::milliseconds(1400);
@@ -57,6 +64,15 @@ void updateScanInterval(chreBleScanMode mode) {
}
}
+void flush() {
+ std::lock_guard<std::mutex> lock(gBatchMutex);
+ for (struct chreBleAdvertisementEvent *batchedEvent : gBatchedAdEvents) {
+ gCallbacks->advertisingEventCallback(batchedEvent);
+ }
+ gBatchedAdEvents.clear();
+ gLastAdDataTimestamp = std::chrono::steady_clock::now();
+}
+
void sendAdReportEvents() {
auto event = chre::MakeUniqueZeroFill<struct chreBleAdvertisementEvent>();
auto report = chre::MakeUniqueZeroFill<struct chreBleAdvertisingReport>();
@@ -69,22 +85,58 @@ void sendAdReportEvents() {
report->dataLength = 2;
event->reports = report.release();
event->numReports = 1;
- gCallbacks->advertisingEventCallback(event.release());
+
+ std::lock_guard<std::mutex> lock(gBatchMutex);
+ if (!gReportDelayMs.has_value() || gReportDelayMs.value() == 0) {
+ gCallbacks->advertisingEventCallback(event.release());
+ } else {
+ gBatchedAdEvents.push_back(event.release());
+ }
}
void stopAllTasks() {
if (gBleAdReportEventTaskId.has_value()) {
TaskManagerSingleton::get()->cancelTask(gBleAdReportEventTaskId.value());
+ gBleAdReportEventTaskId.reset();
+ }
+
+ if (gBleFlushTaskId.has_value()) {
+ TaskManagerSingleton::get()->cancelTask(gBleFlushTaskId.value());
+ gBleFlushTaskId.reset();
}
}
bool startScan() {
stopAllTasks();
- gCallbacks->scanStatusChangeCallback(true, CHRE_ERROR_NONE);
- gBleEnabled = true;
+
+ std::lock_guard<std::mutex> lock(gBatchMutex);
+ gLastAdDataTimestamp = std::chrono::steady_clock::now();
+
gBleAdReportEventTaskId =
TaskManagerSingleton::get()->addTask(sendAdReportEvents, gScanInterval);
- return gBleAdReportEventTaskId.has_value();
+ if (!gBleAdReportEventTaskId.has_value()) {
+ return false;
+ }
+
+ if (gReportDelayMs.has_value()) {
+ gBleFlushTaskId = TaskManagerSingleton::get()->addTask(
+ flush, std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::milliseconds(gReportDelayMs.value())));
+ if (!gBleFlushTaskId.has_value()) {
+ stopAllTasks();
+ return false;
+ }
+ }
+
+ std::optional<uint32_t> callbackTaskId = TaskManagerSingleton::get()->addTask(
+ []() { gCallbacks->scanStatusChangeCallback(true, CHRE_ERROR_NONE); });
+ if (!callbackTaskId.has_value()) {
+ stopAllTasks();
+ return false;
+ }
+
+ gBleEnabled = true;
+ return true;
}
uint32_t chrePalBleGetCapabilities() {
@@ -98,20 +150,33 @@ uint32_t chrePalBleGetFilterCapabilities() {
CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA;
}
-bool chrePalBleStartScan(chreBleScanMode mode, uint32_t /* reportDelayMs */,
- const struct chreBleScanFilter * /* filter */) {
- updateScanInterval(mode);
- if (gDelayScanStart) {
- return true;
+bool chrePalBleStartScan(chreBleScanMode mode, uint32_t reportDelayMs,
+ const struct chreBleScanFilterV1_9 * /* filter */) {
+ {
+ std::lock_guard<std::mutex> lock(gBatchMutex);
+
+ if (gReportDelayMs.has_value()) {
+ gReportDelayMs = std::min(gReportDelayMs.value(), reportDelayMs);
+ } else {
+ gReportDelayMs = reportDelayMs;
+ }
}
- return startScan();
+
+ updateScanInterval(mode);
+ flush();
+ return gDelayScanStart || startScan();
}
bool chrePalBleStopScan() {
stopAllTasks();
- gCallbacks->scanStatusChangeCallback(false, CHRE_ERROR_NONE);
- gBleEnabled = false;
- return true;
+ flush();
+
+ std::optional<uint32_t> callbackTaskId = TaskManagerSingleton::get()->addTask(
+ []() { gCallbacks->scanStatusChangeCallback(false, CHRE_ERROR_NONE); });
+
+ // If the callback is successfully scheduled, then BLE is disabled.
+ gBleEnabled = !callbackTaskId.has_value();
+ return callbackTaskId.has_value();
}
void chrePalBleReleaseAdvertisingEvent(
@@ -125,12 +190,34 @@ void chrePalBleReleaseAdvertisingEvent(
}
bool chrePalBleReadRssi(uint16_t connectionHandle) {
- gCallbacks->readRssiCallback(CHRE_ERROR_NONE, connectionHandle, -65);
- return true;
+ std::optional<uint32_t> readRssiTaskId =
+ TaskManagerSingleton::get()->addTask([connectionHandle]() {
+ gCallbacks->readRssiCallback(CHRE_ERROR_NONE, connectionHandle, -65);
+ });
+
+ return readRssiTaskId.has_value();
+}
+
+bool chrePalBleFlush() {
+ std::optional<uint32_t> flushTaskId =
+ TaskManagerSingleton::get()->addTask([]() {
+ flush();
+ gCallbacks->flushCallback(CHRE_ERROR_NONE);
+ });
+
+ return flushTaskId.has_value();
}
void chrePalBleApiClose() {
stopAllTasks();
+
+ {
+ std::lock_guard<std::mutex> lock(gBatchMutex);
+
+ for (struct chreBleAdvertisementEvent *batchedEvent : gBatchedAdEvents) {
+ chrePalBleReleaseAdvertisingEvent(batchedEvent);
+ }
+ }
}
bool chrePalBleApiOpen(const struct chrePalSystemApi *systemApi,
@@ -172,6 +259,7 @@ const struct chrePalBleApi *chrePalBleGetApi(uint32_t requestedApiVersion) {
.stopScan = chrePalBleStopScan,
.releaseAdvertisingEvent = chrePalBleReleaseAdvertisingEvent,
.readRssi = chrePalBleReadRssi,
+ .flush = chrePalBleFlush,
};
if (!CHRE_PAL_VERSIONS_ARE_COMPATIBLE(kApi.moduleVersion,
diff --git a/platform/linux/pal_gnss.cc b/platform/linux/pal_gnss.cc
index ebb40b51..ae78a648 100644
--- a/platform/linux/pal_gnss.cc
+++ b/platform/linux/pal_gnss.cc
@@ -32,7 +32,7 @@
*/
namespace {
-using chre::TaskManagerSingleton;
+using ::chre::TaskManagerSingleton;
const struct chrePalSystemApi *gSystemApi = nullptr;
const struct chrePalGnssCallbacks *gCallbacks = nullptr;
@@ -40,7 +40,6 @@ const struct chrePalGnssCallbacks *gCallbacks = nullptr;
// Task to deliver asynchronous location data after a CHRE request.
std::mutex gLocationEventsMutex;
std::optional<uint32_t> gLocationEventsTaskId;
-std::optional<uint32_t> gLocationEventsChangeCallbackTaskId;
uint32_t gLocationEventsMinIntervalMs = 0;
bool gDelaySendingLocationEvents = false;
bool gIsLocationEnabled = false;
@@ -49,7 +48,6 @@ bool gIsLocationEnabled = false;
std::optional<uint32_t> gLocationStatusTaskId;
// Task to deliver asynchronous measurement data after a CHRE request.
-std::optional<uint32_t> gMeasurementEventsChangeCallbackTaskId;
std::optional<uint32_t> gMeasurementEventsTaskId;
bool gIsMeasurementEnabled = false;
@@ -73,11 +71,12 @@ void startSendingLocationEvents(uint32_t minIntervalMs) {
std::lock_guard<std::mutex> lock(gLocationEventsMutex);
if (gLocationEventsTaskId.has_value()) {
TaskManagerSingleton::get()->cancelTask(gLocationEventsTaskId.value());
+ gLocationEventsTaskId.reset();
}
- gLocationEventsChangeCallbackTaskId = TaskManagerSingleton::get()->addTask(
+ TaskManagerSingleton::get()->addTask(
[]() { gCallbacks->locationStatusChangeCallback(true, CHRE_ERROR_NONE); },
- std::chrono::milliseconds(0));
+ std::chrono::nanoseconds(0), true /* isOneShot */);
gLocationEventsTaskId = TaskManagerSingleton::get()->addTask(
sendLocationEvents, std::chrono::milliseconds(minIntervalMs));
@@ -108,33 +107,28 @@ void stopMeasurement() {
void stopLocationTasks() {
{
std::lock_guard<std::mutex> lock(gLocationEventsMutex);
- if (gLocationEventsChangeCallbackTaskId.has_value()) {
- TaskManagerSingleton::get()->cancelTask(
- gLocationEventsChangeCallbackTaskId.value());
- }
if (gLocationEventsTaskId.has_value()) {
TaskManagerSingleton::get()->cancelTask(gLocationEventsTaskId.value());
+ gLocationEventsTaskId.reset();
}
}
if (gLocationStatusTaskId.has_value()) {
TaskManagerSingleton::get()->cancelTask(gLocationStatusTaskId.value());
+ gLocationStatusTaskId.reset();
}
}
void stopMeasurementTasks() {
- if (gMeasurementEventsChangeCallbackTaskId.has_value()) {
- TaskManagerSingleton::get()->cancelTask(
- gMeasurementEventsChangeCallbackTaskId.value());
- }
-
if (gMeasurementEventsTaskId.has_value()) {
TaskManagerSingleton::get()->cancelTask(gMeasurementEventsTaskId.value());
+ gMeasurementEventsTaskId.reset();
}
if (gMeasurementStatusTaskId.has_value()) {
TaskManagerSingleton::get()->cancelTask(gMeasurementStatusTaskId.value());
+ gMeasurementStatusTaskId.reset();
}
}
@@ -150,8 +144,7 @@ bool chrePalControlLocationSession(bool enable, uint32_t minIntervalMs,
gLocationEventsMinIntervalMs = minIntervalMs;
if (enable && !gDelaySendingLocationEvents) {
startSendingLocationEvents(minIntervalMs);
- if (!gLocationEventsChangeCallbackTaskId.has_value() ||
- !gLocationEventsTaskId.has_value()) {
+ if (!gLocationEventsTaskId.has_value()) {
return false;
}
} else if (!enable) {
@@ -173,14 +166,14 @@ bool chrePalControlMeasurementSession(bool enable, uint32_t minIntervalMs) {
stopMeasurementTasks();
if (enable) {
- gMeasurementEventsChangeCallbackTaskId =
+ std::optional<uint32_t> measurementEventsChangeCallbackTaskId =
TaskManagerSingleton::get()->addTask(
[]() {
gCallbacks->measurementStatusChangeCallback(true,
CHRE_ERROR_NONE);
},
- std::chrono::milliseconds(0));
- if (!gMeasurementEventsChangeCallbackTaskId.has_value()) {
+ std::chrono::nanoseconds(0), true /* isOneShot */);
+ if (!measurementEventsChangeCallbackTaskId.has_value()) {
return false;
}
diff --git a/platform/linux/pal_sensor.cc b/platform/linux/pal_sensor.cc
index d4df5d35..2fb2bf28 100644
--- a/platform/linux/pal_sensor.cc
+++ b/platform/linux/pal_sensor.cc
@@ -31,7 +31,7 @@
*/
namespace {
-using chre::TaskManagerSingleton;
+using ::chre::TaskManagerSingleton;
const struct chrePalSystemApi *gSystemApi = nullptr;
const struct chrePalSensorCallbacks *gCallbacks = nullptr;
@@ -57,6 +57,7 @@ bool gIsSensor0Enabled = false;
void stopSensor0Task() {
if (gSensor0TaskId.has_value()) {
TaskManagerSingleton::get()->cancelTask(gSensor0TaskId.value());
+ gSensor0TaskId.reset();
}
}
@@ -127,9 +128,7 @@ bool chrePalSensorApiConfigureSensor(uint32_t sensorInfoIndex,
gIsSensor0Enabled = true;
sendSensor0StatusUpdate(intervalNs, true /*enabled*/);
gSensor0TaskId = TaskManagerSingleton::get()->addTask(
- sendSensor0Events,
- std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::nanoseconds(intervalNs)));
+ sendSensor0Events, std::chrono::nanoseconds(intervalNs));
return gSensor0TaskId.has_value();
}
diff --git a/platform/linux/pal_wifi.cc b/platform/linux/pal_wifi.cc
index a28205c2..7013b893 100644
--- a/platform/linux/pal_wifi.cc
+++ b/platform/linux/pal_wifi.cc
@@ -34,7 +34,7 @@
*/
namespace {
-using chre::TaskManagerSingleton;
+using ::chre::TaskManagerSingleton;
const struct chrePalSystemApi *gSystemApi = nullptr;
const struct chrePalWifiCallbacks *gCallbacks = nullptr;
@@ -51,6 +51,9 @@ std::atomic_bool gEnableScanMonitorResponse(true);
//! Whether PAL should respond to scan request.
std::atomic_bool gEnableScanResponse(true);
+//! Thread sync variable for TaskIds.
+std::mutex gRequestScanMutex;
+
//! Task IDs for the scanning tasks
std::optional<uint32_t> gScanMonitorTaskId;
std::optional<uint32_t> gRequestScanTaskId;
@@ -58,10 +61,19 @@ std::optional<uint32_t> gRequestRangingTaskId;
//! How long should each the PAL hold before response.
//! Use to mimic real world hardware process time.
-std::chrono::milliseconds gAsyncRequestDelayResponseTime[chre::asBaseType(
+std::chrono::nanoseconds gAsyncRequestDelayResponseTime[chre::asBaseType(
PalWifiAsyncRequestTypes::NUM_WIFI_REQUEST_TYPE)];
void sendScanResponse() {
+ {
+ std::lock_guard<std::mutex> lock(gRequestScanMutex);
+ if (!gRequestScanTaskId.has_value()) {
+ LOGE("Sending scan response with no pending task");
+ return;
+ }
+ gRequestScanTaskId.reset();
+ }
+
if (gEnableScanResponse) {
auto event = chre::MakeUniqueZeroFill<struct chreWifiScanEvent>();
auto result = chre::MakeUniqueZeroFill<struct chreWifiScanResult>();
@@ -71,9 +83,6 @@ void sendScanResponse() {
event->results = result.release();
gCallbacks->scanEventCallback(event.release());
}
-
- // We just want to delay this task - only execute it once.
- TaskManagerSingleton::get()->cancelTask(gRequestScanTaskId.value());
}
void sendScanMonitorResponse(bool enable) {
@@ -95,18 +104,21 @@ void sendRangingResponse() {
void stopScanMonitorTask() {
if (gScanMonitorTaskId.has_value()) {
TaskManagerSingleton::get()->cancelTask(gScanMonitorTaskId.value());
+ gScanMonitorTaskId.reset();
}
}
void stopRequestScanTask() {
if (gRequestScanTaskId.has_value()) {
TaskManagerSingleton::get()->cancelTask(gRequestScanTaskId.value());
+ gRequestScanTaskId.reset();
}
}
void stopRequestRangingTask() {
if (gRequestRangingTaskId.has_value()) {
TaskManagerSingleton::get()->cancelTask(gRequestRangingTaskId.value());
+ gRequestRangingTaskId.reset();
}
}
@@ -125,7 +137,11 @@ bool chrePalWifiConfigureScanMonitor(bool enable) {
}
bool chrePalWifiApiRequestScan(const struct chreWifiScanParams * /* params */) {
- stopRequestScanTask();
+ std::lock_guard<std::mutex> lock(gRequestScanMutex);
+ if (gRequestScanTaskId.has_value()) {
+ LOGE("Requesting scan when existing scan request still in process");
+ return false;
+ }
std::optional<uint32_t> requestScanTaskCallbackId =
TaskManagerSingleton::get()->addTask([]() {
@@ -135,8 +151,10 @@ bool chrePalWifiApiRequestScan(const struct chreWifiScanParams * /* params */) {
});
if (requestScanTaskCallbackId.has_value()) {
gRequestScanTaskId = TaskManagerSingleton::get()->addTask(
- sendScanResponse, gAsyncRequestDelayResponseTime[chre::asBaseType(
- PalWifiAsyncRequestTypes::SCAN)]);
+ sendScanResponse,
+ gAsyncRequestDelayResponseTime[chre::asBaseType(
+ PalWifiAsyncRequestTypes::SCAN)],
+ /* isOneShot= */ true);
return gRequestScanTaskId.has_value();
}
return false;
@@ -257,7 +275,7 @@ bool chrePalWifiIsScanMonitoringActive() {
void chrePalWifiDelayResponse(PalWifiAsyncRequestTypes requestType,
std::chrono::seconds seconds) {
gAsyncRequestDelayResponseTime[chre::asBaseType(requestType)] =
- std::chrono::duration_cast<std::chrono::milliseconds>(seconds);
+ std::chrono::duration_cast<std::chrono::nanoseconds>(seconds);
}
const struct chrePalWifiApi *chrePalWifiGetApi(uint32_t requestedApiVersion) {
diff --git a/platform/linux/pal_wwan.cc b/platform/linux/pal_wwan.cc
index b7a488c0..64e384c7 100644
--- a/platform/linux/pal_wwan.cc
+++ b/platform/linux/pal_wwan.cc
@@ -29,7 +29,7 @@
*/
namespace {
-using chre::TaskManagerSingleton;
+using ::chre::TaskManagerSingleton;
const struct chrePalSystemApi *gSystemApi = nullptr;
const struct chrePalWwanCallbacks *gCallbacks = nullptr;
@@ -63,6 +63,7 @@ void sendCellInfoResult() {
void stopCellInfoTask() {
if (gCellInfosTaskId.has_value()) {
TaskManagerSingleton::get()->cancelTask(*gCellInfosTaskId);
+ gCellInfosTaskId.reset();
}
}
diff --git a/platform/linux/task_util/task.cc b/platform/linux/task_util/task.cc
index f224c107..7b50f8d8 100644
--- a/platform/linux/task_util/task.cc
+++ b/platform/linux/task_util/task.cc
@@ -19,16 +19,14 @@
namespace chre {
namespace task_manager_internal {
-Task::Task(const TaskFunction &func, std::chrono::milliseconds repeatInterval,
- uint32_t id)
- : mExecutionTimestamp(std::chrono::steady_clock::now() + repeatInterval),
- mRepeatInterval(repeatInterval),
+Task::Task(const TaskFunction &func, std::chrono::nanoseconds intervalOrDelay,
+ uint32_t id, bool isOneShot)
+ : mExecutionTimestamp(std::chrono::steady_clock::now() + intervalOrDelay),
+ mRepeatInterval(isOneShot ? std::chrono::nanoseconds(0)
+ : intervalOrDelay),
+ mFunc(func),
mId(id),
- mHasExecuted(false) {
- if (func != nullptr) {
- mFunc = func;
- }
-}
+ mHasExecuted(false) {}
Task::Task(const Task &rhs)
: mExecutionTimestamp(rhs.mExecutionTimestamp),
@@ -56,7 +54,7 @@ Task &Task::operator=(const Task &rhs) {
void Task::cancel() {
std::lock_guard lock(mExecutionMutex);
- mRepeatInterval = std::chrono::milliseconds(0);
+ mRepeatInterval = std::chrono::nanoseconds(0);
mFunc.reset();
}
diff --git a/platform/linux/task_util/task_manager.cc b/platform/linux/task_util/task_manager.cc
index b2130b08..22bfad7b 100644
--- a/platform/linux/task_util/task_manager.cc
+++ b/platform/linux/task_util/task_manager.cc
@@ -46,7 +46,8 @@ TaskManager::~TaskManager() {
}
std::optional<uint32_t> TaskManager::addTask(
- const Task::TaskFunction &func, std::chrono::milliseconds repeatInterval) {
+ const Task::TaskFunction &func, std::chrono::nanoseconds intervalOrDelay,
+ bool isOneShot) {
std::lock_guard<std::mutex> lock(mMutex);
bool success = false;
@@ -57,7 +58,7 @@ std::optional<uint32_t> TaskManager::addTask(
// select the next ID
assert(mCurrentId < std::numeric_limits<uint32_t>::max());
returnId = mCurrentId++;
- Task task(func, repeatInterval, returnId);
+ Task task(func, intervalOrDelay, returnId, isOneShot);
success = mQueue.push(task);
}
diff --git a/platform/linux/tests/task_manager_test.cc b/platform/linux/tests/task_manager_test.cc
index 6f52579e..28c0a8ef 100644
--- a/platform/linux/tests/task_manager_test.cc
+++ b/platform/linux/tests/task_manager_test.cc
@@ -16,8 +16,8 @@
#include <chrono>
#include <cmath>
+#include <mutex>
#include <optional>
-#include <thread>
#include "gtest/gtest.h"
@@ -25,70 +25,110 @@
namespace {
-uint32_t gVarTaskManager = 0;
-uint32_t gTask1Var = 0;
-uint32_t gTask2Var = 0;
-
-constexpr auto incrementGVar = []() { ++gVarTaskManager; };
-constexpr auto task1Func = []() { ++gTask1Var; };
-constexpr auto task2Func = []() { ++gTask2Var; };
-
-TEST(TaskManager, FlushTasks) {
+TEST(TaskManager, FlushTasksCanBeCalledMultipleTimes) {
chre::TaskManager taskManager;
- for (uint32_t i = 0; i < 50; ++i) {
+
+ constexpr uint32_t numCallsToFlush = 50;
+ for (uint32_t i = 0; i < numCallsToFlush; ++i) {
taskManager.flushTasks();
}
}
-TEST(TaskManager, MultipleNonRepeatingTasks) {
+TEST(TaskManager, MultipleNonRepeatingTasksAreExecuted) {
+ uint32_t counter = 0;
+ std::mutex mutex;
+ std::condition_variable condVar;
chre::TaskManager taskManager;
- gVarTaskManager = 0;
+
constexpr uint32_t numTasks = 50;
+ auto incrementFunc = [&mutex, &condVar, &counter]() {
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ ++counter;
+ }
+
+ condVar.notify_all();
+ };
for (uint32_t i = 0; i < numTasks; ++i) {
- taskManager.addTask(incrementGVar, std::chrono::milliseconds(0));
- std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ std::optional<uint32_t> taskId =
+ taskManager.addTask(incrementFunc,
+ /* intervalOrDelay */ std::chrono::nanoseconds(0));
+ EXPECT_TRUE(taskId.has_value());
}
+
+ std::unique_lock<std::mutex> lock(mutex);
+ condVar.wait(lock, [&counter]() { return counter >= numTasks; });
taskManager.flushTasks();
- EXPECT_TRUE(gVarTaskManager == numTasks);
+ EXPECT_EQ(counter, numTasks);
}
-TEST(TaskManager, MultipleTypesOfTasks) {
+TEST(TaskManager, RepeatingAndOneShotTasksCanExecuteTogether) {
+ uint32_t counter = 0;
+ std::mutex mutex;
+ std::condition_variable condVar;
chre::TaskManager taskManager;
- gVarTaskManager = 0;
+
constexpr uint32_t numTasks = 50;
+ auto incrementFunc = [&mutex, &condVar, &counter]() {
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ ++counter;
+ }
+
+ condVar.notify_all();
+ };
for (uint32_t i = 0; i < numTasks; ++i) {
- taskManager.addTask(incrementGVar, std::chrono::milliseconds(0));
- std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ std::optional<uint32_t> taskId =
+ taskManager.addTask(incrementFunc,
+ /* intervalOrDelay */ std::chrono::nanoseconds(0));
+ EXPECT_TRUE(taskId.has_value());
}
- uint32_t millisecondsToRepeat = 100;
- std::optional<uint32_t> taskId = taskManager.addTask(
- incrementGVar, std::chrono::milliseconds(millisecondsToRepeat));
- EXPECT_TRUE(taskId.has_value());
- uint32_t taskRepeatTimesMax = 11;
- std::this_thread::sleep_for(
- std::chrono::milliseconds(millisecondsToRepeat * taskRepeatTimesMax));
+
+ constexpr std::chrono::nanoseconds interval(50);
+ std::optional<uint32_t> taskId = taskManager.addTask(incrementFunc, interval);
+ ASSERT_TRUE(taskId.has_value());
+
+ constexpr uint32_t taskRepeatTimesMax = 5;
+ std::unique_lock<std::mutex> lock(mutex);
+ condVar.wait(
+ lock, [&counter]() { return counter >= numTasks + taskRepeatTimesMax; });
EXPECT_TRUE(taskManager.cancelTask(taskId.value()));
taskManager.flushTasks();
- EXPECT_TRUE(gVarTaskManager >= numTasks + taskRepeatTimesMax - 1);
+ EXPECT_GE(counter, numTasks + taskRepeatTimesMax);
}
-TEST(TaskManager, FlushTasksWithoutCancel) {
+TEST(TaskManager, TasksCanBeFlushedEvenIfNotCancelled) {
+ uint32_t counter = 0;
+ std::mutex mutex;
+ std::condition_variable condVar;
chre::TaskManager taskManager;
- gVarTaskManager = 0;
+
constexpr uint32_t numTasks = 50;
+ auto incrementFunc = [&mutex, &condVar, &counter]() {
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ ++counter;
+ }
+
+ condVar.notify_all();
+ };
for (uint32_t i = 0; i < numTasks; ++i) {
- taskManager.addTask(incrementGVar, std::chrono::milliseconds(0));
- std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ std::optional<uint32_t> taskId =
+ taskManager.addTask(incrementFunc,
+ /* intervalOrDelay */ std::chrono::nanoseconds(0));
+ EXPECT_TRUE(taskId.has_value());
}
- uint32_t millisecondsToRepeat = 100;
- std::optional<uint32_t> taskId = taskManager.addTask(
- incrementGVar, std::chrono::milliseconds(millisecondsToRepeat));
- EXPECT_TRUE(taskId.has_value());
- uint32_t taskRepeatTimesMax = 11;
- std::this_thread::sleep_for(
- std::chrono::milliseconds(millisecondsToRepeat * taskRepeatTimesMax));
+
+ constexpr std::chrono::nanoseconds interval(50);
+ std::optional<uint32_t> taskId = taskManager.addTask(incrementFunc, interval);
+ ASSERT_TRUE(taskId.has_value());
+
+ constexpr uint32_t taskRepeatTimesMax = 5;
+ std::unique_lock<std::mutex> lock(mutex);
+ condVar.wait(
+ lock, [&counter]() { return counter >= numTasks + taskRepeatTimesMax; });
taskManager.flushTasks();
- EXPECT_TRUE(gVarTaskManager >= numTasks + taskRepeatTimesMax - 1);
+ EXPECT_GE(counter, numTasks + taskRepeatTimesMax);
}
} // namespace
diff --git a/platform/linux/tests/task_test.cc b/platform/linux/tests/task_test.cc
index f20823dc..ed4656a5 100644
--- a/platform/linux/tests/task_test.cc
+++ b/platform/linux/tests/task_test.cc
@@ -31,7 +31,7 @@ constexpr auto incrementGVar = []() { ++gVarTask; };
TEST(Task, Execute) {
gVarTask = 0;
- std::chrono::milliseconds waitTime(1000);
+ std::chrono::milliseconds waitTime(100);
Task task(incrementGVar, waitTime, 0);
EXPECT_FALSE(task.isReadyToExecute());
std::this_thread::sleep_for(waitTime);
@@ -43,7 +43,7 @@ TEST(Task, Execute) {
auto timeDiff =
std::chrono::steady_clock::now() - task.getExecutionTimestamp();
EXPECT_TRUE(
- std::chrono::duration_cast<std::chrono::milliseconds>(timeDiff).count() <=
+ std::chrono::duration_cast<std::chrono::nanoseconds>(timeDiff).count() <=
waitTime.count());
task.cancel();
EXPECT_FALSE(task.isRepeating());
@@ -51,7 +51,7 @@ TEST(Task, Execute) {
TEST(Task, ExecuteNoRepeat) {
gVarTask = 0;
- std::chrono::milliseconds waitTime(0);
+ std::chrono::nanoseconds waitTime(0);
Task task(incrementGVar, waitTime, 0);
EXPECT_TRUE(task.isReadyToExecute());
task.execute();
@@ -62,12 +62,12 @@ TEST(Task, ExecuteNoRepeat) {
TEST(Task, ComparisonOperators) {
constexpr uint32_t numTasks = 6;
- Task tasks[numTasks] = {Task(incrementGVar, std::chrono::milliseconds(0), 0),
- Task(incrementGVar, std::chrono::milliseconds(1), 1),
- Task(incrementGVar, std::chrono::milliseconds(2), 2),
- Task(incrementGVar, std::chrono::milliseconds(3), 3),
- Task(incrementGVar, std::chrono::milliseconds(4), 4),
- Task(incrementGVar, std::chrono::milliseconds(5), 5)};
+ Task tasks[numTasks] = {Task(incrementGVar, std::chrono::nanoseconds(0), 0),
+ Task(incrementGVar, std::chrono::nanoseconds(10), 1),
+ Task(incrementGVar, std::chrono::nanoseconds(20), 2),
+ Task(incrementGVar, std::chrono::nanoseconds(30), 3),
+ Task(incrementGVar, std::chrono::nanoseconds(40), 4),
+ Task(incrementGVar, std::chrono::nanoseconds(50), 5)};
for (uint32_t i = 0; i < numTasks; ++i) {
if (i < numTasks - 1) {
diff --git a/platform/platform.mk b/platform/platform.mk
index 7e5046f8..5212c6d0 100644
--- a/platform/platform.mk
+++ b/platform/platform.mk
@@ -110,7 +110,6 @@ SLPI_SRCS += platform/shared/nanoapp/nanoapp_dso_util.cc
SLPI_SRCS += platform/shared/pal_system_api.cc
SLPI_SRCS += platform/shared/platform_debug_dump_manager.cc
SLPI_SRCS += platform/shared/system_time.cc
-SLPI_SRCS += platform/shared/tracing.cc
SLPI_SRCS += platform/shared/version.cc
SLPI_SRCS += platform/slpi/chre_api_re.cc
SLPI_SRCS += platform/slpi/fatal_error.cc
@@ -227,7 +226,6 @@ SIM_SRCS += platform/shared/memory_manager.cc
SIM_SRCS += platform/shared/nanoapp/nanoapp_dso_util.cc
SIM_SRCS += platform/shared/pal_system_api.cc
SIM_SRCS += platform/shared/system_time.cc
-SIM_SRCS += platform/shared/tracing.cc
SIM_SRCS += platform/shared/version.cc
# Optional audio support.
@@ -336,11 +334,14 @@ endif
# GoogleTest Compiler Flags ####################################################
+GOOGLETEST_CFLAGS += $(FLATBUFFERS_CFLAGS)
+
# The order here is important so that the googletest target prefers shared,
# linux and then SLPI.
GOOGLETEST_CFLAGS += -Iplatform/shared/include
GOOGLETEST_CFLAGS += -Iplatform/linux/include
GOOGLETEST_CFLAGS += -Iplatform/slpi/include
+GOOGLETEST_CFLAGS += -Iplatform/shared/pw_trace/include
# GoogleTest Source Files ######################################################
@@ -350,6 +351,7 @@ GOOGLETEST_COMMON_SRCS += platform/linux/sim/platform_audio.cc
GOOGLETEST_COMMON_SRCS += platform/linux/tests/task_test.cc
GOOGLETEST_COMMON_SRCS += platform/linux/tests/task_manager_test.cc
GOOGLETEST_COMMON_SRCS += platform/tests/log_buffer_test.cc
+GOOGLETEST_COMMON_SRCS += platform/tests/trace_test.cc
GOOGLETEST_COMMON_SRCS += platform/shared/log_buffer.cc
ifeq ($(CHRE_WIFI_NAN_SUPPORT_ENABLED), true)
GOOGLETEST_COMMON_SRCS += platform/linux/pal_nan.cc
@@ -391,7 +393,6 @@ EMBOS_SRCS += $(CHRE_PREFIX)/platform/shared/pal_system_api.cc
EMBOS_SRCS += $(CHRE_PREFIX)/platform/shared/pal_sensor_stub.cc
EMBOS_SRCS += $(CHRE_PREFIX)/platform/shared/platform_debug_dump_manager.cc
EMBOS_SRCS += $(CHRE_PREFIX)/platform/shared/system_time.cc
-EMBOS_SRCS += $(CHRE_PREFIX)/platform/shared/tracing.cc
EMBOS_SRCS += $(CHRE_PREFIX)/platform/shared/version.cc
EMBOS_SRCS += $(CHRE_PREFIX)/platform/shared/nanoapp/nanoapp_dso_util.cc
EMBOS_SRCS += $(CHRE_PREFIX)/platform/shared/nanoapp_loader.cc
@@ -481,7 +482,6 @@ TINYSYS_SRCS += $(CHRE_PREFIX)/platform/shared/nanoapp_loader.cc
TINYSYS_SRCS += $(CHRE_PREFIX)/platform/shared/pal_system_api.cc
TINYSYS_SRCS += $(CHRE_PREFIX)/platform/shared/platform_debug_dump_manager.cc
TINYSYS_SRCS += $(CHRE_PREFIX)/platform/shared/system_time.cc
-TINYSYS_SRCS += $(CHRE_PREFIX)/platform/shared/tracing.cc
TINYSYS_SRCS += $(CHRE_PREFIX)/platform/shared/version.cc
TINYSYS_SRCS += $(CHRE_PREFIX)/platform/shared/nanoapp/nanoapp_dso_util.cc
TINYSYS_SRCS += $(MBEDTLS_SRCS)
diff --git a/platform/shared/audio_pal/platform_audio.cc b/platform/shared/audio_pal/platform_audio.cc
index 4662a93c..e68ff361 100644
--- a/platform/shared/audio_pal/platform_audio.cc
+++ b/platform/shared/audio_pal/platform_audio.cc
@@ -48,6 +48,12 @@ void PlatformAudio::init() {
if (mApi != nullptr) {
if (!mApi->open(&gChrePalSystemApi, &sCallbacks)) {
LOGE("Audio PAL open returned false");
+
+#ifdef CHRE_TELEMETRY_SUPPORT_ENABLED
+ EventLoopManagerSingleton::get()->getTelemetryManager().onPalOpenFailure(
+ TelemetryManager::PalType::AUDIO);
+#endif // CHRE_TELEMETRY_SUPPORT_ENABLED
+
mApi = nullptr;
} else {
LOGD("Opened audio PAL version 0x%08" PRIx32, mApi->moduleVersion);
diff --git a/platform/shared/chre_api_ble.cc b/platform/shared/chre_api_ble.cc
index 5b725b17..1f630174 100644
--- a/platform/shared/chre_api_ble.cc
+++ b/platform/shared/chre_api_ble.cc
@@ -44,38 +44,67 @@ DLL_EXPORT uint32_t chreBleGetFilterCapabilities() {
#endif // CHRE_BLE_SUPPORT_ENABLED
}
-DLL_EXPORT bool chreBleFlushAsync(const void * /* cookie */) {
+DLL_EXPORT bool chreBleFlushAsync(const void *cookie) {
+#ifdef CHRE_BLE_SUPPORT_ENABLED
+ chre::Nanoapp *nanoapp = EventLoopManager::validateChreApiCall(__func__);
+ return nanoapp->permitPermissionUse(NanoappPermissions::CHRE_PERMS_BLE) &&
+ EventLoopManagerSingleton::get()->getBleRequestManager().flushAsync(
+ nanoapp, cookie);
+#else
+ UNUSED_VAR(cookie);
return false;
+#endif // CHRE_BLE_SUPPORT_ENABLED
}
-DLL_EXPORT bool chreBleStartScanAsync(chreBleScanMode mode,
- uint32_t reportDelayMs,
- const struct chreBleScanFilter *filter) {
+DLL_EXPORT bool chreBleStartScanAsyncV1_9(
+ chreBleScanMode mode, uint32_t reportDelayMs,
+ const struct chreBleScanFilterV1_9 *filter, const void *cookie) {
#ifdef CHRE_BLE_SUPPORT_ENABLED
chre::Nanoapp *nanoapp = EventLoopManager::validateChreApiCall(__func__);
return nanoapp->permitPermissionUse(NanoappPermissions::CHRE_PERMS_BLE) &&
EventLoopManagerSingleton::get()
->getBleRequestManager()
- .startScanAsync(nanoapp, mode, reportDelayMs, filter);
+ .startScanAsync(nanoapp, mode, reportDelayMs, filter, cookie);
#else
UNUSED_VAR(mode);
UNUSED_VAR(reportDelayMs);
UNUSED_VAR(filter);
+ UNUSED_VAR(cookie);
return false;
#endif // CHRE_BLE_SUPPORT_ENABLED
}
-DLL_EXPORT bool chreBleStopScanAsync() {
+DLL_EXPORT bool chreBleStartScanAsync(chreBleScanMode mode,
+ uint32_t reportDelayMs,
+ const struct chreBleScanFilter *filter) {
+ if (filter == nullptr) {
+ return chreBleStartScanAsyncV1_9(mode, reportDelayMs, nullptr /* filter */,
+ nullptr /* cookie */);
+ }
+ chreBleScanFilterV1_9 filterV1_9 = {
+ filter->rssiThreshold, filter->scanFilterCount, filter->scanFilters,
+ 0 /* broadcasterAddressFilterCount */,
+ nullptr /* broadcasterAddressFilters */};
+ return chreBleStartScanAsyncV1_9(mode, reportDelayMs, &filterV1_9,
+ nullptr /* cookie */);
+}
+
+DLL_EXPORT bool chreBleStopScanAsyncV1_9(const void *cookie) {
#ifdef CHRE_BLE_SUPPORT_ENABLED
chre::Nanoapp *nanoapp = EventLoopManager::validateChreApiCall(__func__);
return nanoapp->permitPermissionUse(NanoappPermissions::CHRE_PERMS_BLE) &&
EventLoopManagerSingleton::get()->getBleRequestManager().stopScanAsync(
- nanoapp);
+ nanoapp, cookie);
#else
+ UNUSED_VAR(cookie);
return false;
#endif // CHRE_BLE_SUPPORT_ENABLED
}
+DLL_EXPORT bool chreBleStopScanAsync() {
+ return chreBleStopScanAsyncV1_9(nullptr /* cookie */);
+}
+
DLL_EXPORT bool chreBleReadRssiAsync(uint16_t connectionHandle,
const void *cookie) {
#ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED
diff --git a/platform/shared/dram_vote_client.cc b/platform/shared/dram_vote_client.cc
index 6cc484c4..165faf4d 100644
--- a/platform/shared/dram_vote_client.cc
+++ b/platform/shared/dram_vote_client.cc
@@ -18,6 +18,7 @@
#include <cinttypes>
+#include "chre/core/event_loop_manager.h"
#include "chre/platform/assert.h"
#include "chre/platform/fatal_error.h"
#include "chre/platform/log.h"
@@ -77,7 +78,7 @@ void DramVoteClient::decrementDramVoteCount() {
}
}
-Milliseconds DramVoteClient::checkDramDuration() const {
+Milliseconds DramVoteClient::checkDramDuration() {
Milliseconds duration(0);
if (mDramVoteCount > 0) {
duration = Milliseconds(SystemTime::getMonotonicTime()) - mVoteCountStart;
@@ -87,8 +88,18 @@ Milliseconds DramVoteClient::checkDramDuration() const {
// requests. If there's a prolonged period of memory fallback, this might
// indicate a memory leak or inadequate SRAM heap size.
if (duration > kMaxDramDuration) {
- FATAL_ERROR("Forced into DRAM for %" PRIu64 " msec",
- duration.getMilliseconds());
+ if (EventLoopManagerSingleton::isInitialized() &&
+ !EventLoopManagerSingleton::get()
+ ->getEventLoop()
+ .getPowerControlManager()
+ .hostIsAwake()) {
+ // AP is asleep
+ FATAL_ERROR("Forced into DRAM for %" PRIu64 " msec",
+ duration.getMilliseconds());
+ } else {
+ // AP is awake, don't report error, just reset the starting time
+ mVoteCountStart = Milliseconds(SystemTime::getMonotonicTime());
+ }
}
return duration;
}
diff --git a/platform/shared/host_link.cc b/platform/shared/host_link.cc
index a66b7972..2542055c 100644
--- a/platform/shared/host_link.cc
+++ b/platform/shared/host_link.cc
@@ -104,6 +104,15 @@ void HostMessageHandlers::loadNanoappData(
cbData->nanoapp = getLoadManager().releaseNanoapp();
cbData->sendFragmentResponse = !respondBeforeStart;
+ LOGD("Instance ID %" PRIu16 " assigned to app ID 0x%" PRIx64,
+ cbData->nanoapp->getInstanceId(), appId);
+
+ // This message must be sent to the host before the nanoapp is started so
+ // that the host can correctly map the nanoapp instance ID to the app ID
+ // before processing tokenized logs from the nanoapp.
+ sendNanoappInstanceIdInfo(hostClientId, cbData->nanoapp->getInstanceId(),
+ appId);
+
// Note that if this fails, we'll generate the error response in
// the normal deferred callback
EventLoopManagerSingleton::get()->deferCallback(
diff --git a/platform/shared/host_protocol_chre.cc b/platform/shared/host_protocol_chre.cc
index d7b7feac..627a5a6a 100644
--- a/platform/shared/host_protocol_chre.cc
+++ b/platform/shared/host_protocol_chre.cc
@@ -186,6 +186,11 @@ bool HostProtocolChre::decodeMessageFromHost(const void *message,
break;
}
+ case fbs::ChreMessage::PulseRequest: {
+ HostMessageHandlers::handlePulseRequest();
+ break;
+ }
+
default:
LOGW("Got invalid/unexpected message type %" PRIu8,
static_cast<uint8_t>(container->message_type()));
@@ -251,6 +256,11 @@ void HostProtocolChre::finishNanoappListResponse(
hostClientId);
}
+void HostProtocolChre::encodePulseResponse(ChreFlatBufferBuilder &builder) {
+ auto response = fbs::CreatePulseResponse(builder);
+ finalize(builder, fbs::ChreMessage::PulseResponse, response.Union());
+}
+
void HostProtocolChre::encodeLoadNanoappResponse(ChreFlatBufferBuilder &builder,
uint16_t hostClientId,
uint32_t transactionId,
@@ -262,6 +272,14 @@ void HostProtocolChre::encodeLoadNanoappResponse(ChreFlatBufferBuilder &builder,
hostClientId);
}
+void HostProtocolChre::encodeNanoappInstanceIdInfo(
+ ChreFlatBufferBuilder &builder, uint16_t hostClientId, uint16_t instanceId,
+ uint64_t appId) {
+ auto response = fbs::CreateNanoappInstanceIdInfo(builder, instanceId, appId);
+ finalize(builder, fbs::ChreMessage::NanoappInstanceIdInfo, response.Union(),
+ hostClientId);
+}
+
void HostProtocolChre::encodeUnloadNanoappResponse(
ChreFlatBufferBuilder &builder, uint16_t hostClientId,
uint32_t transactionId, bool success) {
diff --git a/platform/shared/idl/host_messages.fbs b/platform/shared/idl/host_messages.fbs
index ff0dcd84..57b0d7cd 100644
--- a/platform/shared/idl/host_messages.fbs
+++ b/platform/shared/idl/host_messages.fbs
@@ -196,6 +196,11 @@ table LoadNanoappResponse {
// TODO: detailed error code?
}
+table NanoappInstanceIdInfo {
+ instance_id: uint;
+ app_id:ulong;
+}
+
table UnloadNanoappRequest {
transaction_id:uint;
@@ -323,7 +328,8 @@ table LogMessageV2 {
/// uint8_t - Log metadata, encoded as follows:
/// [EI(Upper nibble) | Level(Lower nibble)]
/// * Log Type
- /// (0 = No encoding, 1 = Tokenized log, 2 = BT snoop log)
+ /// (0 = No encoding, 1 = Tokenized log,
+ /// 2 = BT snoop log, 3 = Nanoapp Tokenized log)
/// * LogBuffer log level (1 = error, 2 = warn,
/// 3 = info, 4 = debug,
/// 5 = verbose)
@@ -335,7 +341,7 @@ table LogMessageV2 {
/// terminated string (eg: pass to string manipulation functions, get its
/// size via strlen(), etc.).
///
- /// * Encoded logs: The first byte of the log buffer indicates the size of
+ /// * Tokenized logs: The first byte of the log buffer indicates the size of
/// the actual encoded data to follow. For example, if a tokenized log of
/// size 24 bytes were to be represented, a buffer of size 25 bytes would
/// be needed to encode this as: [Size(1B) | Data(24B)]. A decoder would
@@ -349,6 +355,15 @@ table LogMessageV2 {
/// size 24 bytes were to be represented, a buffer of size 26 bytes would
/// be needed to encode this as: [Direction(1B) | Size(1B) | Data(24B)].
///
+ /// * Tokenized nanoapp logs: This log type is specifically for nanoapps with
+ /// tokenized logs enabled. Similar to tokenized logs, the first byte is the
+ /// size of the tokenized log data at the end. The next two bytes is the instance
+ /// ID of the nanoapp which sends this tokenized log message. This instance ID
+ /// will be used to map to the corresponding detokenizer in the log message parser.
+ /// For example, if a nanoapp tokenized log of size 24 bytes were to be sent,
+ /// a buffer of size 27 bytes would be needed to encode this as:
+ /// [Size(1B) | InstanceId (2B) | Data(24B)].
+ ///
/// This pattern repeats until the end of the buffer for multiple log
/// messages. The last byte will always be a null-terminator. There are no
/// padding bytes between these fields. Treat this like a packed struct and be
@@ -428,6 +443,10 @@ table DebugConfiguration {
health_monitor_failure_crash:bool;
}
+// Pulse messages are used to check if CHRE is up running.
+table PulseRequest {}
+table PulseResponse {}
+
/// A union that joins together all possible messages. Note that in FlatBuffers,
/// unions have an implicit type
union ChreMessage {
@@ -475,6 +494,11 @@ union ChreMessage {
NanConfigurationUpdate,
DebugConfiguration,
+
+ PulseRequest,
+ PulseResponse,
+
+ NanoappInstanceIdInfo,
}
struct HostAddress {
diff --git a/platform/shared/include/chre/platform/shared/assert_func.h b/platform/shared/include/chre/platform/shared/assert_func.h
new file mode 100644
index 00000000..55f1ab38
--- /dev/null
+++ b/platform/shared/include/chre/platform/shared/assert_func.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PLATFORM_SHARED_INCLUDE_CHRE_PLATFORM_SHARED_ASSERT_FUNC_H
+#define PLATFORM_SHARED_INCLUDE_CHRE_PLATFORM_SHARED_ASSERT_FUNC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Performs assertion while logging the filename and line provided.
+ *
+ * @param filename The filename containing the assertion being fired.
+ * @param line The line that contains the assertion being fired.
+ */
+void chreDoAssert(const char *filename, size_t line);
+
+#ifdef __cplusplus
+}
+#endif
+
+#define CHRE_ASSERT(condition) \
+ do { \
+ if (!(condition)) { \
+ chreDoAssert(CHRE_FILENAME, __LINE__); \
+ } \
+ } while (0)
+
+#endif // PLATFORM_SHARED_INCLUDE_CHRE_PLATFORM_SHARED_ASSERT_FUNC_H
diff --git a/platform/shared/include/chre/platform/shared/bt_snoop_log.h b/platform/shared/include/chre/platform/shared/bt_snoop_log.h
index 35719b93..d217f4e3 100644
--- a/platform/shared/include/chre/platform/shared/bt_snoop_log.h
+++ b/platform/shared/include/chre/platform/shared/bt_snoop_log.h
@@ -17,6 +17,9 @@
#ifndef CHRE_PLATFORM_SHARED_BT_SNOOP_LOG_H_
#define CHRE_PLATFORM_SHARED_BT_SNOOP_LOG_H_
+#include <cinttypes>
+#include <cstddef>
+
//! Indicates direction of a BT snoop log.
//! TODO(b/294884658): Make the fbs definition as the single source of truth.
enum class BtSnoopDirection : uint8_t {
diff --git a/platform/shared/include/chre/platform/shared/dram_vote_client.h b/platform/shared/include/chre/platform/shared/dram_vote_client.h
index 00476a49..50d51860 100644
--- a/platform/shared/include/chre/platform/shared/dram_vote_client.h
+++ b/platform/shared/include/chre/platform/shared/dram_vote_client.h
@@ -95,7 +95,7 @@ class DramVoteClient : public NonCopyable {
* @return the duration in milliseconds since the system has been voted into
* big image due to incrementDramVoteCount.
*/
- Milliseconds checkDramDuration() const;
+ Milliseconds checkDramDuration();
};
//! Provides an alias to the DramVoteClient singleton
diff --git a/platform/shared/include/chre/platform/shared/generated/host_messages_generated.h b/platform/shared/include/chre/platform/shared/generated/host_messages_generated.h
index ec71ea12..dad31313 100644
--- a/platform/shared/include/chre/platform/shared/generated/host_messages_generated.h
+++ b/platform/shared/include/chre/platform/shared/generated/host_messages_generated.h
@@ -36,6 +36,9 @@ struct LoadNanoappRequestBuilder;
struct LoadNanoappResponse;
struct LoadNanoappResponseBuilder;
+struct NanoappInstanceIdInfo;
+struct NanoappInstanceIdInfoBuilder;
+
struct UnloadNanoappRequest;
struct UnloadNanoappRequestBuilder;
@@ -99,6 +102,12 @@ struct NanConfigurationUpdateBuilder;
struct DebugConfiguration;
struct DebugConfigurationBuilder;
+struct PulseRequest;
+struct PulseRequestBuilder;
+
+struct PulseResponse;
+struct PulseResponseBuilder;
+
struct HostAddress;
struct MessageContainer;
@@ -309,11 +318,14 @@ enum class ChreMessage : uint8_t {
NanConfigurationRequest = 26,
NanConfigurationUpdate = 27,
DebugConfiguration = 28,
+ PulseRequest = 29,
+ PulseResponse = 30,
+ NanoappInstanceIdInfo = 31,
MIN = NONE,
- MAX = DebugConfiguration
+ MAX = NanoappInstanceIdInfo
};
-inline const ChreMessage (&EnumValuesChreMessage())[29] {
+inline const ChreMessage (&EnumValuesChreMessage())[32] {
static const ChreMessage values[] = {
ChreMessage::NONE,
ChreMessage::NanoappMessage,
@@ -343,13 +355,16 @@ inline const ChreMessage (&EnumValuesChreMessage())[29] {
ChreMessage::BatchedMetricLog,
ChreMessage::NanConfigurationRequest,
ChreMessage::NanConfigurationUpdate,
- ChreMessage::DebugConfiguration
+ ChreMessage::DebugConfiguration,
+ ChreMessage::PulseRequest,
+ ChreMessage::PulseResponse,
+ ChreMessage::NanoappInstanceIdInfo
};
return values;
}
inline const char * const *EnumNamesChreMessage() {
- static const char * const names[30] = {
+ static const char * const names[33] = {
"NONE",
"NanoappMessage",
"HubInfoRequest",
@@ -379,13 +394,16 @@ inline const char * const *EnumNamesChreMessage() {
"NanConfigurationRequest",
"NanConfigurationUpdate",
"DebugConfiguration",
+ "PulseRequest",
+ "PulseResponse",
+ "NanoappInstanceIdInfo",
nullptr
};
return names;
}
inline const char *EnumNameChreMessage(ChreMessage e) {
- if (flatbuffers::IsOutRange(e, ChreMessage::NONE, ChreMessage::DebugConfiguration)) return "";
+ if (flatbuffers::IsOutRange(e, ChreMessage::NONE, ChreMessage::NanoappInstanceIdInfo)) return "";
const size_t index = static_cast<size_t>(e);
return EnumNamesChreMessage()[index];
}
@@ -506,6 +524,18 @@ template<> struct ChreMessageTraits<chre::fbs::DebugConfiguration> {
static const ChreMessage enum_value = ChreMessage::DebugConfiguration;
};
+template<> struct ChreMessageTraits<chre::fbs::PulseRequest> {
+ static const ChreMessage enum_value = ChreMessage::PulseRequest;
+};
+
+template<> struct ChreMessageTraits<chre::fbs::PulseResponse> {
+ static const ChreMessage enum_value = ChreMessage::PulseResponse;
+};
+
+template<> struct ChreMessageTraits<chre::fbs::NanoappInstanceIdInfo> {
+ static const ChreMessage enum_value = ChreMessage::NanoappInstanceIdInfo;
+};
+
bool VerifyChreMessage(flatbuffers::Verifier &verifier, const void *obj, ChreMessage type);
bool VerifyChreMessageVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
@@ -1429,6 +1459,58 @@ inline flatbuffers::Offset<LoadNanoappResponse> CreateLoadNanoappResponse(
return builder_.Finish();
}
+struct NanoappInstanceIdInfo FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef NanoappInstanceIdInfoBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_INSTANCE_ID = 4,
+ VT_APP_ID = 6
+ };
+ uint32_t instance_id() const {
+ return GetField<uint32_t>(VT_INSTANCE_ID, 0);
+ }
+ uint64_t app_id() const {
+ return GetField<uint64_t>(VT_APP_ID, 0);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<uint32_t>(verifier, VT_INSTANCE_ID) &&
+ VerifyField<uint64_t>(verifier, VT_APP_ID) &&
+ verifier.EndTable();
+ }
+};
+
+struct NanoappInstanceIdInfoBuilder {
+ typedef NanoappInstanceIdInfo Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_instance_id(uint32_t instance_id) {
+ fbb_.AddElement<uint32_t>(NanoappInstanceIdInfo::VT_INSTANCE_ID, instance_id, 0);
+ }
+ void add_app_id(uint64_t app_id) {
+ fbb_.AddElement<uint64_t>(NanoappInstanceIdInfo::VT_APP_ID, app_id, 0);
+ }
+ explicit NanoappInstanceIdInfoBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ NanoappInstanceIdInfoBuilder &operator=(const NanoappInstanceIdInfoBuilder &);
+ flatbuffers::Offset<NanoappInstanceIdInfo> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<NanoappInstanceIdInfo>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<NanoappInstanceIdInfo> CreateNanoappInstanceIdInfo(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ uint32_t instance_id = 0,
+ uint64_t app_id = 0) {
+ NanoappInstanceIdInfoBuilder builder_(_fbb);
+ builder_.add_app_id(app_id);
+ builder_.add_instance_id(instance_id);
+ return builder_.Finish();
+}
+
struct UnloadNanoappRequest FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef UnloadNanoappRequestBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
@@ -1963,7 +2045,8 @@ struct LogMessageV2 FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
/// uint8_t - Log metadata, encoded as follows:
/// [EI(Upper nibble) | Level(Lower nibble)]
/// * Log Type
- /// (0 = No encoding, 1 = Tokenized log, 2 = BT snoop log)
+ /// (0 = No encoding, 1 = Tokenized log,
+ /// 2 = BT snoop log, 3 = Nanoapp Tokenized log)
/// * LogBuffer log level (1 = error, 2 = warn,
/// 3 = info, 4 = debug,
/// 5 = verbose)
@@ -1975,7 +2058,7 @@ struct LogMessageV2 FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
/// terminated string (eg: pass to string manipulation functions, get its
/// size via strlen(), etc.).
///
- /// * Encoded logs: The first byte of the log buffer indicates the size of
+ /// * Tokenized logs: The first byte of the log buffer indicates the size of
/// the actual encoded data to follow. For example, if a tokenized log of
/// size 24 bytes were to be represented, a buffer of size 25 bytes would
/// be needed to encode this as: [Size(1B) | Data(24B)]. A decoder would
@@ -1989,6 +2072,15 @@ struct LogMessageV2 FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
/// size 24 bytes were to be represented, a buffer of size 26 bytes would
/// be needed to encode this as: [Direction(1B) | Size(1B) | Data(24B)].
///
+ /// * Tokenized nanoapp logs: This log type is specifically for nanoapps with
+ /// tokenized logs enabled. Similar to tokenized logs, the first byte is the
+ /// size of the tokenized log data at the end. The next two bytes is the instance
+ /// ID of the nanoapp which sends this tokenized log message. This instance ID
+ /// will be used to map to the corresponding detokenizer in the log message parser.
+ /// For example, if a nanoapp tokenized log of size 24 bytes were to be sent,
+ /// a buffer of size 27 bytes would be needed to encode this as:
+ /// [Size(1B) | InstanceId (2B) | Data(24B)].
+ ///
/// This pattern repeats until the end of the buffer for multiple log
/// messages. The last byte will always be a null-terminator. There are no
/// padding bytes between these fields. Treat this like a packed struct and be
@@ -2507,6 +2599,66 @@ inline flatbuffers::Offset<DebugConfiguration> CreateDebugConfiguration(
return builder_.Finish();
}
+struct PulseRequest FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef PulseRequestBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ verifier.EndTable();
+ }
+};
+
+struct PulseRequestBuilder {
+ typedef PulseRequest Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit PulseRequestBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ PulseRequestBuilder &operator=(const PulseRequestBuilder &);
+ flatbuffers::Offset<PulseRequest> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<PulseRequest>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<PulseRequest> CreatePulseRequest(
+ flatbuffers::FlatBufferBuilder &_fbb) {
+ PulseRequestBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct PulseResponse FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef PulseResponseBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ verifier.EndTable();
+ }
+};
+
+struct PulseResponseBuilder {
+ typedef PulseResponse Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit PulseResponseBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ PulseResponseBuilder &operator=(const PulseResponseBuilder &);
+ flatbuffers::Offset<PulseResponse> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<PulseResponse>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<PulseResponse> CreatePulseResponse(
+ flatbuffers::FlatBufferBuilder &_fbb) {
+ PulseResponseBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
/// The top-level container that encapsulates all possible messages. Note that
/// per FlatBuffers requirements, we can't use a union as the top-level
/// structure (root type), so we must wrap it in a table.
@@ -2608,6 +2760,15 @@ struct MessageContainer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const chre::fbs::DebugConfiguration *message_as_DebugConfiguration() const {
return message_type() == chre::fbs::ChreMessage::DebugConfiguration ? static_cast<const chre::fbs::DebugConfiguration *>(message()) : nullptr;
}
+ const chre::fbs::PulseRequest *message_as_PulseRequest() const {
+ return message_type() == chre::fbs::ChreMessage::PulseRequest ? static_cast<const chre::fbs::PulseRequest *>(message()) : nullptr;
+ }
+ const chre::fbs::PulseResponse *message_as_PulseResponse() const {
+ return message_type() == chre::fbs::ChreMessage::PulseResponse ? static_cast<const chre::fbs::PulseResponse *>(message()) : nullptr;
+ }
+ const chre::fbs::NanoappInstanceIdInfo *message_as_NanoappInstanceIdInfo() const {
+ return message_type() == chre::fbs::ChreMessage::NanoappInstanceIdInfo ? static_cast<const chre::fbs::NanoappInstanceIdInfo *>(message()) : nullptr;
+ }
/// The originating or destination client ID on the host side, used to direct
/// responses only to the client that sent the request. Although initially
/// populated by the requesting client, this is enforced to be the correct
@@ -2739,6 +2900,18 @@ template<> inline const chre::fbs::DebugConfiguration *MessageContainer::message
return message_as_DebugConfiguration();
}
+template<> inline const chre::fbs::PulseRequest *MessageContainer::message_as<chre::fbs::PulseRequest>() const {
+ return message_as_PulseRequest();
+}
+
+template<> inline const chre::fbs::PulseResponse *MessageContainer::message_as<chre::fbs::PulseResponse>() const {
+ return message_as_PulseResponse();
+}
+
+template<> inline const chre::fbs::NanoappInstanceIdInfo *MessageContainer::message_as<chre::fbs::NanoappInstanceIdInfo>() const {
+ return message_as_NanoappInstanceIdInfo();
+}
+
struct MessageContainerBuilder {
typedef MessageContainer Table;
flatbuffers::FlatBufferBuilder &fbb_;
@@ -2895,6 +3068,18 @@ inline bool VerifyChreMessage(flatbuffers::Verifier &verifier, const void *obj,
auto ptr = reinterpret_cast<const chre::fbs::DebugConfiguration *>(obj);
return verifier.VerifyTable(ptr);
}
+ case ChreMessage::PulseRequest: {
+ auto ptr = reinterpret_cast<const chre::fbs::PulseRequest *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case ChreMessage::PulseResponse: {
+ auto ptr = reinterpret_cast<const chre::fbs::PulseResponse *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case ChreMessage::NanoappInstanceIdInfo: {
+ auto ptr = reinterpret_cast<const chre::fbs::NanoappInstanceIdInfo *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
default: return true;
}
}
diff --git a/platform/shared/include/chre/platform/shared/host_protocol_chre.h b/platform/shared/include/chre/platform/shared/host_protocol_chre.h
index 27bf37fd..eab9e773 100644
--- a/platform/shared/include/chre/platform/shared/host_protocol_chre.h
+++ b/platform/shared/include/chre/platform/shared/host_protocol_chre.h
@@ -70,6 +70,8 @@ class HostMessageHandlers {
static void handleNanoappListRequest(uint16_t hostClientId);
+ static void handlePulseRequest();
+
static void handleDebugConfiguration(
const fbs::DebugConfiguration *debugConfiguration);
@@ -99,6 +101,9 @@ class HostMessageHandlers {
uint32_t transactionId, uint32_t fragmentId,
bool success);
+ static void sendNanoappInstanceIdInfo(uint16_t hostClientId,
+ uint16_t instanceId, uint64_t appId);
+
static void finishLoadingNanoappCallback(
SystemCallbackType type, UniquePtr<LoadNanoappCallbackData> &&cbData);
@@ -200,6 +205,11 @@ class HostProtocolChre : public HostProtocolCommon {
uint16_t hostClientId);
/**
+ * Encodes a response to the host indicating CHRE is up running.
+ */
+ static void encodePulseResponse(ChreFlatBufferBuilder &builder);
+
+ /**
* Encodes a response to the host communicating the result of dynamically
* loading a nanoapp.
*/
@@ -217,6 +227,13 @@ class HostProtocolChre : public HostProtocolCommon {
uint32_t transactionId, bool success);
/**
+ * Encodes a nanoapp's instance ID and app ID to the host.
+ */
+ static void encodeNanoappInstanceIdInfo(ChreFlatBufferBuilder &builder,
+ uint16_t hostClientId,
+ uint16_t instanceId, uint64_t appId);
+
+ /**
* Encodes a buffer of log messages to the host.
*/
static void encodeLogMessages(ChreFlatBufferBuilder &builder,
diff --git a/platform/shared/include/chre/platform/shared/log_buffer.h b/platform/shared/include/chre/platform/shared/log_buffer.h
index 8deaded4..fb271300 100644
--- a/platform/shared/include/chre/platform/shared/log_buffer.h
+++ b/platform/shared/include/chre/platform/shared/log_buffer.h
@@ -23,9 +23,12 @@
#include "chre/platform/mutex.h"
#include "chre/platform/shared/bt_snoop_log.h"
+#include "chre/platform/shared/generated/host_messages_generated.h"
namespace chre {
+using LogType = fbs::LogType;
+
/**
* Values that represent a preferred setting for when the LogBuffer should
* notify the platform that logs are ready to be copied.
@@ -86,6 +89,21 @@ class LogBuffer {
//! message.
static constexpr size_t kLogDataOffset = 5;
+ //! The number of overhead bytes in a printf style string entry. This value
+ //! indicates the size of the null terminator appended to the end of each log.
+ static constexpr size_t kStringLogOverhead = 1;
+
+ //! The number of bytes in a tokenized log entry of the buffer after the
+ //! 'header' and before the tokenized log data is encountered. The value
+ //! indicate the size of the uint8_t logSize field.
+ static constexpr size_t kTokenizedLogOffset = 1;
+
+ //! The number of bytes in a bt snoop log entry of the buffer after the
+ //! 'header' and before the bt snoop log data is encountered. The value
+ //! indicate the size of the uint8_t size field and the BtSnoopDirection
+ //! field.
+ static constexpr size_t kBtSnoopLogOffset = 2;
+
/**
* @param callback The callback object that will receive notifications about
* the state of the log buffer or nullptr if it is not needed.
@@ -169,7 +187,8 @@ class LogBuffer {
/**
*
- * @param logSize The size of the log text in bytes.
+ * @param logSize The size of the log payload, including overhead like
+ * metadata, null terminator, etc.
* @return true if log would cause an overflow of the buffer and would
* overwrite a log if it was pushed onto the buffer.
*/
@@ -233,6 +252,16 @@ class LogBuffer {
*/
size_t getNumLogsDropped();
+ /**
+ * @param startingIndex The index to start from.
+ * @param type. The type of the log. See host_message.fbs.
+ * @return The length of the data portion of a log along with the null
+ * terminator. If a null terminator was not found at most
+ * kLogMaxSize - kLogDataOffset bytes away from the startingIndex
+ * then kLogMaxSize - kLogDataOffset + 1 is returned.
+ */
+ size_t getLogDataLength(size_t startingIndex, LogType type);
+
private:
/**
* Increment the value and take the modulus of the max size of the buffer.
@@ -253,6 +282,11 @@ class LogBuffer {
*/
void copyToBuffer(size_t size, const void *source);
+ template <typename Type>
+ void copyVarToBuffer(const Type *var) {
+ copyToBuffer(sizeof(Type), var);
+ }
+
/**
* Copy from the buffer data to a destination memory location ensuring that
* the copy wraps around the buffer data if needed.
@@ -284,15 +318,6 @@ class LogBuffer {
size_t getNextLogIndex(size_t startingIndex, size_t *logSize);
/**
- * @param startingIndex The index to start from.
- * @return The length of the data portion of a log along with the null
- * terminator. If a null terminator was not found at most
- * kLogMaxSize - kLogDataOffset bytes away from the startingIndex
- * then kLogMaxSize - kLogDataOffset + 1 is returned.
- */
- size_t getLogDataLength(size_t startingIndex);
-
- /**
* Encode the received log message (if tokenization or similar encoding
* is used) and dispatch it.
*/
@@ -311,7 +336,7 @@ class LogBuffer {
* than max size. This function must only be called with the log buffer mutex
* locked.
*/
- void discardExcessOldLogsLocked(bool encoded, uint8_t currentLogLen);
+ void discardExcessOldLogsLocked(uint8_t currentLogLen);
/**
* Add an encoding header to the log message if the encoding param is true.
@@ -328,6 +353,21 @@ class LogBuffer {
void dispatch();
/**
+ * @param metadata The metadata of the log message.
+ * @return The log type of the log message.
+ */
+ LogType getLogTypeFromMetadata(uint8_t metadata);
+
+ /**
+ * Set the upper nibble of the log metadata based on log type and log level.
+ *
+ * @param type The log type of the log message.
+ * @param logLevel The log level of the log message.
+ * @return The metadata of the log message.
+ */
+ uint8_t setLogMetadata(LogType type, LogBufferLogLevel logLevel);
+
+ /**
* The buffer data is stored in the format
*
* [ metadata (1B) , timestamp (4B), data (dataLenB) ]
diff --git a/platform/shared/include/chre/platform/shared/log_buffer_manager.h b/platform/shared/include/chre/platform/shared/log_buffer_manager.h
index cae854e9..44eb9391 100644
--- a/platform/shared/include/chre/platform/shared/log_buffer_manager.h
+++ b/platform/shared/include/chre/platform/shared/log_buffer_manager.h
@@ -21,6 +21,7 @@
#include "chre/platform/condition_variable.h"
#include "chre/platform/mutex.h"
#include "chre/platform/shared/bt_snoop_log.h"
+#include "chre/platform/shared/generated/host_messages_generated.h"
#include "chre/platform/shared/log_buffer.h"
#include "chre/util/singleton.h"
#include "chre_api/chre/re.h"
@@ -31,6 +32,8 @@
namespace chre {
+using LogType = fbs::LogType;
+
/**
* A log buffer manager that platform code can use to buffer logs when the host
* is not available and then send them off when the host becomes available. Uses
@@ -132,7 +135,7 @@ class LogBufferManager : public LogBufferCallbackInterface {
uint32_t getTimestampMs();
- void bufferOverflowGuard(size_t logSize);
+ void bufferOverflowGuard(size_t logSize, LogType type);
LogBuffer mPrimaryLogBuffer;
LogBuffer mSecondaryLogBuffer;
diff --git a/platform/shared/include/chre/target_platform/platform_ble_base.h b/platform/shared/include/chre/target_platform/platform_ble_base.h
index e37e88a6..fe47ed41 100644
--- a/platform/shared/include/chre/target_platform/platform_ble_base.h
+++ b/platform/shared/include/chre/target_platform/platform_ble_base.h
@@ -40,6 +40,7 @@ class PlatformBleBase : public PlatformPal {
static void advertisingEventCallback(struct chreBleAdvertisementEvent *event);
static void readRssiCallback(uint8_t errorCode, uint16_t connectionHandle,
int8_t rssi);
+ static void flushCallback(uint8_t errorCode);
static void handleBtSnoopLog(bool isTxToBtController, const uint8_t *buffer,
size_t size);
};
diff --git a/platform/shared/log_buffer.cc b/platform/shared/log_buffer.cc
index 358c1752..8bfb5ad6 100644
--- a/platform/shared/log_buffer.cc
+++ b/platform/shared/log_buffer.cc
@@ -44,9 +44,8 @@ void LogBuffer::handleLog(LogBufferLogLevel logLevel, uint32_t timestampMs,
void LogBuffer::handleLogVa(LogBufferLogLevel logLevel, uint32_t timestampMs,
const char *logFormat, va_list args) {
- constexpr size_t maxLogLen = kLogMaxSize - kLogDataOffset;
- char tempBuffer[maxLogLen];
- int logLenSigned = vsnprintf(tempBuffer, maxLogLen, logFormat, args);
+ char tempBuffer[kLogMaxSize];
+ int logLenSigned = vsnprintf(tempBuffer, kLogMaxSize, logFormat, args);
processLog(logLevel, timestampMs, tempBuffer, logLenSigned,
false /* encoded */);
}
@@ -54,41 +53,44 @@ void LogBuffer::handleLogVa(LogBufferLogLevel logLevel, uint32_t timestampMs,
#ifdef CHRE_BLE_SUPPORT_ENABLED
void LogBuffer::handleBtLog(BtSnoopDirection direction, uint32_t timestampMs,
const uint8_t *buffer, size_t size) {
- if (size > 0) {
- auto logLen = static_cast<uint8_t>(size);
+ if (size == 0) {
+ return;
+ }
+ auto logLen = static_cast<uint8_t>(size);
- if (size < kLogMaxSize) {
- LockGuard<Mutex> lockGuard(mLock);
+ if (size < kLogMaxSize) {
+ LockGuard<Mutex> lockGuard(mLock);
- // No additional terminator towards the end.
- discardExcessOldLogsLocked(false, logLen);
+ static_assert(sizeof(LogType) == sizeof(uint8_t),
+ "LogType size is not equal to size of uint8_t");
+ static_assert(sizeof(direction) == sizeof(uint8_t),
+ "BtSnoopDirection size is not equal to the size of uint8_t");
+ uint8_t snoopLogDirection = static_cast<uint8_t>(direction);
- uint8_t logType = static_cast<uint8_t>(LogType::BLUETOOTH);
- uint8_t snoopLogDirection = static_cast<uint8_t>(direction);
+ discardExcessOldLogsLocked(logLen + kBtSnoopLogOffset);
- // Set all BT logs to the CHRE_LOG_LEVEL_INFO.
- uint8_t metadata =
- (static_cast<uint8_t>(logType) << 4) | CHRE_LOG_LEVEL_INFO;
- copyToBuffer(sizeof(metadata), &metadata);
+ // Set all BT logs to the CHRE_LOG_LEVEL_INFO.
+ uint8_t metadata =
+ setLogMetadata(LogType::BLUETOOTH, LogBufferLogLevel::INFO);
- copyToBuffer(sizeof(timestampMs), &timestampMs);
- copyToBuffer(sizeof(direction), &snoopLogDirection);
- copyToBuffer(sizeof(logLen), &logLen);
+ copyVarToBuffer(&metadata);
+ copyVarToBuffer(&timestampMs);
+ copyVarToBuffer(&snoopLogDirection);
+ copyVarToBuffer(&logLen);
- copyToBuffer(logLen, buffer);
- } else {
- // Cannot truncate a BT event. Log a failure message instead.
- constexpr char kBtSnoopLogGenericErrorMsg[] =
- "Bt Snoop log message too large";
- static_assert(
- sizeof(kBtSnoopLogGenericErrorMsg) <= kLogMaxSize,
- "Error meessage size needs to be smaller than max log length");
- logLen = static_cast<uint8_t>(sizeof(kBtSnoopLogGenericErrorMsg));
- copyLogToBuffer(LogBufferLogLevel::INFO, timestampMs,
- kBtSnoopLogGenericErrorMsg, logLen, false /* encoded */);
- }
- dispatch();
+ copyToBuffer(logLen, buffer);
+ } else {
+ // Cannot truncate a BT event. Log a failure message instead.
+ constexpr char kBtSnoopLogGenericErrorMsg[] =
+ "Bt Snoop log message too large";
+ static_assert(
+ sizeof(kBtSnoopLogGenericErrorMsg) <= kLogMaxSize,
+ "Error meessage size needs to be smaller than max log length");
+ logLen = static_cast<uint8_t>(sizeof(kBtSnoopLogGenericErrorMsg));
+ copyLogToBuffer(LogBufferLogLevel::INFO, timestampMs,
+ kBtSnoopLogGenericErrorMsg, logLen, false /* encoded */);
}
+ dispatch();
}
#endif // CHRE_BLE_SUPPORT_ENABLED
@@ -106,8 +108,7 @@ size_t LogBuffer::copyLogs(void *destination, size_t size,
bool LogBuffer::logWouldCauseOverflow(size_t logSize) {
LockGuard<Mutex> lock(mLock);
- return (mBufferDataSize + logSize + kLogDataOffset + 1 /* nullptr */ >
- mBufferMaxSize);
+ return (mBufferDataSize + logSize + kLogDataOffset > mBufferMaxSize);
}
void LogBuffer::transferTo(LogBuffer &buffer) {
@@ -202,8 +203,6 @@ size_t LogBuffer::copyLogsLocked(void *destination, size_t size,
copySize = mBufferDataSize;
} else {
size_t logSize;
- // There is guaranteed to be a null terminator within the max log length
- // number of bytes so logStartIndex will not be maxBytes + 1
size_t logStartIndex = getNextLogIndex(mBufferDataHeadIndex, &logSize);
while (copySize + logSize <= size &&
copySize + logSize <= mBufferDataSize) {
@@ -229,69 +228,81 @@ void LogBuffer::resetLocked() {
size_t LogBuffer::getNextLogIndex(size_t startingIndex, size_t *logSize) {
size_t logDataStartIndex =
incrementAndModByBufferMaxSize(startingIndex, kLogDataOffset);
-
- size_t logDataSize = getLogDataLength(logDataStartIndex);
+ LogType type = getLogTypeFromMetadata(mBufferData[startingIndex]);
+ size_t logDataSize = getLogDataLength(logDataStartIndex, type);
*logSize = kLogDataOffset + logDataSize;
return incrementAndModByBufferMaxSize(startingIndex, *logSize);
}
-size_t LogBuffer::getLogDataLength(size_t startingIndex) {
+size_t LogBuffer::getLogDataLength(size_t startingIndex, LogType type) {
size_t currentIndex = startingIndex;
- constexpr size_t maxBytes = kLogMaxSize - kLogDataOffset;
- size_t numBytes = maxBytes + 1;
-
- for (size_t i = 0; i < maxBytes; i++) {
- if (mBufferData[currentIndex] == '\0') {
- // +1 to include the null terminator
- numBytes = i + 1;
- break;
+ size_t numBytes = kLogMaxSize;
+
+ if (type == LogType::STRING) {
+ for (size_t i = 0; i < kLogMaxSize; i++) {
+ if (mBufferData[currentIndex] == '\0') {
+ // +1 to include the null terminator
+ numBytes = i + 1;
+ break;
+ }
+ currentIndex = incrementAndModByBufferMaxSize(currentIndex, 1);
}
- currentIndex = incrementAndModByBufferMaxSize(currentIndex, 1);
+ } else if (type == LogType::TOKENIZED) {
+ numBytes = mBufferData[startingIndex] + kTokenizedLogOffset;
+ } else if (type == LogType::BLUETOOTH) {
+ currentIndex = incrementAndModByBufferMaxSize(startingIndex, 1);
+ numBytes = mBufferData[currentIndex] + kBtSnoopLogOffset;
+ } else {
+ CHRE_ASSERT_LOG(false, "Received unexpected log message type");
}
+
return numBytes;
}
void LogBuffer::processLog(LogBufferLogLevel logLevel, uint32_t timestampMs,
const void *logBuffer, size_t size, bool encoded) {
- if (size > 0) {
- auto logLen = static_cast<uint8_t>(size);
- if (size >= kLogMaxSize) {
- if (!encoded) {
- // Leave space for null terminator to be copied on end
- logLen = static_cast<uint8_t>(kLogMaxSize - 1);
- } else {
- // There is no way of decoding an encoded message if we truncate it, so
- // we do the next best thing and try to log a generic failure message
- // reusing the logbuffer for as much as we can. Note that we also need
- // flip the encoding flag for proper decoding by the host log message
- // parser.
- constexpr char kTokenizedLogGenericErrorMsg[] =
- "Tokenized log message too large";
- static_assert(
- sizeof(kTokenizedLogGenericErrorMsg) <= kLogMaxSize,
- "Error meessage size needs to be smaller than max log length");
- logBuffer = kTokenizedLogGenericErrorMsg;
- logLen = static_cast<uint8_t>(sizeof(kTokenizedLogGenericErrorMsg));
- encoded = false;
- }
- }
- copyLogToBuffer(logLevel, timestampMs, logBuffer, logLen, encoded);
- dispatch();
+ if (size == 0) {
+ return;
+ }
+ auto logLen = static_cast<uint8_t>(size);
+
+ constexpr char kTokenizedLogGenericErrorMsg[] =
+ "Tokenized log message too large";
+
+ // For tokenized logs, need to leave space for the message size offset. For
+ // string logs, need to leave 1 byte for the null terminator at the end.
+ if (!encoded && size >= kLogMaxSize - 1) {
+ // String logs longer than kLogMaxSize - 1 will be truncated.
+ logLen = static_cast<uint8_t>(kLogMaxSize - 1);
+ } else if (encoded && size >= kLogMaxSize - kTokenizedLogOffset) {
+ // There is no way of decoding an encoded message if we truncate it, so
+ // we do the next best thing and try to log a generic failure message
+ // reusing the logbuffer for as much as we can. Note that we also need
+ // flip the encoding flag for proper decoding by the host log message
+ // parser.
+ static_assert(
+ sizeof(kTokenizedLogGenericErrorMsg) <= kLogMaxSize - 1,
+ "Error meessage size needs to be smaller than max log length");
+ logBuffer = kTokenizedLogGenericErrorMsg;
+ logLen = static_cast<uint8_t>(sizeof(kTokenizedLogGenericErrorMsg));
+ encoded = false;
}
+ copyLogToBuffer(logLevel, timestampMs, logBuffer, logLen, encoded);
+ dispatch();
}
void LogBuffer::copyLogToBuffer(LogBufferLogLevel level, uint32_t timestampMs,
const void *logBuffer, uint8_t logLen,
bool encoded) {
LockGuard<Mutex> lockGuard(mLock);
- discardExcessOldLogsLocked(encoded, logLen);
+ // For STRING logs, add 1 byte for null terminator. For TOKENIZED logs, add 1
+ // byte for the size metadata added to the message.
+ discardExcessOldLogsLocked(logLen + 1);
encodeAndCopyLogLocked(level, timestampMs, logBuffer, logLen, encoded);
}
-void LogBuffer::discardExcessOldLogsLocked(bool encoded,
- uint8_t currentLogLen) {
- size_t totalLogSize =
- kLogDataOffset + (encoded ? currentLogLen : currentLogLen + 1);
+void LogBuffer::discardExcessOldLogsLocked(uint8_t currentLogLen) {
+ size_t totalLogSize = kLogDataOffset + currentLogLen;
while (mBufferDataSize + totalLogSize > mBufferMaxSize) {
mNumLogsDropped++;
size_t logSize;
@@ -305,13 +316,13 @@ void LogBuffer::encodeAndCopyLogLocked(LogBufferLogLevel level,
const void *logBuffer, uint8_t logLen,
bool encoded) {
uint8_t metadata =
- (static_cast<uint8_t>(encoded) << 4) | static_cast<uint8_t>(level);
+ setLogMetadata(encoded ? LogType::TOKENIZED : LogType::STRING, level);
- copyToBuffer(sizeof(uint8_t), &metadata);
- copyToBuffer(sizeof(timestampMs), &timestampMs);
+ copyVarToBuffer(&metadata);
+ copyVarToBuffer(&timestampMs);
if (encoded) {
- copyToBuffer(sizeof(uint8_t), &logLen);
+ copyVarToBuffer(&logLen);
}
copyToBuffer(logLen, logBuffer);
if (!encoded) {
@@ -339,4 +350,20 @@ void LogBuffer::dispatch() {
}
}
+LogType LogBuffer::getLogTypeFromMetadata(uint8_t metadata) {
+ LogType type;
+ if ((metadata & 0x20) != 0) {
+ type = LogType::BLUETOOTH;
+ } else if ((metadata & 0x10) != 0) {
+ type = LogType::TOKENIZED;
+ } else {
+ type = LogType::STRING;
+ }
+ return type;
+}
+
+uint8_t LogBuffer::setLogMetadata(LogType type, LogBufferLogLevel logLevel) {
+ return static_cast<uint8_t>(type) << 4 | static_cast<uint8_t>(logLevel);
+}
+
} // namespace chre
diff --git a/platform/shared/log_buffer_manager.cc b/platform/shared/log_buffer_manager.cc
index 82abee60..96b4633e 100644
--- a/platform/shared/log_buffer_manager.cc
+++ b/platform/shared/log_buffer_manager.cc
@@ -18,6 +18,7 @@
#include "chre/core/event_loop_manager.h"
#include "chre/platform/shared/bt_snoop_log.h"
+#include "chre/platform/shared/generated/host_messages_generated.h"
#include "chre/util/lock_guard.h"
void chrePlatformLogToBuffer(chreLogLevel chreLogLevel, const char *format,
@@ -44,6 +45,8 @@ void chrePlatformBtSnoopLog(BtSnoopDirection direction, const uint8_t *buffer,
namespace chre {
+using LogType = fbs::LogType;
+
void LogBufferManager::onLogsReady() {
LockGuard<Mutex> lockGuard(mFlushLogsMutex);
if (!mLogFlushToHostPending) {
@@ -124,7 +127,15 @@ uint32_t LogBufferManager::getTimestampMs() {
return static_cast<uint32_t>(timeNs / kOneMillisecondInNanoseconds);
}
-void LogBufferManager::bufferOverflowGuard(size_t logSize) {
+void LogBufferManager::bufferOverflowGuard(size_t logSize, LogType type) {
+ if (type == LogType::STRING) {
+ // Add one byte because of the null terminator added at the end.
+ logSize = logSize + LogBuffer::kStringLogOverhead;
+ } else if (type == LogType::TOKENIZED) {
+ logSize = logSize + LogBuffer::kTokenizedLogOffset;
+ } else if (type == LogType::BLUETOOTH) {
+ logSize = logSize + LogBuffer::kBtSnoopLogOffset;
+ }
if (mPrimaryLogBuffer.logWouldCauseOverflow(logSize)) {
LockGuard<Mutex> lockGuard(mFlushLogsMutex);
if (!mLogFlushToHostPending) {
@@ -142,7 +153,7 @@ void LogBufferManager::logVa(chreLogLevel logLevel, const char *formatStr,
va_copy(getSizeArgs, args);
size_t logSize = vsnprintf(nullptr, 0, formatStr, getSizeArgs);
va_end(getSizeArgs);
- bufferOverflowGuard(logSize);
+ bufferOverflowGuard(logSize, LogType::STRING);
mPrimaryLogBuffer.handleLogVa(chreToLogBufferLogLevel(logLevel),
getTimestampMs(), formatStr, args);
}
@@ -150,7 +161,7 @@ void LogBufferManager::logVa(chreLogLevel logLevel, const char *formatStr,
void LogBufferManager::logBtSnoop(BtSnoopDirection direction,
const uint8_t *buffer, size_t size) {
#ifdef CHRE_BLE_SUPPORT_ENABLED
- bufferOverflowGuard(size);
+ bufferOverflowGuard(size, LogType::BLUETOOTH);
mPrimaryLogBuffer.handleBtLog(direction, getTimestampMs(), buffer, size);
#else
UNUSED_VAR(direction);
@@ -162,7 +173,7 @@ void LogBufferManager::logBtSnoop(BtSnoopDirection direction,
void LogBufferManager::logEncoded(chreLogLevel logLevel,
const uint8_t *encodedLog,
size_t encodedLogSize) {
- bufferOverflowGuard(encodedLogSize);
+ bufferOverflowGuard(encodedLogSize, LogType::TOKENIZED);
mPrimaryLogBuffer.handleEncodedLog(chreToLogBufferLogLevel(logLevel),
getTimestampMs(), encodedLog,
encodedLogSize);
diff --git a/platform/shared/nanoapp/nanoapp_stack_check.cc b/platform/shared/nanoapp/nanoapp_stack_check.cc
new file mode 100644
index 00000000..3f6b24bf
--- /dev/null
+++ b/platform/shared/nanoapp/nanoapp_stack_check.cc
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "chre/util/nanoapp/log.h"
+#include "chre_api/chre/re.h"
+#include "chre_api/chre/toolchain.h"
+
+/**
+ * @file
+ * Stack check support.
+ *
+ * The symbols defined in this file are needed when the code is compiled with
+ * the -fstack-protector flag.
+ */
+
+#ifndef LOG_TAG
+#define LOG_TAG "[STACK CHECK]"
+#endif // LOG_TAG
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uintptr_t __stack_chk_guard = 0x56494342;
+
+// Terminate a function in case of stack overflow.
+void __stack_chk_fail(void) CHRE_NO_RETURN;
+void __stack_chk_fail(void) {
+ LOGE("Stack corruption detected");
+ chreAbort(/*abortCode=*/0);
+}
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/platform/shared/nanoapp/nanoapp_support_lib_dso.cc b/platform/shared/nanoapp/nanoapp_support_lib_dso.cc
index 2f21df00..55b58403 100644
--- a/platform/shared/nanoapp/nanoapp_support_lib_dso.cc
+++ b/platform/shared/nanoapp/nanoapp_support_lib_dso.cc
@@ -304,12 +304,38 @@ bool chreBleStartScanAsync(chreBleScanMode mode, uint32_t reportDelayMs,
}
WEAK_SYMBOL
+bool chreBleStartScanAsyncV1_9(chreBleScanMode mode, uint32_t reportDelayMs,
+ const struct chreBleScanFilterV1_9 *filter,
+ const void *cookie) {
+ if (chreGetApiVersion() < CHRE_API_VERSION_1_9) {
+ return false;
+ }
+ auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreBleStartScanAsyncV1_9);
+ if (fptr == nullptr) {
+ return false;
+ }
+ return fptr(mode, reportDelayMs, filter, cookie);
+}
+
+WEAK_SYMBOL
bool chreBleStopScanAsync() {
auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreBleStopScanAsync);
return (fptr != nullptr) ? fptr() : false;
}
WEAK_SYMBOL
+bool chreBleStopScanAsyncV1_9(const void *cookie) {
+ if (chreGetApiVersion() < CHRE_API_VERSION_1_9) {
+ return false;
+ }
+ auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreBleStopScanAsyncV1_9);
+ if (fptr == nullptr) {
+ return false;
+ }
+ return fptr(cookie);
+}
+
+WEAK_SYMBOL
bool chreBleReadRssiAsync(uint16_t connectionHandle, const void *cookie) {
auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreBleReadRssiAsync);
return (fptr != nullptr) ? fptr(connectionHandle, cookie) : false;
diff --git a/platform/shared/nanoapp_loader.cc b/platform/shared/nanoapp_loader.cc
index eb4ec31a..377d8ce7 100644
--- a/platform/shared/nanoapp_loader.cc
+++ b/platform/shared/nanoapp_loader.cc
@@ -55,6 +55,10 @@ NanoappLoader *gCurrentlyLoadingNanoapp = nullptr;
//! Indicates whether a failure occurred during static initialization.
bool gStaticInitFailure = false;
+void deleteOpOverride(void* /* ptr */, unsigned int size) {
+ FATAL_ERROR("Nanoapp: delete(void *, unsigned int) override : sz = %u", size);
+}
+
int atexitInternal(struct AtExitCallback &cb) {
if (gCurrentlyLoadingNanoapp == nullptr) {
CHRE_ASSERT_LOG(false,
@@ -179,6 +183,7 @@ const ExportedData kExportedData[] = {
ADD_EXPORTED_C_SYMBOL(__cxa_pure_virtual),
ADD_EXPORTED_SYMBOL(cxaAtexitOverride, "__cxa_atexit"),
ADD_EXPORTED_SYMBOL(atexitOverride, "atexit"),
+ ADD_EXPORTED_SYMBOL(deleteOpOverride, "_ZdlPvj"),
ADD_EXPORTED_C_SYMBOL(dlsym),
ADD_EXPORTED_C_SYMBOL(isgraph),
ADD_EXPORTED_C_SYMBOL(memcmp),
@@ -198,7 +203,9 @@ const ExportedData kExportedData[] = {
ADD_EXPORTED_C_SYMBOL(chreBleGetFilterCapabilities),
ADD_EXPORTED_C_SYMBOL(chreBleFlushAsync),
ADD_EXPORTED_C_SYMBOL(chreBleStartScanAsync),
+ ADD_EXPORTED_C_SYMBOL(chreBleStartScanAsyncV1_9),
ADD_EXPORTED_C_SYMBOL(chreBleStopScanAsync),
+ ADD_EXPORTED_C_SYMBOL(chreBleStopScanAsyncV1_9),
ADD_EXPORTED_C_SYMBOL(chreBleReadRssiAsync),
ADD_EXPORTED_C_SYMBOL(chreBleGetScanStatus),
ADD_EXPORTED_C_SYMBOL(chreConfigureDebugDumpEvent),
diff --git a/platform/shared/platform_ble.cc b/platform/shared/platform_ble.cc
index 3039b13f..9d0bf90c 100644
--- a/platform/shared/platform_ble.cc
+++ b/platform/shared/platform_ble.cc
@@ -31,6 +31,7 @@ const chrePalBleCallbacks PlatformBleBase::sBleCallbacks = {
PlatformBleBase::scanStatusChangeCallback,
PlatformBleBase::advertisingEventCallback,
PlatformBleBase::readRssiCallback,
+ PlatformBleBase::flushCallback,
PlatformBleBase::handleBtSnoopLog,
};
@@ -49,6 +50,12 @@ void PlatformBle::init() {
if (mBleApi != nullptr) {
if (!mBleApi->open(&gChrePalSystemApi, &sBleCallbacks)) {
LOGE("BLE PAL open returned false");
+
+#ifdef CHRE_TELEMETRY_SUPPORT_ENABLED
+ EventLoopManagerSingleton::get()->getTelemetryManager().onPalOpenFailure(
+ TelemetryManager::PalType::BLE);
+#endif // CHRE_TELEMETRY_SUPPORT_ENABLED
+
mBleApi = nullptr;
} else {
LOGD("Opened BLE PAL version 0x%08" PRIx32, mBleApi->moduleVersion);
@@ -78,7 +85,7 @@ uint32_t PlatformBle::getFilterCapabilities() {
}
bool PlatformBle::startScanAsync(chreBleScanMode mode, uint32_t reportDelayMs,
- const struct chreBleScanFilter *filter) {
+ const struct chreBleScanFilterV1_9 *filter) {
if (mBleApi != nullptr) {
prePalApiCall(PalType::BLE);
return mBleApi->startScan(mode, reportDelayMs, filter);
@@ -142,6 +149,20 @@ void PlatformBleBase::readRssiCallback(uint8_t errorCode,
#endif
}
+bool PlatformBle::flushAsync() {
+ if (mBleApi != nullptr) {
+ prePalApiCall(PalType::BLE);
+ return mBleApi->flush();
+ } else {
+ return false;
+ }
+}
+
+void PlatformBleBase::flushCallback(uint8_t errorCode) {
+ EventLoopManagerSingleton::get()->getBleRequestManager().handleFlushComplete(
+ errorCode);
+}
+
void PlatformBleBase::handleBtSnoopLog(bool isTxToBtController,
const uint8_t *buffer, size_t size) {
BtSnoopDirection direction =
diff --git a/platform/shared/pw_trace/include/chre/target_platform/tracing.h b/platform/shared/pw_trace/include/chre/target_platform/tracing.h
new file mode 100644
index 00000000..a48c9ff0
--- /dev/null
+++ b/platform/shared/pw_trace/include/chre/target_platform/tracing.h
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHRE_PLATFORM_SHARED_TRACING_H_
+#define CHRE_PLATFORM_SHARED_TRACING_H_
+
+#include "chre/target_platform/tracing_util.h"
+#include "pw_trace/trace.h"
+
+// Format strings gotten from https://pigweed.dev/pw_trace/#data.
+// Must be macros for string concatenation at preprocessor time.
+#define PW_MAP_PREFIX "@pw_py_map_fmt:{"
+#define PW_MAP_SUFFIX "}"
+
+/**
+ * Traces an instantaneous event.
+ *
+ * @param label A string literal which describes the trace.
+ * @param group <optional> A string literal to group traces together.
+ * @param trace_id <optional> A uint32_t which groups this trace with others
+ * with the same group and trace_id.
+ * Every trace with a trace_id must also have a
+ * group.
+ * @see https://pigweed.dev/pw_trace/#trace-macros
+ */
+#define CHRE_TRACE_INSTANT(label, ...) PW_TRACE_INSTANT(label, ##__VA_ARGS__)
+
+/**
+ * Used to trace the start of a duration event. Should be paired with a
+ * CHRE_TRACE_END (or CHRE_TRACE_END_DATA) with the same
+ * module/label/group/trace_id.
+ *
+ * @param label A string literal which describes the trace.
+ * @param group <optional> A string literal to group traces together.
+ * @param trace_id <optional> A uint32_t which groups this trace with others
+ * with the same group and trace_id.
+ * Every trace with a trace_id must also have a
+ * group.
+ * @see https://pigweed.dev/pw_trace/#trace-macros
+ */
+#define CHRE_TRACE_START(label, ...) PW_TRACE_START(label, ##__VA_ARGS__)
+
+/**
+ * Used to trace the end of a duration event. Should be paired with a
+ * CHRE_TRACE_START (or CHRE_TRACE_START_DATA) with the same
+ * module/label/group/trace_id.
+ *
+ * @param label A string literal which describes the trace.
+ * @param group <optional> A string literal to group traces together.
+ * @param trace_id <optional> A uint32_t which groups this trace with others
+ * with the same group and trace_id.
+ * Every trace with a trace_id must also have a
+ * group.
+ * @see https://pigweed.dev/pw_trace/#trace-macros
+ */
+#define CHRE_TRACE_END(label, ...) PW_TRACE_END(label, ##__VA_ARGS__)
+
+/**
+ * For the group of CHRE_TRACE_INSTANT_DATA... macros.
+ * Use the appropriate macro which contains the parameters you wish to pass to
+ * the trace. If you wish to specify a group you must use either the
+ * CHRE_TRACE_INSTANT_DATA_GROUP macro or CHRE_TRACE_INSTANT_DATA_TRACE_ID macro
+ * with a trace_id.
+ *
+ * Traces an instantaneous event with data variables or literals passed to the
+ * macro, correlating to the dataFmtString.
+ *
+ * @param label A string literal which describes the trace.
+ * @param group A string literal to group traces together.
+ * Must use CHRE_TRACE_INSTANT_DATA_GROUP or
+ * CHRE_TRACE_INSTANT_DATA_TRACE_ID with a trace_id to use this
+ * parameter.
+ * @param trace_id A uint32_t which groups this trace with others with the same
+ * group and trace_id.
+ * Every trace with a trace_id must also have a group.
+ * Must use CHRE_TRACE_INSTANT_DATA_TRACE_ID to use this
+ * parameter.
+ * @param dataFmtString A string literal which is used to relate data to its
+ * size. Use the defined macros "T_X" for ease of use in
+ * the format specifier. The format string must follow the
+ * format "<field name>:<specifier>,..." (omitting the
+ * final comma)
+ * Ex. "data1:" T_U8 ",data2:" T_I32
+ * @param firstData First data variable. Used to enforce proper usage of this
+ * macro (with at least one data variable).
+ * @param VA_ARGS List of variables holding data in the order specified by the
+ * dataFmtString.
+ *
+ * @see https://pigweed.dev/pw_trace/#trace-macros
+ */
+#define CHRE_TRACE_INSTANT_DATA(label, dataFmtString, firstData, ...) \
+ do { \
+ CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER(firstData, ##__VA_ARGS__); \
+ PW_TRACE_INSTANT_DATA(label, PW_MAP_PREFIX dataFmtString PW_MAP_SUFFIX, \
+ chreTraceDataBuffer, chreTraceDataSize); \
+ } while (0)
+
+#define CHRE_TRACE_INSTANT_DATA_GROUP(label, group, dataFmtString, firstData, \
+ ...) \
+ do { \
+ CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER(firstData, ##__VA_ARGS__); \
+ PW_TRACE_INSTANT_DATA(label, group, \
+ PW_MAP_PREFIX dataFmtString PW_MAP_SUFFIX, \
+ chreTraceDataBuffer, chreTraceDataSize); \
+ } while (0)
+
+#define CHRE_TRACE_INSTANT_DATA_TRACE_ID(label, group, trace_id, \
+ dataFmtString, firstData, ...) \
+ do { \
+ CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER(firstData, ##__VA_ARGS__); \
+ PW_TRACE_INSTANT_DATA(label, group, trace_id, \
+ PW_MAP_PREFIX dataFmtString PW_MAP_SUFFIX, \
+ chreTraceDataBuffer, chreTraceDataSize); \
+ } while (0)
+
+/**
+ * For the group of CHRE_TRACE_START_DATA... macros.
+ * Use the appropriate macro which contains the parameters you wish to pass to
+ * the trace. If you wish to specify a group you must use either the
+ * CHRE_TRACE_START_DATA_GROUP macro or CHRE_TRACE_START_DATA_TRACE_ID macro
+ * with a trace_id.
+ *
+ * Used to trace the start of a duration event with data variables or literals
+ * passed to the macro, correlating to the dataFmtString. This should be paired
+ * with a CHRE_TRACE_END (or CHRE_TRACE_END_DATA) with the same
+ * module/label/group/trace_id to measure the duration of this event.
+ *
+ * @param label A string literal which describes the trace.
+ * @param group A string literal to group traces together.
+ * Must use CHRE_TRACE_START_DATA_GROUP or
+ * CHRE_TRACE_START_DATA_TRACE_ID with a trace_id to use this
+ * parameter.
+ * @param trace_id A uint32_t which groups this trace with others with the same
+ * group and trace_id.
+ * Every trace with a trace_id must also have a group.
+ * Must use CHRE_TRACE_START_DATA_TRACE_ID to use this
+ * parameter.
+ * @param dataFmtString A string literal which is used to relate data to its
+ * size. Use the defined macros "T_X" for ease of use in
+ * the format specifier. The format string must follow the
+ * format "<field name>:<specifier>,..." (omitting the
+ * final comma)
+ * Ex. "data1:" T_U8 ",data2:" T_I32
+ * @param firstData First data variable. Used to enforce proper usage of this
+ * macro (with at least one data variable).
+ * @param VA_ARGS List of variables holding data in the order specified by the
+ * dataFmtString.
+ *
+ * @see https://pigweed.dev/pw_trace/#trace-macros
+ */
+#define CHRE_TRACE_START_DATA(label, dataFmtString, firstData, ...) \
+ do { \
+ CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER(firstData, ##__VA_ARGS__); \
+ PW_TRACE_START_DATA(label, PW_MAP_PREFIX dataFmtString PW_MAP_SUFFIX, \
+ chreTraceDataBuffer, chreTraceDataSize); \
+ } while (0)
+
+#define CHRE_TRACE_START_DATA_GROUP(label, group, dataFmtString, firstData, \
+ ...) \
+ do { \
+ CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER(firstData, ##__VA_ARGS__); \
+ PW_TRACE_START_DATA(label, group, \
+ PW_MAP_PREFIX dataFmtString PW_MAP_SUFFIX, \
+ chreTraceDataBuffer, chreTraceDataSize); \
+ } while (0)
+
+#define CHRE_TRACE_START_DATA_TRACE_ID(label, group, trace_id, dataFmtString, \
+ firstData, ...) \
+ do { \
+ CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER(firstData, ##__VA_ARGS__); \
+ PW_TRACE_START_DATA(label, group, trace_id, \
+ PW_MAP_PREFIX dataFmtString PW_MAP_SUFFIX, \
+ chreTraceDataBuffer, chreTraceDataSize); \
+ } while (0)
+
+/**
+ * For the group of CHRE_TRACE_END_DATA... macros.
+ * Use the appropriate macro which contains the parameters you wish to pass to
+ * the trace. If you wish to specify a group you must use either the
+ * CHRE_TRACE_END_DATA_GROUP macro or CHRE_TRACE_END_DATA_TRACE_ID macro
+ * with a trace_id.
+ *
+ * Used to trace the end of a duration event with data variables or literals
+ * passed to the macro, correlating to the dataFmtString. This should be paired
+ * with a CHRE_TRACE_START (or CHRE_TRACE_START_DATA) with the same
+ * module/label/group/trace_id to measure the duration of this event.
+ *
+ * @param label A string literal which describes the trace.
+ * @param group A string literal to group traces together.
+ * Must use CHRE_TRACE_END_DATA_GROUP or
+ * CHRE_TRACE_END_DATA_TRACE_ID with a trace_id to use this
+ * parameter.
+ * @param trace_id A uint32_t which groups this trace with others with the same
+ * group and trace_id.
+ * Every trace with a trace_id must also have a group.
+ * Must use CHRE_TRACE_END_DATA_TRACE_ID to use this
+ * parameter.
+ * @param dataFmtString A string literal which is used to relate data to its
+ * size. Use the defined macros "T_X" for ease of use in
+ * the format specifier. The format string must follow the
+ * format "<field name>:<specifier>,..." (omitting the
+ * final comma)
+ * Ex. "data1:" T_U8 ",data2:" T_I32
+ * @param firstData First data variable. Used to enforce proper usage of this
+ * macro (with at least one data variable).
+ * @param VA_ARGS List of variables holding data in the order specified by the
+ * dataFmtString.
+ *
+ * @see https://pigweed.dev/pw_trace/#trace-macros
+ */
+#define CHRE_TRACE_END_DATA(label, dataFmtString, firstData, ...) \
+ do { \
+ CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER(firstData, ##__VA_ARGS__); \
+ PW_TRACE_END_DATA(label, PW_MAP_PREFIX dataFmtString PW_MAP_SUFFIX, \
+ chreTraceDataBuffer, chreTraceDataSize); \
+ } while (0)
+
+#define CHRE_TRACE_END_DATA_GROUP(label, group, dataFmtString, firstData, ...) \
+ do { \
+ CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER(firstData, ##__VA_ARGS__); \
+ PW_TRACE_END_DATA(label, group, PW_MAP_PREFIX dataFmtString PW_MAP_SUFFIX, \
+ chreTraceDataBuffer, chreTraceDataSize); \
+ } while (0)
+
+#define CHRE_TRACE_END_DATA_TRACE_ID(label, group, trace_id, dataFmtString, \
+ firstData, ...) \
+ do { \
+ CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER(firstData, ##__VA_ARGS__); \
+ PW_TRACE_END_DATA(label, group, trace_id, \
+ PW_MAP_PREFIX dataFmtString PW_MAP_SUFFIX, \
+ chreTraceDataBuffer, chreTraceDataSize); \
+ } while (0)
+
+#endif // CHRE_PLATFORM_SHARED_TRACING_H_
diff --git a/platform/shared/pw_trace/include/chre/target_platform/tracing_util.h b/platform/shared/pw_trace/include/chre/target_platform/tracing_util.h
new file mode 100644
index 00000000..d68ecec0
--- /dev/null
+++ b/platform/shared/pw_trace/include/chre/target_platform/tracing_util.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHRE_PLATFORM_SHARED_TRACING_UTIL_H_
+#define CHRE_PLATFORM_SHARED_TRACING_UTIL_H_
+
+#include "chre/util/macros.h"
+
+namespace tracing_internal {
+
+// Check to make sure pointer size macro is defined.
+#ifndef __SIZEOF_POINTER__
+#error "__SIZEOF_POINTER__ macro not defined - unsupported toolchain being used"
+#endif
+
+constexpr size_t kMaxTraceDataSize = 256;
+
+template <typename T>
+inline constexpr std::size_t chreTraceGetSizeOf() {
+ if constexpr (std::is_pointer_v<T>) {
+ return __SIZEOF_POINTER__;
+ }
+
+ return sizeof(T);
+}
+
+/**
+ * Special case for strings.
+ *
+ * Due to how python struct unpacking works, reading strings requires the data
+ * format string to specify the length of buffer containing the string.
+ * PW_TRACE macros require the data format string to be a string literal, and we
+ * don't always know the str length at compile-time and thus opt to put all
+ * strings in a fixed size buffer of length CHRE_TRACE_MAX_STRING_SIZE. Using
+ * the pascal string option indicates the buffer's first byte contains the size
+ * of string, followed by the string characters.
+ */
+template <>
+inline constexpr std::size_t chreTraceGetSizeOf<const char *>() {
+ return CHRE_TRACE_STR_BUFFER_SIZE;
+}
+template <>
+inline constexpr std::size_t chreTraceGetSizeOf<char *>() {
+ return chreTraceGetSizeOf<const char *>();
+}
+
+template <typename... Types>
+constexpr std::size_t chreTraceGetSizeOfVarArgs() {
+ return (chreTraceGetSizeOf<std::decay_t<Types>>() + ...);
+}
+
+template <typename Data>
+inline void chreTraceInsertVar(uint8_t *buffer, Data data,
+ std::size_t dataSize) {
+ static_assert(std::is_integral_v<Data> || std::is_pointer_v<Data>,
+ "Unsupported data type");
+ memcpy(buffer, &data, dataSize);
+}
+template <>
+inline void chreTraceInsertVar<const char *>(uint8_t *buffer, const char *data,
+ std::size_t) {
+ // Insert size byte metadata as the first byte of the pascal string.
+ *buffer = static_cast<uint8_t>(strnlen(data, CHRE_TRACE_MAX_STRING_SIZE));
+
+ // Insert string after size byte and zero out remainder of buffer.
+ strncpy(reinterpret_cast<char *>(buffer + 1), data,
+ CHRE_TRACE_MAX_STRING_SIZE);
+}
+template <>
+inline void chreTraceInsertVar<char *>(uint8_t *buffer, char *data,
+ std::size_t dataSize) {
+ chreTraceInsertVar<const char *>(buffer, data, dataSize);
+}
+
+/**
+ * Populate the pre-allocated buffer with data passed in.
+ * Should only be called in the CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER
+ * macro.
+ *
+ * Example Usage:
+ * uint_16_t data1; char data2; uint32_t data3;
+ * ... // define data
+ * chreTracePopulateBufferWithArgs(buf, data1, data2, data3);
+ *
+ * @param buffer A buffer to insert data into.
+ * Assumed to be large enough to hold all data since we use the
+ * same size logic to allocate space for the buffer.
+ * @param data Single piece of data to insert into the buffer. Assumed to
+ * have >= 1 data element to insert into the buffer. Strings
+ * assumed to be null-terminated or have length >=
+ * CHRE_TRACE_MAX_STRING_SIZE.
+ * @param args Variable length argument to hold the remainder of the data
+ * to insert into the buffer.
+ */
+template <typename Data, typename... Types>
+void chreTracePopulateBufferWithArgs(uint8_t *buffer, Data data,
+ Types... args) {
+ constexpr std::size_t dataSize = chreTraceGetSizeOf<Data>();
+ tracing_internal::chreTraceInsertVar(buffer, data, dataSize);
+ buffer += dataSize;
+
+ if constexpr (sizeof...(args) > 0) {
+ chreTracePopulateBufferWithArgs(buffer, args...);
+ }
+}
+
+// Create and populate the chreTraceDataBuffer. We allocate only the amount of
+// space required to store all data.
+// Unscoped to export the variables holding the buffer and data size.
+#define CHRE_TRACE_ALLOCATE_AND_POPULATE_DATA_BUFFER(...) \
+ constexpr std::size_t chreTraceDataSize = \
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(__VA_ARGS__)>(); \
+ static_assert(chreTraceDataSize <= tracing_internal::kMaxTraceDataSize, \
+ "Trace data size too large"); \
+ uint8_t chreTraceDataBuffer[chreTraceDataSize]; \
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, \
+ __VA_ARGS__);
+
+} // namespace tracing_internal
+
+#endif // CHRE_PLATFORM_SHARED_TRACING_UTIL_H_ \ No newline at end of file
diff --git a/platform/shared/sensor_pal/platform_sensor_manager.cc b/platform/shared/sensor_pal/platform_sensor_manager.cc
index 28a2c596..3b5af49a 100644
--- a/platform/shared/sensor_pal/platform_sensor_manager.cc
+++ b/platform/shared/sensor_pal/platform_sensor_manager.cc
@@ -44,6 +44,12 @@ void PlatformSensorManager::init() {
if (mSensorApi != nullptr) {
if (!mSensorApi->open(&gChrePalSystemApi, &sSensorCallbacks)) {
LOGE("Sensor PAL open returned false");
+
+#ifdef CHRE_TELEMETRY_SUPPORT_ENABLED
+ EventLoopManagerSingleton::get()->getTelemetryManager().onPalOpenFailure(
+ TelemetryManager::PalType::SENSOR);
+#endif // CHRE_TELEMETRY_SUPPORT_ENABLED
+
mSensorApi = nullptr;
} else {
LOGD("Opened Sensor PAL version 0x%08" PRIx32, mSensorApi->moduleVersion);
diff --git a/platform/slpi/host_link.cc b/platform/slpi/host_link.cc
index e1d6985a..7b2e0cd7 100644
--- a/platform/slpi/host_link.cc
+++ b/platform/slpi/host_link.cc
@@ -908,6 +908,8 @@ void HostMessageHandlers::handleSelfTestRequest(uint16_t hostClientId) {
sendSelfTestResponse(hostClientId, success);
}
+void HostMessageHandlers::handlePulseRequest() {}
+
void HostMessageHandlers::handleNanConfigurationUpdate(bool enabled) {
#ifdef CHRE_WIFI_NAN_SUPPORT_ENABLED
EventLoopManagerSingleton::get()
diff --git a/platform/slpi/include/chre/target_platform/assert.h b/platform/slpi/include/chre/target_platform/assert.h
new file mode 100644
index 00000000..7d00b518
--- /dev/null
+++ b/platform/slpi/include/chre/target_platform/assert.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PLATFORM_SLPI_INCLUDE_CHRE_TARGET_PLATFORM_ASSERT_H
+#define PLATFORM_SLPI_INCLUDE_CHRE_TARGET_PLATFORM_ASSERT_H
+
+#include "chre/platform/shared/assert_func.h"
+
+#endif // PLATFORM_SLPI_INCLUDE_CHRE_TARGET_PLATFORM_ASSERT_H
diff --git a/platform/tests/log_buffer_test.cc b/platform/tests/log_buffer_test.cc
index 674fe8f8..9a71cbc4 100644
--- a/platform/tests/log_buffer_test.cc
+++ b/platform/tests/log_buffer_test.cc
@@ -14,14 +14,18 @@
* limitations under the License.
*/
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <string>
#include "chre/platform/atomic.h"
#include "chre/platform/condition_variable.h"
#include "chre/platform/mutex.h"
+#include "chre/platform/shared/bt_snoop_log.h"
#include "chre/platform/shared/log_buffer.h"
+using testing::ContainerEq;
+
namespace chre {
// TODO(b/146164384): Test that the onLogsReady callback is called
@@ -111,7 +115,7 @@ TEST(LogBuffer, FailOnHandleLargerLogThanBufferSize) {
char outBuffer[kOutBufferSize];
// Note the size of this log is too big to fit in the buffer that we are
// using for the LogBuffer object
- std::string testLogStrStr(1025, 'a');
+ std::string testLogStrStr(kDefaultBufferSize + 1, 'a');
TestLogBufferCallback callback;
LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
@@ -125,32 +129,141 @@ TEST(LogBuffer, FailOnHandleLargerLogThanBufferSize) {
EXPECT_EQ(bytesCopied, 0);
}
-TEST(LogBuffer, LogOverwritten) {
+TEST(LogBuffer, StringLogOverwritten) {
char buffer[kDefaultBufferSize];
constexpr size_t kOutBufferSize = 200;
char outBuffer[kOutBufferSize];
- char testedBuffer[kOutBufferSize];
TestLogBufferCallback callback;
LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
- // This for loop adds 1060 bytes of data through the buffer which is > than
- // 1024
- for (size_t i = 0; i < 10; i++) {
- std::string testLogStrStr(100, 'a' + i);
+ constexpr size_t kLogPayloadSize = 100;
+ constexpr size_t kBufferUsePerLog = LogBuffer::kLogDataOffset +
+ LogBuffer::kStringLogOverhead +
+ kLogPayloadSize;
+ constexpr int kNumInsertions = 10;
+ constexpr int kNumLogDropsExpected =
+ kNumInsertions - kDefaultBufferSize / kBufferUsePerLog;
+ static_assert(kNumLogDropsExpected > 0);
+
+ // This for loop adds 1060 (kNumInsertions * kBufferUsePerLog) bytes of data
+ // through the buffer which is > than 1024.
+ for (size_t i = 0; i < kNumInsertions; i++) {
+ std::string testLogStrStr(kLogPayloadSize, 'a' + i);
const char *testLogStr = testLogStrStr.c_str();
logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testLogStr);
}
- size_t numLogsDropped;
- size_t bytesCopied =
- logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
- memcpy(testedBuffer, outBuffer + LogBuffer::kLogDataOffset, 101);
-
- // Should have read out the second from front test log string which is 'a' + 1
- // = 'b'
- EXPECT_TRUE(strcmp(testedBuffer, std::string(100, 'b').c_str()) == 0);
- EXPECT_EQ(bytesCopied, LogBuffer::kLogDataOffset + 100 + 1);
- // Should have dropped the first log
- EXPECT_EQ(numLogsDropped, 1);
+ EXPECT_EQ(logBuffer.getBufferSize(),
+ (kNumInsertions - kNumLogDropsExpected) * kBufferUsePerLog);
+ EXPECT_EQ(logBuffer.getNumLogsDropped(), kNumLogDropsExpected);
+
+ for (size_t i = logBuffer.getNumLogsDropped(); i < kNumInsertions; i++) {
+ // Should have read out the i-th from front test log string which a string
+ // log 'a' + i.
+ size_t numLogsDropped;
+ size_t bytesCopied =
+ logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
+ EXPECT_TRUE(strcmp(outBuffer + LogBuffer::kLogDataOffset,
+ std::string(kLogPayloadSize, 'a' + i).c_str()) == 0);
+ EXPECT_EQ(bytesCopied, kBufferUsePerLog);
+ }
+}
+
+TEST(LogBuffer, TokenizedLogOverwritten) {
+ char buffer[kDefaultBufferSize];
+ TestLogBufferCallback callback;
+ LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
+
+ constexpr size_t kLogPayloadSize = 100;
+ constexpr size_t kBufferUsePerLog = LogBuffer::kLogDataOffset +
+ LogBuffer::kTokenizedLogOffset +
+ kLogPayloadSize;
+ constexpr int kNumInsertions = 10;
+ constexpr int kNumLogDropsExpected =
+ kNumInsertions - kDefaultBufferSize / kBufferUsePerLog;
+ static_assert(kNumLogDropsExpected > 0);
+
+ // This for loop adds 1060 (kNumInsertions * kBufferUsePerLog) bytes of data
+ // through the buffer which is > than 1024.
+ for (size_t i = 0; i < kNumInsertions; i++) {
+ std::vector<uint8_t> testData(kLogPayloadSize, i);
+ logBuffer.handleEncodedLog(LogBufferLogLevel::INFO, 0, testData.data(),
+ testData.size());
+ }
+ EXPECT_EQ(logBuffer.getBufferSize(),
+ (kNumInsertions - kNumLogDropsExpected) * kBufferUsePerLog);
+ EXPECT_EQ(logBuffer.getNumLogsDropped(), kNumLogDropsExpected);
+
+ for (size_t i = logBuffer.getNumLogsDropped(); i < kNumInsertions; i++) {
+ // Should have read out the i-th from front test log data which is an
+ // integer i.
+ std::vector<uint8_t> outBuffer(kBufferUsePerLog, 0x77);
+ size_t numLogsDropped;
+ size_t bytesCopied =
+ logBuffer.copyLogs(outBuffer.data(), outBuffer.size(), &numLogsDropped);
+
+ // Validate that the log size in Tokenized log header matches the expected
+ // log size.
+ EXPECT_EQ(outBuffer[LogBuffer::kLogDataOffset], kLogPayloadSize);
+
+ outBuffer.erase(outBuffer.begin(), outBuffer.begin() +
+ LogBuffer::kLogDataOffset +
+ LogBuffer::kTokenizedLogOffset);
+ EXPECT_THAT(outBuffer,
+ ContainerEq(std::vector<uint8_t>(kLogPayloadSize, i)));
+ EXPECT_EQ(bytesCopied, kBufferUsePerLog);
+ }
+}
+
+TEST(LogBuffer, BtSnoopLogOverwritten) {
+ char buffer[kDefaultBufferSize];
+ TestLogBufferCallback callback;
+ LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
+
+ constexpr size_t kLogPayloadSize = 100;
+ constexpr size_t kBufferUsePerLog = LogBuffer::kLogDataOffset +
+ LogBuffer::kBtSnoopLogOffset +
+ kLogPayloadSize;
+ constexpr int kNumInsertions = 10;
+ constexpr int kNumLogDropsExpected =
+ kNumInsertions - kDefaultBufferSize / kBufferUsePerLog;
+ static_assert(kNumLogDropsExpected > 0);
+
+ // This for loop adds 1070 (kNumInsertions * kBufferUsePerLog) bytes of data
+ // through the buffer which is > than 1024.
+ for (size_t i = 0; i < kNumInsertions; i++) {
+ std::vector<uint8_t> testData(kLogPayloadSize, i);
+ logBuffer.handleBtLog(BtSnoopDirection::INCOMING_FROM_BT_CONTROLLER, 0,
+ testData.data(), testData.size());
+ }
+ EXPECT_EQ(logBuffer.getBufferSize(),
+ (kNumInsertions - kNumLogDropsExpected) * kBufferUsePerLog);
+ EXPECT_EQ(logBuffer.getNumLogsDropped(), kNumLogDropsExpected);
+
+ for (size_t i = logBuffer.getNumLogsDropped(); i < kNumInsertions; i++) {
+ // Should have read out the i-th from front test log data which is an
+ // integer i.
+ std::vector<uint8_t> outBuffer(kBufferUsePerLog, 0x77);
+ size_t numLogsDropped;
+ size_t bytesCopied =
+ logBuffer.copyLogs(outBuffer.data(), outBuffer.size(), &numLogsDropped);
+
+ // Validate that the Bt Snoop log header matches the expected log direction
+ // and size.
+ constexpr int kBtSnoopLogHeaderSizeOffset = 1;
+ EXPECT_EQ(
+ static_cast<BtSnoopDirection>(outBuffer[LogBuffer::kLogDataOffset]),
+ BtSnoopDirection::INCOMING_FROM_BT_CONTROLLER);
+ EXPECT_EQ(
+ outBuffer[LogBuffer::kLogDataOffset + kBtSnoopLogHeaderSizeOffset],
+ kLogPayloadSize);
+
+ outBuffer.erase(outBuffer.begin(), outBuffer.begin() +
+ LogBuffer::kLogDataOffset +
+ LogBuffer::kBtSnoopLogOffset);
+ EXPECT_THAT(outBuffer,
+ ContainerEq(std::vector<uint8_t>(kLogPayloadSize, i)));
+ EXPECT_EQ(bytesCopied, kBufferUsePerLog);
+ }
}
TEST(LogBuffer, CopyIntoEmptyBuffer) {
@@ -204,16 +317,16 @@ TEST(LogBuffer, TruncateLongLog) {
char outBuffer[kOutBufferSize];
TestLogBufferCallback callback;
LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
- std::string testStr(256, 'a');
+ std::string testStr(LogBuffer::kLogMaxSize + 1, 'a');
logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testStr.c_str());
size_t numLogsDropped;
size_t bytesCopied =
logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
- // Should truncate the logs down to the kLogMaxSize value of 255 by the time
- // it is copied out.
- EXPECT_EQ(bytesCopied, 255);
+ // Should truncate the logs down to the kLogMaxSize + kLogDataOffset by the
+ // time it is copied out.
+ EXPECT_EQ(bytesCopied, LogBuffer::kLogMaxSize + LogBuffer::kLogDataOffset);
}
TEST(LogBuffer, WouldCauseOverflowTest) {
@@ -221,28 +334,33 @@ TEST(LogBuffer, WouldCauseOverflowTest) {
TestLogBufferCallback callback;
LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
- // With an empty buffer inerting one character should not overflow
- // ASSERT because if this fails the next ASSERT statement is undefined most
- // likely.
+ // With an empty buffer inserting an empty string (only null terminator)
+ // should not overflow ASSERT because if this fails the next ASSERT statement
+ // is undefined most likely.
ASSERT_FALSE(logBuffer.logWouldCauseOverflow(1));
- // This for loop adds 1000 bytes of data. There is 24 bytes of space left in
- // the buffer after this loop.
+ // This for loop adds 1000 bytes of data (kLogPayloadSize + kStringLogOverhead
+ // + kLogDataOffset). There is 24 bytes of space left in the buffer after this
+ // loop.
+ constexpr size_t kLogPayloadSize = 94;
for (size_t i = 0; i < 10; i++) {
- std::string testLogStrStr(94, 'a');
+ std::string testLogStrStr(kLogPayloadSize, 'a');
const char *testLogStr = testLogStrStr.c_str();
logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testLogStr);
}
- std::string testLogStrStr(11, 'a');
+ // This adds 18 (kLogPayloadSize + kStringLogOverhead + kLogDataOffset) bytes
+ // of data. After this log entry there is room enough for a log of character
+ // size 1.
+ constexpr size_t kLastLogPayloadSize = 12;
+ std::string testLogStrStr(kLastLogPayloadSize, 'a');
const char *testLogStr = testLogStrStr.c_str();
- // After this log entry there is room enough for a log of character size 1.
logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testLogStr);
- // There should be just enough space for this log
+ // There should be just enough space for this log.
ASSERT_FALSE(logBuffer.logWouldCauseOverflow(1));
- // Inserting any more than a one char log should cause overflow
+ // Inserting any more than a one char log should cause overflow.
ASSERT_TRUE(logBuffer.logWouldCauseOverflow(2));
}
@@ -280,6 +398,47 @@ TEST(LogBuffer, TransferTest) {
ASSERT_EQ(bytesCopied, 0);
}
+TEST(LogBuffer, GetLogDataLengthTest) {
+ char buffer[kDefaultBufferSize];
+
+ TestLogBufferCallback callback;
+ LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
+
+ constexpr size_t kLogPayloadSize = 10;
+ constexpr size_t kBufferUseStringLog = LogBuffer::kLogDataOffset +
+ LogBuffer::kStringLogOverhead +
+ kLogPayloadSize;
+ constexpr size_t kBufferUseTokenizedLog = LogBuffer::kLogDataOffset +
+ LogBuffer::kTokenizedLogOffset +
+ kLogPayloadSize;
+ uint8_t mCurrentLogStartingIndex = 0;
+
+ std::string testLogStr(kLogPayloadSize, 'a');
+ logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testLogStr.c_str());
+ EXPECT_EQ(logBuffer.getLogDataLength(
+ mCurrentLogStartingIndex + LogBuffer::kLogDataOffset,
+ LogType::STRING),
+ LogBuffer::kStringLogOverhead + kLogPayloadSize);
+ mCurrentLogStartingIndex += kBufferUseStringLog;
+
+ std::vector<uint8_t> testLogTokenized(kLogPayloadSize, 0x77);
+ logBuffer.handleEncodedLog(LogBufferLogLevel::INFO, 0,
+ testLogTokenized.data(), testLogTokenized.size());
+ EXPECT_EQ(logBuffer.getLogDataLength(
+ mCurrentLogStartingIndex + LogBuffer::kLogDataOffset,
+ LogType::TOKENIZED),
+ LogBuffer::kTokenizedLogOffset + kLogPayloadSize);
+ mCurrentLogStartingIndex += kBufferUseTokenizedLog;
+
+ std::vector<uint8_t> testLogBtSnoop(kLogPayloadSize, 0x77);
+ logBuffer.handleBtLog(BtSnoopDirection::INCOMING_FROM_BT_CONTROLLER, 0,
+ testLogBtSnoop.data(), testLogBtSnoop.size());
+ EXPECT_EQ(logBuffer.getLogDataLength(
+ mCurrentLogStartingIndex + LogBuffer::kLogDataOffset,
+ LogType::BLUETOOTH),
+ LogBuffer::kBtSnoopLogOffset + kLogPayloadSize);
+}
+
// TODO(srok): Add multithreaded tests
} // namespace chre
diff --git a/platform/tests/trace_test.cc b/platform/tests/trace_test.cc
new file mode 100644
index 00000000..ce162a56
--- /dev/null
+++ b/platform/tests/trace_test.cc
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Ensuring this macro is not defined since we include the tracing macros and
+// tracing utilities separately and do not want to test or include the pw_trace
+// functions.
+#ifdef CHRE_TRACING_ENABLED
+#undef CHRE_TRACING_ENABLED
+#endif // CHRE_TRACING_ENABLED
+
+#include <stdlib.h>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include "chre/platform/tracing.h"
+#include "chre/target_platform/tracing_util.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace tracing_internal {
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::ElementsAreArray;
+
+TEST(Trace, PopulateBufferWithTracedPtr) {
+ const uint8_t var = 0x12;
+ const uint8_t *data = &var;
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ EXPECT_EQ(chreTraceDataSize, __SIZEOF_POINTER__);
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+// Already verified in chre/platform/tracing.h this value is either 8 or 4.
+#if __SIZEOF_POINTER__ == 8
+ EXPECT_EQ(*((uint64_t *)chreTraceDataBuffer), (uint64_t)data);
+#elif __SIZEOF_POINTER__ == 4
+ EXPECT_EQ(*((uint32_t *)chreTraceDataBuffer), (uint32_t)data);
+#else
+#error "Pointer size is of unsupported size"
+#endif
+}
+
+TEST(Trace, PopulateBufferWithTracedBool) {
+ const bool data = true;
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ EXPECT_EQ(chreTraceDataSize, sizeof(bool));
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+ EXPECT_THAT(chreTraceDataBuffer, ElementsAre(1));
+}
+
+TEST(Trace, PopulateBufferWithTracedUInt8) {
+ const uint8_t data = 0x12;
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ EXPECT_EQ(chreTraceDataSize, sizeof(uint8_t));
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+ EXPECT_THAT(chreTraceDataBuffer, ElementsAre(0x12));
+}
+
+TEST(Trace, PopulateBufferWithTracedUInt16) {
+ uint16_t data = 0x1234;
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ EXPECT_EQ(chreTraceDataSize, sizeof(uint16_t));
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+ EXPECT_THAT(chreTraceDataBuffer, ElementsAre(0x34, 0x12));
+}
+
+TEST(Trace, PopulateBufferWithTracedUInt32) {
+ const uint32_t data = 0x12345678;
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ EXPECT_EQ(chreTraceDataSize, sizeof(uint32_t));
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+ EXPECT_THAT(chreTraceDataBuffer, ElementsAre(0x78, 0x56, 0x34, 0x12));
+}
+
+TEST(Trace, PopulateBufferWithTracedUInt64) {
+ const uint64_t data = 0x1234567890123456;
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ EXPECT_EQ(chreTraceDataSize, sizeof(uint64_t));
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+ EXPECT_THAT(chreTraceDataBuffer,
+ ElementsAre(0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12));
+}
+
+TEST(Trace, PopulateBufferWithTracedInt8) {
+ const int8_t data = 0x12;
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ EXPECT_EQ(chreTraceDataSize, sizeof(int8_t));
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+ EXPECT_THAT(chreTraceDataBuffer, ElementsAre(0x12));
+}
+
+TEST(Trace, PopulateBufferWithTracedInt16) {
+ const int16_t data = 0x1234;
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ EXPECT_EQ(chreTraceDataSize, sizeof(int16_t));
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+ EXPECT_THAT(chreTraceDataBuffer, ElementsAre(0x34, 0x12));
+}
+
+TEST(Trace, PopulateBufferWithTracedInt32) {
+ const int32_t data = 0x12345678;
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ EXPECT_EQ(chreTraceDataSize, sizeof(int32_t));
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+ EXPECT_THAT(chreTraceDataBuffer, ElementsAre(0x78, 0x56, 0x34, 0x12));
+}
+
+TEST(Trace, PopulateBufferWithTracedInt64) {
+ const int64_t data = 0x1234567890123456;
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ EXPECT_EQ(chreTraceDataSize, sizeof(int64_t));
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+ EXPECT_THAT(chreTraceDataBuffer,
+ ElementsAre(0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12));
+}
+
+TEST(Trace, PopulateBufferWithTracedChar) {
+ char data = 'a';
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ EXPECT_EQ(chreTraceDataSize, sizeof(char));
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+ EXPECT_THAT(chreTraceDataBuffer, ElementsAre('a'));
+}
+
+TEST(Trace, PopulateBufferWithTracedStrDoesNotOverflow) {
+ const char data[] = "test";
+ const size_t kBufferPadding = 5;
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize + kBufferPadding];
+ memset(chreTraceDataBuffer, 0xFF, chreTraceDataSize + kBufferPadding);
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+ for (std::size_t i = 0; i < kBufferPadding; i++) {
+ EXPECT_EQ(chreTraceDataBuffer[chreTraceDataSize + i], 0xFF);
+ }
+}
+
+TEST(Trace, PopulateBufferWithTracedShortStrAndNullBytePadding) {
+ // expected variable + length
+ const char data[] = "test";
+ uint8_t dataLen = static_cast<uint8_t>(strlen(data));
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(data)>();
+
+ EXPECT_EQ(chreTraceDataSize, CHRE_TRACE_STR_BUFFER_SIZE);
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer, data);
+
+ // Fully populated buffer with data len and null-byte padding at the end.
+ uint8_t expectedBuffer[CHRE_TRACE_STR_BUFFER_SIZE] = {dataLen, 't', 'e', 's',
+ 't'};
+ for (std::size_t i = dataLen + 1; i < CHRE_TRACE_STR_BUFFER_SIZE; i++) {
+ expectedBuffer[i] = '\0';
+ }
+
+ EXPECT_THAT(chreTraceDataBuffer, ElementsAreArray(expectedBuffer));
+}
+
+TEST(Trace, PopulateBufferWithTracedMaxLenStrNoPadding) {
+ // String data buffer to hold max-len string.
+ char dataBuffer[CHRE_TRACE_MAX_STRING_SIZE + 1];
+ // Fully populated buffer with data len and no null-byte padding.
+ // In this case data len should equal CHRE_TRACE_MAX_STRING_SIZE.
+ uint8_t expectedBuffer[CHRE_TRACE_STR_BUFFER_SIZE] = {
+ CHRE_TRACE_MAX_STRING_SIZE};
+
+ // Populate the buffer with str "0123456789..." until we hit max size.
+ for (std::size_t i = 0; i < CHRE_TRACE_MAX_STRING_SIZE; i++) {
+ dataBuffer[i] = '0' + (i % 10);
+ expectedBuffer[i + 1] = '0' + (i % 10);
+ }
+ dataBuffer[CHRE_TRACE_MAX_STRING_SIZE] = '\0';
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(dataBuffer)>();
+
+ EXPECT_EQ(chreTraceDataSize, CHRE_TRACE_STR_BUFFER_SIZE);
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer,
+ dataBuffer);
+
+ EXPECT_THAT(chreTraceDataBuffer, ElementsAreArray(expectedBuffer));
+}
+
+TEST(Trace, PopulateBufferWithTracedStringTuncateToMaxLength) {
+ const size_t kBufferPadding = 5;
+ const std::size_t kOversizeStrLen =
+ CHRE_TRACE_MAX_STRING_SIZE + kBufferPadding;
+ // String data buffer to hold oversized string.
+ char dataBuffer[kOversizeStrLen + 1];
+
+ // Populate the buffer with str "0123456789..." until we hit kOversizeStrLen.
+ for (std::size_t i = 0; i < kOversizeStrLen; i++) {
+ dataBuffer[i] = '0' + (i % 10);
+ }
+ dataBuffer[kOversizeStrLen] = '\0';
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(dataBuffer)>();
+
+ EXPECT_EQ(chreTraceDataSize, CHRE_TRACE_STR_BUFFER_SIZE);
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(chreTraceDataBuffer,
+ dataBuffer);
+
+ // Fully populated buffer with data len and truncated string.
+ // In this case data len should equal CHRE_TRACE_MAX_STRING_SIZE, not
+ // kOversizeStrLen.
+ uint8_t expectedBuffer[CHRE_TRACE_STR_BUFFER_SIZE] = {
+ CHRE_TRACE_MAX_STRING_SIZE};
+
+ // Populate the buffer with str "0123456789..." until we hit
+ // CHRE_TRACE_MAX_STRING_SIZE.
+ for (std::size_t i = 0; i < CHRE_TRACE_MAX_STRING_SIZE; i++) {
+ expectedBuffer[i + 1] = '0' + (i % 10);
+ }
+
+ EXPECT_THAT(chreTraceDataBuffer, ElementsAreArray(expectedBuffer));
+}
+
+TEST(Trace, PopulateBufferWithMultipleTracedData) {
+ uint8_t dataUint8 = 0x12;
+ char dataChar = 'a';
+ uint32_t dataUint32 = 0x12345678;
+ char dataStr[CHRE_TRACE_MAX_STRING_SIZE];
+ strncpy(dataStr, "test", CHRE_TRACE_MAX_STRING_SIZE);
+ uint8_t dataStrLen = static_cast<uint8_t>(strlen(dataStr));
+ std::size_t totalDataSize = sizeof(uint8_t) + sizeof(char) +
+ sizeof(uint32_t) + CHRE_TRACE_STR_BUFFER_SIZE;
+
+ constexpr std::size_t chreTraceDataSize =
+ tracing_internal::chreTraceGetSizeOfVarArgs<TYPE_LIST(
+ dataUint8, dataChar, dataUint32, dataStr)>();
+
+ EXPECT_EQ(chreTraceDataSize, totalDataSize);
+
+ uint8_t expectedBuffer[chreTraceDataSize] = {0x12, 'a', 0x78, 0x56,
+ 0x34, 0x12, dataStrLen};
+ strncpy((char *)(&expectedBuffer[7]), dataStr, CHRE_TRACE_MAX_STRING_SIZE);
+
+ uint8_t chreTraceDataBuffer[chreTraceDataSize];
+ tracing_internal::chreTracePopulateBufferWithArgs(
+ chreTraceDataBuffer, dataUint8, dataChar, dataUint32, dataStr);
+
+ EXPECT_THAT(chreTraceDataBuffer, ElementsAreArray(expectedBuffer));
+}
+
+// TODO(b/302232350): Add a death test for unsupported data types. Currently
+// testing unsupported types (structs) with manual testing.
+
+} // namespace
+} // namespace tracing_internal \ No newline at end of file
diff --git a/platform/tinysys/authentication.cc b/platform/tinysys/authentication.cc
index e33555e4..259ba678 100644
--- a/platform/tinysys/authentication.cc
+++ b/platform/tinysys/authentication.cc
@@ -24,9 +24,14 @@
#include "mbedtls/pk.h"
#include "mbedtls/sha256.h"
+#include "cpufreq_vote.h"
+
namespace chre {
namespace {
+// A data structure needed for SCP chip frequency change
+DECLARE_OPPDEV(gChreScpFreqVote);
+
// All the size below are in bytes
constexpr uint32_t kEcdsaP256SigSize = 64;
constexpr uint32_t kEcdsaP256PublicKeySize = 64;
@@ -101,6 +106,7 @@ struct ImageHeader {
class Authenticator {
public:
Authenticator() {
+ scp_vote_opp(&gChreScpFreqVote, CLK_OPP2);
mbedtls_ecp_group_init(&mGroup);
mbedtls_ecp_point_init(&mQ);
mbedtls_mpi_init(&mR);
@@ -112,6 +118,7 @@ class Authenticator {
mbedtls_mpi_free(&mR);
mbedtls_ecp_point_free(&mQ);
mbedtls_ecp_group_free(&mGroup);
+ scp_unvote_opp(&gChreScpFreqVote, CLK_OPP2);
}
bool loadEcpGroup() {
diff --git a/platform/tinysys/condition_variable_base.cc b/platform/tinysys/condition_variable_base.cc
index 715b46ba..77b993de 100644
--- a/platform/tinysys/condition_variable_base.cc
+++ b/platform/tinysys/condition_variable_base.cc
@@ -32,8 +32,7 @@ void ConditionVariableBase::conditionVariablTimerCallback(
}
ConditionVariable::ConditionVariable() {
- // TODO(b/256870101): Use xSemaphoreCreateBinaryStatic when possible
- semaphoreHandle = xSemaphoreCreateBinary();
+ semaphoreHandle = xSemaphoreCreateBinaryStatic(&mSemaphoreBuffer);
if (semaphoreHandle == nullptr) {
FATAL_ERROR("Failed to create cv semaphore");
}
@@ -79,4 +78,4 @@ bool ConditionVariable::wait_for(Mutex &mutex, Nanoseconds timeout) {
taskEXIT_CRITICAL();
return isTimedOut;
}
-} // namespace chre \ No newline at end of file
+} // namespace chre
diff --git a/platform/tinysys/host_link.cc b/platform/tinysys/host_link.cc
index 3df05170..5ef720a0 100644
--- a/platform/tinysys/host_link.cc
+++ b/platform/tinysys/host_link.cc
@@ -15,6 +15,7 @@
*/
#include "FreeRTOS.h"
+#include "encoding.h"
#include "task.h"
#include "chre/core/event_loop_manager.h"
@@ -83,10 +84,11 @@ size_t gChreSubregionRecvSize;
void *gChreSubregionSendAddr;
size_t gChreSubregionSendSize;
-// TODO(b/263958729): move it to HostLinkBase, and revisit buffer size
+// TODO(b/277235389): move it to HostLinkBase, and revisit buffer size
// payload buffers
#define CHRE_IPI_RECV_BUFFER_SIZE (CHRE_MESSAGE_TO_HOST_MAX_SIZE + 128)
-uint32_t gChreRecvBuffer[CHRE_IPI_RECV_BUFFER_SIZE / sizeof(uint32_t)]
+DRAM_REGION_VARIABLE uint32_t
+ gChreRecvBuffer[CHRE_IPI_RECV_BUFFER_SIZE / sizeof(uint32_t)]
__attribute__((aligned(CACHE_LINE_SIZE)));
#ifdef SCP_CHRE_USE_DMA
@@ -123,6 +125,8 @@ enum class PendingMessageType {
SelfTestResponse,
MetricLog,
NanConfigurationRequest,
+ PulseRequest,
+ PulseResponse,
};
struct PendingMessage {
@@ -151,7 +155,8 @@ struct PendingMessage {
};
constexpr size_t kOutboundQueueSize = 100;
-FixedSizeBlockingQueue<PendingMessage, kOutboundQueueSize> gOutboundQueue;
+DRAM_REGION_VARIABLE FixedSizeBlockingQueue<PendingMessage, kOutboundQueueSize>
+ gOutboundQueue;
typedef void(MessageBuilderFunction)(ChreFlatBufferBuilder &builder,
void *cookie);
@@ -160,7 +165,8 @@ inline HostCommsManager &getHostCommsManager() {
return EventLoopManagerSingleton::get()->getHostCommsManager();
}
-bool generateMessageFromBuilder(ChreFlatBufferBuilder *builder) {
+DRAM_REGION_FUNCTION bool generateMessageFromBuilder(
+ ChreFlatBufferBuilder *builder) {
CHRE_ASSERT(builder != nullptr);
LOGV("%s: message size %d", __func__, builder->GetSize());
bool result =
@@ -172,9 +178,9 @@ bool generateMessageFromBuilder(ChreFlatBufferBuilder *builder) {
return result;
}
-bool generateMessageToHost(const HostMessage *message) {
+DRAM_REGION_FUNCTION bool generateMessageToHost(const HostMessage *message) {
LOGV("%s: message size %zu", __func__, message->message.size());
- // TODO(b/263958729): ideally we'd construct our flatbuffer directly in the
+ // TODO(b/285219398): ideally we'd construct our flatbuffer directly in the
// host-supplied buffer
constexpr size_t kFixedReserveSize = 80;
ChreFlatBufferBuilder builder(message->message.size() + kFixedReserveSize);
@@ -191,7 +197,7 @@ bool generateMessageToHost(const HostMessage *message) {
return result;
}
-int generateHubInfoResponse(uint16_t hostClientId) {
+DRAM_REGION_FUNCTION int generateHubInfoResponse(uint16_t hostClientId) {
constexpr size_t kInitialBufferSize = 192;
constexpr char kHubName[] = "CHRE on Tinysys";
@@ -219,7 +225,7 @@ int generateHubInfoResponse(uint16_t hostClientId) {
return HostLinkBase::send(builder.GetBufferPointer(), builder.GetSize());
}
-bool dequeueMessage(PendingMessage pendingMsg) {
+DRAM_REGION_FUNCTION bool dequeueMessage(PendingMessage pendingMsg) {
LOGV("%s: message type %d", __func__, pendingMsg.type);
bool result = false;
switch (pendingMsg.type) {
@@ -243,6 +249,7 @@ bool dequeueMessage(PendingMessage pendingMsg) {
case PendingMessageType::SelfTestResponse:
case PendingMessageType::MetricLog:
case PendingMessageType::NanConfigurationRequest:
+ case PendingMessageType::PulseResponse:
result = generateMessageFromBuilder(pendingMsg.data.builder);
break;
@@ -260,7 +267,7 @@ bool dequeueMessage(PendingMessage pendingMsg) {
*
* @return true if the message was successfully added to the queue.
*/
-bool enqueueMessage(PendingMessage pendingMsg) {
+DRAM_REGION_FUNCTION bool enqueueMessage(PendingMessage pendingMsg) {
return gOutboundQueue.push(pendingMsg);
}
@@ -278,9 +285,9 @@ bool enqueueMessage(PendingMessage pendingMsg) {
*
* @return true if the message was successfully added to the queue
*/
-bool buildAndEnqueueMessage(PendingMessageType msgType,
- size_t initialBufferSize,
- MessageBuilderFunction *msgBuilder, void *cookie) {
+DRAM_REGION_FUNCTION bool buildAndEnqueueMessage(
+ PendingMessageType msgType, size_t initialBufferSize,
+ MessageBuilderFunction *msgBuilder, void *cookie) {
LOGV("%s: message type %d, size %zu", __func__, msgType, initialBufferSize);
bool pushed = false;
@@ -291,8 +298,6 @@ bool buildAndEnqueueMessage(PendingMessageType msgType,
} else {
msgBuilder(*builder, cookie);
- // TODO(b/263958729): if this fails, ideally we should block for some
- // timeout until there's space in the queue
if (!enqueueMessage(PendingMessage(msgType, builder.get()))) {
LOGE("Couldn't push message type %d to outbound queue",
static_cast<int>(msgType));
@@ -308,7 +313,16 @@ bool buildAndEnqueueMessage(PendingMessageType msgType,
/**
* FlatBuffer message builder callback used with handleNanoappListRequest()
*/
-void buildNanoappListResponse(ChreFlatBufferBuilder &builder, void *cookie) {
+DRAM_REGION_FUNCTION void buildPulseResponse(ChreFlatBufferBuilder &builder,
+ void * /*cookie*/) {
+ HostProtocolChre::encodePulseResponse(builder);
+}
+
+/**
+ * FlatBuffer message builder callback used with handleNanoappListRequest()
+ */
+DRAM_REGION_FUNCTION void buildNanoappListResponse(
+ ChreFlatBufferBuilder &builder, void *cookie) {
LOGV("%s", __func__);
auto nanoappAdderCallback = [](const Nanoapp *nanoapp, void *data) {
auto *cbData = static_cast<NanoappListData *>(data);
@@ -327,8 +341,9 @@ void buildNanoappListResponse(ChreFlatBufferBuilder &builder, void *cookie) {
cbData->hostClientId);
}
-void handleUnloadNanoappCallback(uint16_t /*type*/, void *data,
- void * /*extraData*/) {
+DRAM_REGION_FUNCTION void handleUnloadNanoappCallback(uint16_t /*type*/,
+ void *data,
+ void * /*extraData*/) {
auto *cbData = static_cast<UnloadNanoappCallbackData *>(data);
bool success = false;
uint16_t instanceId;
@@ -356,25 +371,79 @@ void handleUnloadNanoappCallback(uint16_t /*type*/, void *data,
memoryFree(data);
}
+DRAM_REGION_FUNCTION void sendDebugDumpData(uint16_t hostClientId,
+ const char *debugStr,
+ size_t debugStrSize) {
+ struct DebugDumpMessageData {
+ uint16_t hostClientId;
+ const char *debugStr;
+ size_t debugStrSize;
+ };
+
+ auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
+ const auto *data = static_cast<const DebugDumpMessageData *>(cookie);
+ HostProtocolChre::encodeDebugDumpData(builder, data->hostClientId,
+ data->debugStr, data->debugStrSize);
+ };
+
+ constexpr size_t kFixedSizePortion = 52;
+ DebugDumpMessageData data;
+ data.hostClientId = hostClientId;
+ data.debugStr = debugStr;
+ data.debugStrSize = debugStrSize;
+ buildAndEnqueueMessage(PendingMessageType::DebugDumpData,
+ kFixedSizePortion + debugStrSize, msgBuilder, &data);
+}
+
+DRAM_REGION_FUNCTION void sendDebugDumpResponse(uint16_t hostClientId,
+ bool success,
+ uint32_t dataCount) {
+ struct DebugDumpResponseData {
+ uint16_t hostClientId;
+ bool success;
+ uint32_t dataCount;
+ };
+
+ auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
+ const auto *data = static_cast<const DebugDumpResponseData *>(cookie);
+ HostProtocolChre::encodeDebugDumpResponse(builder, data->hostClientId,
+ data->success, data->dataCount);
+ };
+
+ constexpr size_t kInitialSize = 52;
+ DebugDumpResponseData data;
+ data.hostClientId = hostClientId;
+ data.success = success;
+ data.dataCount = dataCount;
+ buildAndEnqueueMessage(PendingMessageType::DebugDumpResponse, kInitialSize,
+ msgBuilder, &data);
+}
} // anonymous namespace
-void sendDebugDumpResultToHost(uint16_t hostClientId, const char * /*debugStr*/,
- size_t /*debugStrSize*/, bool /*complete*/,
- uint32_t /*dataCount*/) {
+DRAM_REGION_FUNCTION void sendDebugDumpResultToHost(uint16_t hostClientId,
+ const char *debugStr,
+ size_t debugStrSize,
+ bool complete,
+ uint32_t dataCount) {
LOGV("%s: host client id %d", __func__, hostClientId);
- // TODO(b/263958729): Implement this.
+ if (debugStrSize > 0) {
+ sendDebugDumpData(hostClientId, debugStr, debugStrSize);
+ }
+ if (complete) {
+ sendDebugDumpResponse(hostClientId, /* success= */ true, dataCount);
+ }
}
-HostLinkBase::HostLinkBase() {
+DRAM_REGION_FUNCTION HostLinkBase::HostLinkBase() {
LOGV("HostLinkBase::%s", __func__);
initializeIpi();
}
-HostLinkBase::~HostLinkBase() {
+DRAM_REGION_FUNCTION HostLinkBase::~HostLinkBase() {
LOGV("HostLinkBase::%s", __func__);
}
-void HostLinkBase::vChreReceiveTask(void *pvParameters) {
+DRAM_REGION_FUNCTION void HostLinkBase::vChreReceiveTask(void *pvParameters) {
int i = 0;
int ret = 0;
@@ -389,15 +458,16 @@ void HostLinkBase::vChreReceiveTask(void *pvParameters) {
}
}
-void HostLinkBase::vChreSendTask(void *pvParameters) {
+DRAM_REGION_FUNCTION void HostLinkBase::vChreSendTask(void *pvParameters) {
while (true) {
auto msg = gOutboundQueue.pop();
dequeueMessage(msg);
}
}
-void HostLinkBase::chreIpiHandler(unsigned int id, void *prdata, void *data,
- unsigned int len) {
+DRAM_REGION_FUNCTION void HostLinkBase::chreIpiHandler(unsigned int id,
+ void *prdata, void *data,
+ unsigned int len) {
/* receive magic and cmd */
struct ScpChreIpiMsg msg = *(struct ScpChreIpiMsg *)data;
@@ -441,7 +511,7 @@ void HostLinkBase::chreIpiHandler(unsigned int id, void *prdata, void *data,
gChreIpiAckToHost[1] = msg.size;
}
-void HostLinkBase::initializeIpi(void) {
+DRAM_REGION_FUNCTION void HostLinkBase::initializeIpi(void) {
LOGV("%s", __func__);
bool success = false;
int ret;
@@ -482,11 +552,11 @@ void HostLinkBase::initializeIpi(void) {
}
}
-void HostLinkBase::receive(HostLinkBase *instance, void *message,
- int messageLen) {
+DRAM_REGION_FUNCTION void HostLinkBase::receive(HostLinkBase *instance,
+ void *message, int messageLen) {
LOGV("%s: message len %d", __func__, messageLen);
- // TODO(b/263958729): A crude way to initially determine daemon's up - set
+ // TODO(b/277128368): A crude way to initially determine daemon's up - set
// a flag on the first message received. This is temporary until a better
// way to do this is available.
instance->setInitialized(true);
@@ -496,7 +566,7 @@ void HostLinkBase::receive(HostLinkBase *instance, void *message,
}
}
-bool HostLinkBase::send(uint8_t *data, size_t dataLen) {
+DRAM_REGION_FUNCTION bool HostLinkBase::send(uint8_t *data, size_t dataLen) {
#ifndef HOST_LINK_IPI_SEND_TIMEOUT_MS
#define HOST_LINK_IPI_SEND_TIMEOUT_MS 100
#endif
@@ -513,7 +583,7 @@ bool HostLinkBase::send(uint8_t *data, size_t dataLen) {
ap_to_scp(reinterpret_cast<uint32_t>(gChreSubregionSendAddr)));
#ifdef SCP_CHRE_USE_DMA
- // TODO(b/263958729): use DMA for larger payload
+ // TODO(b/288415339): use DMA for larger payload
// No need cache operation, because src_dst handled by SCP CPU and dstAddr is
// non-cacheable
#else
@@ -548,14 +618,10 @@ bool HostLinkBase::send(uint8_t *data, size_t dataLen) {
return ret == IPI_ACTION_DONE;
}
-void HostLinkBase::sendTimeSyncRequest() {
- LOGV("%s", __func__);
- // TODO(b/263958729): Implement this.
-}
+DRAM_REGION_FUNCTION void HostLinkBase::sendTimeSyncRequest() {}
-void HostLinkBase::sendLogMessageV2(const uint8_t *logMessage,
- size_t logMessageSize,
- uint32_t numLogsDropped) {
+DRAM_REGION_FUNCTION void HostLinkBase::sendLogMessageV2(
+ const uint8_t *logMessage, size_t logMessageSize, uint32_t numLogsDropped) {
LOGV("%s: size %zu", __func__, logMessageSize);
struct LogMessageData {
const uint8_t *logMsg;
@@ -589,7 +655,7 @@ void HostLinkBase::sendLogMessageV2(const uint8_t *logMessage,
#endif
}
-bool HostLink::sendMessage(HostMessage const *message) {
+DRAM_REGION_FUNCTION bool HostLink::sendMessage(HostMessage const *message) {
LOGV("HostLink::%s size(%zu)", __func__, message->message.size());
bool success = false;
@@ -602,32 +668,31 @@ bool HostLink::sendMessage(HostMessage const *message) {
return success;
}
-// TODO(b/263958729): HostMessageHandlers member function implementations are
+// TODO(b/285219398): HostMessageHandlers member function implementations are
// expected to be (mostly) identical for any platform that uses flatbuffers
// to encode messages - refactor the host link to merge the multiple copies
// we currently have.
-void HostMessageHandlers::handleNanoappMessage(uint64_t appId,
- uint32_t messageType,
- uint16_t hostEndpoint,
- const void *messageData,
- size_t messageDataLen) {
+DRAM_REGION_FUNCTION void HostMessageHandlers::handleNanoappMessage(
+ uint64_t appId, uint32_t messageType, uint16_t hostEndpoint,
+ const void *messageData, size_t messageDataLen) {
LOGV("Parsed nanoapp message from host: app ID 0x%016" PRIx64
", endpoint "
"0x%" PRIx16 ", msgType %" PRIu32 ", payload size %zu",
appId, hostEndpoint, messageType, messageDataLen);
- // TODO(b/263958729): Implement this.
getHostCommsManager().sendMessageToNanoappFromHost(
appId, messageType, hostEndpoint, messageData, messageDataLen);
}
-void HostMessageHandlers::handleHubInfoRequest(uint16_t hostClientId) {
+DRAM_REGION_FUNCTION void HostMessageHandlers::handleHubInfoRequest(
+ uint16_t hostClientId) {
LOGV("%s: host client id %d", __func__, hostClientId);
enqueueMessage(
PendingMessage(PendingMessageType::HubInfoResponse, hostClientId));
}
-void HostMessageHandlers::handleNanoappListRequest(uint16_t hostClientId) {
+DRAM_REGION_FUNCTION void HostMessageHandlers::handleNanoappListRequest(
+ uint16_t hostClientId) {
auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
uint16_t cbHostClientId = NestedDataPtr<uint16_t>(data);
@@ -656,10 +721,9 @@ void HostMessageHandlers::handleNanoappListRequest(uint16_t hostClientId) {
NestedDataPtr<uint16_t>(hostClientId), callback);
}
-void HostMessageHandlers::sendFragmentResponse(uint16_t hostClientId,
- uint32_t transactionId,
- uint32_t fragmentId,
- bool success) {
+DRAM_REGION_FUNCTION void HostMessageHandlers::sendFragmentResponse(
+ uint16_t hostClientId, uint32_t transactionId, uint32_t fragmentId,
+ bool success) {
struct FragmentedLoadInfoResponse {
uint16_t hostClientId;
uint32_t transactionId;
@@ -685,7 +749,17 @@ void HostMessageHandlers::sendFragmentResponse(uint16_t hostClientId,
kInitialBufferSize, msgBuilder, &response);
}
-void HostMessageHandlers::handleLoadNanoappRequest(
+DRAM_REGION_FUNCTION void HostMessageHandlers::handlePulseRequest() {
+ auto callback = [](uint16_t /*type*/, void * /*data*/, void * /*extraData*/) {
+ buildAndEnqueueMessage(PendingMessageType::PulseResponse,
+ /*initialBufferSize= */ 48, buildPulseResponse,
+ /* cookie= */ nullptr);
+ };
+ EventLoopManagerSingleton::get()->deferCallback(
+ SystemCallbackType::PulseResponse, /* data= */ nullptr, callback);
+}
+
+DRAM_REGION_FUNCTION void HostMessageHandlers::handleLoadNanoappRequest(
uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
uint32_t appVersion, uint32_t appFlags, uint32_t targetApiVersion,
const void *buffer, size_t bufferLen, const char *appFileName,
@@ -697,7 +771,7 @@ void HostMessageHandlers::handleLoadNanoappRequest(
respondBeforeStart);
}
-void HostMessageHandlers::handleUnloadNanoappRequest(
+DRAM_REGION_FUNCTION void HostMessageHandlers::handleUnloadNanoappRequest(
uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
bool allowSystemNanoappUnload) {
LOGD("Unload nanoapp request from client %" PRIu16 " (txnID %" PRIu32
@@ -718,22 +792,31 @@ void HostMessageHandlers::handleUnloadNanoappRequest(
}
}
-void HostLink::flushMessagesSentByNanoapp(uint64_t /* appId */) {
+DRAM_REGION_FUNCTION void HostLink::flushMessagesSentByNanoapp(
+ uint64_t /* appId */) {
// Not implemented
}
-void HostMessageHandlers::handleTimeSyncMessage(int64_t offset) {
+DRAM_REGION_FUNCTION void HostMessageHandlers::handleTimeSyncMessage(
+ int64_t offset) {
LOGE("%s unsupported.", __func__);
}
-void HostMessageHandlers::handleDebugDumpRequest(uint16_t hostClientId) {
+DRAM_REGION_FUNCTION void HostMessageHandlers::handleDebugDumpRequest(
+ uint16_t hostClientId) {
LOGV("%s: host client id %d", __func__, hostClientId);
- // TODO(b/263958729): Implement this.
+ if (!EventLoopManagerSingleton::get()
+ ->getDebugDumpManager()
+ .onDebugDumpRequested(hostClientId)) {
+ LOGE("Couldn't trigger debug dump process");
+ sendDebugDumpResponse(hostClientId, /* success= */ false,
+ /* dataCount= */ 0);
+ }
}
-void HostMessageHandlers::handleSettingChangeMessage(fbs::Setting setting,
- fbs::SettingState state) {
- // TODO(b/267207477): Refactor handleSettingChangeMessage to shared code
+DRAM_REGION_FUNCTION void HostMessageHandlers::handleSettingChangeMessage(
+ fbs::Setting setting, fbs::SettingState state) {
+ // TODO(b/285219398): Refactor handleSettingChangeMessage to shared code
Setting chreSetting;
bool chreSettingEnabled;
if (HostProtocolChre::getSettingFromFbs(setting, &chreSetting) &&
@@ -743,16 +826,17 @@ void HostMessageHandlers::handleSettingChangeMessage(fbs::Setting setting,
}
}
-void HostMessageHandlers::handleSelfTestRequest(uint16_t hostClientId) {
+DRAM_REGION_FUNCTION void HostMessageHandlers::handleSelfTestRequest(
+ uint16_t hostClientId) {
LOGV("%s: host client id %d", __func__, hostClientId);
- // TODO(b/263958729): Implement this.
}
-void HostMessageHandlers::handleNanConfigurationUpdate(bool /* enabled */) {
+DRAM_REGION_FUNCTION void HostMessageHandlers::handleNanConfigurationUpdate(
+ bool /* enabled */) {
LOGE("%s NAN unsupported.", __func__);
}
-void sendAudioRequest() {
+DRAM_REGION_FUNCTION void sendAudioRequest() {
auto msgBuilder = [](ChreFlatBufferBuilder &builder, void * /*cookie*/) {
HostProtocolChre::encodeLowPowerMicAccessRequest(builder);
};
@@ -761,7 +845,7 @@ void sendAudioRequest() {
kInitialSize, msgBuilder, /* cookie= */ nullptr);
}
-void sendAudioRelease() {
+DRAM_REGION_FUNCTION void sendAudioRelease() {
auto msgBuilder = [](ChreFlatBufferBuilder &builder, void * /*cookie*/) {
HostProtocolChre::encodeLowPowerMicAccessRelease(builder);
};
diff --git a/platform/tinysys/include/chre/target_platform/condition_variable_base.h b/platform/tinysys/include/chre/target_platform/condition_variable_base.h
index ba030217..46f2f939 100644
--- a/platform/tinysys/include/chre/target_platform/condition_variable_base.h
+++ b/platform/tinysys/include/chre/target_platform/condition_variable_base.h
@@ -47,6 +47,9 @@ class ConditionVariableBase {
/** semaphore implementing the condition variable */
SemaphoreHandle_t semaphoreHandle;
+ /** Buffer used to store state used by the semaphore */
+ StaticSemaphore_t mSemaphoreBuffer;
+
/** True if wait_for() times out before semaphoreHandle is given */
bool isTimedOut = false;
diff --git a/run_pal_impl_tests.sh b/run_pal_impl_tests.sh
index 4b0daedb..9e7426ef 100755
--- a/run_pal_impl_tests.sh
+++ b/run_pal_impl_tests.sh
@@ -3,6 +3,15 @@
# Quit if any command produces an error.
set -e
+BUILD_ONLY="false"
+while getopts "b" opt; do
+ case ${opt} in
+ b)
+ BUILD_ONLY="true"
+ ;;
+ esac
+done
+
# Build and run the CHRE unit test binary.
JOB_COUNT=$((`grep -c ^processor /proc/cpuinfo`))
@@ -14,4 +23,13 @@ export RUN_PAL_IMPL_TESTS=true
make clean
make google_x86_googletest_debug -j$JOB_COUNT
-./out/google_x86_googletest_debug/libchre $1
+
+if [ "$BUILD_ONLY" = "false" ]; then
+./out/google_x86_googletest_debug/libchre ${@:1}
+else
+ if [ ! -f ./out/google_x86_googletest_debug/libchre ]; then
+ echo "./out/google_x86_googletest_debug/libchre does not exist."
+ echo "run_pal_impl_test.sh failed to build the binary."
+ exit 1
+ fi
+fi \ No newline at end of file
diff --git a/run_sim.sh b/run_sim.sh
index 680dadd3..6b8ad8d1 100755
--- a/run_sim.sh
+++ b/run_sim.sh
@@ -30,4 +30,9 @@ make clean && make google_x86_linux_debug -j$JOB_COUNT
if [ "$BUILD_ONLY" = "false" ]; then
./out/google_x86_linux_debug/libchre ${@:1}
+else
+ if [ ! -f ./out/google_x86_linux_debug/libchre ]; then
+ echo "./out/google_x86_linux_debug/libchre does not exist."
+ exit 1
+ fi
fi
diff --git a/run_tests.sh b/run_tests.sh
index b73c2534..ddb2271e 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -3,6 +3,15 @@
# Quit if any command produces an error.
set -e
+BUILD_ONLY="false"
+while getopts "b" opt; do
+ case ${opt} in
+ b)
+ BUILD_ONLY="true"
+ ;;
+ esac
+done
+
# Build and run the CHRE unit test binary.
JOB_COUNT=$((`grep -c ^processor /proc/cpuinfo`))
@@ -12,4 +21,12 @@ export CHRE_VARIANT_MK_INCLUDES="$CHRE_VARIANT_MK_INCLUDES \
make clean
make google_x86_googletest_debug -j$JOB_COUNT
-./out/google_x86_googletest_debug/libchre "$@"
+
+if [ "$BUILD_ONLY" = "false" ]; then
+./out/google_x86_googletest_debug/libchre ${@:1}
+else
+ if [ ! -f ./out/google_x86_googletest_debug/libchre ]; then
+ echo "./out/google_x86_googletest_debug/libchre does not exist."
+ exit 1
+ fi
+fi \ No newline at end of file
diff --git a/test/simulation/README.md b/test/simulation/README.md
index db380ea7..86938ad3 100644
--- a/test/simulation/README.md
+++ b/test/simulation/README.md
@@ -31,9 +31,8 @@ TEST_F(TestBase, <PrefixedTestName>) {
CREATE_CHRE_TEST_EVENT(MY_TEST_EVENT, 0);
// 2. Create a test Nanpoapp by inheriting TestNanoapp.
- struct App : public TestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public TestNanoapp {
+ void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override {
switch (eventType) {
// 3. Handle system events.
case CHRE_EVENT_WIFI_ASYNC_RESULT: {
@@ -54,36 +53,45 @@ TEST_F(TestBase, <PrefixedTestName>) {
}
}
}
- };
+ }
};
// 6. Load the app and add initial expectations.
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());;
EXPECT_TRUE(...);
// 7. Send test events to the Nanoapp to execute some actions and add
// expectations about the result.
- sendEventToNanoapp(app, MY_TEST_EVENT);
+ sendEventToNanoapp(appId, MY_TEST_EVENT);
waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT);
EXPECT_TRUE(...);
// 8. Optionally unload the Nanoapp
- unloadNanoapp(app);
+ unloadNanoapp(appId);
}
```
##### Test app (#2, #6, #8)
-Inherit from `TestNanoapp` to create a test nanoapp. The following
-properties oif a nanoapp can be overridden `name`, `id`, `version`, `perms`,
-`start`, `handleEvent`, and `end`.
+Inherit from `TestNanoapp` to create a test nanoapp.
+
+If you need to customize any of the nanoapp `name`, `id`, `version`, or `perms`,
+you will need to add a constructor calling the `TestNanoapp` constructor with that info, i.e.:
+
+```
+class App: public TestNanoapp {
+ public:
+ explicit App(TestNanoappInfo info): TestNanoapp(info) {}
+
+ // ...
+};
+```
-Typical tests only override of few of the above properties:
+The nanoapp entry points are implemented as methods of the class:
-* `perms` to set the permissions required for the test,
-* `start` to put the system in a known state before each test,
-* `handleEvent` is probably the most important function where system and test
- events are handled. See the sections below for more details.
+- `start`,
+- `handleEvent`,
+- `end`.
##### Test events (#1)
@@ -97,15 +105,14 @@ Add code to `handleEvent` to handle the system events you are interested in for
the test:
```cpp
-decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_WIFI_ASYNC_RESULT: {
// ...
break;
}
}
-};
+}
```
The handler would typically send an event back to the nanoapp, see the next
@@ -137,20 +144,18 @@ Waiting for an event as described above is sufficient to express a boolean
expectation. For example the status of an event:
```cpp
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
- switch (eventType) {
- case CHRE_EVENT_WIFI_ASYNC_RESULT: {
- auto *event = static_cast<const chreAsyncResult *>(eventData);
- if (event->success) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_ASYNC_RESULT);
- }
- break;
+void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (event->success) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_ASYNC_RESULT);
}
+ break;
}
- };
-};
+ }
+}
```
With the above snippet `waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT)` will timeout
@@ -160,20 +165,19 @@ Sometimes you want to attach additional data alongside the event. Simply pass
the data as the second argument to pushEvent:
```cpp
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
- switch (eventType) {
- case CHRE_EVENT_WIFI_ASYNC_RESULT: {
- auto *event = static_cast<const chreAsyncResult *>(eventData);
- if (event->success) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_ASYNC_RESULT,
- *(static_cast<const uint32_t *>(event->cookie)));
- }
- break;
+ void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (event->success) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_ASYNC_RESULT,
+ *(static_cast<const uint32_t *>(event->cookie)));
}
+ break;
}
- };
+ }
+ }
```
The data must be trivially copyable (a scalar or a struct of scalar are safe).
@@ -197,15 +201,14 @@ CREATE_CHRE_TEST_EVENT(MY_TEST_EVENT, 0);
// ...
-sendEventToNanoapp(app, MY_TEST_EVENT);
+sendEventToNanoapp(appId, MY_TEST_EVENT);
```
The code to be executed in the context of the nanoapp should be added to its
`handleEvent` function:
```cpp
-decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override {
switch (eventType) {
// Test event are received with a CHRE_EVENT_TEST_EVENT type.
case CHRE_EVENT_TEST_EVENT: {
@@ -218,14 +221,14 @@ decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
}
}
}
-};
+}
```
It is possible to send data alongside a test event:
```cpp
bool enable = true;
-sendEventToNanoapp(app, MY_TEST_EVENT, &enable);
+sendEventToNanoapp(appId, MY_TEST_EVENT, &enable);
```
The data should be a scalar type or a struct of scalars. Be careful not to send
@@ -236,8 +239,7 @@ The `handleEvent` function receives a copy of the data in the `data` field of
the `TestEvent`:
```cpp
-decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override {
switch (eventType) {
// Test event are received with a CHRE_EVENT_TEST_EVENT type.
case CHRE_EVENT_TEST_EVENT: {
@@ -250,5 +252,5 @@ decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
}
}
}
-};
+}
```
diff --git a/test/simulation/audio_test.cc b/test/simulation/audio_test.cc
index df03aaa9..85ddc6d3 100644
--- a/test/simulation/audio_test.cc
+++ b/test/simulation/audio_test.cc
@@ -36,31 +36,33 @@
namespace chre {
namespace {
-struct AudioNanoapp : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_AUDIO;
+class AudioNanoapp : public TestNanoapp {
+ public:
+ AudioNanoapp()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_AUDIO}) {}
- decltype(nanoappStart) *start = []() {
+ bool start() override {
chreUserSettingConfigureEvents(CHRE_USER_SETTING_MICROPHONE,
true /* enable */);
return true;
- };
+ }
};
TEST_F(TestBase, AudioCanSubscribeAndUnsubscribeToDataEvents) {
CREATE_CHRE_TEST_EVENT(CONFIGURE, 0);
- struct App : public AudioNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
- static int count = 0;
-
+ class App : public AudioNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_AUDIO_DATA: {
auto event =
static_cast<const struct chreAudioDataEvent *>(eventData);
if (event->handle == 0) {
- count++;
- if (count == 3) {
+ mCount++;
+ if (mCount == 3) {
TestEventQueueSingleton::get()->pushEvent(CHRE_EVENT_AUDIO_DATA);
}
}
@@ -91,15 +93,18 @@ TEST_F(TestBase, AudioCanSubscribeAndUnsubscribeToDataEvents) {
}
}
}
- };
+ }
+
+ protected:
+ int mCount = 0;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
EXPECT_FALSE(chrePalAudioIsHandle0Enabled());
bool enable = true;
bool success;
- sendEventToNanoapp(app, CONFIGURE, enable);
+ sendEventToNanoapp(appId, CONFIGURE, enable);
waitForEvent(CONFIGURE, &success);
EXPECT_TRUE(success);
waitForEvent(CHRE_EVENT_AUDIO_SAMPLING_CHANGE);
@@ -108,7 +113,7 @@ TEST_F(TestBase, AudioCanSubscribeAndUnsubscribeToDataEvents) {
waitForEvent(CHRE_EVENT_AUDIO_DATA);
enable = false;
- sendEventToNanoapp(app, CONFIGURE, enable);
+ sendEventToNanoapp(appId, CONFIGURE, enable);
waitForEvent(CONFIGURE, &success);
EXPECT_TRUE(success);
EXPECT_FALSE(chrePalAudioIsHandle0Enabled());
@@ -117,9 +122,9 @@ TEST_F(TestBase, AudioCanSubscribeAndUnsubscribeToDataEvents) {
TEST_F(TestBase, AudioUnsubscribeToDataEventsOnUnload) {
CREATE_CHRE_TEST_EVENT(CONFIGURE, 0);
- struct App : public AudioNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public AudioNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType, const void *eventData) {
switch (eventType) {
case CHRE_EVENT_AUDIO_SAMPLING_CHANGE: {
auto event =
@@ -145,21 +150,21 @@ TEST_F(TestBase, AudioUnsubscribeToDataEventsOnUnload) {
}
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
EXPECT_FALSE(chrePalAudioIsHandle0Enabled());
bool enable = true;
bool success;
- sendEventToNanoapp(app, CONFIGURE, enable);
+ sendEventToNanoapp(appId, CONFIGURE, enable);
waitForEvent(CONFIGURE, &success);
EXPECT_TRUE(success);
waitForEvent(CHRE_EVENT_AUDIO_SAMPLING_CHANGE);
EXPECT_TRUE(chrePalAudioIsHandle0Enabled());
- unloadNanoapp(app);
+ unloadNanoapp(appId);
EXPECT_FALSE(chrePalAudioIsHandle0Enabled());
}
diff --git a/test/simulation/ble_test.cc b/test/simulation/ble_test.cc
index 24fe044e..a0714202 100644
--- a/test/simulation/ble_test.cc
+++ b/test/simulation/ble_test.cc
@@ -43,11 +43,14 @@ TEST_F(TestBase, BleCapabilitiesTest) {
CREATE_CHRE_TEST_EVENT(GET_CAPABILITIES, 0);
CREATE_CHRE_TEST_EVENT(GET_FILTER_CAPABILITIES, 1);
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI;
-
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_TEST_EVENT: {
auto event = static_cast<const TestEvent *>(eventData);
@@ -66,37 +69,40 @@ TEST_F(TestBase, BleCapabilitiesTest) {
}
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
uint32_t capabilities;
- sendEventToNanoapp(app, GET_CAPABILITIES);
+ sendEventToNanoapp(appId, GET_CAPABILITIES);
waitForEvent(GET_CAPABILITIES, &capabilities);
ASSERT_EQ(capabilities, CHRE_BLE_CAPABILITIES_SCAN |
CHRE_BLE_CAPABILITIES_SCAN_RESULT_BATCHING |
CHRE_BLE_CAPABILITIES_SCAN_FILTER_BEST_EFFORT);
- sendEventToNanoapp(app, GET_FILTER_CAPABILITIES);
+ sendEventToNanoapp(appId, GET_FILTER_CAPABILITIES);
waitForEvent(GET_FILTER_CAPABILITIES, &capabilities);
ASSERT_EQ(capabilities, CHRE_BLE_FILTER_CAPABILITIES_RSSI |
CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA);
}
-struct BleTestNanoapp : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_BLE;
+class BleTestNanoapp : public TestNanoapp {
+ public:
+ BleTestNanoapp()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_BLE}) {}
- decltype(nanoappStart) *start = []() {
+ bool start() override {
chreUserSettingConfigureEvents(CHRE_USER_SETTING_BLE_AVAILABLE,
true /* enable */);
return true;
- };
+ }
- decltype(nanoappEnd) *end = []() {
+ void end() override {
chreUserSettingConfigureEvents(CHRE_USER_SETTING_BLE_AVAILABLE,
false /* enable */);
- };
+ }
};
/**
@@ -109,9 +115,10 @@ TEST_F(TestBase, BleSimpleScanTest) {
CREATE_CHRE_TEST_EVENT(STOP_SCAN, 2);
CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3);
- struct App : public BleTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public BleTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_BLE_ASYNC_RESULT: {
auto *event = static_cast<const struct chreAsyncResult *>(eventData);
@@ -150,20 +157,20 @@ TEST_F(TestBase, BleSimpleScanTest) {
break;
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
bool success;
- sendEventToNanoapp(app, START_SCAN);
+ sendEventToNanoapp(appId, START_SCAN);
waitForEvent(START_SCAN, &success);
EXPECT_TRUE(success);
waitForEvent(SCAN_STARTED);
ASSERT_TRUE(chrePalIsBleEnabled());
waitForEvent(CHRE_EVENT_BLE_ADVERTISEMENT);
- sendEventToNanoapp(app, STOP_SCAN);
+ sendEventToNanoapp(appId, STOP_SCAN);
waitForEvent(STOP_SCAN, &success);
EXPECT_TRUE(success);
waitForEvent(SCAN_STOPPED);
@@ -174,9 +181,10 @@ TEST_F(TestBase, BleStopScanOnUnload) {
CREATE_CHRE_TEST_EVENT(START_SCAN, 0);
CREATE_CHRE_TEST_EVENT(SCAN_STARTED, 1);
- struct App : public BleTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public BleTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_BLE_ASYNC_RESULT: {
auto *event = static_cast<const struct chreAsyncResult *>(eventData);
@@ -200,19 +208,19 @@ TEST_F(TestBase, BleStopScanOnUnload) {
break;
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
- bool success;
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
- sendEventToNanoapp(app, START_SCAN);
+ bool success;
+ sendEventToNanoapp(appId, START_SCAN);
waitForEvent(START_SCAN, &success);
EXPECT_TRUE(success);
waitForEvent(SCAN_STARTED);
ASSERT_TRUE(chrePalIsBleEnabled());
- unloadNanoapp(app);
+ unloadNanoapp(appId);
ASSERT_FALSE(chrePalIsBleEnabled());
}
@@ -226,9 +234,9 @@ TEST_F(TestBase, BleStartTwiceScanTest) {
CREATE_CHRE_TEST_EVENT(STOP_SCAN, 2);
CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3);
- struct App : public BleTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public BleTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType, const void *eventData) {
switch (eventType) {
case CHRE_EVENT_BLE_ASYNC_RESULT: {
auto *event = static_cast<const struct chreAsyncResult *>(eventData);
@@ -266,24 +274,24 @@ TEST_F(TestBase, BleStartTwiceScanTest) {
}
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
bool success;
- sendEventToNanoapp(app, START_SCAN);
+ sendEventToNanoapp(appId, START_SCAN);
waitForEvent(START_SCAN, &success);
EXPECT_TRUE(success);
waitForEvent(SCAN_STARTED);
- sendEventToNanoapp(app, START_SCAN);
+ sendEventToNanoapp(appId, START_SCAN);
waitForEvent(START_SCAN, &success);
EXPECT_TRUE(success);
waitForEvent(SCAN_STARTED);
waitForEvent(CHRE_EVENT_BLE_ADVERTISEMENT);
- sendEventToNanoapp(app, STOP_SCAN);
+ sendEventToNanoapp(appId, STOP_SCAN);
waitForEvent(STOP_SCAN, &success);
EXPECT_TRUE(success);
waitForEvent(SCAN_STOPPED);
@@ -299,9 +307,10 @@ TEST_F(TestBase, BleStopTwiceScanTest) {
CREATE_CHRE_TEST_EVENT(STOP_SCAN, 2);
CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3);
- struct App : public BleTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public BleTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_BLE_ASYNC_RESULT: {
auto *event = static_cast<const struct chreAsyncResult *>(eventData);
@@ -331,23 +340,23 @@ TEST_F(TestBase, BleStopTwiceScanTest) {
}
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
- bool success;
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
- sendEventToNanoapp(app, STOP_SCAN);
+ bool success;
+ sendEventToNanoapp(appId, STOP_SCAN);
waitForEvent(STOP_SCAN, &success);
EXPECT_TRUE(success);
waitForEvent(SCAN_STOPPED);
- sendEventToNanoapp(app, STOP_SCAN);
+ sendEventToNanoapp(appId, STOP_SCAN);
waitForEvent(STOP_SCAN, &success);
EXPECT_TRUE(success);
waitForEvent(SCAN_STOPPED);
- unloadNanoapp(app);
+ unloadNanoapp(appId);
}
/**
@@ -362,9 +371,10 @@ TEST_F(TestBase, BleSettingChangeTest) {
CREATE_CHRE_TEST_EVENT(SCAN_STARTED, 1);
CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3);
- struct App : public BleTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public BleTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_BLE_ASYNC_RESULT: {
auto *event = static_cast<const struct chreAsyncResult *>(eventData);
@@ -406,13 +416,13 @@ TEST_F(TestBase, BleSettingChangeTest) {
}
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
- bool success;
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
- sendEventToNanoapp(app, START_SCAN);
+ bool success;
+ sendEventToNanoapp(appId, START_SCAN);
waitForEvent(START_SCAN, &success);
EXPECT_TRUE(success);
@@ -448,9 +458,10 @@ TEST_F(TestBase, BleSettingChangeTest) {
TEST_F(TestBase, BleSettingDisabledStartScanTest) {
CREATE_CHRE_TEST_EVENT(START_SCAN, 0);
- struct App : public BleTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public BleTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_BLE_ASYNC_RESULT: {
auto *event = static_cast<const struct chreAsyncResult *>(eventData);
@@ -483,10 +494,10 @@ TEST_F(TestBase, BleSettingDisabledStartScanTest) {
}
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
Setting::BLE_AVAILABLE, false /* enable */);
@@ -496,7 +507,7 @@ TEST_F(TestBase, BleSettingDisabledStartScanTest) {
EXPECT_FALSE(enabled);
bool success;
- sendEventToNanoapp(app, START_SCAN);
+ sendEventToNanoapp(appId, START_SCAN);
waitForEvent(START_SCAN, &success);
EXPECT_TRUE(success);
waitForEvent(CHRE_EVENT_BLE_ASYNC_RESULT);
@@ -511,9 +522,10 @@ TEST_F(TestBase, BleSettingDisabledStopScanTest) {
CREATE_CHRE_TEST_EVENT(STOP_SCAN, 2);
CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3);
- struct App : public BleTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public BleTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_BLE_ASYNC_RESULT: {
auto *event = static_cast<const struct chreAsyncResult *>(eventData);
@@ -548,10 +560,10 @@ TEST_F(TestBase, BleSettingDisabledStopScanTest) {
}
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
Setting::BLE_AVAILABLE, false /* enable */);
@@ -561,7 +573,7 @@ TEST_F(TestBase, BleSettingDisabledStopScanTest) {
EXPECT_FALSE(enabled);
bool success;
- sendEventToNanoapp(app, STOP_SCAN);
+ sendEventToNanoapp(appId, STOP_SCAN);
waitForEvent(STOP_SCAN, &success);
EXPECT_TRUE(success);
waitForEvent(SCAN_STOPPED);
@@ -571,15 +583,14 @@ TEST_F(TestBase, BleSettingDisabledStopScanTest) {
* Test that a nanoapp can read RSSI successfully.
*/
TEST_F(TestBase, BleReadRssi) {
- constexpr auto kConnectionHandle = 6;
- constexpr auto kCookie = 123;
+ constexpr uint16_t kConnectionHandle = 6;
+ constexpr uint32_t kCookie = 123;
CREATE_CHRE_TEST_EVENT(RSSI_REQUEST, 1);
CREATE_CHRE_TEST_EVENT(RSSI_REQUEST_SENT, 2);
- struct App : public BleTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public BleTestNanoapp {
+ void handleEvent(uint32_t, uint16_t eventType, const void *eventData) {
switch (eventType) {
case CHRE_EVENT_BLE_RSSI_READ: {
auto *event =
@@ -611,10 +622,10 @@ TEST_F(TestBase, BleReadRssi) {
}
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
Setting::BLE_AVAILABLE, true /* enabled */);
@@ -623,7 +634,7 @@ TEST_F(TestBase, BleReadRssi) {
EXPECT_TRUE(enabled);
bool success;
- sendEventToNanoapp(app, RSSI_REQUEST);
+ sendEventToNanoapp(appId, RSSI_REQUEST);
waitForEvent(RSSI_REQUEST_SENT, &success);
EXPECT_TRUE(success);
waitForEvent(CHRE_EVENT_BLE_RSSI_READ);
@@ -640,9 +651,12 @@ TEST_F(TestBase, BleStartScanTwiceBeforeAsyncResponseTest) {
CREATE_CHRE_TEST_EVENT(STOP_SCAN, 2);
CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3);
- struct App : public BleTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ struct testData {
+ void *cookie;
+ };
+
+ class App : public BleTestNanoapp {
+ void handleEvent(uint32_t, uint16_t eventType, const void *eventData) {
switch (eventType) {
case CHRE_EVENT_BLE_ASYNC_RESULT: {
auto *event = static_cast<const struct chreAsyncResult *>(eventData);
@@ -650,60 +664,203 @@ TEST_F(TestBase, BleStartScanTwiceBeforeAsyncResponseTest) {
(event->requestType == CHRE_BLE_REQUEST_TYPE_START_SCAN)
? SCAN_STARTED
: SCAN_STOPPED;
- TestEventQueueSingleton::get()->pushEvent(type, event->errorCode);
+ TestEventQueueSingleton::get()->pushEvent(type, *event);
break;
}
case CHRE_EVENT_TEST_EVENT: {
auto event = static_cast<const TestEvent *>(eventData);
switch (event->type) {
case START_SCAN: {
- const bool success = chreBleStartScanAsync(
- CHRE_BLE_SCAN_MODE_BACKGROUND, 0, nullptr);
+ auto data = static_cast<testData *>(event->data);
+ const bool success = chreBleStartScanAsyncV1_9(
+ CHRE_BLE_SCAN_MODE_BACKGROUND, 0, nullptr, data->cookie);
TestEventQueueSingleton::get()->pushEvent(START_SCAN, success);
break;
}
case STOP_SCAN: {
- const bool success = chreBleStopScanAsync();
+ auto data = static_cast<testData *>(event->data);
+ const bool success = chreBleStopScanAsyncV1_9(data->cookie);
TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success);
break;
}
}
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
bool success;
delayBleScanStart(true /* delay */);
- sendEventToNanoapp(app, START_SCAN);
+ testData data;
+ uint32_t cookieOne = 1;
+ data.cookie = &cookieOne;
+ sendEventToNanoapp(appId, START_SCAN, data);
waitForEvent(START_SCAN, &success);
EXPECT_TRUE(success);
- sendEventToNanoapp(app, START_SCAN);
+ uint32_t cookieTwo = 2;
+ data.cookie = &cookieTwo;
+ sendEventToNanoapp(appId, START_SCAN, data);
waitForEvent(START_SCAN, &success);
EXPECT_TRUE(success);
- uint8_t errorCode;
- waitForEvent(SCAN_STARTED, &errorCode);
- EXPECT_EQ(errorCode, CHRE_ERROR_OBSOLETE_REQUEST);
+ chreAsyncResult result;
+ waitForEvent(SCAN_STARTED, &result);
+ EXPECT_EQ(result.errorCode, CHRE_ERROR_OBSOLETE_REQUEST);
+ EXPECT_EQ(result.cookie, &cookieOne);
// Respond to the first scan request. CHRE will then attempt the next scan
// request at which point the PAL should no longer delay the response.
delayBleScanStart(false /* delay */);
EXPECT_TRUE(startBleScan());
- waitForEvent(SCAN_STARTED, &errorCode);
- EXPECT_EQ(errorCode, CHRE_ERROR_NONE);
+ waitForEvent(SCAN_STARTED, &result);
+ EXPECT_EQ(result.errorCode, CHRE_ERROR_NONE);
+ EXPECT_EQ(result.cookie, &cookieTwo);
- sendEventToNanoapp(app, STOP_SCAN);
+ sendEventToNanoapp(appId, STOP_SCAN, data);
waitForEvent(STOP_SCAN, &success);
EXPECT_TRUE(success);
waitForEvent(SCAN_STOPPED);
}
+/**
+ * This test validates that a nanoapp can call flush only when an existing scan
+ * is enabled for the nanoapp. This test validates that batching will hold the
+ * data and flush will send the batched data and then a flush complete event.
+ */
+TEST_F(TestBase, BleFlush) {
+ CREATE_CHRE_TEST_EVENT(START_SCAN, 0);
+ CREATE_CHRE_TEST_EVENT(SCAN_STARTED, 1);
+ CREATE_CHRE_TEST_EVENT(STOP_SCAN, 2);
+ CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3);
+ CREATE_CHRE_TEST_EVENT(CALL_FLUSH, 4);
+ CREATE_CHRE_TEST_EVENT(SAW_BLE_AD_AND_FLUSH_COMPLETE, 5);
+
+ class App : public BleTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_BLE_ASYNC_RESULT: {
+ auto *event = static_cast<const struct chreAsyncResult *>(eventData);
+ if (event->errorCode == CHRE_ERROR_NONE) {
+ uint16_t type =
+ (event->requestType == CHRE_BLE_REQUEST_TYPE_START_SCAN)
+ ? SCAN_STARTED
+ : SCAN_STOPPED;
+ TestEventQueueSingleton::get()->pushEvent(type);
+ }
+ break;
+ }
+
+ case CHRE_EVENT_BLE_ADVERTISEMENT: {
+ mSawBleAdvertisementEvent = true;
+ break;
+ }
+
+ case CHRE_EVENT_BLE_FLUSH_COMPLETE: {
+ auto *event = static_cast<const struct chreAsyncResult *>(eventData);
+ mSawFlushCompleteEvent = event->success && event->cookie == &mCookie;
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case START_SCAN: {
+ const bool success = chreBleStartScanAsync(
+ CHRE_BLE_SCAN_MODE_AGGRESSIVE, 60000, nullptr);
+ TestEventQueueSingleton::get()->pushEvent(START_SCAN, success);
+ break;
+ }
+
+ case STOP_SCAN: {
+ const bool success = chreBleStopScanAsync();
+ TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success);
+ break;
+ }
+
+ case CALL_FLUSH: {
+ const bool success = chreBleFlushAsync(&mCookie);
+ TestEventQueueSingleton::get()->pushEvent(CALL_FLUSH, success);
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if (mSawBleAdvertisementEvent && mSawFlushCompleteEvent) {
+ TestEventQueueSingleton::get()->pushEvent(
+ SAW_BLE_AD_AND_FLUSH_COMPLETE);
+ mSawBleAdvertisementEvent = false;
+ mSawFlushCompleteEvent = false;
+ }
+ }
+
+ private:
+ uint32_t mCookie;
+ bool mSawBleAdvertisementEvent = false;
+ bool mSawFlushCompleteEvent = false;
+ };
+
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
+ // Flushing before a scan should fail.
+ bool success;
+ sendEventToNanoapp(appId, CALL_FLUSH);
+ waitForEvent(CALL_FLUSH, &success);
+ ASSERT_FALSE(success);
+
+ // Start a scan with batching.
+ sendEventToNanoapp(appId, START_SCAN);
+ waitForEvent(START_SCAN, &success);
+ ASSERT_TRUE(success);
+ waitForEvent(SCAN_STARTED);
+ ASSERT_TRUE(chrePalIsBleEnabled());
+
+ // Call flush again multiple times and get the complete event.
+ // We should only receive data when flush is called as the batch
+ // delay is extremely large.
+ constexpr uint32_t kNumFlushCalls = 3;
+ for (uint32_t i = 0; i < kNumFlushCalls; ++i) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(250));
+
+ sendEventToNanoapp(appId, CALL_FLUSH);
+ waitForEvent(CALL_FLUSH, &success);
+ ASSERT_TRUE(success);
+
+ // Wait for some data and a flush complete.
+ // This ensures we receive both advertisement events
+ // and a flush complete event. We are not guaranteed
+ // that the advertisement events will come after
+ // the CALL_FLUSH event or before. If they come
+ // before, then they will be ignored. This
+ // change allows the advertisement events to come
+ // after during the normal expiration of the
+ // batch timer, which is valid (call flush, get
+ // any advertisement events, flush complete event
+ // might get some advertisement events afterwards).
+ waitForEvent(SAW_BLE_AD_AND_FLUSH_COMPLETE);
+ }
+
+ // Stop a scan.
+ sendEventToNanoapp(appId, STOP_SCAN);
+ waitForEvent(STOP_SCAN, &success);
+ ASSERT_TRUE(success);
+ waitForEvent(SCAN_STOPPED);
+ ASSERT_FALSE(chrePalIsBleEnabled());
+
+ // Flushing after a scan should fail.
+ sendEventToNanoapp(appId, CALL_FLUSH);
+ waitForEvent(CALL_FLUSH, &success);
+ ASSERT_FALSE(success);
+}
+
} // namespace
} // namespace chre
diff --git a/test/simulation/gnss_test.cc b/test/simulation/gnss_test.cc
index 5b2a6dc0..f9e388bd 100644
--- a/test/simulation/gnss_test.cc
+++ b/test/simulation/gnss_test.cc
@@ -61,73 +61,77 @@ TEST_F(TestBase, GnssSubscriptionWithSettingChange) {
uint32_t cookie;
};
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_GNSS;
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
- decltype(nanoappStart) *start = []() {
+ bool start() override {
chreUserSettingConfigureEvents(CHRE_USER_SETTING_LOCATION,
true /*enabled*/);
return true;
- };
-
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- static uint32_t cookie;
- switch (eventType) {
- case CHRE_EVENT_GNSS_ASYNC_RESULT: {
- auto *event = static_cast<const chreAsyncResult *>(eventData);
- if (event->success) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_GNSS_ASYNC_RESULT,
- *(static_cast<const uint32_t *>(event->cookie)));
- }
- break;
- }
+ }
- case CHRE_EVENT_SETTING_CHANGED_LOCATION: {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_SETTING_CHANGED_LOCATION);
- break;
- }
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_GNSS_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (event->success) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_GNSS_ASYNC_RESULT,
+ *(static_cast<const uint32_t *>(event->cookie)));
+ }
+ break;
+ }
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case LOCATION_REQUEST: {
- auto request =
- static_cast<const LocationRequest *>(event->data);
- bool success;
- if (request->enable) {
- cookie = request->cookie;
- success = chreGnssLocationSessionStartAsync(
- 1000 /*minIntervalMs*/, 1000 /*minTimeToNextFixMs*/,
- &cookie);
- } else {
- cookie = request->cookie;
- success = chreGnssLocationSessionStopAsync(&cookie);
- }
- TestEventQueueSingleton::get()->pushEvent(LOCATION_REQUEST,
- success);
- break;
- }
+ case CHRE_EVENT_SETTING_CHANGED_LOCATION: {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_SETTING_CHANGED_LOCATION);
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case LOCATION_REQUEST: {
+ auto request = static_cast<const LocationRequest *>(event->data);
+ bool success;
+ mCookie = request->cookie;
+ if (request->enable) {
+ success = chreGnssLocationSessionStartAsync(
+ 1000 /*minIntervalMs*/, 1000 /*minTimeToNextFixMs*/,
+ &mCookie);
+ } else {
+ success = chreGnssLocationSessionStopAsync(&mCookie);
}
+ TestEventQueueSingleton::get()->pushEvent(LOCATION_REQUEST,
+ success);
+ break;
}
}
- };
+ }
+ }
+ }
- decltype(nanoappEnd) *end = []() {
+ void end() override {
chreUserSettingConfigureEvents(CHRE_USER_SETTING_LOCATION,
false /*enabled*/);
- };
+ }
+
+ protected:
+ uint32_t mCookie;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
bool success;
EXPECT_FALSE(chrePalGnssIsLocationEnabled());
chrePalGnssDelaySendingLocationEvents(true);
LocationRequest request{.enable = true, .cookie = 0x123};
- sendEventToNanoapp(app, LOCATION_REQUEST, request);
+ sendEventToNanoapp(appId, LOCATION_REQUEST, request);
waitForEvent(LOCATION_REQUEST, &success);
EXPECT_TRUE(success);
chrePalGnssStartSendingLocationEvents();
@@ -155,7 +159,7 @@ TEST_F(TestBase, GnssSubscriptionWithSettingChange) {
std::chrono::milliseconds(1000)));
request.enable = false;
- sendEventToNanoapp(app, LOCATION_REQUEST, request);
+ sendEventToNanoapp(appId, LOCATION_REQUEST, request);
waitForEvent(LOCATION_REQUEST, &success);
EXPECT_TRUE(success);
chrePalGnssStartSendingLocationEvents();
@@ -173,12 +177,14 @@ TEST_F(TestBase, GnssCanSubscribeAndUnsubscribeToLocation) {
uint32_t cookie;
};
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_GNSS;
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
- static uint32_t cookie;
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_GNSS_ASYNC_RESULT: {
auto *event = static_cast<const chreAsyncResult *>(eventData);
@@ -196,14 +202,13 @@ TEST_F(TestBase, GnssCanSubscribeAndUnsubscribeToLocation) {
case LOCATION_REQUEST: {
auto request = static_cast<const LocationRequest *>(event->data);
bool success;
+ mCookie = request->cookie;
if (request->enable) {
- cookie = request->cookie;
success = chreGnssLocationSessionStartAsync(
1000 /*minIntervalMs*/, 1000 /*minTimeToNextFixMs*/,
- &cookie);
+ &mCookie);
} else {
- cookie = request->cookie;
- success = chreGnssLocationSessionStopAsync(&cookie);
+ success = chreGnssLocationSessionStopAsync(&mCookie);
}
TestEventQueueSingleton::get()->pushEvent(LOCATION_REQUEST,
success);
@@ -212,15 +217,19 @@ TEST_F(TestBase, GnssCanSubscribeAndUnsubscribeToLocation) {
}
}
}
- };
+ }
+
+ protected:
+ uint32_t mCookie;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
bool success;
EXPECT_FALSE(chrePalGnssIsLocationEnabled());
LocationRequest request{.enable = true, .cookie = 0x123};
- sendEventToNanoapp(app, LOCATION_REQUEST, request);
+ sendEventToNanoapp(appId, LOCATION_REQUEST, request);
waitForEvent(LOCATION_REQUEST, &success);
EXPECT_TRUE(success);
uint32_t cookie;
@@ -229,7 +238,7 @@ TEST_F(TestBase, GnssCanSubscribeAndUnsubscribeToLocation) {
EXPECT_TRUE(chrePalGnssIsLocationEnabled());
request.enable = false;
- sendEventToNanoapp(app, LOCATION_REQUEST, request);
+ sendEventToNanoapp(appId, LOCATION_REQUEST, request);
waitForEvent(LOCATION_REQUEST, &success);
EXPECT_TRUE(success);
waitForEvent(CHRE_EVENT_GNSS_ASYNC_RESULT, &cookie);
@@ -245,12 +254,14 @@ TEST_F(TestBase, GnssUnsubscribeToLocationOnUnload) {
uint32_t cookie;
};
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_GNSS;
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
- static uint32_t cookie;
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_GNSS_ASYNC_RESULT: {
auto *event = static_cast<const chreAsyncResult *>(eventData);
@@ -268,10 +279,10 @@ TEST_F(TestBase, GnssUnsubscribeToLocationOnUnload) {
case LOCATION_REQUEST: {
auto request = static_cast<const LocationRequest *>(event->data);
if (request->enable) {
- cookie = request->cookie;
+ mCookie = request->cookie;
const bool success = chreGnssLocationSessionStartAsync(
1000 /*minIntervalMs*/, 1000 /*minTimeToNextFixMs*/,
- &cookie);
+ &mCookie);
TestEventQueueSingleton::get()->pushEvent(LOCATION_REQUEST,
success);
}
@@ -280,14 +291,18 @@ TEST_F(TestBase, GnssUnsubscribeToLocationOnUnload) {
}
}
}
- };
+ }
+
+ protected:
+ uint32_t mCookie;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
EXPECT_FALSE(chrePalGnssIsLocationEnabled());
LocationRequest request{.enable = true, .cookie = 0x123};
- sendEventToNanoapp(app, LOCATION_REQUEST, request);
+ sendEventToNanoapp(appId, LOCATION_REQUEST, request);
bool success;
waitForEvent(LOCATION_REQUEST, &success);
EXPECT_TRUE(success);
@@ -296,7 +311,7 @@ TEST_F(TestBase, GnssUnsubscribeToLocationOnUnload) {
EXPECT_EQ(cookie, request.cookie);
EXPECT_TRUE(chrePalGnssIsLocationEnabled());
- unloadNanoapp(app);
+ unloadNanoapp(appId);
EXPECT_FALSE(chrePalGnssIsLocationEnabled());
}
@@ -308,54 +323,61 @@ TEST_F(TestBase, GnssCanSubscribeAndUnsubscribeToMeasurement) {
uint32_t cookie;
};
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_GNSS;
-
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- static uint32_t cookie;
- switch (eventType) {
- case CHRE_EVENT_GNSS_ASYNC_RESULT: {
- auto *event = static_cast<const chreAsyncResult *>(eventData);
- if (event->success) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_GNSS_ASYNC_RESULT,
- *(static_cast<const uint32_t *>(event->cookie)));
- }
- break;
- }
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ static uint32_t cookie;
+ switch (eventType) {
+ case CHRE_EVENT_GNSS_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (event->success) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_GNSS_ASYNC_RESULT,
+ *(static_cast<const uint32_t *>(event->cookie)));
+ }
+ break;
+ }
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case MEASUREMENT_REQUEST: {
- auto request =
- static_cast<const MeasurementRequest *>(event->data);
- bool success;
- if (request->enable) {
- cookie = request->cookie;
- success = chreGnssMeasurementSessionStartAsync(
- 1000 /*minIntervalMs*/, &cookie);
- } else {
- cookie = request->cookie;
- success = chreGnssMeasurementSessionStopAsync(&cookie);
- }
- TestEventQueueSingleton::get()->pushEvent(MEASUREMENT_REQUEST,
- success);
- break;
- }
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case MEASUREMENT_REQUEST: {
+ auto request =
+ static_cast<const MeasurementRequest *>(event->data);
+ bool success;
+ mCookie = request->cookie;
+ if (request->enable) {
+ success = chreGnssMeasurementSessionStartAsync(
+ 1000 /*minIntervalMs*/, &mCookie);
+ } else {
+ cookie = request->cookie;
+ success = chreGnssMeasurementSessionStopAsync(&mCookie);
}
+ TestEventQueueSingleton::get()->pushEvent(MEASUREMENT_REQUEST,
+ success);
+ break;
}
}
- };
+ }
+ }
+ }
+
+ protected:
+ uint32_t mCookie;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
bool success;
EXPECT_FALSE(chrePalGnssIsLocationEnabled());
MeasurementRequest request{.enable = true, .cookie = 0x123};
- sendEventToNanoapp(app, MEASUREMENT_REQUEST, request);
+ sendEventToNanoapp(appId, MEASUREMENT_REQUEST, request);
waitForEvent(MEASUREMENT_REQUEST, &success);
EXPECT_TRUE(success);
uint32_t cookie;
@@ -364,7 +386,7 @@ TEST_F(TestBase, GnssCanSubscribeAndUnsubscribeToMeasurement) {
EXPECT_TRUE(chrePalGnssIsMeasurementEnabled());
request.enable = false;
- sendEventToNanoapp(app, MEASUREMENT_REQUEST, request);
+ sendEventToNanoapp(appId, MEASUREMENT_REQUEST, request);
waitForEvent(MEASUREMENT_REQUEST, &success);
EXPECT_TRUE(success);
waitForEvent(CHRE_EVENT_GNSS_ASYNC_RESULT, &cookie);
@@ -380,49 +402,55 @@ TEST_F(TestBase, GnssUnsubscribeToMeasurementOnUnload) {
uint32_t cookie;
};
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_GNSS;
-
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- static uint32_t cookie;
- switch (eventType) {
- case CHRE_EVENT_GNSS_ASYNC_RESULT: {
- auto *event = static_cast<const chreAsyncResult *>(eventData);
- if (event->success) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_GNSS_ASYNC_RESULT,
- *(static_cast<const uint32_t *>(event->cookie)));
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_GNSS_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (event->success) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_GNSS_ASYNC_RESULT,
+ *(static_cast<const uint32_t *>(event->cookie)));
+ }
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case MEASUREMENT_REQUEST: {
+ auto request =
+ static_cast<const MeasurementRequest *>(event->data);
+ if (request->enable) {
+ mCookie = request->cookie;
+ const bool success = chreGnssMeasurementSessionStartAsync(
+ 1000 /*minIntervalMs*/, &mCookie);
+ TestEventQueueSingleton::get()->pushEvent(MEASUREMENT_REQUEST,
+ success);
}
break;
}
+ }
+ }
+ }
+ }
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case MEASUREMENT_REQUEST: {
- auto request =
- static_cast<const MeasurementRequest *>(event->data);
- if (request->enable) {
- cookie = request->cookie;
- const bool success = chreGnssMeasurementSessionStartAsync(
- 1000 /*minIntervalMs*/, &cookie);
- TestEventQueueSingleton::get()->pushEvent(
- MEASUREMENT_REQUEST, success);
- }
- break;
- }
- }
- }
- };
- };
+ protected:
+ uint32_t mCookie;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
EXPECT_FALSE(chrePalGnssIsLocationEnabled());
MeasurementRequest request{.enable = true, .cookie = 0x123};
- sendEventToNanoapp(app, MEASUREMENT_REQUEST, request);
+ sendEventToNanoapp(appId, MEASUREMENT_REQUEST, request);
bool success;
waitForEvent(MEASUREMENT_REQUEST, &success);
EXPECT_TRUE(success);
@@ -431,46 +459,50 @@ TEST_F(TestBase, GnssUnsubscribeToMeasurementOnUnload) {
EXPECT_EQ(cookie, request.cookie);
EXPECT_TRUE(chrePalGnssIsMeasurementEnabled());
- unloadNanoapp(app);
+ unloadNanoapp(appId);
EXPECT_FALSE(chrePalGnssIsMeasurementEnabled());
}
TEST_F(TestBase, GnssCanSubscribeAndUnsubscribeToPassiveListener) {
CREATE_CHRE_TEST_EVENT(LISTENER_REQUEST, 0);
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_GNSS;
-
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- switch (eventType) {
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case LISTENER_REQUEST: {
- auto enable = *(static_cast<const bool *>(event->data));
- const bool success =
- chreGnssConfigurePassiveLocationListener(enable);
- TestEventQueueSingleton::get()->pushEvent(LISTENER_REQUEST,
- success);
- break;
- }
- }
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case LISTENER_REQUEST: {
+ auto enable = *(static_cast<const bool *>(event->data));
+ const bool success =
+ chreGnssConfigurePassiveLocationListener(enable);
+ TestEventQueueSingleton::get()->pushEvent(LISTENER_REQUEST,
+ success);
+ break;
}
}
- };
+ }
+ }
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
bool success;
EXPECT_FALSE(chrePalGnssIsPassiveLocationListenerEnabled());
- sendEventToNanoapp(app, LISTENER_REQUEST, true);
+ sendEventToNanoapp(appId, LISTENER_REQUEST, true);
waitForEvent(LISTENER_REQUEST, &success);
EXPECT_TRUE(success);
EXPECT_TRUE(chrePalGnssIsPassiveLocationListenerEnabled());
- sendEventToNanoapp(app, LISTENER_REQUEST, false);
+ sendEventToNanoapp(appId, LISTENER_REQUEST, false);
waitForEvent(LISTENER_REQUEST, &success);
EXPECT_TRUE(success);
EXPECT_FALSE(chrePalGnssIsPassiveLocationListenerEnabled());
@@ -479,38 +511,42 @@ TEST_F(TestBase, GnssCanSubscribeAndUnsubscribeToPassiveListener) {
TEST_F(TestBase, GnssUnsubscribeToPassiveListenerOnUnload) {
CREATE_CHRE_TEST_EVENT(LISTENER_REQUEST, 0);
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_GNSS;
-
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- switch (eventType) {
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case LISTENER_REQUEST: {
- auto enable = *(static_cast<const bool *>(event->data));
- const bool success =
- chreGnssConfigurePassiveLocationListener(enable);
- TestEventQueueSingleton::get()->pushEvent(LISTENER_REQUEST,
- success);
- }
- }
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case LISTENER_REQUEST: {
+ auto enable = *(static_cast<const bool *>(event->data));
+ const bool success =
+ chreGnssConfigurePassiveLocationListener(enable);
+ TestEventQueueSingleton::get()->pushEvent(LISTENER_REQUEST,
+ success);
}
}
- };
+ }
+ }
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
EXPECT_FALSE(chrePalGnssIsPassiveLocationListenerEnabled());
- sendEventToNanoapp(app, LISTENER_REQUEST, true);
+ sendEventToNanoapp(appId, LISTENER_REQUEST, true);
bool success;
waitForEvent(LISTENER_REQUEST, &success);
EXPECT_TRUE(success);
EXPECT_TRUE(chrePalGnssIsPassiveLocationListenerEnabled());
- unloadNanoapp(app);
+ unloadNanoapp(appId);
EXPECT_FALSE(chrePalGnssIsPassiveLocationListenerEnabled());
}
diff --git a/test/simulation/host_endpoint_notification_test.cc b/test/simulation/host_endpoint_notification_test.cc
index 67d3f981..75e3a7eb 100644
--- a/test/simulation/host_endpoint_notification_test.cc
+++ b/test/simulation/host_endpoint_notification_test.cc
@@ -52,31 +52,31 @@ TEST_F(TestBase, HostEndpointDisconnectedTest) {
uint16_t endpointId;
};
- struct App : public TestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- switch (eventType) {
- case CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION: {
- auto notification =
- *(struct chreHostEndpointNotification *)eventData;
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION, notification);
- } break;
-
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case SETUP_NOTIFICATION: {
- auto config = static_cast<const Config *>(event->data);
- const bool success = chreConfigureHostEndpointNotifications(
- config->endpointId, config->enable);
- TestEventQueueSingleton::get()->pushEvent(SETUP_NOTIFICATION,
- success);
- }
- }
+ class App : public TestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION: {
+ auto notification = *(struct chreHostEndpointNotification *)eventData;
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION, notification);
+ } break;
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case SETUP_NOTIFICATION: {
+ auto config = static_cast<const Config *>(event->data);
+ const bool success = chreConfigureHostEndpointNotifications(
+ config->endpointId, config->enable);
+ TestEventQueueSingleton::get()->pushEvent(SETUP_NOTIFICATION,
+ success);
}
}
- };
+ }
+ }
+ }
};
struct chreHostEndpointInfo info;
@@ -88,10 +88,11 @@ TEST_F(TestBase, HostEndpointDisconnectedTest) {
strcpy(&info.endpointTag[0], "Test tag");
getHostEndpointManager().postHostEndpointConnected(info);
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
Config config = {.enable = true, .endpointId = kHostEndpointId};
- sendEventToNanoapp(app, SETUP_NOTIFICATION, config);
+ sendEventToNanoapp(appId, SETUP_NOTIFICATION, config);
bool success;
waitForEvent(SETUP_NOTIFICATION, &success);
EXPECT_TRUE(success);
diff --git a/test/simulation/inc/rpc_test.h b/test/simulation/inc/rpc_test.h
index ce71d4e4..1fcc7df6 100644
--- a/test/simulation/inc/rpc_test.h
+++ b/test/simulation/inc/rpc_test.h
@@ -42,12 +42,21 @@ class RpcTestService final
chre_rpc_NumberMessage &response);
};
-struct Env {
+class Env {
+ public:
RpcTestService mRpcTestService;
chre::RpcServer mServer;
chre::RpcClient mClient{kPwRcpServerAppId};
pw::rpc::NanopbUnaryReceiver<chre_rpc_NumberMessage> mIncrementCall;
uint32_t mNumber;
+
+ void closeServer() {
+ mServer.close();
+ }
+
+ void closeClient() {
+ mClient.close();
+ }
};
typedef Singleton<Env> EnvSingleton;
diff --git a/test/simulation/inc/test_base.h b/test/simulation/inc/test_base.h
index 0b02741b..95ac29c7 100644
--- a/test/simulation/inc/test_base.h
+++ b/test/simulation/inc/test_base.h
@@ -21,6 +21,8 @@
#include <cstdint>
#include <thread>
+#include "chre/core/event_loop_manager.h"
+#include "chre/core/nanoapp.h"
#include "chre/platform/system_timer.h"
#include "chre/util/time.h"
#include "test_event_queue.h"
@@ -74,6 +76,24 @@ class TestBase : public testing::Test {
TestEventQueueSingleton::get()->waitForEvent(eventType, eventData);
}
+ /**
+ * Retrieves the Nanoapp instance from its ID.
+ *
+ * @param id Nanoapp ID
+ * @return A pointer to the Nanoapp instance or nullptr if not found.
+ */
+ Nanoapp *getNanoappByAppId(uint64_t id) {
+ uint16_t instanceId;
+ EXPECT_TRUE(EventLoopManagerSingleton::get()
+ ->getEventLoop()
+ .findNanoappInstanceIdByAppId(id, &instanceId));
+ Nanoapp *nanoapp = EventLoopManagerSingleton::get()
+ ->getEventLoop()
+ .findNanoappByInstanceId(instanceId);
+ EXPECT_NE(nanoapp, nullptr);
+ return nanoapp;
+ }
+
std::thread mChreThread;
SystemTimer mSystemTimer;
};
diff --git a/test/simulation/inc/test_util.h b/test/simulation/inc/test_util.h
index 0a12e4c8..9e796018 100644
--- a/test/simulation/inc/test_util.h
+++ b/test/simulation/inc/test_util.h
@@ -28,7 +28,77 @@
namespace chre {
-struct TestNanoapp;
+constexpr uint64_t kDefaultTestNanoappId = 0x0123456789abcdef;
+
+/**
+ * Unregister all nanoapps.
+ *
+ * This is called by the test framework to unregister all nanoapps after each
+ * test. The destructor is called when the nanoapp is unregistered.
+ */
+void unregisterAllTestNanoapps();
+
+/**
+ * Information about a test nanoapp.
+ */
+struct TestNanoappInfo {
+ const char *name = "Test";
+ uint64_t id = kDefaultTestNanoappId;
+ uint32_t version = 0;
+ uint32_t perms = NanoappPermissions::CHRE_PERMS_NONE;
+};
+
+/**
+ * Test nanoapp.
+ *
+ * Tests typically inherit this class and override the entry points to test the
+ * nanoapp behavior.
+ *
+ * The bulk of the code should be in the handleEvent method to respond to
+ * events sent to the nanoapp by the platform and by the sendEventToNanoapp
+ * function. start and end can be use to setup and cleanup the test environment
+ * around each test.
+ *
+ * Note: end is only executed when the nanoapp is explicitly unloaded.
+ */
+class TestNanoapp {
+ public:
+ TestNanoapp() = default;
+ explicit TestNanoapp(TestNanoappInfo info) : mTestNanoappInfo(info) {}
+ virtual ~TestNanoapp() {}
+
+ // NanoappStart Entrypoint.
+ virtual bool start() {
+ return true;
+ }
+
+ // nanoappHandleEvent Entrypoint.
+ virtual void handleEvent(uint32_t /*senderInstanceId*/,
+ uint16_t /*eventType*/, const void * /*eventData*/) {
+ }
+
+ // nanoappEnd Entrypoint.
+ virtual void end() {}
+
+ const char *name() {
+ return mTestNanoappInfo.name;
+ }
+
+ uint64_t id() {
+ return mTestNanoappInfo.id;
+ }
+
+ uint32_t version() {
+ return mTestNanoappInfo.version;
+ }
+
+ uint32_t perms() {
+ return mTestNanoappInfo.perms;
+ }
+
+ private:
+ const TestNanoappInfo mTestNanoappInfo;
+};
/**
* @return the statically loaded nanoapp based on the arguments.
@@ -85,30 +155,9 @@ void loadNanoapp(const char *name, uint64_t appId, uint32_t appVersion,
*
* This function returns after the nanoapp start has been executed.
*
- * @return An instance of the TestNanoapp.
+ * @return The id of the nanoapp.
*/
-template <class Nanoapp>
-Nanoapp loadNanoapp() {
- static_assert(std::is_base_of<TestNanoapp, Nanoapp>::value);
- Nanoapp app;
- loadNanoapp(app.name, app.id, app.version, app.perms, app.start,
- app.handleEvent, app.end);
-
- return app;
-}
-
-/**
- * Unload a test nanoapp.
- *
- * This function returns after the nanoapp end has been executed.
- *
- * @param app An instance of TestNanoapp.
- */
-template <class Nanoapp>
-void unloadNanoapp(Nanoapp app) {
- static_assert(std::is_base_of<TestNanoapp, Nanoapp>::value);
- unloadNanoapp(app.id);
-}
+uint64_t loadNanoapp(UniquePtr<TestNanoapp> app);
/**
* Unload nanoapp corresponding to appId.
@@ -117,8 +166,7 @@ void unloadNanoapp(Nanoapp app) {
*
* @param appId App Id of nanoapp to be unloaded.
*/
-template <>
-void unloadNanoapp<uint64_t>(uint64_t appId);
+void unloadNanoapp(uint64_t appId);
/**
* A convenience deferred callback function that can be used to start an already
@@ -141,31 +189,6 @@ void testFinishUnloadingNanoappCallback(uint16_t type, void *data,
void *extraData);
/**
- * Test nanoapp.
- *
- * Tests typically inherit this struct to test the nanoapp behavior.
- * The bulk of the code should be in the handleEvent closure to respond to
- * events sent to the nanoapp by the platform and by the sendEventToNanoapp
- * function. start and end can be use to setup and cleanup the test environment
- * around each test.
- *
- * Note: end is only executed when the nanoapp is explicitly unloaded.
- */
-struct TestNanoapp {
- const char *name = "Test";
- uint64_t id = 0x0123456789abcdef;
- uint32_t version = 0;
- uint32_t perms = NanoappPermissions::CHRE_PERMS_NONE;
-
- decltype(nanoappStart) *start = []() { return true; };
-
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t,
- const void *) {};
-
- decltype(nanoappEnd) *end = []() {};
-};
-
-/**
* Deallocate the memory allocated for a TestEvent.
*/
void freeTestEventDataCallback(uint16_t /*eventType*/, void *eventData);
@@ -176,27 +199,10 @@ void freeTestEventDataCallback(uint16_t /*eventType*/, void *eventData);
* This function is typically used to execute code in the context of the
* nanoapp in its handleEvent method.
*
- * @param app An instance of TestNanoapp.
+ * @param appId ID of the nanoapp.
* @param eventType The event to send.
*/
-template <class Nanoapp>
-void sendEventToNanoapp(const Nanoapp &app, uint16_t eventType) {
- static_assert(std::is_base_of<TestNanoapp, Nanoapp>::value);
- uint16_t instanceId;
- if (EventLoopManagerSingleton::get()
- ->getEventLoop()
- .findNanoappInstanceIdByAppId(app.id, &instanceId)) {
- auto event = memoryAlloc<TestEvent>();
- ASSERT_NE(event, nullptr);
- event->type = eventType;
- EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
- CHRE_EVENT_TEST_EVENT, static_cast<void *>(event),
- freeTestEventDataCallback, instanceId);
-
- } else {
- LOGE("No instance found for nanoapp id = 0x%016" PRIx64, app.id);
- }
-}
+void sendEventToNanoapp(uint64_t appId, uint16_t eventType);
/**
* Sends a message to a nanoapp with data.
@@ -208,19 +214,18 @@ void sendEventToNanoapp(const Nanoapp &app, uint16_t eventType) {
* populated with the eventType and a pointer to as copy of the evenData as
* a CHRE_EVENT_TEST_EVENT event.
*
- * @param app An instance of TestNanoapp.
+ * @param appId ID of the nanoapp.
* @param eventType The event to send.
* @param eventData The data to send.
*/
-template <class Nanoapp, class T>
-void sendEventToNanoapp(const Nanoapp &app, uint16_t eventType,
+template <class T>
+void sendEventToNanoapp(uint64_t appId, uint16_t eventType,
const T &eventData) {
- static_assert(std::is_base_of<TestNanoapp, Nanoapp>::value);
static_assert(std::is_trivial<T>::value);
uint16_t instanceId;
if (EventLoopManagerSingleton::get()
->getEventLoop()
- .findNanoappInstanceIdByAppId(app.id, &instanceId)) {
+ .findNanoappInstanceIdByAppId(appId, &instanceId)) {
auto event = memoryAlloc<TestEvent>();
ASSERT_NE(event, nullptr);
event->type = eventType;
@@ -232,7 +237,7 @@ void sendEventToNanoapp(const Nanoapp &app, uint16_t eventType,
CHRE_EVENT_TEST_EVENT, static_cast<void *>(event),
freeTestEventDataCallback, instanceId);
} else {
- LOGE("No instance found for nanoapp id = 0x%016" PRIx64, app.id);
+ LOGE("No instance found for nanoapp id = 0x%016" PRIx64, appId);
}
}
diff --git a/test/simulation/memory_test.cc b/test/simulation/memory_test.cc
index 5acd2e97..a3047346 100644
--- a/test/simulation/memory_test.cc
+++ b/test/simulation/memory_test.cc
@@ -33,25 +33,14 @@
namespace chre {
namespace {
-Nanoapp *getNanoappByAppId(uint64_t id) {
- uint16_t instanceId;
- EXPECT_TRUE(EventLoopManagerSingleton::get()
- ->getEventLoop()
- .findNanoappInstanceIdByAppId(id, &instanceId));
- Nanoapp *nanoapp =
- EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
- instanceId);
- EXPECT_NE(nanoapp, nullptr);
- return nanoapp;
-}
-
TEST_F(TestBase, MemoryAllocateAndFree) {
CREATE_CHRE_TEST_EVENT(ALLOCATE, 0);
CREATE_CHRE_TEST_EVENT(FREE, 1);
- struct App : public TestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public TestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_TEST_EVENT: {
auto event = static_cast<const TestEvent *>(eventData);
@@ -71,21 +60,22 @@ TEST_F(TestBase, MemoryAllocateAndFree) {
}
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
MemoryManager &memManager =
EventLoopManagerSingleton::get()->getMemoryManager();
- Nanoapp *nanoapp = getNanoappByAppId(app.id);
+ Nanoapp *nanoapp = getNanoappByAppId(appId);
+ ASSERT_NE(nanoapp, nullptr);
EXPECT_EQ(nanoapp->getTotalAllocatedBytes(), 0);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 0);
EXPECT_EQ(memManager.getAllocationCount(), 0);
void *ptr1;
- sendEventToNanoapp(app, ALLOCATE, 100);
+ sendEventToNanoapp(appId, ALLOCATE, 100);
waitForEvent(ALLOCATE, &ptr1);
EXPECT_NE(ptr1, nullptr);
EXPECT_EQ(nanoapp->getTotalAllocatedBytes(), 100);
@@ -93,20 +83,20 @@ TEST_F(TestBase, MemoryAllocateAndFree) {
EXPECT_EQ(memManager.getAllocationCount(), 1);
void *ptr2;
- sendEventToNanoapp(app, ALLOCATE, 200);
+ sendEventToNanoapp(appId, ALLOCATE, 200);
waitForEvent(ALLOCATE, &ptr2);
EXPECT_NE(ptr2, nullptr);
EXPECT_EQ(nanoapp->getTotalAllocatedBytes(), 100 + 200);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 100 + 200);
EXPECT_EQ(memManager.getAllocationCount(), 2);
- sendEventToNanoapp(app, FREE, ptr1);
+ sendEventToNanoapp(appId, FREE, ptr1);
waitForEvent(FREE);
EXPECT_EQ(nanoapp->getTotalAllocatedBytes(), 200);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 200);
EXPECT_EQ(memManager.getAllocationCount(), 1);
- sendEventToNanoapp(app, FREE, ptr2);
+ sendEventToNanoapp(appId, FREE, ptr2);
waitForEvent(FREE);
EXPECT_EQ(nanoapp->getTotalAllocatedBytes(), 0);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 0);
@@ -116,9 +106,10 @@ TEST_F(TestBase, MemoryAllocateAndFree) {
TEST_F(TestBase, MemoryFreeOnNanoappUnload) {
CREATE_CHRE_TEST_EVENT(ALLOCATE, 0);
- struct App : public TestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public TestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_TEST_EVENT: {
auto event = static_cast<const TestEvent *>(eventData);
@@ -132,21 +123,22 @@ TEST_F(TestBase, MemoryFreeOnNanoappUnload) {
}
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
MemoryManager &memManager =
EventLoopManagerSingleton::get()->getMemoryManager();
- Nanoapp *nanoapp = getNanoappByAppId(app.id);
+ Nanoapp *nanoapp = getNanoappByAppId(appId);
+ ASSERT_NE(nanoapp, nullptr);
EXPECT_EQ(nanoapp->getTotalAllocatedBytes(), 0);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 0);
EXPECT_EQ(memManager.getAllocationCount(), 0);
void *ptr1;
- sendEventToNanoapp(app, ALLOCATE, 100);
+ sendEventToNanoapp(appId, ALLOCATE, 100);
waitForEvent(ALLOCATE, &ptr1);
EXPECT_NE(ptr1, nullptr);
EXPECT_EQ(nanoapp->getTotalAllocatedBytes(), 100);
@@ -154,14 +146,14 @@ TEST_F(TestBase, MemoryFreeOnNanoappUnload) {
EXPECT_EQ(memManager.getAllocationCount(), 1);
void *ptr2;
- sendEventToNanoapp(app, ALLOCATE, 200);
+ sendEventToNanoapp(appId, ALLOCATE, 200);
waitForEvent(ALLOCATE, &ptr2);
EXPECT_NE(ptr2, nullptr);
EXPECT_EQ(nanoapp->getTotalAllocatedBytes(), 100 + 200);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 100 + 200);
EXPECT_EQ(memManager.getAllocationCount(), 2);
- unloadNanoapp(app);
+ unloadNanoapp(appId);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 0);
EXPECT_EQ(memManager.getAllocationCount(), 0);
}
@@ -170,9 +162,10 @@ TEST_F(TestBase, MemoryStressTestShouldNotTriggerErrors) {
CREATE_CHRE_TEST_EVENT(ALLOCATE, 0);
CREATE_CHRE_TEST_EVENT(FREE, 1);
- struct App : public TestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public TestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_TEST_EVENT: {
auto event = static_cast<const TestEvent *>(eventData);
@@ -192,13 +185,13 @@ TEST_F(TestBase, MemoryStressTestShouldNotTriggerErrors) {
}
}
}
- };
+ }
};
MemoryManager &memManager =
EventLoopManagerSingleton::get()->getMemoryManager();
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 0);
EXPECT_EQ(memManager.getAllocationCount(), 0);
@@ -207,55 +200,55 @@ TEST_F(TestBase, MemoryStressTestShouldNotTriggerErrors) {
void *ptr2;
void *ptr3;
- sendEventToNanoapp(app, ALLOCATE, 100);
+ sendEventToNanoapp(appId, ALLOCATE, 100);
waitForEvent(ALLOCATE, &ptr1);
- sendEventToNanoapp(app, ALLOCATE, 200);
+ sendEventToNanoapp(appId, ALLOCATE, 200);
waitForEvent(ALLOCATE, &ptr2);
- sendEventToNanoapp(app, ALLOCATE, 300);
+ sendEventToNanoapp(appId, ALLOCATE, 300);
waitForEvent(ALLOCATE, &ptr3);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 100 + 200 + 300);
EXPECT_EQ(memManager.getAllocationCount(), 3);
// Free middle, last, and first blocks.
- sendEventToNanoapp(app, FREE, ptr2);
+ sendEventToNanoapp(appId, FREE, ptr2);
waitForEvent(FREE);
- sendEventToNanoapp(app, FREE, ptr3);
+ sendEventToNanoapp(appId, FREE, ptr3);
waitForEvent(FREE);
- sendEventToNanoapp(app, FREE, ptr1);
+ sendEventToNanoapp(appId, FREE, ptr1);
waitForEvent(FREE);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 0);
EXPECT_EQ(memManager.getAllocationCount(), 0);
- sendEventToNanoapp(app, ALLOCATE, 100);
+ sendEventToNanoapp(appId, ALLOCATE, 100);
waitForEvent(ALLOCATE, &ptr1);
- sendEventToNanoapp(app, ALLOCATE, 200);
+ sendEventToNanoapp(appId, ALLOCATE, 200);
waitForEvent(ALLOCATE, &ptr2);
- sendEventToNanoapp(app, ALLOCATE, 300);
+ sendEventToNanoapp(appId, ALLOCATE, 300);
waitForEvent(ALLOCATE, &ptr3);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 100 + 200 + 300);
EXPECT_EQ(memManager.getAllocationCount(), 3);
// Free last, last and last blocks.
- sendEventToNanoapp(app, FREE, ptr3);
+ sendEventToNanoapp(appId, FREE, ptr3);
waitForEvent(FREE);
- sendEventToNanoapp(app, FREE, ptr2);
+ sendEventToNanoapp(appId, FREE, ptr2);
waitForEvent(FREE);
- sendEventToNanoapp(app, FREE, ptr1);
+ sendEventToNanoapp(appId, FREE, ptr1);
waitForEvent(FREE);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 0);
EXPECT_EQ(memManager.getAllocationCount(), 0);
- sendEventToNanoapp(app, ALLOCATE, 100);
+ sendEventToNanoapp(appId, ALLOCATE, 100);
waitForEvent(ALLOCATE, &ptr1);
- sendEventToNanoapp(app, ALLOCATE, 200);
+ sendEventToNanoapp(appId, ALLOCATE, 200);
waitForEvent(ALLOCATE, &ptr2);
- sendEventToNanoapp(app, ALLOCATE, 300);
+ sendEventToNanoapp(appId, ALLOCATE, 300);
waitForEvent(ALLOCATE, &ptr3);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 100 + 200 + 300);
EXPECT_EQ(memManager.getAllocationCount(), 3);
// Automatic cleanup.
- unloadNanoapp(app);
+ unloadNanoapp(appId);
EXPECT_EQ(memManager.getTotalAllocatedBytes(), 0);
EXPECT_EQ(memManager.getAllocationCount(), 0);
}
diff --git a/test/simulation/rpc_test.cc b/test/simulation/rpc_test.cc
index ffcd564e..a023f640 100644
--- a/test/simulation/rpc_test.cc
+++ b/test/simulation/rpc_test.cc
@@ -46,8 +46,9 @@ pw::Status RpcTestService::Increment(const chre_rpc_NumberMessage &request,
namespace {
TEST_F(TestBase, PwRpcCanPublishServicesInNanoappStart) {
- struct App : public TestNanoapp {
- decltype(nanoappStart) *start = []() -> bool {
+ class App : public TestNanoapp {
+ public:
+ bool start() override {
struct chreNanoappRpcService servicesA[] = {
{.id = 1, .version = 0},
{.id = 2, .version = 0},
@@ -60,21 +61,12 @@ TEST_F(TestBase, PwRpcCanPublishServicesInNanoappStart) {
return chrePublishRpcServices(servicesA, 2 /* numServices */) &&
chrePublishRpcServices(servicesB, 2 /* numServices */);
- };
+ }
};
- auto app = loadNanoapp<App>();
-
- uint16_t instanceId;
- EXPECT_TRUE(EventLoopManagerSingleton::get()
- ->getEventLoop()
- .findNanoappInstanceIdByAppId(app.id, &instanceId));
-
- Nanoapp *napp =
- EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
- instanceId);
-
- ASSERT_FALSE(napp == nullptr);
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+ Nanoapp *napp = getNanoappByAppId(appId);
+ ASSERT_NE(napp, nullptr);
EXPECT_EQ(napp->getRpcServices().size(), 4);
EXPECT_EQ(napp->getRpcServices()[0].id, 1);
@@ -84,8 +76,8 @@ TEST_F(TestBase, PwRpcCanPublishServicesInNanoappStart) {
}
TEST_F(TestBase, PwRpcCanNotPublishDuplicateServices) {
- struct App : public TestNanoapp {
- decltype(nanoappStart) *start = []() -> bool {
+ class App : public TestNanoapp {
+ bool start() override {
struct chreNanoappRpcService servicesA[] = {
{.id = 1, .version = 0},
{.id = 2, .version = 0},
@@ -103,21 +95,12 @@ TEST_F(TestBase, PwRpcCanNotPublishDuplicateServices) {
EXPECT_FALSE(chrePublishRpcServices(servicesB, 2 /* numServices */));
return success;
- };
+ }
};
- auto app = loadNanoapp<App>();
-
- uint16_t instanceId;
- EXPECT_TRUE(EventLoopManagerSingleton::get()
- ->getEventLoop()
- .findNanoappInstanceIdByAppId(app.id, &instanceId));
-
- Nanoapp *napp =
- EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
- instanceId);
-
- ASSERT_FALSE(napp == nullptr);
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+ Nanoapp *napp = getNanoappByAppId(appId);
+ ASSERT_NE(napp, nullptr);
EXPECT_EQ(napp->getRpcServices().size(), 2);
EXPECT_EQ(napp->getRpcServices()[0].id, 1);
@@ -125,51 +108,31 @@ TEST_F(TestBase, PwRpcCanNotPublishDuplicateServices) {
}
TEST_F(TestBase, PwRpcDifferentAppCanPublishSameServices) {
- struct App1 : public TestNanoapp {
- uint64_t id = 0x01;
+ class App : public TestNanoapp {
+ public:
+ explicit App(uint64_t id) : TestNanoapp(TestNanoappInfo{.id = id}) {}
- decltype(nanoappStart) *start = []() -> bool {
+ bool start() override {
struct chreNanoappRpcService services[] = {
{.id = 1, .version = 0},
{.id = 2, .version = 0},
};
return chrePublishRpcServices(services, 2 /* numServices */);
- };
- };
-
- struct App2 : public App1 {
- uint64_t id = 0x02;
+ }
};
- auto app1 = loadNanoapp<App1>();
- auto app2 = loadNanoapp<App2>();
-
- uint16_t instanceId1;
- EXPECT_TRUE(EventLoopManagerSingleton::get()
- ->getEventLoop()
- .findNanoappInstanceIdByAppId(app1.id, &instanceId1));
-
- Nanoapp *napp1 =
- EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
- instanceId1);
-
- ASSERT_FALSE(napp1 == nullptr);
+ uint64_t app1Id = loadNanoapp(MakeUnique<App>(0x01));
+ uint64_t app2Id = loadNanoapp(MakeUnique<App>(0x02));
+ Nanoapp *napp1 = getNanoappByAppId(app1Id);
+ ASSERT_NE(napp1, nullptr);
EXPECT_EQ(napp1->getRpcServices().size(), 2);
EXPECT_EQ(napp1->getRpcServices()[0].id, 1);
EXPECT_EQ(napp1->getRpcServices()[1].id, 2);
- uint16_t instanceId2;
- EXPECT_TRUE(EventLoopManagerSingleton::get()
- ->getEventLoop()
- .findNanoappInstanceIdByAppId(app2.id, &instanceId2));
-
- Nanoapp *napp2 =
- EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
- instanceId2);
-
- ASSERT_FALSE(napp2 == nullptr);
+ Nanoapp *napp2 = getNanoappByAppId(app2Id);
+ ASSERT_NE(napp2, nullptr);
EXPECT_EQ(napp2->getRpcServices().size(), 2);
EXPECT_EQ(napp2->getRpcServices()[0].id, 1);
@@ -179,57 +142,51 @@ TEST_F(TestBase, PwRpcDifferentAppCanPublishSameServices) {
TEST_F(TestBase, PwRpcCanNotPublishServicesOutsideOfNanoappStart) {
CREATE_CHRE_TEST_EVENT(PUBLISH_SERVICES, 0);
- struct App : public TestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- switch (eventType) {
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case PUBLISH_SERVICES: {
- struct chreNanoappRpcService services[] = {
- {.id = 1, .version = 0},
- {.id = 2, .version = 0},
- };
-
- bool success =
- chrePublishRpcServices(services, 2 /* numServices */);
- TestEventQueueSingleton::get()->pushEvent(PUBLISH_SERVICES,
- success);
- break;
- }
- }
+ class App : public TestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case PUBLISH_SERVICES: {
+ struct chreNanoappRpcService services[] = {
+ {.id = 1, .version = 0},
+ {.id = 2, .version = 0},
+ };
+
+ bool success =
+ chrePublishRpcServices(services, 2 /* numServices */);
+ TestEventQueueSingleton::get()->pushEvent(PUBLISH_SERVICES,
+ success);
+ break;
}
}
- };
+ }
+ }
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
bool success = true;
- sendEventToNanoapp(app, PUBLISH_SERVICES);
+ sendEventToNanoapp(appId, PUBLISH_SERVICES);
waitForEvent(PUBLISH_SERVICES, &success);
EXPECT_FALSE(success);
- uint16_t instanceId;
- EXPECT_TRUE(EventLoopManagerSingleton::get()
- ->getEventLoop()
- .findNanoappInstanceIdByAppId(app.id, &instanceId));
-
- Nanoapp *napp =
- EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
- instanceId);
-
- ASSERT_FALSE(napp == nullptr);
+ Nanoapp *napp = getNanoappByAppId(appId);
+ ASSERT_NE(napp, nullptr);
EXPECT_EQ(napp->getRpcServices().size(), 0);
}
TEST_F(TestBase, PwRpcRegisterServicesShouldGracefullyFailOnDuplicatedService) {
- struct App : public TestNanoapp {
- decltype(nanoappStart) *start = []() -> bool {
+ class App : public TestNanoapp {
+ public:
+ bool start() override {
static RpcTestService testService;
- EnvSingleton::init();
+
chre::RpcServer::Service service = {.service = testService,
.id = 0xca8f7150a3f05847,
.version = 0x01020034};
@@ -243,49 +200,59 @@ TEST_F(TestBase, PwRpcRegisterServicesShouldGracefullyFailOnDuplicatedService) {
EXPECT_FALSE(server.registerServices(1, &service));
return status;
- };
+ }
+
+ void end() override {
+ EnvSingleton::get()->closeServer();
+ }
};
- auto app = loadNanoapp<App>();
+ EnvSingleton::init();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+ unloadNanoapp(appId);
+ EnvSingleton::deinit();
}
TEST_F(TestBase, PwRpcGetNanoappInfoByAppIdReturnsServices) {
CREATE_CHRE_TEST_EVENT(QUERY_INFO, 0);
- struct App : public TestNanoapp {
- decltype(nanoappStart) *start = []() -> bool {
+ class App : public TestNanoapp {
+ public:
+ bool start() override {
struct chreNanoappRpcService services[] = {
{.id = 1, .version = 2},
{.id = 2, .version = 3},
};
return chrePublishRpcServices(services, 2 /* numServices */);
- };
+ }
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
- static struct chreNanoappInfo info;
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_TEST_EVENT: {
auto event = static_cast<const TestEvent *>(eventData);
switch (event->type) {
case QUERY_INFO: {
auto id = static_cast<uint64_t *>(event->data);
- bool success = chreGetNanoappInfoByAppId(*id, &info);
- const struct chreNanoappInfo *pInfo = success ? &info : nullptr;
+ bool success = chreGetNanoappInfoByAppId(*id, &mInfo);
+ const struct chreNanoappInfo *pInfo = success ? &mInfo : nullptr;
TestEventQueueSingleton::get()->pushEvent(QUERY_INFO, pInfo);
break;
}
}
}
}
- };
+ }
+
+ protected:
+ struct chreNanoappInfo mInfo;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
struct chreNanoappInfo *pInfo = nullptr;
- sendEventToNanoapp(app, QUERY_INFO, app.id);
+ sendEventToNanoapp(appId, QUERY_INFO, appId);
waitForEvent(QUERY_INFO, &pInfo);
EXPECT_TRUE(pInfo != nullptr);
EXPECT_EQ(pInfo->rpcServiceCount, 2);
@@ -301,12 +268,12 @@ TEST_F(TestBase, PwRpcGetNanoappInfoByAppIdReturnsServices) {
TEST_F(TestBase, PwRpcClientNanoappCanRequestServerNanoapp) {
CREATE_CHRE_TEST_EVENT(INCREMENT_REQUEST, 0);
- struct ClientApp : public TestNanoapp {
- uint64_t id = kPwRcpClientAppId;
+ class ClientApp : public TestNanoapp {
+ public:
+ ClientApp() : TestNanoapp(TestNanoappInfo{.id = kPwRcpClientAppId}) {}
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t senderInstanceId,
- uint16_t eventType,
- const void *eventData) {
+ void handleEvent(uint32_t senderInstanceId, uint16_t eventType,
+ const void *eventData) override {
Env *env = EnvSingleton::get();
env->mClient.handleEvent(senderInstanceId, eventType, eventData);
@@ -341,37 +308,49 @@ TEST_F(TestBase, PwRpcClientNanoappCanRequestServerNanoapp) {
}
}
}
- };
+ }
+
+ void end() {
+ EnvSingleton::get()->closeClient();
+ }
};
- struct ServerApp : public TestNanoapp {
- uint64_t id = kPwRcpServerAppId;
- decltype(nanoappStart) *start = []() {
- EnvSingleton::init();
+ class ServerApp : public TestNanoapp {
+ public:
+ ServerApp() : TestNanoapp(TestNanoappInfo{.id = kPwRcpServerAppId}) {}
+
+ bool start() override {
chre::RpcServer::Service service = {
.service = EnvSingleton::get()->mRpcTestService,
.id = 0xca8f7150a3f05847,
.version = 0x01020034};
return EnvSingleton::get()->mServer.registerServices(1, &service);
- };
+ }
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t senderInstanceId,
- uint16_t eventType,
- const void *eventData) {
+ void handleEvent(uint32_t senderInstanceId, uint16_t eventType,
+ const void *eventData) override {
EnvSingleton::get()->mServer.handleEvent(senderInstanceId, eventType,
eventData);
- };
+ }
+
+ void end() {
+ EnvSingleton::get()->closeServer();
+ }
};
- auto server = loadNanoapp<ServerApp>();
- auto client = loadNanoapp<ClientApp>();
+ EnvSingleton::init();
+ uint64_t serverId = loadNanoapp(MakeUnique<ServerApp>());
+ uint64_t clientId = loadNanoapp(MakeUnique<ClientApp>());
bool status;
constexpr uint32_t kNumber = 101;
- sendEventToNanoapp(client, INCREMENT_REQUEST, kNumber);
+ sendEventToNanoapp(clientId, INCREMENT_REQUEST, kNumber);
waitForEvent(INCREMENT_REQUEST, &status);
EXPECT_TRUE(status);
EXPECT_EQ(EnvSingleton::get()->mNumber, kNumber + 1);
+ unloadNanoapp(serverId);
+ unloadNanoapp(clientId);
+ EnvSingleton::deinit();
}
TEST_F(TestBase, PwRpcRpcClientHasServiceCheckForAMatchingService) {
@@ -383,16 +362,15 @@ TEST_F(TestBase, PwRpcRpcClientHasServiceCheckForAMatchingService) {
uint64_t appId;
};
- struct App : public TestNanoapp {
- decltype(nanoappStart) *start = []() -> bool {
+ class App : public TestNanoapp {
+ public:
+ bool start() override {
struct chreNanoappRpcService services[] = {{.id = 1, .version = 2}};
return chrePublishRpcServices(services, 1 /* numServices */);
- };
+ }
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
- static struct chreNanoappInfo info;
+ void handleEvent(uint32_t, uint16_t eventType, const void *eventData) {
switch (eventType) {
case CHRE_EVENT_TEST_EVENT: {
auto event = static_cast<const TestEvent *>(eventData);
@@ -411,20 +389,20 @@ TEST_F(TestBase, PwRpcRpcClientHasServiceCheckForAMatchingService) {
break;
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
ServiceInfo service;
bool hasService = false;
- service = {.id = 1, .version = 2, .appId = app.id};
- sendEventToNanoapp(app, QUERY_HAS_SERVICE, service);
+ service = {.id = 1, .version = 2, .appId = appId};
+ sendEventToNanoapp(appId, QUERY_HAS_SERVICE, service);
waitForEvent(QUERY_HAS_SERVICE, &hasService);
EXPECT_TRUE(hasService);
- service = {.id = 10, .version = 2, .appId = app.id};
- sendEventToNanoapp(app, QUERY_HAS_SERVICE, service);
+ service = {.id = 10, .version = 2, .appId = appId};
+ sendEventToNanoapp(appId, QUERY_HAS_SERVICE, service);
waitForEvent(QUERY_HAS_SERVICE, &hasService);
EXPECT_FALSE(hasService);
}
diff --git a/test/simulation/sensor_test.cc b/test/simulation/sensor_test.cc
index f75a2c17..91d9ad1a 100644
--- a/test/simulation/sensor_test.cc
+++ b/test/simulation/sensor_test.cc
@@ -44,36 +44,38 @@ TEST_F(TestBase, SensorCanSubscribeAndUnsubscribeToDataEvents) {
enum chreSensorConfigureMode mode;
};
- struct App : public TestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- switch (eventType) {
- case CHRE_EVENT_SENSOR_SAMPLING_CHANGE: {
- auto *event =
- static_cast<const struct chreSensorSamplingStatusEvent *>(
- eventData);
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_SENSOR_SAMPLING_CHANGE, *event);
+ class App : public TestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_SENSOR_SAMPLING_CHANGE: {
+ auto *event =
+ static_cast<const struct chreSensorSamplingStatusEvent *>(
+ eventData);
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_SENSOR_SAMPLING_CHANGE, *event);
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case CONFIGURE: {
+ auto config = static_cast<const Configuration *>(event->data);
+ const bool success = chreSensorConfigure(
+ config->sensorHandle, config->mode, config->interval, 0);
+ TestEventQueueSingleton::get()->pushEvent(CONFIGURE, success);
break;
}
-
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case CONFIGURE: {
- auto config = static_cast<const Configuration *>(event->data);
- const bool success = chreSensorConfigure(
- config->sensorHandle, config->mode, config->interval, 0);
- TestEventQueueSingleton::get()->pushEvent(CONFIGURE, success);
- break;
- }
- }
- }
}
- };
+ }
+ }
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
bool success;
EXPECT_FALSE(chrePalSensorIsSensor0Enabled());
@@ -81,7 +83,7 @@ TEST_F(TestBase, SensorCanSubscribeAndUnsubscribeToDataEvents) {
Configuration config{.sensorHandle = 0,
.interval = 100,
.mode = CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS};
- sendEventToNanoapp(app, CONFIGURE, config);
+ sendEventToNanoapp(appId, CONFIGURE, config);
waitForEvent(CONFIGURE, &success);
EXPECT_TRUE(success);
struct chreSensorSamplingStatusEvent event;
@@ -94,7 +96,7 @@ TEST_F(TestBase, SensorCanSubscribeAndUnsubscribeToDataEvents) {
config = {.sensorHandle = 0,
.interval = 50,
.mode = CHRE_SENSOR_CONFIGURE_MODE_DONE};
- sendEventToNanoapp(app, CONFIGURE, config);
+ sendEventToNanoapp(appId, CONFIGURE, config);
waitForEvent(CONFIGURE, &success);
EXPECT_TRUE(success);
EXPECT_FALSE(chrePalSensorIsSensor0Enabled());
@@ -109,42 +111,44 @@ TEST_F(TestBase, SensorUnsubscribeToDataEventsOnUnload) {
enum chreSensorConfigureMode mode;
};
- struct App : public TestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- switch (eventType) {
- case CHRE_EVENT_SENSOR_SAMPLING_CHANGE: {
- auto *event =
- static_cast<const struct chreSensorSamplingStatusEvent *>(
- eventData);
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_SENSOR_SAMPLING_CHANGE, *event);
+ class App : public TestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_SENSOR_SAMPLING_CHANGE: {
+ auto *event =
+ static_cast<const struct chreSensorSamplingStatusEvent *>(
+ eventData);
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_SENSOR_SAMPLING_CHANGE, *event);
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case CONFIGURE: {
+ auto config = static_cast<const Configuration *>(event->data);
+ const bool success = chreSensorConfigure(
+ config->sensorHandle, config->mode, config->interval, 0);
+ TestEventQueueSingleton::get()->pushEvent(CONFIGURE, success);
break;
}
-
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case CONFIGURE: {
- auto config = static_cast<const Configuration *>(event->data);
- const bool success = chreSensorConfigure(
- config->sensorHandle, config->mode, config->interval, 0);
- TestEventQueueSingleton::get()->pushEvent(CONFIGURE, success);
- break;
- }
- }
- }
}
- };
+ }
+ }
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
EXPECT_FALSE(chrePalSensorIsSensor0Enabled());
Configuration config{.sensorHandle = 0,
.interval = 100,
.mode = CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS};
- sendEventToNanoapp(app, CONFIGURE, config);
+ sendEventToNanoapp(appId, CONFIGURE, config);
bool success;
waitForEvent(CONFIGURE, &success);
EXPECT_TRUE(success);
@@ -155,7 +159,7 @@ TEST_F(TestBase, SensorUnsubscribeToDataEventsOnUnload) {
EXPECT_TRUE(event.status.enabled);
EXPECT_TRUE(chrePalSensorIsSensor0Enabled());
- unloadNanoapp(app);
+ unloadNanoapp(appId);
EXPECT_FALSE(chrePalSensorIsSensor0Enabled());
}
diff --git a/test/simulation/settings_test.cc b/test/simulation/settings_test.cc
index c11731e1..8dd5314a 100644
--- a/test/simulation/settings_test.cc
+++ b/test/simulation/settings_test.cc
@@ -35,8 +35,8 @@ namespace chre {
namespace {
-int8_t gExpectedLocationSettingState = CHRE_USER_SETTING_STATE_DISABLED;
-int8_t gExpectedWifiSettingState = CHRE_USER_SETTING_STATE_DISABLED;
+int8_t gExpectedLocationSettingState;
+int8_t gExpectedWifiSettingState;
bool start() {
bool success = chreGnssLocationSessionStartAsync(50, 50, nullptr);
@@ -120,6 +120,9 @@ void startTestNanoapp() {
constexpr uint32_t kAppPerms =
NanoappPermissions::CHRE_PERMS_GNSS | NanoappPermissions::CHRE_PERMS_WIFI;
+ gExpectedLocationSettingState = CHRE_USER_SETTING_STATE_DISABLED;
+ gExpectedWifiSettingState = CHRE_USER_SETTING_STATE_DISABLED;
+
UniquePtr<Nanoapp> nanoapp = createStaticNanoapp(
"Test nanoapp", kAppId, kAppVersion, kAppPerms, start, handleEvent, end);
EventLoopManagerSingleton::get()->deferCallback(
diff --git a/test/simulation/test_base.cc b/test/simulation/test_base.cc
index 622b84cc..bdec520e 100644
--- a/test/simulation/test_base.cc
+++ b/test/simulation/test_base.cc
@@ -76,6 +76,7 @@ void TestBase::TearDown() {
TestEventQueueSingleton::deinit();
TaskManagerSingleton::deinit();
deleteNanoappInfos();
+ unregisterAllTestNanoapps();
}
TEST_F(TestBase, CanLoadAndStartSingleNanoapp) {
@@ -118,6 +119,36 @@ TEST_F(TestBase, CanLoadAndStartMultipleNanoapps) {
EXPECT_NE(id1, id2);
}
+TEST_F(TestBase, methods) {
+ CREATE_CHRE_TEST_EVENT(SOME_EVENT, 0);
+
+ class App : public TestNanoapp {
+ public:
+ explicit App(TestNanoappInfo info) : TestNanoapp(info) {}
+ bool start() override {
+ LOGE("start");
+ mTest = 0xc0ffee;
+ return true;
+ }
+
+ void handleEvent(uint32_t /*senderInstanceId*/, uint16_t /*eventType*/,
+ const void * /**eventData*/) override {
+ LOGE("handleEvent %" PRIx16, mTest);
+ }
+
+ void end() override {
+ LOGE("end");
+ }
+
+ protected:
+ uint32_t mTest = 0;
+ };
+
+ uint64_t appId = loadNanoapp(MakeUnique<App>(TestNanoappInfo{.id = 0x456}));
+
+ sendEventToNanoapp(appId, SOME_EVENT);
+}
+
// Explicitly instantiate the TestEventQueueSingleton to reduce codesize.
template class Singleton<TestEventQueue>;
diff --git a/test/simulation/test_util.cc b/test/simulation/test_util.cc
index acc17fbb..44398ab7 100644
--- a/test/simulation/test_util.cc
+++ b/test/simulation/test_util.cc
@@ -17,6 +17,7 @@
#include "test_util.h"
#include <gtest/gtest.h>
+#include <unordered_map>
#include "chre/core/event_loop_manager.h"
#include "chre/core/nanoapp.h"
@@ -29,13 +30,102 @@
namespace chre {
namespace {
-
-// Keep the chreNslNanoappInfo instances alive for the lifetime of the
-// test nanoapps.
+/**
+ * List of chreNslNanoappInfo.
+ *
+ * Keep the chreNslNanoappInfo instances alive for the lifetime of the test
+ * nanoapps.
+ */
DynamicVector<UniquePtr<chreNslNanoappInfo>> gNanoappInfos;
+/** Registry of nanoapp by ID. */
+std::unordered_map<uint64_t, UniquePtr<TestNanoapp>> nanoapps;
+
+/**
+ * @return a pointer to a registered nanoapp or nullptr if the appId is not
+ * registered.
+ */
+TestNanoapp *queryNanoapp(uint64_t appId) {
+ return nanoapps.count(appId) == 0 ? nullptr : nanoapps[appId].get();
+}
+
+/**
+ * Nanoapp start.
+ *
+ * Invokes the start method of a registered TestNanoapp.
+ */
+bool start() {
+ uint64_t id = chreGetAppId();
+ TestNanoapp *app = queryNanoapp(id);
+ if (app == nullptr) {
+ LOGE("[start] unregistered nanoapp 0x%016" PRIx64, id);
+ return false;
+ }
+ return app->start();
+}
+
+/**
+ * Nanoapp handleEvent.
+ *
+ * Invokes the handleMethod method of a registered TestNanoapp.
+ */
+void handleEvent(uint32_t senderInstanceId, uint16_t eventType,
+ const void *eventData) {
+ uint64_t id = chreGetAppId();
+ TestNanoapp *app = queryNanoapp(id);
+ if (app == nullptr) {
+ LOGE("[handleEvent] unregistered nanoapp 0x%016" PRIx64, id);
+ } else {
+ app->handleEvent(senderInstanceId, eventType, eventData);
+ }
+}
+
+/**
+ * Nanoapp end.
+ *
+ * Invokes the end method of a registered TestNanoapp.
+ */
+void end() {
+ uint64_t id = chreGetAppId();
+ TestNanoapp *app = queryNanoapp(id);
+ if (app == nullptr) {
+ LOGE("[end] unregistered nanoapp 0x%016" PRIx64, id);
+ } else {
+ app->end();
+ }
+}
+
+/**
+ * Registers a test nanoapp.
+ *
+ * TestNanoapps are registered when they are loaded so that their entry point
+ * methods can be called.
+ */
+void registerNanoapp(UniquePtr<TestNanoapp> app) {
+ if (nanoapps.count(app->id()) != 0) {
+ LOGE("A nanoapp with the same id is already registered");
+ } else {
+ nanoapps[app->id()] = std::move(app);
+ }
+}
+
+/**
+ * Unregisters a nanoapp.
+ *
+ * Calls the TestNanoapp destructor.
+ */
+void unregisterNanoapp(uint64_t appId) {
+ if (nanoapps.erase(appId) == 0) {
+ LOGE("The nanoapp is not registered");
+ }
+}
+
} // namespace
+void unregisterAllTestNanoapps() {
+ nanoapps.clear();
+}
+
UniquePtr<Nanoapp> createStaticNanoapp(
const char *name, uint64_t appId, uint32_t appVersion, uint32_t appPerms,
decltype(nanoappStart) *startFunc,
@@ -83,14 +173,11 @@ bool defaultNanoappStart() {
return true;
}
-void defaultNanoappHandleEvent(uint32_t senderInstanceId, uint16_t eventType,
- const void *eventData) {
- UNUSED_VAR(senderInstanceId);
- UNUSED_VAR(eventType);
- UNUSED_VAR(eventData);
-}
+void defaultNanoappHandleEvent(uint32_t /*senderInstanceId*/,
+ uint16_t /*eventType*/,
+ const void * /*eventData*/) {}
-void defaultNanoappEnd(){};
+void defaultNanoappEnd() {}
void loadNanoapp(const char *name, uint64_t appId, uint32_t appVersion,
uint32_t appPerms, decltype(nanoappStart) *startFunc,
@@ -107,8 +194,33 @@ void loadNanoapp(const char *name, uint64_t appId, uint32_t appVersion,
CHRE_EVENT_SIMULATION_TEST_NANOAPP_LOADED);
}
-template <>
-void unloadNanoapp<uint64_t>(uint64_t appId) {
+uint64_t loadNanoapp(UniquePtr<TestNanoapp> app) {
+ TestNanoapp *pApp = app.get();
+ registerNanoapp(std::move(app));
+ loadNanoapp(pApp->name(), pApp->id(), pApp->version(), pApp->perms(), &start,
+ &handleEvent, &end);
+
+ return pApp->id();
+}
+
+void sendEventToNanoapp(uint64_t appId, uint16_t eventType) {
+ uint16_t instanceId;
+ if (EventLoopManagerSingleton::get()
+ ->getEventLoop()
+ .findNanoappInstanceIdByAppId(appId, &instanceId)) {
+ auto event = memoryAlloc<TestEvent>();
+ ASSERT_NE(event, nullptr);
+ event->type = eventType;
+ EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+ CHRE_EVENT_TEST_EVENT, static_cast<void *>(event),
+ freeTestEventDataCallback, instanceId);
+
+ } else {
+ LOGE("No instance found for nanoapp id = 0x%016" PRIx64, appId);
+ }
+}
+
+void unloadNanoapp(uint64_t appId) {
uint64_t *ptr = memoryAlloc<uint64_t>();
ASSERT_NE(ptr, nullptr);
*ptr = appId;
@@ -118,6 +230,8 @@ void unloadNanoapp<uint64_t>(uint64_t appId) {
TestEventQueueSingleton::get()->waitForEvent(
CHRE_EVENT_SIMULATION_TEST_NANOAPP_UNLOADED);
+
+ unregisterNanoapp(appId);
}
void testFinishLoadingNanoappCallback(SystemCallbackType /* type */,
diff --git a/test/simulation/timer_test.cc b/test/simulation/timer_test.cc
index 1e81da02..ff76ddbe 100644
--- a/test/simulation/timer_test.cc
+++ b/test/simulation/timer_test.cc
@@ -46,18 +46,16 @@ TEST_F(TestTimer, SetupAndCancelPeriodicTimer) {
CREATE_CHRE_TEST_EVENT(START_TIMER, 0);
CREATE_CHRE_TEST_EVENT(STOP_TIMER, 1);
- struct App : public TestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
- static const uint32_t cookie = 123;
+ class App : public TestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
- static int count = 0;
-
case CHRE_EVENT_TIMER: {
auto data = static_cast<const uint32_t *>(eventData);
- if (*data == cookie) {
- count++;
- if (count == 3) {
+ if (*data == mCookie) {
+ mCount++;
+ if (mCount == 3) {
TestEventQueueSingleton::get()->pushEvent(CHRE_EVENT_TIMER);
}
}
@@ -68,8 +66,8 @@ TEST_F(TestTimer, SetupAndCancelPeriodicTimer) {
auto event = static_cast<const TestEvent *>(eventData);
switch (event->type) {
case START_TIMER: {
- uint32_t handle = chreTimerSet(kOneMillisecondInNanoseconds,
- &cookie, false /*oneShot*/);
+ uint32_t handle = chreTimerSet(10 * kOneMillisecondInNanoseconds,
+ &mCookie, false /*oneShot*/);
TestEventQueueSingleton::get()->pushEvent(START_TIMER, handle);
break;
}
@@ -82,10 +80,14 @@ TEST_F(TestTimer, SetupAndCancelPeriodicTimer) {
}
}
}
- };
+ }
+
+ protected:
+ const uint32_t mCookie = 123;
+ int mCount = 0;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
TimerPool &timerPool =
EventLoopManagerSingleton::get()->getEventLoop().getTimerPool();
@@ -93,10 +95,10 @@ TEST_F(TestTimer, SetupAndCancelPeriodicTimer) {
uint16_t instanceId;
EXPECT_TRUE(EventLoopManagerSingleton::get()
->getEventLoop()
- .findNanoappInstanceIdByAppId(app.id, &instanceId));
+ .findNanoappInstanceIdByAppId(appId, &instanceId));
uint32_t handle;
- sendEventToNanoapp(app, START_TIMER);
+ sendEventToNanoapp(appId, START_TIMER);
waitForEvent(START_TIMER, &handle);
EXPECT_NE(handle, CHRE_TIMER_INVALID);
EXPECT_TRUE(hasNanoappTimers(timerPool, instanceId));
@@ -106,13 +108,13 @@ TEST_F(TestTimer, SetupAndCancelPeriodicTimer) {
bool success;
// Cancelling an active timer should be successful.
- sendEventToNanoapp(app, STOP_TIMER, handle);
+ sendEventToNanoapp(appId, STOP_TIMER, handle);
waitForEvent(STOP_TIMER, &success);
EXPECT_TRUE(success);
EXPECT_FALSE(hasNanoappTimers(timerPool, instanceId));
// Cancelling an inactive time should return false.
- sendEventToNanoapp(app, STOP_TIMER, handle);
+ sendEventToNanoapp(appId, STOP_TIMER, handle);
waitForEvent(STOP_TIMER, &success);
EXPECT_FALSE(success);
}
@@ -120,18 +122,15 @@ TEST_F(TestTimer, SetupAndCancelPeriodicTimer) {
TEST_F(TestTimer, CancelPeriodicTimerOnUnload) {
CREATE_CHRE_TEST_EVENT(START_TIMER, 0);
- struct App : public TestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
- static const uint32_t cookie = 123;
+ class App : public TestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType, const void *eventData) {
switch (eventType) {
- static int count = 0;
-
case CHRE_EVENT_TIMER: {
auto data = static_cast<const uint32_t *>(eventData);
- if (*data == cookie) {
- count++;
- if (count == 3) {
+ if (*data == mCookie) {
+ mCount++;
+ if (mCount == 3) {
TestEventQueueSingleton::get()->pushEvent(CHRE_EVENT_TIMER);
}
}
@@ -142,18 +141,22 @@ TEST_F(TestTimer, CancelPeriodicTimerOnUnload) {
auto event = static_cast<const TestEvent *>(eventData);
switch (event->type) {
case START_TIMER: {
- uint32_t handle = chreTimerSet(kOneMillisecondInNanoseconds,
- &cookie, false /*oneShot*/);
+ uint32_t handle = chreTimerSet(10 * kOneMillisecondInNanoseconds,
+ &mCookie, false /*oneShot*/);
TestEventQueueSingleton::get()->pushEvent(START_TIMER, handle);
break;
}
}
}
}
- };
+ }
+
+ protected:
+ const uint32_t mCookie = 123;
+ int mCount = 0;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
TimerPool &timerPool =
EventLoopManagerSingleton::get()->getEventLoop().getTimerPool();
@@ -161,17 +164,17 @@ TEST_F(TestTimer, CancelPeriodicTimerOnUnload) {
uint16_t instanceId;
EXPECT_TRUE(EventLoopManagerSingleton::get()
->getEventLoop()
- .findNanoappInstanceIdByAppId(app.id, &instanceId));
+ .findNanoappInstanceIdByAppId(appId, &instanceId));
uint32_t handle;
- sendEventToNanoapp(app, START_TIMER);
+ sendEventToNanoapp(appId, START_TIMER);
waitForEvent(START_TIMER, &handle);
EXPECT_NE(handle, CHRE_TIMER_INVALID);
EXPECT_TRUE(hasNanoappTimers(timerPool, instanceId));
waitForEvent(CHRE_EVENT_TIMER);
- unloadNanoapp(app);
+ unloadNanoapp(appId);
EXPECT_FALSE(hasNanoappTimers(timerPool, instanceId));
}
diff --git a/test/simulation/wifi_nan_test.cc b/test/simulation/wifi_nan_test.cc
index 560e97a7..bab012ee 100644
--- a/test/simulation/wifi_nan_test.cc
+++ b/test/simulation/wifi_nan_test.cc
@@ -53,15 +53,18 @@ namespace {
* - Grant WiFi permissions,
* - Initialize the WiFi state in start.
*/
-struct NanTestNanoapp : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI;
+class NanTestNanoapp : public TestNanoapp {
+ public:
+ NanTestNanoapp()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
- decltype(nanoappStart) *start = []() {
+ bool start() override {
EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
Setting::WIFI_AVAILABLE, true /* enabled */);
PalNanEngineSingleton::get()->setFlags(PalNanEngine::Flags::NONE);
return true;
- };
+ }
};
/**
@@ -71,37 +74,38 @@ struct NanTestNanoapp : public TestNanoapp {
TEST_F(TestBase, WifiNanDisabledViaSettings) {
CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
- struct App : public NanTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- constexpr uint32_t kSubscribeCookie = 0x10aded;
-
- switch (eventType) {
- case CHRE_EVENT_WIFI_ASYNC_RESULT: {
- auto *event = static_cast<const chreAsyncResult *>(eventData);
- if (event->requestType == CHRE_WIFI_REQUEST_TYPE_NAN_SUBSCRIBE) {
- ASSERT_EQ(event->errorCode, CHRE_ERROR_FUNCTION_DISABLED);
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_ASYNC_RESULT);
- }
- break;
- }
+ class App : public NanTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ constexpr uint32_t kSubscribeCookie = 0x10aded;
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case NAN_SUBSCRIBE: {
- auto config = (chreWifiNanSubscribeConfig *)(event->data);
- chreWifiNanSubscribe(config, &kSubscribeCookie);
- break;
- }
- }
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (event->requestType == CHRE_WIFI_REQUEST_TYPE_NAN_SUBSCRIBE) {
+ ASSERT_EQ(event->errorCode, CHRE_ERROR_FUNCTION_DISABLED);
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_ASYNC_RESULT);
+ }
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case NAN_SUBSCRIBE: {
+ auto config = (chreWifiNanSubscribeConfig *)(event->data);
+ chreWifiNanSubscribe(config, &kSubscribeCookie);
+ break;
}
}
- };
+ }
+ }
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
Setting::WIFI_AVAILABLE, false /* enabled */);
@@ -110,7 +114,7 @@ TEST_F(TestBase, WifiNanDisabledViaSettings) {
.subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
.service = "SomeServiceName",
};
- sendEventToNanoapp(app, NAN_SUBSCRIBE, config);
+ sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT);
}
@@ -122,54 +126,54 @@ TEST_F(TestBase, WifiNanDisabledViaSettings) {
TEST_F(TestBase, WifiNanSuccessfulSubscribe) {
CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
- struct App : public NanTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- const uint32_t kSubscribeCookie = 0x10aded;
-
- switch (eventType) {
- case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
- auto event =
- static_cast<const chreWifiNanIdentifierEvent *>(eventData);
- if (event->result.errorCode == CHRE_ERROR_NONE) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
- }
- break;
- }
+ class App : public NanTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ const uint32_t kSubscribeCookie = 0x10aded;
- case CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT: {
- auto event =
- static_cast<const chreWifiNanDiscoveryEvent *>(eventData);
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT, event->subscribeId);
- break;
- }
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
+ auto event =
+ static_cast<const chreWifiNanIdentifierEvent *>(eventData);
+ if (event->result.errorCode == CHRE_ERROR_NONE) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
+ }
+ break;
+ }
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case NAN_SUBSCRIBE: {
- auto config = (chreWifiNanSubscribeConfig *)(event->data);
- const bool success =
- chreWifiNanSubscribe(config, &kSubscribeCookie);
- TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE,
- success);
- break;
- }
- }
+ case CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT: {
+ auto event =
+ static_cast<const chreWifiNanDiscoveryEvent *>(eventData);
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT, event->subscribeId);
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case NAN_SUBSCRIBE: {
+ auto config = (chreWifiNanSubscribeConfig *)(event->data);
+ const bool success =
+ chreWifiNanSubscribe(config, &kSubscribeCookie);
+ TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE, success);
+ break;
}
}
- };
+ }
+ }
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
chreWifiNanSubscribeConfig config = {
.subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
.service = "SomeServiceName",
};
- sendEventToNanoapp(app, NAN_SUBSCRIBE, config);
+ sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
bool success;
waitForEvent(NAN_SUBSCRIBE, &success);
EXPECT_TRUE(success);
@@ -188,46 +192,46 @@ TEST_F(TestBase, WifiNanSuccessfulSubscribe) {
TEST_F(TestBase, WifiNanUnsSubscribeOnNanoappUnload) {
CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
- struct App : public NanTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- const uint32_t kSubscribeCookie = 0x10aded;
-
- switch (eventType) {
- case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
- auto event =
- static_cast<const chreWifiNanIdentifierEvent *>(eventData);
- if (event->result.errorCode == CHRE_ERROR_NONE) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
- }
- break;
- }
+ class App : public NanTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ const uint32_t kSubscribeCookie = 0x10aded;
+
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
+ auto event =
+ static_cast<const chreWifiNanIdentifierEvent *>(eventData);
+ if (event->result.errorCode == CHRE_ERROR_NONE) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
+ }
+ break;
+ }
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case NAN_SUBSCRIBE: {
- auto config = (chreWifiNanSubscribeConfig *)(event->data);
- const bool success =
- chreWifiNanSubscribe(config, &kSubscribeCookie);
- TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE,
- success);
- break;
- }
- }
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case NAN_SUBSCRIBE: {
+ auto config = (chreWifiNanSubscribeConfig *)(event->data);
+ const bool success =
+ chreWifiNanSubscribe(config, &kSubscribeCookie);
+ TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE, success);
+ break;
}
}
- };
+ }
+ }
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
chreWifiNanSubscribeConfig config = {
.subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
.service = "SomeServiceName",
};
- sendEventToNanoapp(app, NAN_SUBSCRIBE, config);
+ sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
bool success;
waitForEvent(NAN_SUBSCRIBE, &success);
EXPECT_TRUE(success);
@@ -236,7 +240,7 @@ TEST_F(TestBase, WifiNanUnsSubscribeOnNanoappUnload) {
waitForEvent(CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, &id);
EXPECT_TRUE(PalNanEngineSingleton::get()->isSubscriptionActive(id));
- unloadNanoapp(app);
+ unloadNanoapp(appId);
EXPECT_FALSE(PalNanEngineSingleton::get()->isSubscriptionActive(id));
}
@@ -249,40 +253,40 @@ TEST_F(TestBase, WifiNanUnsSubscribeOnNanoappUnload) {
TEST_F(TestBase, WifiNanUnuccessfulSubscribeTest) {
CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
- struct App : public NanTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- const uint32_t kSubscribeCookie = 0x10aded;
-
- switch (eventType) {
- case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
- auto event =
- static_cast<const chreWifiNanIdentifierEvent *>(eventData);
- if (event->result.errorCode != CHRE_ERROR_NONE) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT);
- }
- break;
- }
+ class App : public NanTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ const uint32_t kSubscribeCookie = 0x10aded;
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case NAN_SUBSCRIBE: {
- auto config = (chreWifiNanSubscribeConfig *)(event->data);
- const bool success =
- chreWifiNanSubscribe(config, &kSubscribeCookie);
- TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE,
- success);
- break;
- }
- }
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
+ auto event =
+ static_cast<const chreWifiNanIdentifierEvent *>(eventData);
+ if (event->result.errorCode != CHRE_ERROR_NONE) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT);
+ }
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case NAN_SUBSCRIBE: {
+ auto config = (chreWifiNanSubscribeConfig *)(event->data);
+ const bool success =
+ chreWifiNanSubscribe(config, &kSubscribeCookie);
+ TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE, success);
+ break;
}
}
- };
+ }
+ }
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
PalNanEngineSingleton::get()->setFlags(PalNanEngine::Flags::FAIL_SUBSCRIBE);
@@ -290,7 +294,7 @@ TEST_F(TestBase, WifiNanUnuccessfulSubscribeTest) {
.subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
.service = "SomeServiceName",
};
- sendEventToNanoapp(app, NAN_SUBSCRIBE, config);
+ sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
bool success;
waitForEvent(NAN_SUBSCRIBE, &success);
EXPECT_TRUE(success);
@@ -305,9 +309,10 @@ TEST_F(TestBase, WifiNanUnuccessfulSubscribeTest) {
TEST_F(TestBase, WifiNanServiceTerminatedTest) {
CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
- struct App : public NanTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
+ class App : public NanTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
const uint32_t kSubscribeCookie = 0x10aded;
switch (eventType) {
@@ -350,16 +355,16 @@ TEST_F(TestBase, WifiNanServiceTerminatedTest) {
}
}
}
- };
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
chreWifiNanSubscribeConfig config = {
.subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
.service = "SomeServiceName",
};
- sendEventToNanoapp(app, NAN_SUBSCRIBE, config);
+ sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
bool success;
waitForEvent(NAN_SUBSCRIBE, &success);
EXPECT_TRUE(success);
@@ -390,63 +395,63 @@ TEST_F(TestBase, WifiNanServiceLostTest) {
uint32_t publish;
};
- struct App : public NanTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- const uint32_t kSubscribeCookie = 0x10aded;
-
- switch (eventType) {
- case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
- auto event =
- static_cast<const chreWifiNanIdentifierEvent *>(eventData);
- if (event->result.errorCode == CHRE_ERROR_NONE) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
- }
- break;
- }
+ class App : public NanTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ const uint32_t kSubscribeCookie = 0x10aded;
- case CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT: {
- auto event =
- static_cast<const chreWifiNanDiscoveryEvent *>(eventData);
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT, event->subscribeId);
- break;
- }
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
+ auto event =
+ static_cast<const chreWifiNanIdentifierEvent *>(eventData);
+ if (event->result.errorCode == CHRE_ERROR_NONE) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
+ }
+ break;
+ }
- case CHRE_EVENT_WIFI_NAN_SESSION_LOST: {
- auto event =
- static_cast<const chreWifiNanSessionLostEvent *>(eventData);
- Ids ids = {.subscribe = event->id, .publish = event->peerId};
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_NAN_SESSION_LOST, ids);
- break;
- }
+ case CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT: {
+ auto event =
+ static_cast<const chreWifiNanDiscoveryEvent *>(eventData);
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT, event->subscribeId);
+ break;
+ }
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case NAN_SUBSCRIBE: {
- auto config = (chreWifiNanSubscribeConfig *)(event->data);
- const bool success =
- chreWifiNanSubscribe(config, &kSubscribeCookie);
- TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE,
- success);
- break;
- }
- }
+ case CHRE_EVENT_WIFI_NAN_SESSION_LOST: {
+ auto event =
+ static_cast<const chreWifiNanSessionLostEvent *>(eventData);
+ Ids ids = {.subscribe = event->id, .publish = event->peerId};
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_NAN_SESSION_LOST, ids);
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case NAN_SUBSCRIBE: {
+ auto config = (chreWifiNanSubscribeConfig *)(event->data);
+ const bool success =
+ chreWifiNanSubscribe(config, &kSubscribeCookie);
+ TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE, success);
+ break;
}
}
- };
+ }
+ }
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
chreWifiNanSubscribeConfig config = {
.subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
.service = "SomeServiceName",
};
- sendEventToNanoapp(app, NAN_SUBSCRIBE, config);
+ sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
bool success;
waitForEvent(NAN_SUBSCRIBE, &success);
EXPECT_TRUE(success);
@@ -474,70 +479,71 @@ TEST_F(TestBase, WifiNanRangingTest) {
CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
CREATE_CHRE_TEST_EVENT(REQUEST_RANGING, 1);
- struct App : public NanTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- const uint32_t kRangingCookie = 0xfa11;
- const uint32_t kSubscribeCookie = 0x10aded;
-
- switch (eventType) {
- case CHRE_EVENT_WIFI_ASYNC_RESULT: {
- auto *event = static_cast<const chreAsyncResult *>(eventData);
- if (event->requestType == CHRE_WIFI_REQUEST_TYPE_RANGING) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_ASYNC_RESULT);
- }
- break;
- }
+ class App : public NanTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ const uint32_t kRangingCookie = 0xfa11;
+ const uint32_t kSubscribeCookie = 0x10aded;
+
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (event->requestType == CHRE_WIFI_REQUEST_TYPE_RANGING) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_ASYNC_RESULT);
+ }
+ break;
+ }
+
+ case CHRE_EVENT_WIFI_RANGING_RESULT: {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_RANGING_RESULT);
+ break;
+ }
- case CHRE_EVENT_WIFI_RANGING_RESULT: {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_RANGING_RESULT);
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case NAN_SUBSCRIBE: {
+ auto config = (chreWifiNanSubscribeConfig *)(event->data);
+ const bool success =
+ chreWifiNanSubscribe(config, &kSubscribeCookie);
+ TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE, success);
break;
}
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case NAN_SUBSCRIBE: {
- auto config = (chreWifiNanSubscribeConfig *)(event->data);
- const bool success =
- chreWifiNanSubscribe(config, &kSubscribeCookie);
- TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE,
- success);
- break;
- }
-
- case REQUEST_RANGING: {
- uint8_t fakeMacAddress[CHRE_WIFI_BSSID_LEN] = {0x1, 0x2, 0x3,
- 0x4, 0x5, 0x6};
- struct chreWifiNanRangingParams fakeRangingParams;
- std::memcpy(fakeRangingParams.macAddress, fakeMacAddress,
- CHRE_WIFI_BSSID_LEN);
- const bool success = chreWifiNanRequestRangingAsync(
- &fakeRangingParams, &kRangingCookie);
- TestEventQueueSingleton::get()->pushEvent(REQUEST_RANGING,
- success);
- break;
- }
- }
+ case REQUEST_RANGING: {
+ uint8_t fakeMacAddress[CHRE_WIFI_BSSID_LEN] = {0x1, 0x2, 0x3,
+ 0x4, 0x5, 0x6};
+ struct chreWifiNanRangingParams fakeRangingParams;
+ std::memcpy(fakeRangingParams.macAddress, fakeMacAddress,
+ CHRE_WIFI_BSSID_LEN);
+ const bool success = chreWifiNanRequestRangingAsync(
+ &fakeRangingParams, &kRangingCookie);
+ TestEventQueueSingleton::get()->pushEvent(REQUEST_RANGING,
+ success);
+ break;
}
}
- };
+ }
+ }
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
bool success;
chreWifiNanSubscribeConfig config = {
.subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
.service = "SomeServiceName",
};
- sendEventToNanoapp(app, NAN_SUBSCRIBE, config);
+ sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
waitForEvent(NAN_SUBSCRIBE, &success);
EXPECT_TRUE(success);
- sendEventToNanoapp(app, REQUEST_RANGING, config);
+ sendEventToNanoapp(appId, REQUEST_RANGING, config);
waitForEvent(REQUEST_RANGING, &success);
EXPECT_TRUE(success);
waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT);
@@ -550,52 +556,52 @@ TEST_F(TestBase, WifiNanSubscribeCancelTest) {
CREATE_CHRE_TEST_EVENT(NAN_UNSUBSCRIBE, 2);
CREATE_CHRE_TEST_EVENT(NAN_UNSUBSCRIBE_DONE, 3);
- struct App : public NanTestNanoapp {
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- const uint32_t kSubscribeCookie = 0x10aded;
-
- switch (eventType) {
- case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
- auto event =
- static_cast<const chreWifiNanIdentifierEvent *>(eventData);
- if (event->result.errorCode == CHRE_ERROR_NONE) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
- }
+ class App : public NanTestNanoapp {
+ public:
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ const uint32_t kSubscribeCookie = 0x10aded;
+
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
+ auto event =
+ static_cast<const chreWifiNanIdentifierEvent *>(eventData);
+ if (event->result.errorCode == CHRE_ERROR_NONE) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
+ }
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case NAN_SUBSCRIBE: {
+ auto config = (chreWifiNanSubscribeConfig *)(event->data);
+ bool success = chreWifiNanSubscribe(config, &kSubscribeCookie);
+ TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE_DONE,
+ success);
break;
}
-
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case NAN_SUBSCRIBE: {
- auto config = (chreWifiNanSubscribeConfig *)(event->data);
- bool success =
- chreWifiNanSubscribe(config, &kSubscribeCookie);
- TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE_DONE,
- success);
- break;
- }
- case NAN_UNSUBSCRIBE: {
- auto *id = static_cast<uint32_t *>(event->data);
- bool success = chreWifiNanSubscribeCancel(*id);
- // Note that since we're 'simulating' NAN functionality here,
- // the async subscribe cancel event will be handled before
- // the return event below is posted. For a real on-device (or
- // non-simulated) test, this won't be the case, and care must
- // be taken to handle the asynchronicity appropriately.
- TestEventQueueSingleton::get()->pushEvent(
- NAN_UNSUBSCRIBE_DONE, success);
- break;
- }
- }
+ case NAN_UNSUBSCRIBE: {
+ auto *id = static_cast<uint32_t *>(event->data);
+ bool success = chreWifiNanSubscribeCancel(*id);
+ // Note that since we're 'simulating' NAN functionality here,
+ // the async subscribe cancel event will be handled before
+ // the return event below is posted. For a real on-device (or
+ // non-simulated) test, this won't be the case, and care must
+ // be taken to handle the asynchronicity appropriately.
+ TestEventQueueSingleton::get()->pushEvent(NAN_UNSUBSCRIBE_DONE,
+ success);
+ break;
}
}
- };
+ }
+ }
+ }
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
chreWifiNanSubscribeConfig config = {
.subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
@@ -603,7 +609,7 @@ TEST_F(TestBase, WifiNanSubscribeCancelTest) {
};
bool success = false;
- sendEventToNanoapp(app, NAN_SUBSCRIBE, config);
+ sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
waitForEvent(NAN_SUBSCRIBE_DONE, &success);
ASSERT_TRUE(success);
@@ -615,7 +621,7 @@ TEST_F(TestBase, WifiNanSubscribeCancelTest) {
EXPECT_EQ(wifiRequestManager.getNumNanSubscriptions(), 1);
success = false;
- sendEventToNanoapp(app, NAN_UNSUBSCRIBE, id);
+ sendEventToNanoapp(appId, NAN_UNSUBSCRIBE, id);
waitForEvent(NAN_UNSUBSCRIBE_DONE, &success);
ASSERT_TRUE(success);
// TODO(b/272351526): consider adding an async result event to catch when the
diff --git a/test/simulation/wifi_scan_test.cc b/test/simulation/wifi_scan_test.cc
index 4f8d80d3..70bfa7c9 100644
--- a/test/simulation/wifi_scan_test.cc
+++ b/test/simulation/wifi_scan_test.cc
@@ -40,6 +40,9 @@ struct WifiAsyncData {
chreError errorCode;
};
+constexpr uint64_t kAppOneId = 0x0123456789000001;
+constexpr uint64_t kAppTwoId = 0x0123456789000002;
+
class WifiScanRequestQueueTestBase : public TestBase {
public:
void SetUp() {
@@ -56,15 +59,18 @@ class WifiScanRequestQueueTestBase : public TestBase {
}
};
-struct WifiScanTestNanoapp : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI;
+class WifiScanTestNanoapp : public TestNanoapp {
+ public:
+ WifiScanTestNanoapp()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
- constexpr uint8_t kMaxPendingCookie = 10;
- static uint32_t cookies[kMaxPendingCookie];
- static uint8_t nextFreeCookieIndex = 0;
+ explicit WifiScanTestNanoapp(uint64_t id)
+ : TestNanoapp(TestNanoappInfo{
+ .id = id, .perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_WIFI_ASYNC_RESULT: {
auto *event = static_cast<const chreAsyncResult *>(eventData);
@@ -86,12 +92,12 @@ struct WifiScanTestNanoapp : public TestNanoapp {
switch (event->type) {
case SCAN_REQUEST:
bool success = false;
- if (nextFreeCookieIndex < kMaxPendingCookie) {
- cookies[nextFreeCookieIndex] =
+ if (mNextFreeCookieIndex < kMaxPendingCookie) {
+ mCookies[mNextFreeCookieIndex] =
*static_cast<uint32_t *>(event->data);
success = chreWifiRequestScanAsyncDefault(
- &cookies[nextFreeCookieIndex]);
- nextFreeCookieIndex++;
+ &mCookies[mNextFreeCookieIndex]);
+ mNextFreeCookieIndex++;
} else {
LOGE("Too many cookies passed from test body!");
}
@@ -99,11 +105,16 @@ struct WifiScanTestNanoapp : public TestNanoapp {
}
}
}
- };
+ }
+
+ protected:
+ static constexpr uint8_t kMaxPendingCookie = 10;
+ uint32_t mCookies[kMaxPendingCookie];
+ uint8_t mNextFreeCookieIndex = 0;
};
TEST_F(TestBase, WifiScanBasicSettingTest) {
- auto app = loadNanoapp<WifiScanTestNanoapp>();
+ uint64_t appId = loadNanoapp(MakeUnique<WifiScanTestNanoapp>());
EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
Setting::WIFI_AVAILABLE, true /* enabled */);
@@ -112,7 +123,7 @@ TEST_F(TestBase, WifiScanBasicSettingTest) {
bool success;
WifiAsyncData wifiAsyncData;
- sendEventToNanoapp(app, SCAN_REQUEST, firstCookie);
+ sendEventToNanoapp(appId, SCAN_REQUEST, firstCookie);
waitForEvent(SCAN_REQUEST, &success);
EXPECT_TRUE(success);
@@ -125,7 +136,7 @@ TEST_F(TestBase, WifiScanBasicSettingTest) {
Setting::WIFI_AVAILABLE, false /* enabled */);
constexpr uint32_t secondCookie = 0x2020;
- sendEventToNanoapp(app, SCAN_REQUEST, secondCookie);
+ sendEventToNanoapp(appId, SCAN_REQUEST, secondCookie);
waitForEvent(SCAN_REQUEST, &success);
EXPECT_TRUE(success);
@@ -135,67 +146,197 @@ TEST_F(TestBase, WifiScanBasicSettingTest) {
EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
Setting::WIFI_AVAILABLE, true /* enabled */);
- unloadNanoapp(app);
+ unloadNanoapp(appId);
}
TEST_F(WifiScanRequestQueueTestBase, WifiQueuedScanSettingChangeTest) {
- struct WifiScanTestNanoappTwo : public WifiScanTestNanoapp {
- uint64_t id = 0x1123456789abcdef;
+ CREATE_CHRE_TEST_EVENT(CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT,
+ 1);
+ CREATE_CHRE_TEST_EVENT(CONCURRENT_NANOAPP_READ_ASYNC_EVENT, 2);
+ // Expecting to receive two event, one from each nanoapp.
+ constexpr uint8_t kExpectedReceiveAsyncResultCount = 2;
+ // receivedAsyncEventCount is shared across apps and must be static.
+ // But we want it initialized each time the test is executed.
+ static uint8_t receivedAsyncEventCount;
+ receivedAsyncEventCount = 0;
+
+ class WifiScanTestConcurrentNanoapp : public TestNanoapp {
+ public:
+ explicit WifiScanTestConcurrentNanoapp(uint64_t id)
+ : TestNanoapp(TestNanoappInfo{
+ .id = id, .perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ mReceivedAsyncResult = WifiAsyncData{
+ .cookie = static_cast<const uint32_t *>(event->cookie),
+ .errorCode = static_cast<chreError>(event->errorCode)};
+ ++receivedAsyncEventCount;
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ bool success = false;
+ switch (event->type) {
+ case SCAN_REQUEST:
+ mSentCookie = *static_cast<uint32_t *>(event->data);
+ success = chreWifiRequestScanAsyncDefault(&(mSentCookie));
+ TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST, success);
+ break;
+ case CONCURRENT_NANOAPP_READ_ASYNC_EVENT:
+ TestEventQueueSingleton::get()->pushEvent(
+ CONCURRENT_NANOAPP_READ_ASYNC_EVENT, mReceivedAsyncResult);
+ break;
+ }
+ }
+ }
+
+ if (receivedAsyncEventCount == kExpectedReceiveAsyncResultCount) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT);
+ }
+ }
+
+ protected:
+ uint32_t mSentCookie;
+ WifiAsyncData mReceivedAsyncResult;
};
- auto firstApp = loadNanoapp<WifiScanTestNanoapp>();
- auto secondApp = loadNanoapp<WifiScanTestNanoappTwo>();
+ uint64_t appOneId =
+ loadNanoapp(MakeUnique<WifiScanTestConcurrentNanoapp>(kAppOneId));
+ uint64_t appTwoId =
+ loadNanoapp(MakeUnique<WifiScanTestConcurrentNanoapp>(kAppTwoId));
- constexpr uint32_t firstRequestCookie = 0x1010;
- constexpr uint32_t secondRequestCookie = 0x2020;
+ constexpr uint32_t appOneRequestCookie = 0x1010;
+ constexpr uint32_t appTwoRequestCookie = 0x2020;
bool success;
- sendEventToNanoapp(firstApp, SCAN_REQUEST, firstRequestCookie);
+ sendEventToNanoapp(appOneId, SCAN_REQUEST, appOneRequestCookie);
waitForEvent(SCAN_REQUEST, &success);
EXPECT_TRUE(success);
- sendEventToNanoapp(secondApp, SCAN_REQUEST, secondRequestCookie);
+ sendEventToNanoapp(appTwoId, SCAN_REQUEST, appTwoRequestCookie);
waitForEvent(SCAN_REQUEST, &success);
EXPECT_TRUE(success);
EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
Setting::WIFI_AVAILABLE, false /* enabled */);
+ // We need to make sure that each nanoapp has received one async result before
+ // further analysis.
+ waitForEvent(CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT);
+
WifiAsyncData wifiAsyncData;
- waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &wifiAsyncData);
+ sendEventToNanoapp(appOneId, CONCURRENT_NANOAPP_READ_ASYNC_EVENT);
+ waitForEvent(CONCURRENT_NANOAPP_READ_ASYNC_EVENT, &wifiAsyncData);
EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_NONE);
- EXPECT_EQ(*wifiAsyncData.cookie, firstRequestCookie);
- waitForEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
+ EXPECT_EQ(*wifiAsyncData.cookie, appOneRequestCookie);
- waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &wifiAsyncData);
+ sendEventToNanoapp(appTwoId, CONCURRENT_NANOAPP_READ_ASYNC_EVENT);
+ waitForEvent(CONCURRENT_NANOAPP_READ_ASYNC_EVENT, &wifiAsyncData);
EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_FUNCTION_DISABLED);
- EXPECT_EQ(*wifiAsyncData.cookie, secondRequestCookie);
+ EXPECT_EQ(*wifiAsyncData.cookie, appTwoRequestCookie);
EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
Setting::WIFI_AVAILABLE, true /* enabled */);
- unloadNanoapp(firstApp);
- unloadNanoapp(secondApp);
+ unloadNanoapp(appOneId);
+ unloadNanoapp(appTwoId);
}
TEST_F(WifiScanRequestQueueTestBase, WifiScanRejectRequestFromSameNanoapp) {
- auto app = loadNanoapp<WifiScanTestNanoapp>();
+ CREATE_CHRE_TEST_EVENT(RECEIVED_ALL_EXPECTED_EVENTS, 1);
+ CREATE_CHRE_TEST_EVENT(READ_ASYNC_EVENT, 2);
- constexpr uint32_t firstRequestCookie = 0x1010;
- constexpr uint32_t secondRequestCookie = 0x2020;
+ static constexpr uint8_t kExpectedReceivedScanRequestCount = 2;
+
+ class WifiScanTestBufferedAsyncResultNanoapp : public TestNanoapp {
+ public:
+ WifiScanTestBufferedAsyncResultNanoapp()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ mReceivedAsyncResult = WifiAsyncData{
+ .cookie = static_cast<const uint32_t *>(event->cookie),
+ .errorCode = static_cast<chreError>(event->errorCode)};
+ ++mReceivedAsyncEventCount;
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ bool success = false;
+ switch (event->type) {
+ case SCAN_REQUEST:
+ if (mReceivedScanRequestCount >=
+ kExpectedReceivedScanRequestCount) {
+ LOGE("Asking too many scan request");
+ } else {
+ mReceivedCookies[mReceivedScanRequestCount] =
+ *static_cast<uint32_t *>(event->data);
+ success = chreWifiRequestScanAsyncDefault(
+ &(mReceivedCookies[mReceivedScanRequestCount]));
+ ++mReceivedScanRequestCount;
+ TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST,
+ success);
+ }
+ break;
+ case READ_ASYNC_EVENT:
+ TestEventQueueSingleton::get()->pushEvent(READ_ASYNC_EVENT,
+ mReceivedAsyncResult);
+ break;
+ }
+ }
+ }
+ if (mReceivedAsyncEventCount == kExpectedReceivedAsyncResultCount &&
+ mReceivedScanRequestCount == kExpectedReceivedScanRequestCount) {
+ TestEventQueueSingleton::get()->pushEvent(RECEIVED_ALL_EXPECTED_EVENTS);
+ }
+ }
+
+ protected:
+ // We are only expecting to receive one async result since the second
+ // request is expected to fail.
+ const uint8_t kExpectedReceivedAsyncResultCount = 1;
+ uint8_t mReceivedAsyncEventCount = 0;
+ uint8_t mReceivedScanRequestCount = 0;
+
+ // We need to have two cookie storage to separate the two scan request.
+ uint32_t mReceivedCookies[kExpectedReceivedScanRequestCount];
+ WifiAsyncData mReceivedAsyncResult;
+ };
+
+ uint64_t appId =
+ loadNanoapp(MakeUnique<WifiScanTestBufferedAsyncResultNanoapp>());
+
+ constexpr uint32_t kFirstRequestCookie = 0x1010;
+ constexpr uint32_t kSecondRequestCookie = 0x2020;
bool success;
- sendEventToNanoapp(app, SCAN_REQUEST, firstRequestCookie);
+ sendEventToNanoapp(appId, SCAN_REQUEST, kFirstRequestCookie);
waitForEvent(SCAN_REQUEST, &success);
EXPECT_TRUE(success);
- sendEventToNanoapp(app, SCAN_REQUEST, secondRequestCookie);
+ sendEventToNanoapp(appId, SCAN_REQUEST, kSecondRequestCookie);
waitForEvent(SCAN_REQUEST, &success);
EXPECT_FALSE(success);
+ // We need to make sure that the nanoapp has received one async result and did
+ // two scan requests before further analysis.
+ waitForEvent(RECEIVED_ALL_EXPECTED_EVENTS);
+
WifiAsyncData wifiAsyncData;
- waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &wifiAsyncData);
+ sendEventToNanoapp(appId, READ_ASYNC_EVENT);
+ waitForEvent(READ_ASYNC_EVENT, &wifiAsyncData);
EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_NONE);
- EXPECT_EQ(*wifiAsyncData.cookie, firstRequestCookie);
- waitForEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
+ EXPECT_EQ(*wifiAsyncData.cookie, kFirstRequestCookie);
- unloadNanoapp(app);
+ unloadNanoapp(appId);
}
TEST_F(WifiScanRequestQueueTestBase, WifiScanActiveScanFromDistinctNanoapps) {
@@ -203,36 +344,25 @@ TEST_F(WifiScanRequestQueueTestBase, WifiScanActiveScanFromDistinctNanoapps) {
1);
CREATE_CHRE_TEST_EVENT(CONCURRENT_NANOAPP_READ_COOKIE, 2);
- struct AppCookies {
- uint32_t sent = 0;
- uint32_t received = 0;
- };
-
- constexpr uint64_t kAppOneId = 0x0123456789000001;
- constexpr uint64_t kAppTwoId = 0x0123456789000002;
-
- struct WifiScanTestConcurrentNanoappOne : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI;
- uint64_t id = kAppOneId;
+ constexpr uint8_t kExpectedReceiveAsyncResultCount = 2;
+ // receivedCookieCount is shared across apps and must be static.
+ // But we want it initialized each time the test is executed.
+ static uint8_t receivedCookieCount;
+ receivedCookieCount = 0;
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
- constexpr uint8_t kExpectedReceiveAsyncResultCount = 2;
- static uint8_t receivedCookieCount = 0;
- static AppCookies appOneCookies;
- static AppCookies appTwoCookies;
-
- // Retrieve cookies from different apps that have the same access to
- // static storage due to inheritance.
- AppCookies *appCookies =
- chreGetAppId() == kAppTwoId ? &appTwoCookies : &appOneCookies;
+ class WifiScanTestConcurrentNanoapp : public TestNanoapp {
+ public:
+ explicit WifiScanTestConcurrentNanoapp(uint64_t id)
+ : TestNanoapp(TestNanoappInfo{
+ .id = id, .perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
switch (eventType) {
case CHRE_EVENT_WIFI_ASYNC_RESULT: {
auto *event = static_cast<const chreAsyncResult *>(eventData);
if (event->errorCode == CHRE_ERROR_NONE) {
- appCookies->received =
- *static_cast<const uint32_t *>(event->cookie);
+ mReceivedCookie = *static_cast<const uint32_t *>(event->cookie);
++receivedCookieCount;
} else {
LOGE("Received failed async result");
@@ -248,54 +378,54 @@ TEST_F(WifiScanRequestQueueTestBase, WifiScanActiveScanFromDistinctNanoapps) {
case CHRE_EVENT_TEST_EVENT: {
auto event = static_cast<const TestEvent *>(eventData);
bool success = false;
- uint32_t expectedCookie;
switch (event->type) {
case SCAN_REQUEST:
- appCookies->sent = *static_cast<uint32_t *>(event->data);
- success = chreWifiRequestScanAsyncDefault(&(appCookies->sent));
+ mSentCookie = *static_cast<uint32_t *>(event->data);
+ success = chreWifiRequestScanAsyncDefault(&(mSentCookie));
TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST, success);
break;
case CONCURRENT_NANOAPP_READ_COOKIE:
TestEventQueueSingleton::get()->pushEvent(
- CONCURRENT_NANOAPP_READ_COOKIE, appCookies->received);
+ CONCURRENT_NANOAPP_READ_COOKIE, mReceivedCookie);
break;
}
}
- };
- };
- };
+ }
+ }
- struct WifiScanTestConcurrentNanoappTwo
- : public WifiScanTestConcurrentNanoappOne {
- uint64_t id = kAppTwoId;
+ protected:
+ uint32_t mSentCookie;
+ uint32_t mReceivedCookie;
};
- auto appOne = loadNanoapp<WifiScanTestConcurrentNanoappOne>();
- auto appTwo = loadNanoapp<WifiScanTestConcurrentNanoappTwo>();
+ uint64_t appOneId =
+ loadNanoapp(MakeUnique<WifiScanTestConcurrentNanoapp>(kAppOneId));
+ uint64_t appTwoId =
+ loadNanoapp(MakeUnique<WifiScanTestConcurrentNanoapp>(kAppTwoId));
constexpr uint32_t kAppOneRequestCookie = 0x1010;
constexpr uint32_t kAppTwoRequestCookie = 0x2020;
bool success;
- sendEventToNanoapp(appOne, SCAN_REQUEST, kAppOneRequestCookie);
+ sendEventToNanoapp(appOneId, SCAN_REQUEST, kAppOneRequestCookie);
waitForEvent(SCAN_REQUEST, &success);
EXPECT_TRUE(success);
- sendEventToNanoapp(appTwo, SCAN_REQUEST, kAppTwoRequestCookie);
+ sendEventToNanoapp(appTwoId, SCAN_REQUEST, kAppTwoRequestCookie);
waitForEvent(SCAN_REQUEST, &success);
EXPECT_TRUE(success);
waitForEvent(CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT);
uint32_t receivedCookie;
- sendEventToNanoapp(appOne, CONCURRENT_NANOAPP_READ_COOKIE);
+ sendEventToNanoapp(appOneId, CONCURRENT_NANOAPP_READ_COOKIE);
waitForEvent(CONCURRENT_NANOAPP_READ_COOKIE, &receivedCookie);
EXPECT_EQ(kAppOneRequestCookie, receivedCookie);
- sendEventToNanoapp(appTwo, CONCURRENT_NANOAPP_READ_COOKIE);
+ sendEventToNanoapp(appTwoId, CONCURRENT_NANOAPP_READ_COOKIE);
waitForEvent(CONCURRENT_NANOAPP_READ_COOKIE, &receivedCookie);
EXPECT_EQ(kAppTwoRequestCookie, receivedCookie);
- unloadNanoapp(appOne);
- unloadNanoapp(appTwo);
+ unloadNanoapp(appOneId);
+ unloadNanoapp(appTwoId);
}
} // namespace
diff --git a/test/simulation/wifi_test.cc b/test/simulation/wifi_test.cc
index 43c9384c..deca31c8 100644
--- a/test/simulation/wifi_test.cc
+++ b/test/simulation/wifi_test.cc
@@ -41,53 +41,58 @@ TEST_F(TestBase, WifiCanSubscribeAndUnsubscribeToScanMonitoring) {
uint32_t cookie;
};
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI;
-
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- static uint32_t cookie;
-
- switch (eventType) {
- case CHRE_EVENT_WIFI_ASYNC_RESULT: {
- auto *event = static_cast<const chreAsyncResult *>(eventData);
- if (event->success) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_ASYNC_RESULT,
- *(static_cast<const uint32_t *>(event->cookie)));
- }
- break;
- }
-
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case MONITORING_REQUEST:
- auto request =
- static_cast<const MonitoringRequest *>(event->data);
- cookie = request->cookie;
- bool success = chreWifiConfigureScanMonitorAsync(
- request->enable, &cookie);
- TestEventQueueSingleton::get()->pushEvent(MONITORING_REQUEST,
- success);
- }
- }
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (event->success) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_ASYNC_RESULT,
+ *(static_cast<const uint32_t *>(event->cookie)));
}
- };
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case MONITORING_REQUEST:
+ auto request =
+ static_cast<const MonitoringRequest *>(event->data);
+ mCookie = request->cookie;
+ bool success =
+ chreWifiConfigureScanMonitorAsync(request->enable, &mCookie);
+ TestEventQueueSingleton::get()->pushEvent(MONITORING_REQUEST,
+ success);
+ }
+ }
+ }
+ }
+
+ protected:
+ uint32_t mCookie;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
EXPECT_FALSE(chrePalWifiIsScanMonitoringActive());
MonitoringRequest request{.enable = true, .cookie = 0x123};
- sendEventToNanoapp(app, MONITORING_REQUEST, request);
+ sendEventToNanoapp(appId, MONITORING_REQUEST, request);
uint32_t cookie;
waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &cookie);
EXPECT_EQ(cookie, request.cookie);
EXPECT_TRUE(chrePalWifiIsScanMonitoringActive());
request = {.enable = false, .cookie = 0x456};
- sendEventToNanoapp(app, MONITORING_REQUEST, request);
+ sendEventToNanoapp(appId, MONITORING_REQUEST, request);
bool success;
waitForEvent(MONITORING_REQUEST, &success);
EXPECT_TRUE(success);
@@ -104,46 +109,51 @@ TEST_F(TestBase, WifiScanMonitoringDisabledOnUnload) {
uint32_t cookie;
};
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI;
-
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- static uint32_t cookie;
-
- switch (eventType) {
- case CHRE_EVENT_WIFI_ASYNC_RESULT: {
- auto *event = static_cast<const chreAsyncResult *>(eventData);
- if (event->success) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_ASYNC_RESULT,
- *(static_cast<const uint32_t *>(event->cookie)));
- }
- break;
- }
-
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case MONITORING_REQUEST:
- auto request =
- static_cast<const MonitoringRequest *>(event->data);
- cookie = request->cookie;
- bool success = chreWifiConfigureScanMonitorAsync(
- request->enable, &cookie);
- TestEventQueueSingleton::get()->pushEvent(MONITORING_REQUEST,
- success);
- }
- }
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (event->success) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_ASYNC_RESULT,
+ *(static_cast<const uint32_t *>(event->cookie)));
}
- };
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case MONITORING_REQUEST:
+ auto request =
+ static_cast<const MonitoringRequest *>(event->data);
+ mCookie = request->cookie;
+ bool success =
+ chreWifiConfigureScanMonitorAsync(request->enable, &mCookie);
+ TestEventQueueSingleton::get()->pushEvent(MONITORING_REQUEST,
+ success);
+ }
+ }
+ }
+ }
+
+ protected:
+ uint32_t mCookie;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
EXPECT_FALSE(chrePalWifiIsScanMonitoringActive());
MonitoringRequest request{.enable = true, .cookie = 0x123};
- sendEventToNanoapp(app, MONITORING_REQUEST, request);
+ sendEventToNanoapp(appId, MONITORING_REQUEST, request);
bool success;
waitForEvent(MONITORING_REQUEST, &success);
EXPECT_TRUE(success);
@@ -152,7 +162,7 @@ TEST_F(TestBase, WifiScanMonitoringDisabledOnUnload) {
EXPECT_EQ(cookie, request.cookie);
EXPECT_TRUE(chrePalWifiIsScanMonitoringActive());
- unloadNanoapp(app);
+ unloadNanoapp(appId);
EXPECT_FALSE(chrePalWifiIsScanMonitoringActive());
}
@@ -164,46 +174,51 @@ TEST_F(TestBase, WifiScanMonitoringDisabledOnUnloadAndCanBeReEnabled) {
uint32_t cookie;
};
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI;
-
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- static uint32_t cookie;
-
- switch (eventType) {
- case CHRE_EVENT_WIFI_ASYNC_RESULT: {
- auto *event = static_cast<const chreAsyncResult *>(eventData);
- if (event->success) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_ASYNC_RESULT,
- *(static_cast<const uint32_t *>(event->cookie)));
- }
- break;
- }
-
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case MONITORING_REQUEST:
- auto request =
- static_cast<const MonitoringRequest *>(event->data);
- cookie = request->cookie;
- bool success = chreWifiConfigureScanMonitorAsync(
- request->enable, &cookie);
- TestEventQueueSingleton::get()->pushEvent(MONITORING_REQUEST,
- success);
- }
- }
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (event->success) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_ASYNC_RESULT,
+ *(static_cast<const uint32_t *>(event->cookie)));
+ }
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case MONITORING_REQUEST:
+ auto request =
+ static_cast<const MonitoringRequest *>(event->data);
+ mCookie = request->cookie;
+ bool success =
+ chreWifiConfigureScanMonitorAsync(request->enable, &mCookie);
+ TestEventQueueSingleton::get()->pushEvent(MONITORING_REQUEST,
+ success);
}
- };
+ }
+ }
+ }
+
+ protected:
+ uint32_t mCookie;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
EXPECT_FALSE(chrePalWifiIsScanMonitoringActive());
MonitoringRequest request{.enable = true, .cookie = 0x123};
- sendEventToNanoapp(app, MONITORING_REQUEST, request);
+ sendEventToNanoapp(appId, MONITORING_REQUEST, request);
bool success;
waitForEvent(MONITORING_REQUEST, &success);
EXPECT_TRUE(success);
@@ -212,14 +227,14 @@ TEST_F(TestBase, WifiScanMonitoringDisabledOnUnloadAndCanBeReEnabled) {
EXPECT_EQ(cookie, request.cookie);
EXPECT_TRUE(chrePalWifiIsScanMonitoringActive());
- unloadNanoapp(app);
+ unloadNanoapp(appId);
EXPECT_FALSE(chrePalWifiIsScanMonitoringActive());
- app = loadNanoapp<App>();
+ appId = loadNanoapp(MakeUnique<App>());
EXPECT_FALSE(chrePalWifiIsScanMonitoringActive());
request = {.enable = true, .cookie = 0x456};
- sendEventToNanoapp(app, MONITORING_REQUEST, request);
+ sendEventToNanoapp(appId, MONITORING_REQUEST, request);
waitForEvent(MONITORING_REQUEST, &success);
EXPECT_TRUE(success);
waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &cookie);
diff --git a/test/simulation/wifi_timeout_test.cc b/test/simulation/wifi_timeout_test.cc
index 6e448b0b..7c310fd7 100644
--- a/test/simulation/wifi_timeout_test.cc
+++ b/test/simulation/wifi_timeout_test.cc
@@ -20,8 +20,10 @@
#include "chre/core/settings.h"
#include "chre/platform/linux/pal_wifi.h"
#include "chre/platform/log.h"
+#include "chre/util/nanoapp/app_id.h"
#include "chre/util/system/napp_permissions.h"
#include "chre_api/chre/event.h"
+#include "chre_api/chre/re.h"
#include "chre_api/chre/wifi.h"
#include "gtest/gtest.h"
#include "test_base.h"
@@ -31,29 +33,142 @@
namespace chre {
namespace {
-// WifiTimeoutTestBase needs to set timeout more than max wifi async timeout
-// time. If not, waitForEvent will timeout before actual timeout happens in
-// CHRE, making us unable to observe how system handles timeout.
+// WifiTimeoutTestBase needs to set timeout more than the max waitForEvent()
+// should process (Currently it is
+// WifiCanDispatchSecondScanRequestInQueueAfterFirstTimeout). If not,
+// waitForEvent will timeout before actual timeout happens in CHRE, making us
+// unable to observe how system handles timeout.
class WifiTimeoutTestBase : public TestBase {
protected:
uint64_t getTimeoutNs() const override {
- return 2 * CHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS;
+ return 3 * CHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS;
}
};
+CREATE_CHRE_TEST_EVENT(SCAN_REQUEST, 20);
+CREATE_CHRE_TEST_EVENT(REQUEST_TIMED_OUT, 21);
+
TEST_F(WifiTimeoutTestBase, WifiScanRequestTimeoutTest) {
- CREATE_CHRE_TEST_EVENT(SCAN_REQUEST, 1);
+ class ScanTestNanoapp : public TestNanoapp {
+ public:
+ explicit ScanTestNanoapp()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
+
+ bool start() override {
+ mRequestTimer = CHRE_TIMER_INVALID;
+ return true;
+ }
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (mRequestTimer != CHRE_TIMER_INVALID) {
+ chreTimerCancel(mRequestTimer);
+ mRequestTimer = CHRE_TIMER_INVALID;
+ }
+ if (event->success) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_ASYNC_RESULT,
+ *(static_cast<const uint32_t *>(event->cookie)));
+ }
+ break;
+ }
+
+ case CHRE_EVENT_WIFI_SCAN_RESULT: {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_SCAN_RESULT);
+ break;
+ }
+
+ case CHRE_EVENT_TIMER: {
+ TestEventQueueSingleton::get()->pushEvent(REQUEST_TIMED_OUT);
+ mRequestTimer = CHRE_TIMER_INVALID;
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case SCAN_REQUEST:
+ bool success = false;
+ mCookie = *static_cast<uint32_t *>(event->data);
+ if (chreWifiRequestScanAsyncDefault(&mCookie)) {
+ mRequestTimer =
+ chreTimerSet(CHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS, nullptr,
+ true /* oneShot */);
+ success = mRequestTimer != CHRE_TIMER_INVALID;
+ }
+ TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST, success);
+ break;
+ }
+ break;
+ }
+ }
+ }
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI;
+ protected:
+ uint32_t mCookie;
+ uint32_t mRequestTimer;
+ };
- decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
- const void *eventData) {
- static uint32_t cookie;
+ uint64_t appId = loadNanoapp(MakeUnique<ScanTestNanoapp>());
+ constexpr uint32_t timeOutCookie = 0xdead;
+ chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN,
+ false /* enableResponse */);
+ sendEventToNanoapp(appId, SCAN_REQUEST, timeOutCookie);
+ bool success;
+ waitForEvent(SCAN_REQUEST, &success);
+ EXPECT_TRUE(success);
+
+ waitForEvent(REQUEST_TIMED_OUT);
+
+ // Make sure that we can still request scan after a timedout
+ // request.
+ constexpr uint32_t successCookie = 0x0101;
+ chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN,
+ true /* enableResponse */);
+ sendEventToNanoapp(appId, SCAN_REQUEST, successCookie);
+ waitForEvent(SCAN_REQUEST, &success);
+ EXPECT_TRUE(success);
+ waitForEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
+
+ unloadNanoapp(appId);
+}
+
+TEST_F(WifiTimeoutTestBase, WifiCanDispatchQueuedRequestAfterOneTimeout) {
+ constexpr uint8_t kNanoappNum = 2;
+ // receivedTimeout is shared across apps and must be static.
+ // But we want it initialized each time the test is executed.
+ static uint8_t receivedTimeout;
+ receivedTimeout = 0;
+
+ class ScanTestNanoapp : public TestNanoapp {
+ public:
+ explicit ScanTestNanoapp(uint64_t id = kDefaultTestNanoappId)
+ : TestNanoapp(TestNanoappInfo{
+ .id = id, .perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
+
+ bool start() override {
+ for (uint8_t i = 0; i < kNanoappNum; ++i) {
+ mRequestTimers[i] = CHRE_TIMER_INVALID;
+ }
+ return true;
+ }
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ size_t index = id() - CHRE_VENDOR_ID_EXAMPLE - 1;
switch (eventType) {
case CHRE_EVENT_WIFI_ASYNC_RESULT: {
auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (mRequestTimers[index] != CHRE_TIMER_INVALID) {
+ chreTimerCancel(mRequestTimers[index]);
+ mRequestTimers[index] = CHRE_TIMER_INVALID;
+ }
if (event->success) {
TestEventQueueSingleton::get()->pushEvent(
CHRE_EVENT_WIFI_ASYNC_RESULT,
@@ -68,43 +183,76 @@ TEST_F(WifiTimeoutTestBase, WifiScanRequestTimeoutTest) {
break;
}
+ case CHRE_EVENT_TIMER: {
+ if (eventData == &mCookie[index]) {
+ receivedTimeout++;
+ mRequestTimers[index] = CHRE_TIMER_INVALID;
+ }
+ if (receivedTimeout == 2) {
+ TestEventQueueSingleton::get()->pushEvent(REQUEST_TIMED_OUT);
+ }
+ break;
+ }
+
case CHRE_EVENT_TEST_EVENT: {
auto event = static_cast<const TestEvent *>(eventData);
switch (event->type) {
case SCAN_REQUEST:
- cookie = *static_cast<uint32_t *>(event->data);
- bool success = chreWifiRequestScanAsyncDefault(&cookie);
+ bool success = false;
+ mCookie[index] = *static_cast<uint32_t *>(event->data);
+ if (chreWifiRequestScanAsyncDefault(&mCookie[index])) {
+ mRequestTimers[index] =
+ chreTimerSet(CHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS,
+ &mCookie[index], true /* oneShot */);
+ success = mRequestTimers[index] != CHRE_TIMER_INVALID;
+ }
TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST, success);
+ break;
}
+ break;
}
}
- };
+ }
+
+ protected:
+ uint32_t mCookie[kNanoappNum];
+ uint32_t mRequestTimers[kNanoappNum];
};
+ constexpr uint64_t kAppOneId = makeExampleNanoappId(1);
+ constexpr uint64_t kAppTwoId = makeExampleNanoappId(2);
- auto app = loadNanoapp<App>();
+ uint64_t firstAppId = loadNanoapp(MakeUnique<ScanTestNanoapp>(kAppOneId));
+ uint64_t secondAppId = loadNanoapp(MakeUnique<ScanTestNanoapp>(kAppTwoId));
constexpr uint32_t timeOutCookie = 0xdead;
- chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN, false);
- sendEventToNanoapp(app, SCAN_REQUEST, timeOutCookie);
+ chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN,
+ false /* enableResponse */);
bool success;
+ sendEventToNanoapp(firstAppId, SCAN_REQUEST, timeOutCookie);
+ waitForEvent(SCAN_REQUEST, &success);
+ EXPECT_TRUE(success);
+ sendEventToNanoapp(secondAppId, SCAN_REQUEST, timeOutCookie);
waitForEvent(SCAN_REQUEST, &success);
EXPECT_TRUE(success);
- // Add 1 second to prevent race condition.
- constexpr uint8_t kWifiScanRequestTimeoutSec =
- (CHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS / CHRE_NSEC_PER_SEC) + 1;
- std::this_thread::sleep_for(std::chrono::seconds(kWifiScanRequestTimeoutSec));
+ waitForEvent(REQUEST_TIMED_OUT);
- // Make sure that we can still request scan after a timedout
+ // Make sure that we can still request scan for both nanoapps after a timedout
// request.
constexpr uint32_t successCookie = 0x0101;
- chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN, true);
- sendEventToNanoapp(app, SCAN_REQUEST, successCookie);
+ chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN,
+ true /* enableResponse */);
+ sendEventToNanoapp(firstAppId, SCAN_REQUEST, successCookie);
+ waitForEvent(SCAN_REQUEST, &success);
+ EXPECT_TRUE(success);
+ waitForEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
+ sendEventToNanoapp(secondAppId, SCAN_REQUEST, successCookie);
waitForEvent(SCAN_REQUEST, &success);
EXPECT_TRUE(success);
waitForEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
- unloadNanoapp(app);
+ unloadNanoapp(firstAppId);
+ unloadNanoapp(secondAppId);
}
TEST_F(WifiTimeoutTestBase, WifiScanMonitorTimeoutTest) {
@@ -115,61 +263,83 @@ TEST_F(WifiTimeoutTestBase, WifiScanMonitorTimeoutTest) {
uint32_t cookie;
};
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI;
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- static uint32_t cookie;
+ bool start() override {
+ mRequestTimer = CHRE_TIMER_INVALID;
+ return true;
+ }
- switch (eventType) {
- case CHRE_EVENT_WIFI_ASYNC_RESULT: {
- auto *event = static_cast<const chreAsyncResult *>(eventData);
- if (event->success) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_ASYNC_RESULT,
- *(static_cast<const uint32_t *>(event->cookie)));
- }
- break;
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_ASYNC_RESULT: {
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (event->success) {
+ if (mRequestTimer != CHRE_TIMER_INVALID) {
+ chreTimerCancel(mRequestTimer);
+ mRequestTimer = CHRE_TIMER_INVALID;
}
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_ASYNC_RESULT,
+ *(static_cast<const uint32_t *>(event->cookie)));
+ }
+ break;
+ }
+
+ case CHRE_EVENT_TIMER: {
+ mRequestTimer = CHRE_TIMER_INVALID;
+ TestEventQueueSingleton::get()->pushEvent(REQUEST_TIMED_OUT);
+ break;
+ }
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case SCAN_MONITOR_REQUEST:
- auto request =
- static_cast<const MonitoringRequest *>(event->data);
- cookie = request->cookie;
- bool success = chreWifiConfigureScanMonitorAsync(
- request->enable, &cookie);
- TestEventQueueSingleton::get()->pushEvent(
- SCAN_MONITOR_REQUEST, success);
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case SCAN_MONITOR_REQUEST:
+ bool success = false;
+ auto request =
+ static_cast<const MonitoringRequest *>(event->data);
+ if (chreWifiConfigureScanMonitorAsync(request->enable,
+ &mCookie)) {
+ mCookie = request->cookie;
+ mRequestTimer = chreTimerSet(CHRE_TEST_ASYNC_RESULT_TIMEOUT_NS,
+ nullptr, true /* oneShot */);
+ success = mRequestTimer != CHRE_TIMER_INVALID;
}
- }
+
+ TestEventQueueSingleton::get()->pushEvent(SCAN_MONITOR_REQUEST,
+ success);
}
- };
+ }
+ }
+ }
+
+ protected:
+ uint32_t mCookie;
+ uint32_t mRequestTimer;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
MonitoringRequest timeoutRequest{.enable = true, .cookie = 0xdead};
chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN_MONITORING, false);
- sendEventToNanoapp(app, SCAN_MONITOR_REQUEST, timeoutRequest);
+ sendEventToNanoapp(appId, SCAN_MONITOR_REQUEST, timeoutRequest);
bool success;
waitForEvent(SCAN_MONITOR_REQUEST, &success);
EXPECT_TRUE(success);
- // Add 1 second to prevent race condition.
- constexpr uint8_t kWifiConfigureScanMonitorTimeoutSec =
- (CHRE_TEST_ASYNC_RESULT_TIMEOUT_NS / CHRE_NSEC_PER_SEC) + 1;
- std::this_thread::sleep_for(
- std::chrono::seconds(kWifiConfigureScanMonitorTimeoutSec));
+ waitForEvent(REQUEST_TIMED_OUT);
// Make sure that we can still request to change scan monitor after a timedout
// request.
MonitoringRequest enableRequest{.enable = true, .cookie = 0x1010};
chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN_MONITORING, true);
- sendEventToNanoapp(app, SCAN_MONITOR_REQUEST, enableRequest);
+ sendEventToNanoapp(appId, SCAN_MONITOR_REQUEST, enableRequest);
waitForEvent(SCAN_MONITOR_REQUEST, &success);
EXPECT_TRUE(success);
@@ -179,7 +349,7 @@ TEST_F(WifiTimeoutTestBase, WifiScanMonitorTimeoutTest) {
EXPECT_TRUE(chrePalWifiIsScanMonitoringActive());
MonitoringRequest disableRequest{.enable = false, .cookie = 0x0101};
- sendEventToNanoapp(app, SCAN_MONITOR_REQUEST, disableRequest);
+ sendEventToNanoapp(appId, SCAN_MONITOR_REQUEST, disableRequest);
waitForEvent(SCAN_MONITOR_REQUEST, &success);
EXPECT_TRUE(success);
@@ -187,87 +357,105 @@ TEST_F(WifiTimeoutTestBase, WifiScanMonitorTimeoutTest) {
EXPECT_EQ(cookie, disableRequest.cookie);
EXPECT_FALSE(chrePalWifiIsScanMonitoringActive());
- unloadNanoapp(app);
+ unloadNanoapp(appId);
}
TEST_F(WifiTimeoutTestBase, WifiRequestRangingTimeoutTest) {
CREATE_CHRE_TEST_EVENT(RANGING_REQUEST, 0);
- CREATE_CHRE_TEST_EVENT(RANGING_RESULT_TIMEOUT, 1);
-
- struct App : public TestNanoapp {
- uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI;
-
- decltype(nanoappHandleEvent) *handleEvent =
- [](uint32_t, uint16_t eventType, const void *eventData) {
- static uint32_t cookie;
-
- switch (eventType) {
- case CHRE_EVENT_WIFI_ASYNC_RESULT: {
- auto *event = static_cast<const chreAsyncResult *>(eventData);
- if (event->success) {
- if (event->errorCode == 0) {
- TestEventQueueSingleton::get()->pushEvent(
- CHRE_EVENT_WIFI_ASYNC_RESULT,
- *(static_cast<const uint32_t *>(event->cookie)));
- }
- } else if (event->errorCode == CHRE_ERROR_TIMEOUT) {
- TestEventQueueSingleton::get()->pushEvent(
- RANGING_RESULT_TIMEOUT,
- *(static_cast<const uint32_t *>(event->cookie)));
- }
- break;
+
+ class App : public TestNanoapp {
+ public:
+ App()
+ : TestNanoapp(
+ TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
+
+ bool start() override {
+ mRequestTimer = CHRE_TIMER_INVALID;
+ return true;
+ }
+
+ void handleEvent(uint32_t, uint16_t eventType,
+ const void *eventData) override {
+ switch (eventType) {
+ case CHRE_EVENT_WIFI_ASYNC_RESULT: {
+ if (mRequestTimer != CHRE_TIMER_INVALID) {
+ chreTimerCancel(mRequestTimer);
+ mRequestTimer = CHRE_TIMER_INVALID;
+ }
+
+ auto *event = static_cast<const chreAsyncResult *>(eventData);
+ if (event->success) {
+ if (event->errorCode == 0) {
+ TestEventQueueSingleton::get()->pushEvent(
+ CHRE_EVENT_WIFI_ASYNC_RESULT,
+ *(static_cast<const uint32_t *>(event->cookie)));
}
+ }
+ break;
+ }
- case CHRE_EVENT_TEST_EVENT: {
- auto event = static_cast<const TestEvent *>(eventData);
- switch (event->type) {
- case RANGING_REQUEST:
- cookie = *static_cast<uint32_t *>(event->data);
-
- // Placeholder parameters since linux PAL does not use this to
- // generate response
- struct chreWifiRangingTarget dummyRangingTarget = {
- .macAddress = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc},
- .primaryChannel = 0xdef02468,
- .centerFreqPrimary = 0xace13579,
- .centerFreqSecondary = 0xbdf369cf,
- .channelWidth = 0x48,
- };
-
- struct chreWifiRangingParams dummyRangingParams = {
- .targetListLen = 1,
- .targetList = &dummyRangingTarget,
- };
-
- bool success =
- chreWifiRequestRangingAsync(&dummyRangingParams, &cookie);
- TestEventQueueSingleton::get()->pushEvent(RANGING_REQUEST,
- success);
+ case CHRE_EVENT_TIMER: {
+ mRequestTimer = CHRE_TIMER_INVALID;
+ TestEventQueueSingleton::get()->pushEvent(REQUEST_TIMED_OUT);
+ break;
+ }
+
+ case CHRE_EVENT_TEST_EVENT: {
+ auto event = static_cast<const TestEvent *>(eventData);
+ switch (event->type) {
+ case RANGING_REQUEST:
+ bool success = false;
+ mCookie = *static_cast<uint32_t *>(event->data);
+
+ // Placeholder parameters since linux PAL does not use this to
+ // generate response
+ struct chreWifiRangingTarget dummyRangingTarget = {
+ .macAddress = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc},
+ .primaryChannel = 0xdef02468,
+ .centerFreqPrimary = 0xace13579,
+ .centerFreqSecondary = 0xbdf369cf,
+ .channelWidth = 0x48,
+ };
+
+ struct chreWifiRangingParams dummyRangingParams = {
+ .targetListLen = 1,
+ .targetList = &dummyRangingTarget,
+ };
+
+ if (chreWifiRequestRangingAsync(&dummyRangingParams, &mCookie)) {
+ mRequestTimer =
+ chreTimerSet(CHRE_TEST_WIFI_RANGING_RESULT_TIMEOUT_NS,
+ nullptr, true /* oneShot */);
+ success = mRequestTimer != CHRE_TIMER_INVALID;
}
- }
+ TestEventQueueSingleton::get()->pushEvent(RANGING_REQUEST,
+ success);
}
- };
+ }
+ }
+ }
+
+ protected:
+ uint32_t mCookie;
+ uint32_t mRequestTimer;
};
- auto app = loadNanoapp<App>();
+ uint64_t appId = loadNanoapp(MakeUnique<App>());
+
uint32_t timeOutCookie = 0xdead;
chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::RANGING, false);
- sendEventToNanoapp(app, RANGING_REQUEST, timeOutCookie);
+ sendEventToNanoapp(appId, RANGING_REQUEST, timeOutCookie);
bool success;
waitForEvent(RANGING_REQUEST, &success);
EXPECT_TRUE(success);
- // Add 1 second to prevent race condition
- constexpr uint8_t kWifiRequestRangingTimeoutSec =
- (CHRE_TEST_WIFI_RANGING_RESULT_TIMEOUT_NS / CHRE_NSEC_PER_SEC) + 1;
- std::this_thread::sleep_for(
- std::chrono::seconds(kWifiRequestRangingTimeoutSec));
+ waitForEvent(REQUEST_TIMED_OUT);
// Make sure that we can still request ranging after a timedout request
uint32_t successCookie = 0x0101;
chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::RANGING, true);
- sendEventToNanoapp(app, RANGING_REQUEST, successCookie);
+ sendEventToNanoapp(appId, RANGING_REQUEST, successCookie);
waitForEvent(RANGING_REQUEST, &success);
EXPECT_TRUE(success);
@@ -275,7 +463,7 @@ TEST_F(WifiTimeoutTestBase, WifiRequestRangingTimeoutTest) {
waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &cookie);
EXPECT_EQ(cookie, successCookie);
- unloadNanoapp(app);
+ unloadNanoapp(appId);
}
} // namespace
diff --git a/util/dynamic_vector_base.cc b/util/dynamic_vector_base.cc
index ee7570bc..23cc1209 100644
--- a/util/dynamic_vector_base.cc
+++ b/util/dynamic_vector_base.cc
@@ -35,8 +35,10 @@ bool DynamicVectorBase::doReserve(size_t newCapacity, size_t elementSize) {
if (!success) {
void *newData = memoryAlloc(newCapacity * elementSize);
if (newData != nullptr) {
- memcpy(newData, mData, mSize * elementSize);
- memoryFree(mData);
+ if (mData != nullptr) {
+ memcpy(newData, mData, mSize * elementSize);
+ memoryFree(mData);
+ }
mData = newData;
mCapacity = newCapacity;
success = true;
diff --git a/util/include/chre/util/array_queue_impl.h b/util/include/chre/util/array_queue_impl.h
index c2982f4b..0172c0e3 100644
--- a/util/include/chre/util/array_queue_impl.h
+++ b/util/include/chre/util/array_queue_impl.h
@@ -132,8 +132,7 @@ void ArrayQueueCore<ElementType, StorageType>::pop() {
template <typename ElementType, typename StorageType>
void ArrayQueueCore<ElementType, StorageType>::pop_back() {
if (mSize > 0) {
- size_t absoluteIndex = relativeIndexToAbsolute(mSize - 1);
- StorageType::data()[absoluteIndex].~ElementType();
+ StorageType::data()[mTail].~ElementType();
pullTail();
}
}
diff --git a/util/include/chre/util/dynamic_vector_impl.h b/util/include/chre/util/dynamic_vector_impl.h
index b3221986..4ce6e7df 100644
--- a/util/include/chre/util/dynamic_vector_impl.h
+++ b/util/include/chre/util/dynamic_vector_impl.h
@@ -189,9 +189,11 @@ bool DynamicVector<ElementType>::doReserve(size_type newCapacity,
ElementType *newData = static_cast<ElementType *>(
memoryAlloc(newCapacity * sizeof(ElementType)));
if (newData != nullptr) {
- uninitializedMoveOrCopy(data(), mSize, newData);
- destroy(data(), mSize);
- memoryFree(data());
+ if (data() != nullptr) {
+ uninitializedMoveOrCopy(data(), mSize, newData);
+ destroy(data(), mSize);
+ memoryFree(data());
+ }
mData = newData;
mCapacity = newCapacity;
success = true;
diff --git a/util/include/chre/util/intrusive_list_base.h b/util/include/chre/util/intrusive_list_base.h
index 212b5243..76c89092 100644
--- a/util/include/chre/util/intrusive_list_base.h
+++ b/util/include/chre/util/intrusive_list_base.h
@@ -53,7 +53,7 @@ class IntrusiveListBase : public NonCopyable {
IntrusiveListBase() {
mSentinelNode.next = &mSentinelNode;
mSentinelNode.prev = &mSentinelNode;
- };
+ }
/**
* Link a new node to the end of the linked list.
diff --git a/util/include/chre/util/macros.h b/util/include/chre/util/macros.h
index 4f4877cd..f6de1816 100644
--- a/util/include/chre/util/macros.h
+++ b/util/include/chre/util/macros.h
@@ -63,6 +63,50 @@
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
+/**
+ * Obtain the number of arguments passed into a macro up till 20 args
+ */
+#define VA_NUM_ARGS(...) \
+ VA_NUM_ARGS_IMPL(__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, \
+ 8, 7, 6, 5, 4, 3, 2, 1)
+#define VA_NUM_ARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
+ _13, _14_, _15, _16, _17, _18, _19, _20, N, ...) \
+ N
+
+/**
+ * Concats two preprocessor tokens together.
+ * If passed in args are macros, they are resolved first, then concat'd
+ */
+#define MACRO_CONCAT2(x, y) x##y
+#define MACRO_CONCAT(x, y) MACRO_CONCAT2(x, y)
+
+/**
+ * Get a list of types of the passed in parameters to TYPE_LIST(...)
+ */
+#define TYPE_LIST_1(a) decltype(a)
+#define TYPE_LIST_2(a, ...) decltype(a), TYPE_LIST_1(__VA_ARGS__)
+#define TYPE_LIST_3(a, ...) decltype(a), TYPE_LIST_2(__VA_ARGS__)
+#define TYPE_LIST_4(a, ...) decltype(a), TYPE_LIST_3(__VA_ARGS__)
+#define TYPE_LIST_5(a, ...) decltype(a), TYPE_LIST_4(__VA_ARGS__)
+#define TYPE_LIST_6(a, ...) decltype(a), TYPE_LIST_5(__VA_ARGS__)
+#define TYPE_LIST_7(a, ...) decltype(a), TYPE_LIST_6(__VA_ARGS__)
+#define TYPE_LIST_8(a, ...) decltype(a), TYPE_LIST_7(__VA_ARGS__)
+#define TYPE_LIST_9(a, ...) decltype(a), TYPE_LIST_8(__VA_ARGS__)
+#define TYPE_LIST_10(a, ...) decltype(a), TYPE_LIST_9(__VA_ARGS__)
+#define TYPE_LIST_11(a, ...) decltype(a), TYPE_LIST_10(__VA_ARGS__)
+#define TYPE_LIST_12(a, ...) decltype(a), TYPE_LIST_11(__VA_ARGS__)
+#define TYPE_LIST_13(a, ...) decltype(a), TYPE_LIST_12(__VA_ARGS__)
+#define TYPE_LIST_14(a, ...) decltype(a), TYPE_LIST_13(__VA_ARGS__)
+#define TYPE_LIST_15(a, ...) decltype(a), TYPE_LIST_14(__VA_ARGS__)
+#define TYPE_LIST_16(a, ...) decltype(a), TYPE_LIST_15(__VA_ARGS__)
+#define TYPE_LIST_17(a, ...) decltype(a), TYPE_LIST_16(__VA_ARGS__)
+#define TYPE_LIST_18(a, ...) decltype(a), TYPE_LIST_17(__VA_ARGS__)
+#define TYPE_LIST_19(a, ...) decltype(a), TYPE_LIST_18(__VA_ARGS__)
+#define TYPE_LIST_20(a, ...) decltype(a), TYPE_LIST_19(__VA_ARGS__)
+
+#define TYPE_LIST(...) \
+ MACRO_CONCAT(TYPE_LIST_, VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
+
// Compiler-specific functionality
#if defined(__clang__) || defined(__GNUC__)
diff --git a/util/include/chre/util/nanoapp/app_id.h b/util/include/chre/util/nanoapp/app_id.h
index edc9803f..2ec40c79 100644
--- a/util/include/chre/util/nanoapp/app_id.h
+++ b/util/include/chre/util/nanoapp/app_id.h
@@ -50,7 +50,7 @@ constexpr uint64_t makeNanoappId(uint64_t vendor, uint32_t appNumber) {
}
/**
- * @return App ID combining the given 3-byte app number and Google's 5-byte
+ * @return App ID combining the given 3-byte app number and the example 5-byte
* vendor ID
*/
constexpr uint64_t makeExampleNanoappId(uint32_t appNumber) {
@@ -67,8 +67,8 @@ constexpr uint64_t makeGoogleNanoappId(uint32_t appNumber) {
// clang-format off
constexpr uint64_t kHelloWorldAppId = makeExampleNanoappId(1);
-constexpr uint64_t kMessageWorldAppId = makeExampleNanoappId(2);
-constexpr uint64_t kTimerWorldAppId = makeExampleNanoappId(3);
+constexpr uint64_t kTimerWorldAppId = makeExampleNanoappId(2);
+constexpr uint64_t kMessageWorldAppId = makeExampleNanoappId(3);
constexpr uint64_t kSensorWorldAppId = makeExampleNanoappId(4);
constexpr uint64_t kGnssWorldAppId = makeExampleNanoappId(5);
constexpr uint64_t kWifiWorldAppId = makeExampleNanoappId(6);
diff --git a/util/include/chre/util/nanoapp/ble.h b/util/include/chre/util/nanoapp/ble.h
index c00ce305..ba9e4443 100644
--- a/util/include/chre/util/nanoapp/ble.h
+++ b/util/include/chre/util/nanoapp/ble.h
@@ -87,6 +87,15 @@ bool createBleScanFilterForKnownBeacons(struct chreBleScanFilter &filter,
chreBleGenericFilter *genericFilters,
uint8_t numGenericFilters);
+/**
+ * Similar to createBleScanFilterForKnownBeacons but creates a
+ * chreBleScanFilterV1_9 instead of a chreBleScanFilter. The
+ * broadcasterAddressFilters are set to empty.
+ */
+bool createBleScanFilterForKnownBeaconsV1_9(
+ struct chreBleScanFilterV1_9 &filter, chreBleGenericFilter *genericFilters,
+ uint8_t numGenericFilters);
+
} // namespace chre
#endif // CHRE_UTIL_NANOAPP_BLE_H_
diff --git a/util/include/chre/util/nanoapp/math.h b/util/include/chre/util/nanoapp/math.h
index 8346bb8f..bfcdb9e8 100644
--- a/util/include/chre/util/nanoapp/math.h
+++ b/util/include/chre/util/nanoapp/math.h
@@ -26,4 +26,7 @@
//! The constant pi in single-precision floating point format.
#define CHRE_PI_F (3.14159265358979f)
+//! The constant pi in double-precision floating point format.
+#define CHRE_PI_D (3.1415926535897932)
+
#endif // CHRE_UTIL_NANOAPP_MATH_H_
diff --git a/util/include/chre/util/nanoapp/string.h b/util/include/chre/util/nanoapp/string.h
new file mode 100644
index 00000000..4b277e97
--- /dev/null
+++ b/util/include/chre/util/nanoapp/string.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHRE_UTIL_NANOAPP_STRING_H_
+#define CHRE_UTIL_NANOAPP_STRING_H_
+
+#include <cstdint>
+
+#include "chre_api/chre.h"
+
+namespace chre {
+
+/**
+ * Copies a null-terminated string from source to destination up to the length
+ * of the source string or the destinationBufferSize - 1. Pads with null
+ * characters.
+ *
+ * @param destination the destination null-terminated string.
+ * @param source the source null-terminated string.
+ * @param destinationBufferSize the size of the destination buffer.
+ */
+void copyString(char *destination, const char *source,
+ size_t destinationBufferSize);
+
+} // namespace chre
+
+#endif // CHRE_UTIL_NANOAPP_STRING_H_
diff --git a/util/include/chre/util/pigweed/chre_channel_output.h b/util/include/chre/util/pigweed/chre_channel_output.h
index 9f815b8f..69c7f604 100644
--- a/util/include/chre/util/pigweed/chre_channel_output.h
+++ b/util/include/chre/util/pigweed/chre_channel_output.h
@@ -32,47 +32,26 @@ namespace chre {
*/
struct ChrePigweedNanoappMessage {
size_t msgSize;
- void *msg;
-};
-
-/**
- * ChannelOutput that can be used for nanoapps wishing to utilize
- * pw::rpc::Server and pw::rpc::Client for RPC communication between other
- * nanoapps and Android app host clients.
- */
-class ChreChannelOutputBase : public pw::rpc::ChannelOutput {
- public:
- // Random value chosen that matches Java client util, but is random enough
- // to not conflict with other CHRE messages the nanoapp and client may send.
- static constexpr uint32_t PW_RPC_CHRE_HOST_MESSAGE_TYPE = INT32_MAX - 10;
-
- // Random values chosen to be towards the end of the nanoapp event type region
- // so it doesn't conflict with existing nanoapp messages that can be sent.
- static constexpr uint16_t PW_RPC_CHRE_NAPP_REQUEST_EVENT_TYPE =
- UINT16_MAX - 10;
- static constexpr uint16_t PW_RPC_CHRE_NAPP_RESPONSE_EVENT_TYPE =
- UINT16_MAX - 9;
-
- size_t MaximumTransmissionUnit() override;
-
- protected:
- ChreChannelOutputBase();
+ uint8_t msg[];
};
/**
* Channel output that must be used on the server side of the channel between
* two nanoapps.
*/
-class ChreServerNanoappChannelOutput : public ChreChannelOutputBase {
+class ChreServerNanoappChannelOutput : public pw::rpc::ChannelOutput {
public:
explicit ChreServerNanoappChannelOutput(RpcPermission &permission)
- : mPermission(permission) {}
+ : ChannelOutput("CHRE"), mPermission(permission) {}
+
/**
* Sets the nanoapp instance ID that is being communicated with over this
* channel output.
*/
void setClient(uint32_t nanoappInstanceId);
+ size_t MaximumTransmissionUnit() override;
+
pw::Status Send(pw::span<const std::byte> buffer) override;
private:
@@ -84,8 +63,10 @@ class ChreServerNanoappChannelOutput : public ChreChannelOutputBase {
* Channel output that must be used on the client side of the channel between
* two nanoapps.
*/
-class ChreClientNanoappChannelOutput : public ChreChannelOutputBase {
+class ChreClientNanoappChannelOutput : public pw::rpc::ChannelOutput {
public:
+ ChreClientNanoappChannelOutput() : ChannelOutput("CHRE") {}
+
/**
* Sets the server instance ID.
*
@@ -95,6 +76,8 @@ class ChreClientNanoappChannelOutput : public ChreChannelOutputBase {
*/
void setServer(uint32_t instanceId);
+ size_t MaximumTransmissionUnit() override;
+
pw::Status Send(pw::span<const std::byte> buffer) override;
private:
@@ -105,15 +88,18 @@ class ChreClientNanoappChannelOutput : public ChreChannelOutputBase {
* Channel output that must be used if the channel is between a nanoapp and
* host client.
*/
-class ChreServerHostChannelOutput : public ChreChannelOutputBase {
+class ChreServerHostChannelOutput : public pw::rpc::ChannelOutput {
public:
explicit ChreServerHostChannelOutput(RpcPermission &permission)
- : mPermission(permission) {}
+ : ChannelOutput("CHRE"), mPermission(permission) {}
+
/**
* Sets the host endpoint being communicated with.
*/
void setHostEndpoint(uint16_t hostEndpoint);
+ size_t MaximumTransmissionUnit() override;
+
pw::Status Send(pw::span<const std::byte> buffer) override;
private:
diff --git a/util/include/chre/util/pigweed/rpc_client.h b/util/include/chre/util/pigweed/rpc_client.h
index 17756dc8..4920b648 100644
--- a/util/include/chre/util/pigweed/rpc_client.h
+++ b/util/include/chre/util/pigweed/rpc_client.h
@@ -46,15 +46,11 @@ class RpcClient : public NonCopyable {
explicit RpcClient(uint64_t serverNanoappId)
: mServerNanoappId((serverNanoappId)) {}
- ~RpcClient() {
- chreConfigureNanoappInfoEvents(false);
- }
-
/**
* Handles events related to RPC services.
*
* Handles the following events:
- * - PW_RPC_CHRE_NAPP_RESPONSE_EVENT_TYPE: handle the server responses,
+ * - CHRE_EVENT_RPC_RESPONSE: handle the server responses,
* - CHRE_EVENT_NANOAPP_STOPPED: close the channel when the server nanoapp
* terminates.
*
@@ -87,12 +83,17 @@ class RpcClient : public NonCopyable {
*/
bool hasService(uint64_t id, uint32_t version);
+ /**
+ * Must be called from nanoapp end.
+ */
+ void close();
+
private:
/**
* Handles responses from the server.
*
- * This method must be called when nanoapps receive a
- * PW_RPC_CHRE_NAPP_RESPONSE_EVENT_TYPE event.
+ * This method must be called when nanoapps receive a CHRE_EVENT_RPC_RESPONSE
+ * event.
*
* @param senderInstanceId The Instance ID for the source of this event.
* @param eventData The associated data, if any.
diff --git a/platform/shared/tracing.cc b/util/include/chre/util/pigweed/rpc_common.h
index 876fe199..ee9096db 100644
--- a/platform/shared/tracing.cc
+++ b/util/include/chre/util/pigweed/rpc_common.h
@@ -14,23 +14,26 @@
* limitations under the License.
*/
-#include "chre/platform/tracing.h"
-#include "chre/util/macros.h"
+#ifndef CHRE_UTIL_PIGWEED_RPC_COMMON_H_
+#define CHRE_UTIL_PIGWEED_RPC_COMMON_H_
-namespace chre {
+#include <cstdint>
-void traceRegisterNanoapp(uint16_t instanceId, const char *name) {
- UNUSED_VAR(instanceId);
- UNUSED_VAR(name);
-}
+/**
+ * @file
+ * Common definitions across nanoapp and host sides.
+ */
-void traceNanoappHandleEventStart(uint16_t instanceId, uint16_t eventType) {
- UNUSED_VAR(instanceId);
- UNUSED_VAR(eventType);
-}
+namespace chre {
+/** The upper 16b of a channel ID are set to 1 for host clients. */
+constexpr uint32_t kChannelIdHostClient = 1 << 16;
-void traceNanoappHandleEventEnd(uint16_t instanceId) {
- UNUSED_VAR(instanceId);
-}
+/** Mask to extract the host ID / nanoapp ID from a channel ID. */
+constexpr uint32_t kRpcClientIdMask = 0xffff;
+
+/** Maximum ID for a nanoapp as the value is encoded on 16b. */
+constexpr uint32_t kRpcNanoappMaxId = 0xffff;
} // namespace chre
+
+#endif // CHRE_UTIL_PIGWEED_RPC_COMMON_H_ \ No newline at end of file
diff --git a/util/include/chre/util/pigweed/rpc_helper.h b/util/include/chre/util/pigweed/rpc_helper.h
index 032693a1..08bd2bf6 100644
--- a/util/include/chre/util/pigweed/rpc_helper.h
+++ b/util/include/chre/util/pigweed/rpc_helper.h
@@ -19,19 +19,11 @@
#include <cstdint>
+#include "chre/util/pigweed/rpc_common.h"
#include "chre_api/chre.h"
namespace chre {
-/** The upper 16b of a channel ID are set to 1 for host clients. */
-constexpr uint32_t kChannelIdHostClient = 1 << 16;
-
-/** Mask to extract the host ID / nanoapp ID from a channel ID. */
-constexpr uint32_t kRpcClientIdMask = 0xffff;
-
-/** Maximum ID for a nanoapp as the value is encoded on 16b. */
-constexpr uint32_t kRpcNanoappMaxId = 0xffff;
-
/**
* Returns whether the endpoint matches.
*
diff --git a/util/include/chre/util/pigweed/rpc_server.h b/util/include/chre/util/pigweed/rpc_server.h
index df02621e..ec0f86d6 100644
--- a/util/include/chre/util/pigweed/rpc_server.h
+++ b/util/include/chre/util/pigweed/rpc_server.h
@@ -58,7 +58,6 @@ class RpcServer : public NonCopyable {
};
RpcServer() : mHostOutput(mPermission), mNanoappOutput(mPermission) {}
- ~RpcServer();
/**
* Registers services to the server and to CHRE.
@@ -101,7 +100,7 @@ class RpcServer : public NonCopyable {
*
* Handles the following events:
* - CHRE_EVENT_MESSAGE_FROM_HOST: respond to host RPC requests,
- * - PW_RPC_CHRE_NAPP_REQUEST_EVENT_TYPE: respond to nanoapp RPC requests,
+ * - CHRE_EVENT_RPC_REQUEST: respond to nanoapp RPC requests,
* - CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION: close the channel when the host
* terminates,
* - CHRE_EVENT_NANOAPP_STOPPED: close the channel when a nanoapp
@@ -116,6 +115,13 @@ class RpcServer : public NonCopyable {
bool handleEvent(uint32_t senderInstanceId, uint16_t eventType,
const void *eventData);
+ /**
+ * Close all connections to the server.
+ *
+ * Must be called from the nanoapp end.
+ */
+ void close();
+
private:
/**
* Handles messages from host clients.
@@ -131,8 +137,8 @@ class RpcServer : public NonCopyable {
/**
* Handles messages from nanoapp clients.
*
- * This method must be called when nanoapps receive a
- * PW_RPC_CHRE_NAPP_REQUEST_EVENT_TYPE event.
+ * This method must be called when nanoapps receive a CHRE_EVENT_RPC_REQUEST
+ * event.
*
* @param eventData The associated data, if any.
* @return whether the RPC was handled successfully.
diff --git a/util/include/chre/util/segmented_queue.h b/util/include/chre/util/segmented_queue.h
index d3d7fb5c..025d2f02 100644
--- a/util/include/chre/util/segmented_queue.h
+++ b/util/include/chre/util/segmented_queue.h
@@ -92,7 +92,7 @@ class SegmentedQueue : public NonCopyable {
*/
bool empty() const {
return mSize == 0;
- };
+ }
/**
* Push a element to the end of the segmented queue.
@@ -403,4 +403,4 @@ class SegmentedQueue : public NonCopyable {
#include "chre/util/segmented_queue_impl.h"
-#endif // CHRE_UTIL_SEGMENTED_QUEUE_H_ \ No newline at end of file
+#endif // CHRE_UTIL_SEGMENTED_QUEUE_H_
diff --git a/util/include/chre/util/segmented_queue_impl.h b/util/include/chre/util/segmented_queue_impl.h
index 8bd16457..049ab615 100644
--- a/util/include/chre/util/segmented_queue_impl.h
+++ b/util/include/chre/util/segmented_queue_impl.h
@@ -20,9 +20,8 @@
#include <type_traits>
#include <utility>
-#include "chre/util/segmented_queue.h"
-
#include "chre/util/container_support.h"
+#include "chre/util/segmented_queue.h"
namespace chre {
@@ -205,11 +204,29 @@ void SegmentedQueue<ElementType, kBlockSize>::fillGaps(
return;
}
- // TODO(b/264326627): Check if gapIndices is reverse order.
- // TODO(b/264326627): Give a detailed explanation (example)\.
// Move the elements between each gap indices section by section from the
// section that is closest to the head. The destination index = the gap index
// - how many gaps has been filled.
+ //
+ // For instance, assuming we have elements that we want to remove (gaps) at
+ // these indices = [8, 7, 5, 2] and the last element is at index 10.
+ //
+ // The first iteration will move the items at index 3, 4, which is the first
+ // section, to index 2, 3 and overwrite the original item at index 2, making
+ // the queue: [0, 1, 3, 4, x, 5, 6, ...., 10] where x means empty slot.
+ //
+ // The second iteration will do a similar thing, move item 6 to the empty
+ // slot, which could be calculated by using the index of the last gap and how
+ // many gaps has been filled. So the queue turns into:
+ // [0, 1, 3, 4, 6, x, x, 7, 8, 9, 10], note that there are now two empty slots
+ // since there are two gaps filled.
+ //
+ // The third iteration does not move anything since there are no items between
+ // 7 and 8.
+ //
+ // The final iteration is a special case to close the final gap. After the
+ // final iteration, the queue will become: [1, 3, 4, 6, 9, 10].
+
for (size_t i = gapCount - 1; i > 0; --i) {
moveElements(advanceOrWrapAround(gapIndices[i]),
subtractOrWrapAround(gapIndices[i], gapCount - 1 - i),
diff --git a/util/include/chre/util/synchronized_expandable_memory_pool_impl.h b/util/include/chre/util/synchronized_expandable_memory_pool_impl.h
index 8b58ce78..8e20913f 100644
--- a/util/include/chre/util/synchronized_expandable_memory_pool_impl.h
+++ b/util/include/chre/util/synchronized_expandable_memory_pool_impl.h
@@ -17,6 +17,8 @@
#ifndef CHRE_UTIL_SYNCHRONIZED_EXPANDABLE_MEMORY_POOL_IMPL_H_
#define CHRE_UTIL_SYNCHRONIZED_EXPANDABLE_MEMORY_POOL_IMPL_H_
+#include <algorithm>
+
#include "chre/util/lock_guard.h"
#include "chre/util/memory_pool.h"
#include "chre/util/synchronized_expandable_memory_pool.h"
diff --git a/util/include/chre/util/synchronized_memory_pool.h b/util/include/chre/util/synchronized_memory_pool.h
index bce38863..2c6245b1 100644
--- a/util/include/chre/util/synchronized_memory_pool.h
+++ b/util/include/chre/util/synchronized_memory_pool.h
@@ -38,7 +38,7 @@ class SynchronizedMemoryPool : public NonCopyable {
* fails.
*/
template <typename... Args>
- ElementType *allocate(Args &&... args);
+ ElementType *allocate(Args &&...args);
/**
* Releases the memory of a previously allocated element. The pointer provided
diff --git a/util/include/chre/util/synchronized_memory_pool_impl.h b/util/include/chre/util/synchronized_memory_pool_impl.h
index 9d117187..526c3f92 100644
--- a/util/include/chre/util/synchronized_memory_pool_impl.h
+++ b/util/include/chre/util/synchronized_memory_pool_impl.h
@@ -25,7 +25,7 @@ namespace chre {
template <typename ElementType, size_t kSize>
template <typename... Args>
ElementType *SynchronizedMemoryPool<ElementType, kSize>::allocate(
- Args &&... args) {
+ Args &&...args) {
LockGuard<Mutex> lock(mMutex);
return mMemoryPool.allocate(args...);
}
diff --git a/util/include/chre/util/system/ble_util.h b/util/include/chre/util/system/ble_util.h
new file mode 100644
index 00000000..50720080
--- /dev/null
+++ b/util/include/chre/util/system/ble_util.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHRE_UTIL_SYSTEM_BLE_UTIL_H_
+#define CHRE_UTIL_SYSTEM_BLE_UTIL_H_
+
+#include "chre_api/chre.h"
+
+namespace chre {
+
+/**
+ * Populates a legacy chreBleAdvertisingReport's fields with values from the
+ * payload. The chreBleAdvertisingReport is based on the LE Extended Advertising
+ * Report Event defined in the BT Core Spec v5.3, Vol 4, Part E,
+ * Section 7.7.65.13. But for legacy LE Advertising Report Events (BT Core Spec
+ * v5.3, Vol 4, Part E, Section 7.7.65.2), some of these fields are only
+ * included in the payload. We parse out these fields to make it easier for the
+ * nanoapp to access this data.
+ *
+ * @param report CHRE BLE Advertising Report
+ */
+void populateLegacyAdvertisingReportFields(chreBleAdvertisingReport &report);
+
+} // namespace chre
+
+#endif // CHRE_UTIL_SYSTEM_BLE_UTIL_H_
diff --git a/util/include/chre/util/system/stats_container.h b/util/include/chre/util/system/stats_container.h
index d2e18d4d..4a5e4041 100644
--- a/util/include/chre/util/system/stats_container.h
+++ b/util/include/chre/util/system/stats_container.h
@@ -41,7 +41,7 @@ class StatsContainer {
* it should not be bigger than the default value to prevent rounding to 0
*/
StatsContainer(uint32_t averageWindow_ = 512)
- : mAverageWindow(averageWindow_){};
+ : mAverageWindow(averageWindow_) {}
/**
* Add a new value to the metric collection and update mean/max value
@@ -68,14 +68,14 @@ class StatsContainer {
*/
T getMean() const {
return mMean;
- };
+ }
/**
* @return the max value
*/
T getMax() const {
return mMax;
- };
+ }
/**
* @return the average window
@@ -97,4 +97,4 @@ class StatsContainer {
} // namespace chre
-#endif // CHRE_UTIL_SYSTEM_STATS_CONTAINER_H_ \ No newline at end of file
+#endif // CHRE_UTIL_SYSTEM_STATS_CONTAINER_H_
diff --git a/util/include/chre/util/time.h b/util/include/chre/util/time.h
index b3fef77e..a0e210ba 100644
--- a/util/include/chre/util/time.h
+++ b/util/include/chre/util/time.h
@@ -21,6 +21,9 @@
namespace chre {
+//! The number of seconds in one day.
+constexpr uint64_t kOneDayInSeconds(60 * 60 * 24);
+
//! The number of milliseconds in one min.
constexpr uint64_t kOneMinuteInMilliseconds(60000);
diff --git a/util/nanoapp/ble.cc b/util/nanoapp/ble.cc
index 09de5c43..50e0fb79 100644
--- a/util/nanoapp/ble.cc
+++ b/util/nanoapp/ble.cc
@@ -57,4 +57,28 @@ bool createBleScanFilterForKnownBeacons(struct chreBleScanFilter &filter,
return true;
}
+bool createBleScanFilterForKnownBeaconsV1_9(
+ struct chreBleScanFilterV1_9 &filter, chreBleGenericFilter *genericFilters,
+ uint8_t numGenericFilters) {
+ if (numGenericFilters < kNumScanFilters) {
+ return false;
+ }
+ memset(&filter, 0, sizeof(filter));
+
+ genericFilters[0] = createBleGenericFilter(
+ CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE, kNumScanFilters,
+ kGoogleEddystoneUuid, kGoogleUuidMask);
+ genericFilters[1] = createBleGenericFilter(
+ CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE, kNumScanFilters,
+ kGoogleNearbyFastpairUuid, kGoogleUuidMask);
+
+ filter.rssiThreshold = kRssiThreshold;
+ filter.genericFilterCount = kNumScanFilters;
+ filter.genericFilters = genericFilters;
+
+ filter.broadcasterAddressFilterCount = 0;
+ filter.broadcasterAddressFilters = nullptr;
+ return true;
+}
+
} // namespace chre
diff --git a/util/nanoapp/string.cc b/util/nanoapp/string.cc
new file mode 100644
index 00000000..3d160ad8
--- /dev/null
+++ b/util/nanoapp/string.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "chre/util/nanoapp/string.h"
+#include "chre/util/nanoapp/assert.h"
+
+namespace chre {
+
+void copyString(char *destination, const char *source,
+ size_t destinationBufferSize) {
+ CHRE_ASSERT_NOT_NULL(destination);
+ CHRE_ASSERT_NOT_NULL(source);
+
+ if (destinationBufferSize == 0) {
+ return;
+ }
+
+ uint32_t i;
+ for (i = 0; i < destinationBufferSize - 1 && source[i] != '\0'; ++i) {
+ destination[i] = source[i];
+ }
+
+ memset(&destination[i], 0, destinationBufferSize - i);
+}
+
+} // namespace chre
diff --git a/util/pigweed/chre_channel_output.cc b/util/pigweed/chre_channel_output.cc
index f88e5203..9fdce478 100644
--- a/util/pigweed/chre_channel_output.cc
+++ b/util/pigweed/chre_channel_output.cc
@@ -50,7 +50,6 @@ pw::Status sendToNanoapp(uint32_t targetInstanceId, uint16_t eventType,
}
data->msgSize = buffer.size();
- data->msg = &data[1];
memcpy(data->msg, buffer.data(), buffer.size());
if (!chreSendEvent(eventType, data, nappMessageFreeCb, targetInstanceId)) {
@@ -63,12 +62,6 @@ pw::Status sendToNanoapp(uint32_t targetInstanceId, uint16_t eventType,
} // namespace
-ChreChannelOutputBase::ChreChannelOutputBase() : ChannelOutput("CHRE") {}
-
-size_t ChreChannelOutputBase::MaximumTransmissionUnit() {
- return CHRE_MESSAGE_TO_HOST_MAX_SIZE - sizeof(ChrePigweedNanoappMessage);
-}
-
void ChreServerNanoappChannelOutput::setClient(uint32_t nanoappInstanceId) {
CHRE_ASSERT(nanoappInstanceId <= kRpcNanoappMaxId);
if (nanoappInstanceId <= kRpcNanoappMaxId) {
@@ -78,14 +71,17 @@ void ChreServerNanoappChannelOutput::setClient(uint32_t nanoappInstanceId) {
}
}
+size_t ChreServerNanoappChannelOutput::MaximumTransmissionUnit() {
+ return CHRE_MESSAGE_TO_HOST_MAX_SIZE - sizeof(ChrePigweedNanoappMessage);
+}
+
pw::Status ChreServerNanoappChannelOutput::Send(
pw::span<const std::byte> buffer) {
// The permission is not enforced across nanoapps but we still need to
// reset the value as it is only applicable to the next message.
mPermission.getAndReset();
- return sendToNanoapp(mClientInstanceId, PW_RPC_CHRE_NAPP_RESPONSE_EVENT_TYPE,
- buffer);
+ return sendToNanoapp(mClientInstanceId, CHRE_EVENT_RPC_RESPONSE, buffer);
}
void ChreClientNanoappChannelOutput::setServer(uint32_t instanceId) {
@@ -97,16 +93,23 @@ void ChreClientNanoappChannelOutput::setServer(uint32_t instanceId) {
}
}
+size_t ChreClientNanoappChannelOutput::MaximumTransmissionUnit() {
+ return CHRE_MESSAGE_TO_HOST_MAX_SIZE - sizeof(ChrePigweedNanoappMessage);
+}
+
pw::Status ChreClientNanoappChannelOutput::Send(
pw::span<const std::byte> buffer) {
- return sendToNanoapp(mServerInstanceId, PW_RPC_CHRE_NAPP_REQUEST_EVENT_TYPE,
- buffer);
+ return sendToNanoapp(mServerInstanceId, CHRE_EVENT_RPC_REQUEST, buffer);
}
void ChreServerHostChannelOutput::setHostEndpoint(uint16_t hostEndpoint) {
mEndpointId = hostEndpoint;
}
+size_t ChreServerHostChannelOutput::MaximumTransmissionUnit() {
+ return CHRE_MESSAGE_TO_HOST_MAX_SIZE - sizeof(ChrePigweedNanoappMessage);
+}
+
pw::Status ChreServerHostChannelOutput::Send(pw::span<const std::byte> buffer) {
CHRE_ASSERT(mEndpointId != CHRE_HOST_ENDPOINT_UNSPECIFIED);
pw::Status returnCode = PW_STATUS_OK;
@@ -119,7 +122,7 @@ pw::Status ChreServerHostChannelOutput::Send(pw::span<const std::byte> buffer) {
} else {
memcpy(data, buffer.data(), buffer.size());
if (!chreSendMessageWithPermissions(
- data, buffer.size(), PW_RPC_CHRE_HOST_MESSAGE_TYPE, mEndpointId,
+ data, buffer.size(), CHRE_MESSAGE_TYPE_RPC, mEndpointId,
permission, heapFreeMessageCallback)) {
returnCode = PW_STATUS_INVALID_ARGUMENT;
}
diff --git a/util/pigweed/rpc_client.cc b/util/pigweed/rpc_client.cc
index 72c034a5..6cf84626 100644
--- a/util/pigweed/rpc_client.cc
+++ b/util/pigweed/rpc_client.cc
@@ -33,7 +33,7 @@ namespace chre {
bool RpcClient::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
const void *eventData) {
switch (eventType) {
- case chre::ChreChannelOutputBase::PW_RPC_CHRE_NAPP_RESPONSE_EVENT_TYPE:
+ case CHRE_EVENT_RPC_RESPONSE:
return handleMessageFromServer(senderInstanceId, eventData);
case CHRE_EVENT_NANOAPP_STOPPED:
handleNanoappStopped(eventData);
@@ -58,10 +58,15 @@ bool RpcClient::hasService(uint64_t id, uint32_t version) {
return false;
}
+void RpcClient::close() {
+ chreConfigureNanoappInfoEvents(false);
+}
+
bool RpcClient::handleMessageFromServer(uint32_t senderInstanceId,
const void *eventData) {
auto data = static_cast<const chre::ChrePigweedNanoappMessage *>(eventData);
- pw::span packet(static_cast<const std::byte *>(data->msg), data->msgSize);
+ pw::span packet(reinterpret_cast<const std::byte *>(data->msg),
+ data->msgSize);
struct chreNanoappInfo info;
if (!chreGetNanoappInfoByAppId(mServerNanoappId, &info) ||
diff --git a/util/pigweed/rpc_server.cc b/util/pigweed/rpc_server.cc
index 1ee225a9..0bf7d671 100644
--- a/util/pigweed/rpc_server.cc
+++ b/util/pigweed/rpc_server.cc
@@ -29,15 +29,6 @@
namespace chre {
-RpcServer::~RpcServer() {
- chreConfigureNanoappInfoEvents(false);
- // TODO(b/251257328): Disable all notifications at once.
- while (!mConnectedHosts.empty()) {
- chreConfigureHostEndpointNotifications(mConnectedHosts[0], false);
- mConnectedHosts.erase(0);
- }
-}
-
bool RpcServer::registerServices(size_t numServices,
RpcServer::Service *services) {
// Avoid blowing up the stack with chreServices.
@@ -77,7 +68,7 @@ bool RpcServer::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
switch (eventType) {
case CHRE_EVENT_MESSAGE_FROM_HOST:
return handleMessageFromHost(eventData);
- case ChreChannelOutputBase::PW_RPC_CHRE_NAPP_REQUEST_EVENT_TYPE:
+ case CHRE_EVENT_RPC_REQUEST:
return handleMessageFromNanoapp(senderInstanceId, eventData);
case CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION:
handleHostClientNotification(eventData);
@@ -90,11 +81,19 @@ bool RpcServer::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
}
}
+void RpcServer::close() {
+ chreConfigureNanoappInfoEvents(false);
+ // TODO(b/251257328): Disable all notifications at once.
+ while (!mConnectedHosts.empty()) {
+ chreConfigureHostEndpointNotifications(mConnectedHosts[0], false);
+ mConnectedHosts.erase(0);
+ }
+}
+
bool RpcServer::handleMessageFromHost(const void *eventData) {
auto *hostMessage = static_cast<const chreMessageFromHostData *>(eventData);
- if (hostMessage->messageType !=
- ChreChannelOutputBase::PW_RPC_CHRE_HOST_MESSAGE_TYPE) {
+ if (hostMessage->messageType != CHRE_MESSAGE_TYPE_RPC) {
return false;
}
@@ -138,7 +137,8 @@ bool RpcServer::handleMessageFromHost(const void *eventData) {
bool RpcServer::handleMessageFromNanoapp(uint32_t senderInstanceId,
const void *eventData) {
const auto data = static_cast<const ChrePigweedNanoappMessage *>(eventData);
- pw::span packet(static_cast<const std::byte *>(data->msg), data->msgSize);
+ pw::span packet(reinterpret_cast<const std::byte *>(data->msg),
+ data->msgSize);
pw::Result<uint32_t> result = pw::rpc::ExtractChannelId(packet);
if (result.status() != PW_STATUS_OK) {
diff --git a/util/system/ble_util.cc b/util/system/ble_util.cc
new file mode 100644
index 00000000..eb614260
--- /dev/null
+++ b/util/system/ble_util.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "chre/util/system/ble_util.h"
+
+#include <cinttypes>
+
+#include "chre/platform/log.h"
+
+namespace chre {
+
+namespace {
+
+// Tx Power Level AD Type defined in the BT Core Spec v5.3 Assigned Numbers,
+// Generic Access Profile (ref:
+// https://www.bluetooth.com/specifications/assigned-numbers/).
+constexpr uint8_t kTxPowerLevelAdType = 0x0A;
+constexpr uint8_t kAdTypeOffset = 1;
+constexpr uint8_t kExpectedAdDataLength = 2;
+
+/**
+ * Gets the TX Power from the data field of legacy AD reports. This function
+ * parses the advertising data which is defined in the BT Core Spec v5.3, Vol 3,
+ * Part C, Section 11, Advertising and Scan Response Data Format, and checks for
+ * the presence of the Tx Power Level AD Type.
+ *
+ * @param data Advertising data.
+ * @param dataLength Length of advertising data.
+ * @return int8_t Tx Power value.
+ */
+int8_t getTxPowerFromLegacyReport(const uint8_t *data, size_t dataLength) {
+ size_t i = 0;
+ while (i < dataLength) {
+ uint8_t adDataLength = data[i];
+ if (adDataLength == 0 || (adDataLength >= dataLength - i)) {
+ break;
+ }
+ if (data[i + kAdTypeOffset] == kTxPowerLevelAdType &&
+ adDataLength == kExpectedAdDataLength) {
+ return static_cast<int8_t>(data[i + kExpectedAdDataLength]);
+ }
+ i += kAdTypeOffset + adDataLength;
+ }
+ return CHRE_BLE_TX_POWER_NONE;
+}
+
+} // namespace
+
+void populateLegacyAdvertisingReportFields(chreBleAdvertisingReport &report) {
+ if ((report.eventTypeAndDataStatus & CHRE_BLE_EVENT_TYPE_FLAG_LEGACY) != 0 &&
+ report.txPower == CHRE_BLE_TX_POWER_NONE) {
+ report.txPower = getTxPowerFromLegacyReport(report.data, report.dataLength);
+ }
+}
+
+} // namespace chre
diff --git a/util/tests/array_queue_test.cc b/util/tests/array_queue_test.cc
index fbacaedf..d1e0d6de 100644
--- a/util/tests/array_queue_test.cc
+++ b/util/tests/array_queue_test.cc
@@ -103,6 +103,15 @@ TEST(ArrayQueueTest, SimplePushPopBackPush) {
EXPECT_EQ(5, q[0]);
EXPECT_EQ(6, q[1]);
EXPECT_EQ(7, q[2]);
+
+ q.pop_back();
+
+ EXPECT_EQ(5, q[0]);
+ EXPECT_EQ(6, q[1]);
+
+ q.pop();
+
+ EXPECT_EQ(6, q[0]);
}
TEST(ArrayQueueTest, TestSize) {
@@ -192,12 +201,19 @@ TEST(ArrayQueueTest, TestFront) {
TEST(ArrayQueueTest, TestBack) {
ArrayQueue<int, 3> q;
q.push(1);
- EXPECT_EQ(1, q.back());
- q.pop();
+ EXPECT_EQ(1, q.back()); // 1 x x
q.push(2);
- EXPECT_EQ(2, q.back());
+ EXPECT_EQ(2, q.back()); // 1 2 x
+ q.pop();
+ EXPECT_EQ(2, q.back()); // x 2 x
q.push(3);
- EXPECT_EQ(3, q.back());
+ EXPECT_EQ(3, q.back()); // x 2 3
+ q.push(4);
+ EXPECT_EQ(4, q.back()); // 4 2 3 (forward wrap-around)
+ q.pop_back();
+ EXPECT_EQ(3, q.back()); // x 2 3 (backwards wrap-around)
+ q.pop();
+ EXPECT_EQ(3, q.back()); // x x 3
}
TEST(ArrayQueueDeathTest, InvalidSubscript) {
diff --git a/util/tests/ble_util_test.cc b/util/tests/ble_util_test.cc
new file mode 100644
index 00000000..762a6aa7
--- /dev/null
+++ b/util/tests/ble_util_test.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+
+#include <string.h>
+
+#include "chre/util/system/ble_util.h"
+
+TEST(BleUtil, PopulateTxPower) {
+ chreBleAdvertisingReport report;
+ memset(&report, 0, sizeof(report));
+ report.txPower = CHRE_BLE_TX_POWER_NONE;
+ report.eventTypeAndDataStatus = CHRE_BLE_EVENT_TYPE_FLAG_LEGACY;
+ int8_t txPower = -11;
+ uint8_t data[3] = {0x02, 0x0A, static_cast<uint8_t>(txPower)};
+ report.data = data;
+ report.dataLength = 3;
+ chre::populateLegacyAdvertisingReportFields(report);
+ EXPECT_EQ(report.txPower, txPower);
+}
diff --git a/util/tests/string_test.cc b/util/tests/string_test.cc
new file mode 100644
index 00000000..74c2df71
--- /dev/null
+++ b/util/tests/string_test.cc
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+
+#include "chre/util/nanoapp/string.h"
+
+using ::chre::copyString;
+
+TEST(StringDeathTest, InvalidInput) {
+ char destination[100];
+ ASSERT_DEATH(copyString(nullptr, nullptr, 0), ".*");
+ ASSERT_DEATH(copyString(nullptr, destination, 1), ".*");
+ ASSERT_DEATH(copyString(destination, nullptr, 2), ".*");
+}
+
+TEST(String, ZeroCharsToCopy) {
+ const char *source = "hello world";
+ constexpr size_t destinationLength = 100;
+ char destination[destinationLength];
+ char fillValue = 123;
+
+ memset(destination, fillValue, destinationLength);
+
+ copyString(destination, source, 0);
+ for (size_t i = 0; i < destinationLength; ++i) {
+ ASSERT_EQ(destination[i], fillValue);
+ }
+}
+
+TEST(String, EmptyStringPadsWithZeroes) {
+ const char *source = "";
+ constexpr size_t destinationLength = 100;
+ char destination[destinationLength];
+ char fillValue = 123;
+
+ memset(destination, fillValue, destinationLength);
+
+ copyString(destination, source, destinationLength);
+ for (size_t i = 0; i < destinationLength; ++i) {
+ ASSERT_EQ(destination[i], 0);
+ }
+}
+
+TEST(String, NormalCopyOneChar) {
+ const char *source = "hello world";
+ constexpr size_t destinationLength = 100;
+ char destination[destinationLength];
+ char fillValue = 123;
+
+ memset(destination, fillValue, destinationLength);
+
+ copyString(destination, source, 2); // one char + '\0'
+ ASSERT_EQ(destination[0], source[0]);
+ ASSERT_EQ(destination[1], 0);
+ for (size_t i = 2; i < destinationLength; ++i) {
+ ASSERT_EQ(destination[i], fillValue);
+ }
+}
+
+TEST(String, NormalCopyAllChars) {
+ const char *source = "hello world";
+ constexpr size_t sourceLength = 11;
+ constexpr size_t destinationLength = 100;
+ char destination[destinationLength];
+ char fillValue = 123;
+
+ memset(destination, fillValue, destinationLength);
+
+ copyString(destination, source, sourceLength + 1); // account for '\0'
+ size_t i = 0;
+ for (; i < sourceLength; ++i) {
+ ASSERT_EQ(destination[i], source[i]);
+ }
+
+ ASSERT_EQ(destination[i], 0);
+ ++i;
+
+ for (; i < destinationLength; ++i) {
+ ASSERT_EQ(destination[i], fillValue);
+ }
+}
+
+TEST(String, NormalCopyGreaterThanSourceLength) {
+ const char *source = "hello world";
+ constexpr size_t sourceLength = 11;
+ constexpr size_t destinationLength = 100;
+ char destination[destinationLength];
+ char fillValue = 123;
+
+ memset(destination, fillValue, destinationLength);
+
+ copyString(destination, source, destinationLength);
+ size_t i = 0;
+ for (; i < sourceLength; ++i) {
+ ASSERT_EQ(destination[i], source[i]);
+ }
+
+ for (; i < destinationLength; ++i) {
+ ASSERT_EQ(destination[i], 0);
+ }
+}
+
+TEST(String, NormalCopyLessThanSourceLength) {
+ const char *source = "hello world";
+ constexpr size_t sourceLength = 11;
+ constexpr size_t destinationLength = 5;
+ char destination[destinationLength];
+ char fillValue = 123;
+
+ memset(destination, fillValue, destinationLength);
+
+ copyString(destination, source, destinationLength);
+ size_t i = 0;
+ for (; i < destinationLength - 1; ++i) {
+ ASSERT_EQ(destination[i], source[i]);
+ }
+ ASSERT_EQ(destination[i], 0);
+}
diff --git a/util/tests/synchronized_expandable_memory_pool_test.cc b/util/tests/synchronized_expandable_memory_pool_test.cc
index 3b88e598..f5957a9e 100644
--- a/util/tests/synchronized_expandable_memory_pool_test.cc
+++ b/util/tests/synchronized_expandable_memory_pool_test.cc
@@ -16,7 +16,6 @@
#include "chre/util/synchronized_expandable_memory_pool.h"
-#include "chre/util/synchronized_memory_pool.h"
#include "gtest/gtest.h"
using chre::SynchronizedExpandableMemoryPool;
@@ -102,4 +101,4 @@ TEST(SynchronizedExpandAbleMemoryPool, HysteresisDeallocation) {
// Once it is empty, it should not still hold maxBlockCount as before.
EXPECT_EQ(testMemoryPool.getFreeSpaceCount(), blockSize * maxBlockCount);
EXPECT_EQ(testMemoryPool.getBlockCount(), staticBlockCount);
-} \ No newline at end of file
+}
diff --git a/util/tests/synchronized_memory_pool_test.cc b/util/tests/synchronized_memory_pool_test.cc
new file mode 100644
index 00000000..cecff880
--- /dev/null
+++ b/util/tests/synchronized_memory_pool_test.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "chre/util/synchronized_memory_pool.h"
+
+#include "gtest/gtest.h"
+
+using chre::SynchronizedMemoryPool;
+
+namespace {
+
+class ConstructorCount {
+ public:
+ ConstructorCount(int value_) : value(value_) {
+ sConstructedCounter++;
+ }
+ ~ConstructorCount() {
+ sConstructedCounter--;
+ }
+ int getValue() {
+ return value;
+ }
+
+ static ssize_t sConstructedCounter;
+
+ private:
+ const int value;
+};
+
+ssize_t ConstructorCount::sConstructedCounter = 0;
+
+} // namespace
+
+TEST(SynchronizedMemoryPool, FreeBlockCheck) {
+ constexpr uint8_t maxSize = 12;
+ constexpr uint8_t blankSpace = 2;
+
+ SynchronizedMemoryPool<int, maxSize> testMemoryPool;
+ int *tempDataPtrs[maxSize];
+
+ for (int i = 0; i < maxSize - blankSpace; ++i) {
+ tempDataPtrs[i] = testMemoryPool.allocate(i);
+ }
+
+ EXPECT_EQ(testMemoryPool.getFreeBlockCount(), blankSpace);
+
+ for (int i = 0; i < maxSize - blankSpace; ++i) {
+ testMemoryPool.deallocate(tempDataPtrs[i]);
+ }
+}
diff --git a/util/util.mk b/util/util.mk
index 7c6337e8..1a7ae3e8 100644
--- a/util/util.mk
+++ b/util/util.mk
@@ -16,7 +16,9 @@ COMMON_SRCS += $(CHRE_PREFIX)/util/nanoapp/audio.cc
COMMON_SRCS += $(CHRE_PREFIX)/util/nanoapp/ble.cc
COMMON_SRCS += $(CHRE_PREFIX)/util/nanoapp/callbacks.cc
COMMON_SRCS += $(CHRE_PREFIX)/util/nanoapp/debug.cc
+COMMON_SRCS += $(CHRE_PREFIX)/util/nanoapp/string.cc
COMMON_SRCS += $(CHRE_PREFIX)/util/nanoapp/wifi.cc
+COMMON_SRCS += $(CHRE_PREFIX)/util/system/ble_util.cc
COMMON_SRCS += $(CHRE_PREFIX)/util/system/event_callbacks.cc
COMMON_SRCS += $(CHRE_PREFIX)/util/system/debug_dump.cc
@@ -43,6 +45,7 @@ GOOGLETEST_SRCS += $(CHRE_PREFIX)/util/tests/shared_ptr_test.cc
GOOGLETEST_SRCS += $(CHRE_PREFIX)/util/tests/singleton_test.cc
GOOGLETEST_SRCS += $(CHRE_PREFIX)/util/tests/stats_container_test.cc
GOOGLETEST_SRCS += $(CHRE_PREFIX)/util/tests/synchronized_expandable_memory_pool_test.cc
+GOOGLETEST_SRCS += $(CHRE_PREFIX)/util/tests/synchronized_memory_pool_test.cc
GOOGLETEST_SRCS += $(CHRE_PREFIX)/util/tests/time_test.cc
GOOGLETEST_SRCS += $(CHRE_PREFIX)/util/tests/unique_ptr_test.cc
diff --git a/variant/exynos-embos/variant.mk b/variant/exynos-embos/variant.mk
index 03868f49..a35e3688 100644
--- a/variant/exynos-embos/variant.mk
+++ b/variant/exynos-embos/variant.mk
@@ -27,9 +27,6 @@ COMMON_CFLAGS += -DCHRE_VARIANT_SUPPLIES_STATIC_NANOAPP_LIST
EMBOS_CFLAGS += -DCHRE_EVENT_PER_BLOCK=32
EMBOS_CFLAGS += -DCHRE_MAX_EVENT_BLOCKS=4
-EMBOS_CFLAGS += -DCHRE_UNSCHEDULED_EVENT_PER_BLOCK=32
-EMBOS_CFLAGS += -DCHRE_MAX_UNSCHEDULED_EVENT_BLOCKS=4
-
# Optional Features ############################################################
CHRE_AUDIO_SUPPORT_ENABLED = true
diff --git a/variant/tinysys/variant.mk b/variant/tinysys/variant.mk
index 15cf183b..69ab3f9c 100644
--- a/variant/tinysys/variant.mk
+++ b/variant/tinysys/variant.mk
@@ -60,9 +60,6 @@ COMMON_CFLAGS += -DCHRE_VARIANT_SUPPLIES_STATIC_NANOAPP_LIST
TINYSYS_CFLAGS += -DCHRE_EVENT_PER_BLOCK=32
TINYSYS_CFLAGS += -DCHRE_MAX_EVENT_BLOCKS=4
-TINYSYS_CFLAGS += -DCHRE_UNSCHEDULED_EVENT_PER_BLOCK=32
-TINYSYS_CFLAGS += -DCHRE_MAX_UNSCHEDULED_EVENT_BLOCKS=4
-
# Optional Features ############################################################
CHRE_AUDIO_SUPPORT_ENABLED = true