summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Laver <lavers@google.com>2020-02-04 22:57:22 -0800
committerSteven Laver <lavers@google.com>2020-02-06 14:27:42 -0800
commit89ec9480cf4430b6728b16396a408c1aa26f19a9 (patch)
treef9a888e63588b25c457d8871f6fbb6b673044f1a
parent4e64db5a184f0734778df5e1c12d32f702220b35 (diff)
parent146a5a28331209aa145c0af2f883b7e023ce4800 (diff)
Merge RP1A.200204.001
Change-Id: Icdc452e8cf70e432759c112a5b5b12b61e40f0bc
-rwxr-xr-xaudio/common/all-versions/copyHAL.sh4
-rw-r--r--audio/common/all-versions/default/service/Android.bp19
-rw-r--r--audio/common/all-versions/default/service/service.cpp102
-rw-r--r--audio/core/all-versions/default/PrimaryDevice.cpp3
-rw-r--r--audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp12
-rw-r--r--audio/core/all-versions/vts/functional/Android.bp18
-rw-r--r--audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml40
-rw-r--r--audio/effect/6.0/xml/api/current.txt71
-rw-r--r--audio/effect/6.0/xml/audio_effects_conf.xsd95
-rw-r--r--automotive/audiocontrol/1.0/default/Android.bp5
-rw-r--r--automotive/audiocontrol/2.0/Android.bp20
-rw-r--r--automotive/audiocontrol/2.0/IAudioControl.hal78
-rw-r--r--automotive/audiocontrol/2.0/ICloseHandle.hal34
-rw-r--r--automotive/audiocontrol/2.0/IFocusListener.hal55
-rw-r--r--automotive/audiocontrol/2.0/default/Android.bp39
-rw-r--r--automotive/audiocontrol/2.0/default/AudioControl.cpp60
-rw-r--r--automotive/audiocontrol/2.0/default/AudioControl.h49
-rw-r--r--automotive/audiocontrol/2.0/default/CloseHandle.cpp35
-rw-r--r--automotive/audiocontrol/2.0/default/CloseHandle.h48
-rw-r--r--automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc4
-rw-r--r--automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml11
-rw-r--r--automotive/audiocontrol/2.0/default/service.cpp52
-rw-r--r--automotive/audiocontrol/2.0/types.hal31
-rw-r--r--automotive/audiocontrol/2.0/vts/functional/Android.bp29
-rw-r--r--automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp155
-rw-r--r--automotive/evs/1.1/IEvsEnumerator.hal7
-rw-r--r--automotive/evs/1.1/default/Android.bp2
-rw-r--r--automotive/evs/1.1/default/EvsEnumerator.cpp2
-rw-r--r--automotive/evs/1.1/default/EvsEnumerator.h1
-rw-r--r--automotive/evs/1.1/default/ServiceNames.h2
-rw-r--r--automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp2
-rw-r--r--automotive/evs/1.1/vts/fuzzing/Android.bp50
-rw-r--r--automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp84
-rw-r--r--automotive/evs/1.1/vts/fuzzing/common.h57
-rw-r--r--automotive/vehicle/2.0/default/Android.bp70
-rw-r--r--automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp15
-rw-r--r--automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp56
-rw-r--r--automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc10
-rw-r--r--automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc4
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto14
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp162
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h40
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp229
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h49
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp115
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h49
-rw-r--r--automotive/vehicle/2.0/types.hal466
-rw-r--r--biometrics/face/1.1/Android.bp17
-rw-r--r--biometrics/face/1.1/IBiometricsFace.hal117
-rw-r--r--biometrics/face/1.1/default/Android.bp36
-rw-r--r--biometrics/face/1.1/default/BiometricsFace.cpp129
-rw-r--r--biometrics/face/1.1/default/BiometricsFace.h88
-rw-r--r--biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc10
-rw-r--r--biometrics/face/1.1/default/manifest_face_default.xml11
-rw-r--r--biometrics/face/1.1/default/service.cpp50
-rw-r--r--biometrics/face/1.1/vts/functional/Android.bp29
-rw-r--r--biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp205
-rw-r--r--biometrics/fingerprint/2.2/Android.bp19
-rw-r--r--biometrics/fingerprint/2.2/IBiometricsFingerprint.hal58
-rw-r--r--biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal35
-rw-r--r--biometrics/fingerprint/2.2/types.hal42
-rw-r--r--biometrics/fingerprint/2.2/vts/functional/Android.bp29
-rw-r--r--biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp166
-rw-r--r--camera/device/3.4/default/ExternalCameraDeviceSession.cpp596
-rw-r--r--camera/device/3.4/default/ExternalCameraUtils.cpp547
-rw-r--r--camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h225
-rw-r--r--camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h2
-rw-r--r--camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h147
-rw-r--r--camera/device/3.5/default/ExternalCameraDeviceSession.cpp10
-rw-r--r--camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h64
-rw-r--r--camera/device/3.6/default/Android.bp67
-rw-r--r--camera/device/3.6/default/ExternalCameraDevice.cpp91
-rw-r--r--camera/device/3.6/default/ExternalCameraDeviceSession.cpp357
-rw-r--r--camera/device/3.6/default/ExternalCameraOfflineSession.cpp554
-rw-r--r--camera/device/3.6/default/OWNERS1
-rw-r--r--camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h208
-rw-r--r--camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h77
-rw-r--r--camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h232
-rw-r--r--camera/metadata/3.5/types.hal28
-rw-r--r--camera/provider/2.4/ICameraProvider.hal2
-rw-r--r--camera/provider/2.4/ICameraProviderCallback.hal4
-rw-r--r--camera/provider/2.4/default/Android.bp5
-rw-r--r--camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp16
-rw-r--r--camera/provider/2.4/vts/functional/Android.bp1
-rw-r--r--camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp66
-rw-r--r--camera/provider/2.5/default/Android.bp9
-rw-r--r--camera/provider/2.6/Android.bp26
-rw-r--r--camera/provider/2.6/ICameraProvider.hal110
-rw-r--r--camera/provider/2.6/ICameraProviderCallback.hal54
-rw-r--r--camera/provider/2.6/types.hal30
-rw-r--r--compatibility_matrices/Android.mk21
-rw-r--r--compatibility_matrices/compatibility_matrix.current.xml26
-rw-r--r--current.txt45
-rw-r--r--drm/1.0/default/OWNERS6
-rw-r--r--drm/1.0/vts/OWNERS6
-rw-r--r--drm/1.0/vts/functional/Android.bp62
-rw-r--r--drm/1.0/vts/functional/drm_hal_clearkey_test.cpp201
-rw-r--r--drm/1.0/vts/functional/drm_hal_test_main.cpp71
l---------[-rw-r--r--]drm/1.0/vts/functional/drm_hal_vendor_module_api.h235
-rw-r--r--drm/1.0/vts/functional/drm_hal_vendor_test.cpp264
-rw-r--r--drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h201
-rw-r--r--drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_vendor_test.h209
-rw-r--r--drm/1.0/vts/functional/include/drm_hal_vendor_module_api.h234
-rw-r--r--drm/1.0/vts/functional/include/drm_vts_helper.h58
-rw-r--r--drm/1.0/vts/functional/include/vendor_modules.h (renamed from drm/1.0/vts/functional/vendor_modules.h)5
-rw-r--r--drm/1.0/vts/functional/vendor_modules.cpp12
-rw-r--r--drm/1.1/vts/OWNERS6
-rw-r--r--drm/1.1/vts/functional/Android.bp43
-rw-r--r--drm/1.1/vts/functional/drm_hal_clearkey_test.cpp227
-rw-r--r--drm/1.1/vts/functional/drm_hal_test_main.cpp52
-rw-r--r--drm/1.1/vts/functional/include/android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h209
-rw-r--r--drm/1.2/vts/OWNERS6
-rw-r--r--drm/1.2/vts/functional/Android.bp48
-rw-r--r--drm/1.2/vts/functional/drm_hal_common.cpp84
-rw-r--r--drm/1.2/vts/functional/drm_hal_test.cpp130
-rw-r--r--drm/1.2/vts/functional/drm_hal_test_main.cpp80
-rw-r--r--drm/1.2/vts/functional/include/android/hardware/drm/1.2/vts/drm_hal_common.h (renamed from drm/1.2/vts/functional/drm_hal_common.h)40
-rw-r--r--drm/1.2/vts/functional/vendor_modules.cpp72
-rw-r--r--drm/1.2/vts/functional/vendor_modules.h73
-rw-r--r--drm/1.3/vts/OWNERS9
-rw-r--r--drm/1.3/vts/functional/Android.bp78
-rw-r--r--drm/1.3/vts/functional/drm_hal_test.cpp60
-rw-r--r--drm/1.3/vts/functional/drm_hal_test_main.cpp134
-rw-r--r--drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h86
-rw-r--r--dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp2
-rw-r--r--dumpstate/1.1/Android.bp18
-rw-r--r--dumpstate/1.1/IDumpstateDevice.hal53
-rw-r--r--dumpstate/1.1/types.hal62
-rw-r--r--dumpstate/1.1/vts/functional/Android.bp29
-rw-r--r--dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp176
-rw-r--r--gnss/1.0/IGnssCallback.hal1
-rw-r--r--gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp14
-rw-r--r--gnss/1.1/vts/functional/Android.bp6
-rw-r--r--gnss/1.1/vts/functional/gnss_hal_test_cases.cpp10
-rw-r--r--gnss/2.0/vts/functional/gnss_hal_test_cases.cpp6
-rw-r--r--gnss/2.1/Android.bp2
-rw-r--r--gnss/2.1/IGnss.hal11
-rw-r--r--gnss/2.1/IGnssMeasurementCallback.hal113
-rw-r--r--gnss/2.1/default/Android.bp1
-rw-r--r--gnss/2.1/default/Gnss.cpp8
-rw-r--r--gnss/2.1/default/Gnss.h2
-rw-r--r--gnss/2.1/default/GnssMeasurementCorrections.cpp39
-rw-r--r--gnss/2.1/default/GnssMeasurementCorrections.h11
-rw-r--r--gnss/2.1/types.hal46
-rw-r--r--gnss/2.1/vts/functional/Android.bp6
-rw-r--r--gnss/2.1/vts/functional/gnss_hal_test.cpp7
-rw-r--r--gnss/2.1/vts/functional/gnss_hal_test.h14
-rw-r--r--gnss/2.1/vts/functional/gnss_hal_test_cases.cpp62
-rw-r--r--gnss/common/utils/default/Utils.cpp27
-rw-r--r--gnss/common/utils/vts/Android.bp1
-rw-r--r--gnss/common/utils/vts/Utils.cpp16
-rw-r--r--gnss/common/utils/vts/include/Utils.h9
-rw-r--r--gnss/measurement_corrections/1.1/Android.bp19
-rw-r--r--gnss/measurement_corrections/1.1/IMeasurementCorrections.hal40
-rw-r--r--gnss/measurement_corrections/1.1/types.hal58
-rw-r--r--graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl2
-rw-r--r--graphics/composer/2.1/utils/vts/Android.bp3
-rw-r--r--graphics/composer/2.1/utils/vts/ComposerVts.cpp7
-rw-r--r--graphics/composer/2.2/utils/vts/Android.bp3
-rw-r--r--graphics/composer/2.2/utils/vts/ComposerVts.cpp1
-rw-r--r--graphics/composer/2.2/utils/vts/RenderEngineVts.cpp10
-rw-r--r--graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h1
-rw-r--r--graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h2
-rw-r--r--graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h2
-rw-r--r--graphics/composer/2.2/vts/functional/Android.bp10
-rw-r--r--graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp2
-rw-r--r--graphics/composer/2.3/utils/vts/Android.bp1
-rw-r--r--graphics/composer/2.3/utils/vts/ComposerVts.cpp7
-rw-r--r--graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h1
-rw-r--r--graphics/composer/2.4/IComposerClient.hal74
-rw-r--r--graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h21
-rw-r--r--graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h8
-rw-r--r--graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h37
-rw-r--r--graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h4
-rw-r--r--graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h62
-rw-r--r--graphics/composer/2.4/utils/vts/Android.bp2
-rw-r--r--graphics/composer/2.4/utils/vts/ComposerVts.cpp17
-rw-r--r--graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h4
-rw-r--r--graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp29
-rw-r--r--health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp4
-rw-r--r--health/2.1/README.md22
-rw-r--r--health/2.1/default/android.hardware.health@2.1-service.rc2
-rw-r--r--health/2.1/vts/functional/Android.bp5
-rw-r--r--health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp10
-rw-r--r--health/utils/libhealthloop/utils.cpp2
-rw-r--r--identity/1.0/Android.bp7
-rw-r--r--keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h1
-rw-r--r--keymaster/4.1/types.hal19
-rw-r--r--light/aidl/Android.bp18
-rw-r--r--light/aidl/android/hardware/light/BrightnessMode.aidl58
-rw-r--r--light/aidl/android/hardware/light/FlashMode.aidl34
-rw-r--r--light/aidl/android/hardware/light/HwLight.aidl42
-rw-r--r--light/aidl/android/hardware/light/HwLightState.aidl64
-rw-r--r--light/aidl/android/hardware/light/ILights.aidl47
-rw-r--r--light/aidl/android/hardware/light/LightType.aidl35
-rw-r--r--light/aidl/default/Android.bp16
-rw-r--r--light/aidl/default/Lights.cpp39
-rw-r--r--light/aidl/default/Lights.h35
-rw-r--r--light/aidl/default/lights-default.rc5
-rw-r--r--light/aidl/default/lights-default.xml6
-rw-r--r--light/aidl/default/main.cpp35
-rw-r--r--light/aidl/vts/functional/Android.bp35
-rw-r--r--light/aidl/vts/functional/VtsHalLightTargetTest.cpp171
-rw-r--r--light/utils/Android.bp4
-rw-r--r--light/utils/main.cpp104
-rw-r--r--memtrack/1.0/default/Memtrack.cpp4
-rw-r--r--neuralnetworks/1.3/Android.bp1
-rw-r--r--neuralnetworks/1.3/IFencedExecutionCallback.hal61
-rw-r--r--neuralnetworks/1.3/IPreparedModel.hal89
-rw-r--r--neuralnetworks/1.3/types.hal130
-rw-r--r--neuralnetworks/1.3/types.t13
-rw-r--r--neuralnetworks/1.3/vts/functional/Android.bp1
-rw-r--r--neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp74
-rw-r--r--neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h2
-rw-r--r--neuralnetworks/1.3/vts/functional/ValidateModel.cpp15
-rw-r--r--neuralnetworks/1.3/vts/functional/ValidateRequest.cpp18
-rw-r--r--neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp18
-rw-r--r--radio/1.1/vts/functional/radio_hidl_hal_api.cpp4
-rw-r--r--radio/1.5/IRadio.hal44
-rw-r--r--radio/1.5/IRadioResponse.hal58
-rw-r--r--radio/1.5/types.hal76
-rw-r--r--radio/1.5/vts/functional/radio_hidl_hal_api.cpp49
-rw-r--r--radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h7
-rw-r--r--radio/1.5/vts/functional/radio_response.cpp12
-rw-r--r--radio/config/1.3/types.hal20
-rw-r--r--rebootescrow/aidl/default/RebootEscrow.cpp11
-rw-r--r--rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h7
-rw-r--r--rebootescrow/aidl/default/rebootescrow-default.rc4
-rw-r--r--rebootescrow/aidl/default/service.cpp8
-rw-r--r--rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp12
-rw-r--r--secure_element/1.2/Android.bp18
-rw-r--r--secure_element/1.2/ISecureElement.hal35
-rw-r--r--secure_element/1.2/vts/functional/Android.bp27
-rw-r--r--secure_element/1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp101
-rw-r--r--sensors/2.0/multihal/HalProxy.cpp4
-rw-r--r--soundtrigger/2.3/types.hal2
-rw-r--r--tv/tuner/1.0/TEST_MAPPING7
-rw-r--r--tv/tuner/1.0/vts/functional/Android.bp7
-rw-r--r--tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp56
-rw-r--r--vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl5
-rw-r--r--vibrator/aidl/android/hardware/vibrator/IVibrator.aidl21
-rw-r--r--vibrator/aidl/default/Vibrator.cpp26
-rw-r--r--vibrator/aidl/default/include/vibrator-impl/Vibrator.h3
-rw-r--r--vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp47
-rw-r--r--wifi/1.2/IWifiStaIface.hal2
-rw-r--r--wifi/1.3/IWifiStaIface.hal2
-rw-r--r--wifi/1.4/default/wifi.cpp4
-rw-r--r--wifi/1.4/default/wifi_legacy_hal.cpp7
-rw-r--r--wifi/1.4/default/wifi_legacy_hal.h3
249 files changed, 11107 insertions, 2225 deletions
diff --git a/audio/common/all-versions/copyHAL.sh b/audio/common/all-versions/copyHAL.sh
index d07012fe04..56559d13e3 100755
--- a/audio/common/all-versions/copyHAL.sh
+++ b/audio/common/all-versions/copyHAL.sh
@@ -26,6 +26,7 @@ readonly IMPL_FACTORYHAL=$IMPL_DIRECTORY/include/libaudiohal/FactoryHalHidl.h
readonly VTS_DIRECTORY=test/vts-testcase/hal/audio
readonly VTS_LIST=test/vts/tools/build/tasks/list/vts_test_lib_hidl_package_list.mk
readonly WATCHDOG=frameworks/base/services/core/java/com/android/server/Watchdog.cpp
+readonly DUMP_UTILS=frameworks/native/libs/dumputils/dump_utils.cpp
readonly GSI_CURRENT=build/make/target/product/gsi/current.txt
readonly BASE_VERSION=${1:-$(ls $ANDROID_BUILD_TOP/$HAL_DIRECTORY | grep -E '[0-9]+\.[0-9]+' |
@@ -171,6 +172,9 @@ runIfNeeded $(dirname $VTS_LIST) updateAudioVersion -v original_before=1 $(basen
echo "Now update watchdog"
runIfNeeded $(dirname $WATCHDOG) updateAudioVersion -v original_before=1 $(basename $WATCHDOG)
+echo "Now update dumputils"
+runIfNeeded $(dirname $DUMP_UTILS) updateAudioVersion -v original_before=1 $(basename $DUMP_UTILS)
+
echo "Now update GSI current.txt"
runIfNeeded $(dirname $GSI_CURRENT) update-vndk-list.sh
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
index 6737ba6428..e5d47706c3 100644
--- a/audio/common/all-versions/default/service/Android.bp
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -25,25 +25,6 @@ cc_binary {
"liblog",
"libutils",
"libhardware",
- "android.hardware.audio@2.0",
- "android.hardware.audio@4.0",
- "android.hardware.audio@5.0",
- "android.hardware.audio@6.0",
- "android.hardware.audio.common@2.0",
- "android.hardware.audio.common@4.0",
- "android.hardware.audio.common@5.0",
- "android.hardware.audio.common@6.0",
- "android.hardware.audio.effect@2.0",
- "android.hardware.audio.effect@4.0",
- "android.hardware.audio.effect@5.0",
- "android.hardware.audio.effect@6.0",
- "android.hardware.bluetooth.a2dp@1.0",
- "android.hardware.bluetooth.audio@2.0",
- "android.hardware.soundtrigger@2.0",
- "android.hardware.soundtrigger@2.1",
- "android.hardware.soundtrigger@2.2",
- "android.hardware.soundtrigger@2.3",
- "com.qualcomm.qti.bluetooth_audio@1.0",
],
arch : {
arm : {
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index d53443356a..2801769863 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -16,20 +16,9 @@
#define LOG_TAG "audiohalservice"
-#include <android/hardware/audio/2.0/IDevicesFactory.h>
-#include <android/hardware/audio/4.0/IDevicesFactory.h>
-#include <android/hardware/audio/5.0/IDevicesFactory.h>
-#include <android/hardware/audio/6.0/IDevicesFactory.h>
-#include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/5.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/6.0/IEffectsFactory.h>
-#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
-#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
-#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
-#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
-#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
-#include <android/hardware/soundtrigger/2.3/ISoundTriggerHw.h>
+#include <string>
+#include <vector>
+
#include <binder/ProcessState.h>
#include <cutils/properties.h>
#include <hidl/HidlTransportSupport.h>
@@ -39,6 +28,8 @@
using namespace android::hardware;
using android::OK;
+using InterfacesList = std::vector<std::string>;
+
#ifdef ARCH_ARM_32
//default h/w binder memsize is 1 MB
#define DEFAULT_HW_BINDER_MEM_SIZE_KB 1024
@@ -55,9 +46,14 @@ size_t getHWBinderMmapSize(){
* If any registers successfully, do not register any other and return true.
* If all fail, return false.
*/
-template <class... Factories>
-bool registerPassthroughServiceImplementations() {
- return ((registerPassthroughServiceImplementation<Factories>() != OK) && ...);
+template <class Iter>
+static bool registerPassthroughServiceImplementations(Iter first, Iter last) {
+ for (; first != last; ++first) {
+ if (registerPassthroughServiceImplementation(*first) == OK) {
+ return true;
+ }
+ }
+ return false;
}
int main(int /* argc */, char* /* argv */ []) {
@@ -77,36 +73,58 @@ int main(int /* argc */, char* /* argv */ []) {
}
configureRpcThreadpool(16, true /*callerWillJoin*/);
- // Keep versions on a separate line for easier parsing
+ // Automatic formatting tries to compact the lines, making them less readable
// clang-format off
- LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
- audio::V6_0::IDevicesFactory,
- audio::V5_0::IDevicesFactory,
- audio::V4_0::IDevicesFactory,
- audio::V2_0::IDevicesFactory>()),
- "Could not register audio core API");
+ const std::vector<InterfacesList> mandatoryInterfaces = {
+ {
+ "Audio Core API",
+ "android.hardware.audio@6.0::IDevicesFactory",
+ "android.hardware.audio@5.0::IDevicesFactory",
+ "android.hardware.audio@4.0::IDevicesFactory",
+ "android.hardware.audio@2.0::IDevicesFactory"
+ },
+ {
+ "Audio Effect API",
+ "android.hardware.audio.effect@6.0::IEffectsFactory",
+ "android.hardware.audio.effect@5.0::IEffectsFactory",
+ "android.hardware.audio.effect@4.0::IEffectsFactory",
+ "android.hardware.audio.effect@2.0::IEffectsFactory",
+ }
+ };
- LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
- audio::effect::V6_0::IEffectsFactory,
- audio::effect::V5_0::IEffectsFactory,
- audio::effect::V4_0::IEffectsFactory,
- audio::effect::V2_0::IEffectsFactory>()),
- "Could not register audio effect API");
+ const std::vector<InterfacesList> optionalInterfaces = {
+ {
+ "Soundtrigger API",
+ "android.hardware.soundtrigger@2.3::ISoundTriggerHw",
+ "android.hardware.soundtrigger@2.2::ISoundTriggerHw",
+ "android.hardware.soundtrigger@2.1::ISoundTriggerHw",
+ "android.hardware.soundtrigger@2.0::ISoundTriggerHw",
+ },
+ {
+ "Bluetooth Audio API",
+ "android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory"
+ },
+ // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported
+ {
+ "Bluetooth Audio Offload API",
+ "android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioOffload"
+ }
+ };
// clang-format on
- ALOGW_IF((registerPassthroughServiceImplementations<
- soundtrigger::V2_3::ISoundTriggerHw, soundtrigger::V2_2::ISoundTriggerHw,
- soundtrigger::V2_1::ISoundTriggerHw, soundtrigger::V2_0::ISoundTriggerHw>()),
- "Could not register soundtrigger API");
-
- ALOGW_IF(registerPassthroughServiceImplementations<
- bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>(),
- "Could not register Bluetooth audio API");
+ for (const auto& listIter : mandatoryInterfaces) {
+ auto iter = listIter.begin();
+ const std::string& interfaceFamilyName = *iter++;
+ LOG_ALWAYS_FATAL_IF(!registerPassthroughServiceImplementations(iter, listIter.end()),
+ "Could not register %s", interfaceFamilyName.c_str());
+ }
- // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported
- ALOGW_IF(registerPassthroughServiceImplementations<
- bluetooth::a2dp::V1_0::IBluetoothAudioOffload>(),
- "Could not register Bluetooth audio offload API");
+ for (const auto& listIter : optionalInterfaces) {
+ auto iter = listIter.begin();
+ const std::string& interfaceFamilyName = *iter++;
+ ALOGW_IF(!registerPassthroughServiceImplementations(iter, listIter.end()),
+ "Could not register %s", interfaceFamilyName.c_str());
+ }
joinRpcThreadpool();
}
diff --git a/audio/core/all-versions/default/PrimaryDevice.cpp b/audio/core/all-versions/default/PrimaryDevice.cpp
index 679f85dad3..11c1c5a4df 100644
--- a/audio/core/all-versions/default/PrimaryDevice.cpp
+++ b/audio/core/all-versions/default/PrimaryDevice.cpp
@@ -203,6 +203,9 @@ Return<Result> PrimaryDevice::setMode(AudioMode mode) {
case AudioMode::RINGTONE:
case AudioMode::IN_CALL:
case AudioMode::IN_COMMUNICATION:
+#if MAJOR_VERSION >= 6
+ case AudioMode::CALL_SCREEN:
+#endif
break; // Valid values
default:
return Result::INVALID_ARGUMENTS;
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index 709b7cd369..b0eb2e0cfb 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -244,7 +244,13 @@ TEST_P(OutputStreamTest, updateSourceMetadata) {
TEST_P(AudioPrimaryHidlTest, setMode) {
doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
// Test Invalid values
- for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) {
+#if MAJOR_VERSION >= 6
+ int maxMode = int(AudioMode::CALL_SCREEN);
+#else
+ int maxMode = int(AudioMode::IN_COMMUNICATION);
+#endif
+
+ for (int mode : {-2, -1, maxMode + 1}) {
ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode)))
<< "mode=" << mode;
}
@@ -253,6 +259,10 @@ TEST_P(AudioPrimaryHidlTest, setMode) {
AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode);
}
+ // AudioMode::CALL_SCREEN as support is optional
+#if MAJOR_VERSION >= 6
+ ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setMode(AudioMode::CALL_SCREEN));
+#endif
}
TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) {
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index 1818e36112..715f3763b2 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -48,7 +48,7 @@ cc_test {
"-DMAJOR_VERSION=2",
"-DMINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
- ]
+ ],
}
cc_test {
@@ -65,7 +65,7 @@ cc_test {
"-DMAJOR_VERSION=4",
"-DMINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
- ]
+ ],
}
cc_test {
@@ -82,7 +82,7 @@ cc_test {
"-DMAJOR_VERSION=5",
"-DMINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
- ]
+ ],
}
cc_test {
@@ -99,5 +99,15 @@ cc_test {
"-DMAJOR_VERSION=6",
"-DMINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
- ]
+ ],
+ // Use test_config for vts-core suite.
+ // TODO(b/146104851): Add auto-gen rules and remove it.
+ test_config: "VtsHalAudioV6_0TargetTest.xml",
+ data: [
+ ":audio_policy_configuration_V6_0",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml
new file mode 100644
index 0000000000..05edc0dc7d
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalAudioV6_0TargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="stop"/>
+ <option name="run-command" value="setprop vts.native_server.on 1"/>
+ <option name="teardown-command" value="start"/>
+ <option name="teardown-command" value="setprop vts.native_server.on 0"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsHalAudioV6_0TargetTest->/data/local/tmp/VtsHalAudioV6_0TargetTest" />
+ <option name="push" value="audio_policy_configuration_V6_0.xsd->/data/local/tmp/audio_policy_configuration_V6_0.xsd" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalAudioV6_0TargetTest" />
+ </test>
+</configuration>
diff --git a/audio/effect/6.0/xml/api/current.txt b/audio/effect/6.0/xml/api/current.txt
index 2dfcb9b348..072cf8f9b8 100644
--- a/audio/effect/6.0/xml/api/current.txt
+++ b/audio/effect/6.0/xml/api/current.txt
@@ -3,11 +3,13 @@ package audio.effects.V6_0 {
public class AudioEffectsConf {
ctor public AudioEffectsConf();
+ method public audio.effects.V6_0.AudioEffectsConf.DeviceEffects getDeviceEffects();
method public audio.effects.V6_0.EffectsType getEffects();
method public audio.effects.V6_0.LibrariesType getLibraries();
method public audio.effects.V6_0.AudioEffectsConf.Postprocess getPostprocess();
method public audio.effects.V6_0.AudioEffectsConf.Preprocess getPreprocess();
method public audio.effects.V6_0.VersionType getVersion();
+ method public void setDeviceEffects(audio.effects.V6_0.AudioEffectsConf.DeviceEffects);
method public void setEffects(audio.effects.V6_0.EffectsType);
method public void setLibraries(audio.effects.V6_0.LibrariesType);
method public void setPostprocess(audio.effects.V6_0.AudioEffectsConf.Postprocess);
@@ -15,6 +17,11 @@ package audio.effects.V6_0 {
method public void setVersion(audio.effects.V6_0.VersionType);
}
+ public static class AudioEffectsConf.DeviceEffects {
+ ctor public AudioEffectsConf.DeviceEffects();
+ method public java.util.List<audio.effects.V6_0.DeviceProcessType> getDevicePort();
+ }
+
public static class AudioEffectsConf.Postprocess {
ctor public AudioEffectsConf.Postprocess();
method public java.util.List<audio.effects.V6_0.StreamPostprocessType> getStream();
@@ -25,6 +32,68 @@ package audio.effects.V6_0 {
method public java.util.List<audio.effects.V6_0.StreamPreprocessType> getStream();
}
+ public class DeviceProcessType extends audio.effects.V6_0.StreamProcessingType {
+ ctor public DeviceProcessType();
+ }
+
+ public enum DeviceType {
+ method public String getRawName();
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_AUX_DIGITAL;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_BACK_MIC;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_BUILTIN_MIC;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_BUS;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_COMMUNICATION;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_ECHO_REFERENCE;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_FM_TUNER;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_HDMI;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_HDMI_ARC;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_IP;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_LINE;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_LOOPBACK;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_PROXY;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_SPDIF;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_TELEPHONY_RX;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_TV_TUNER;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_USB_ACCESSORY;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_USB_DEVICE;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_USB_HEADSET;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_VOICE_CALL;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_WIRED_HEADSET;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_AUX_LINE;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BUS;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_EARPIECE;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_ECHO_CANCELLER;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_FM;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_HDMI;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_HDMI_ARC;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_HEARING_AID;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_IP;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_LINE;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_PROXY;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_SPDIF;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_SPEAKER;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_TELEPHONY_TX;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_USB_DEVICE;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_USB_HEADSET;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ }
+
public class EffectImplType {
ctor public EffectImplType();
method public String getLibrary();
@@ -69,6 +138,8 @@ package audio.effects.V6_0 {
public enum StreamInputType {
method public String getRawName();
enum_constant public static final audio.effects.V6_0.StreamInputType camcorder;
+ enum_constant public static final audio.effects.V6_0.StreamInputType echo_reference;
+ enum_constant public static final audio.effects.V6_0.StreamInputType fm_tuner;
enum_constant public static final audio.effects.V6_0.StreamInputType mic;
enum_constant public static final audio.effects.V6_0.StreamInputType unprocessed;
enum_constant public static final audio.effects.V6_0.StreamInputType voice_call;
diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd
index a7ff20bb1c..fcfecda821 100644
--- a/audio/effect/6.0/xml/audio_effects_conf.xsd
+++ b/audio/effect/6.0/xml/audio_effects_conf.xsd
@@ -36,6 +36,8 @@
<xs:enumeration value="voice_communication"/>
<xs:enumeration value="unprocessed"/>
<xs:enumeration value="voice_performance"/>
+ <xs:enumeration value="echo_reference"/>
+ <xs:enumeration value="fm_tuner"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="streamOutputType">
@@ -58,6 +60,65 @@
<xs:pattern value="[^/].*"/>
</xs:restriction>
</xs:simpleType>
+ <xs:simpleType name="deviceType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/>
+ <!-- Due to the xml format, IN types can not be a separated from OUT types -->
+ <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
+ </xs:restriction>
+ </xs:simpleType>
<!-- Complex types -->
<xs:complexType name="librariesType">
<xs:annotation>
@@ -174,6 +235,33 @@
</xs:extension>
</xs:complexContent>
</xs:complexType>
+ <xs:complexType name="deviceProcessType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio Device Effects configuration. The processing configuration consists
+ of a list of effects to be automatically added on a device Port when involved in an audio
+ patch.
+ Valid device type are listed in "deviceType" and shall be aligned.
+ Each stream element contains a list of "apply" elements. The value of the
+ "effect" attr must correspond to the name of an "effect" element.
+ Note that if the device is involved in a hardware patch, the effect must be hardware
+ accelerated.
+ Example:
+ <devicePort address="BUS00_USAGE_MAIN" type="AUDIO_DEVICE_OUT_BUS">
+ <apply effect="equalizer"/>
+ <apply effect="effect2"/>
+ </devicePort>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="aec:streamProcessingType">
+ <xs:complexType>
+ <xs:attribute name="address" type="xs:string" use="required"/>
+ <xs:attribute name="type" type="aec:deviceType" use="required"/>
+ </xs:complexType>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
<!-- Root element -->
<xs:element name="audio_effects_conf">
<xs:complexType>
@@ -194,6 +282,13 @@
</xs:sequence>
</xs:complexType>
</xs:element>
+ <xs:element name="deviceEffects" minOccurs="0" maxOccurs="1">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="devicePort" type="aec:deviceProcessType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
</xs:sequence>
<xs:attribute name="version" type="aec:versionType" use="required"/>
</xs:complexType>
diff --git a/automotive/audiocontrol/1.0/default/Android.bp b/automotive/audiocontrol/1.0/default/Android.bp
index 3d04c890bc..ae4b8057ae 100644
--- a/automotive/audiocontrol/1.0/default/Android.bp
+++ b/automotive/audiocontrol/1.0/default/Android.bp
@@ -30,9 +30,4 @@ cc_binary {
"libutils",
],
vintf_fragments: ["audiocontrol_manifest.xml"],
- cflags: [
- "-DLOG_TAG=\"AudCntrlDrv\"",
- "-O0",
- "-g",
- ],
}
diff --git a/automotive/audiocontrol/2.0/Android.bp b/automotive/audiocontrol/2.0/Android.bp
new file mode 100644
index 0000000000..2a9f8499e3
--- /dev/null
+++ b/automotive/audiocontrol/2.0/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.automotive.audiocontrol@2.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IAudioControl.hal",
+ "ICloseHandle.hal",
+ "IFocusListener.hal",
+ ],
+ interfaces: [
+ "android.hidl.base@1.0",
+ "android.hardware.audio.common@6.0",
+ ],
+ gen_java: true,
+}
diff --git a/automotive/audiocontrol/2.0/IAudioControl.hal b/automotive/audiocontrol/2.0/IAudioControl.hal
new file mode 100644
index 0000000000..1073498f61
--- /dev/null
+++ b/automotive/audiocontrol/2.0/IAudioControl.hal
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+import ICloseHandle;
+import IFocusListener;
+import android.hardware.audio.common@6.0::AudioUsage;
+
+/**
+ * Interacts with the car's audio subsystem to manage audio sources and volumes
+ */
+interface IAudioControl {
+ /**
+ * Registers focus listener to be used by HAL for requesting and abandoning audio focus.
+ *
+ * It is expected that there will only ever be a single focus listener registered. If the
+ * observer dies, the HAL implementation must unregister observer automatically. If called when
+ * a listener is already registered, the existing one should be unregistered and replaced with
+ * the new listener.
+ *
+ * @param listener the listener interface
+ * @return closeHandle A handle to unregister observer.
+ */
+ registerFocusListener(IFocusListener listener) generates (ICloseHandle closeHandle);
+
+ /**
+ * Notifies HAL of changes in audio focus status for focuses requested or abandoned by the HAL.
+ *
+ * This will be called in response to IFocusListener's requestAudioFocus and
+ * abandonAudioFocus, as well as part of any change in focus being held by the HAL due focus
+ * request from other activities or services.
+ *
+ * The HAL is not required to wait for an callback of AUDIOFOCUS_GAIN before playing audio, nor
+ * is it required to stop playing audio in the event of a AUDIOFOCUS_LOSS callback is received.
+ *
+ * @param usage The audio usage associated with the focus change {@code AttributeUsage}
+ * @param zoneId The identifier for the audio zone that the HAL is playing the stream in
+ * @param focusChange the AudioFocusChange that has occurred
+ */
+ oneway onAudioFocusChange(bitfield<AudioUsage> usage, int32_t zoneId,
+ bitfield<AudioFocusChange> focusChange);
+
+ /**
+ * Control the right/left balance setting of the car speakers.
+ *
+ * This is intended to shift the speaker volume toward the right (+) or left (-) side of
+ * the car. 0.0 means "centered". +1.0 means fully right. -1.0 means fully left.
+ *
+ * A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1
+ * range.
+ */
+ oneway setBalanceTowardRight(float value);
+
+ /**
+ * Control the fore/aft fade setting of the car speakers.
+ *
+ * This is intended to shift the speaker volume toward the front (+) or back (-) of the car.
+ * 0.0 means "centered". +1.0 means fully forward. -1.0 means fully rearward.
+ *
+ * A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1
+ * range.
+ */
+ oneway setFadeTowardFront(float value);
+};
diff --git a/automotive/audiocontrol/2.0/ICloseHandle.hal b/automotive/audiocontrol/2.0/ICloseHandle.hal
new file mode 100644
index 0000000000..537af6d635
--- /dev/null
+++ b/automotive/audiocontrol/2.0/ICloseHandle.hal
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+/**
+ * Represents a generic close handle to remove a callback that doesn't need
+ * active interface.
+ *
+ * When close() is called OR when the interface is released, the underlying
+ * resources must be freed.
+ */
+interface ICloseHandle {
+ /**
+ * Closes the handle.
+ *
+ * The call must not fail and must be issued by the client at most once.
+ * Otherwise, the server must ignore subsequent calls.
+ */
+ close();
+};
diff --git a/automotive/audiocontrol/2.0/IFocusListener.hal b/automotive/audiocontrol/2.0/IFocusListener.hal
new file mode 100644
index 0000000000..4fd5ef0425
--- /dev/null
+++ b/automotive/audiocontrol/2.0/IFocusListener.hal
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+import android.hardware.audio.common@6.0::AudioUsage;
+
+/**
+ * Callback interface for audio focus listener.
+ *
+ * For typical configuration, the listener the car audio service.
+ */
+interface IFocusListener {
+ /**
+ * Called whenever HAL is requesting focus as it is starting to play audio of a given usage in a
+ * specified zone.
+ *
+ * In response, IAudioControl#onAudioFocusChange will be called with focusChange status. This
+ * interaction is oneway to avoid blocking HAL so that it is not required to wait for a response
+ * before playing audio.
+ *
+ * @param usage The audio usage associated with the focus request {@code AttributeUsage}
+ * @param zoneId The identifier for the audio zone where the HAL is requesting focus
+ * @param focusGain The AudioFocusChange associated with this request. Should be one of the
+ * following: GAIN, GAIN_TRANSIENT, GAIN_TRANSIENT_MAY_DUCK, GAIN_TRANSIENT_EXCLUSIVE.
+ */
+ oneway requestAudioFocus(bitfield<AudioUsage> usage, int32_t zoneId,
+ bitfield<AudioFocusChange> focusGain);
+
+ /**
+ * Called whenever HAL is abandoning focus as it is finished playing audio of a given usage in a
+ * specific zone.
+ *
+ * In response, IAudioControl#onAudioFocusChange will be called with focusChange status. This
+ * interaction is oneway to avoid blocking HAL so that it is not required to wait for a response
+ * before stopping audio playback.
+ *
+ * @param usage The audio usage for which the HAL is abandoning focus {@code AttributeUsage}
+ * @param zoneId The identifier for the audio zone that the HAL abandoning focus
+ */
+ oneway abandonAudioFocus(bitfield<AudioUsage> usage, int32_t zoneId);
+};
diff --git a/automotive/audiocontrol/2.0/default/Android.bp b/automotive/audiocontrol/2.0/default/Android.bp
new file mode 100644
index 0000000000..44ad0281fe
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/Android.bp
@@ -0,0 +1,39 @@
+// 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.
+
+cc_binary {
+ name: "android.hardware.automotive.audiocontrol@2.0-service",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "AudioControl.cpp",
+ "service.cpp",
+ "CloseHandle.cpp",
+ ],
+ init_rc: ["android.hardware.automotive.audiocontrol@2.0-service.rc"],
+
+ shared_libs: [
+ "android.hardware.automotive.audiocontrol@2.0",
+ "libbase",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ vintf_fragments: ["audiocontrol2_manifest.xml"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/automotive/audiocontrol/2.0/default/AudioControl.cpp b/automotive/audiocontrol/2.0/default/AudioControl.cpp
new file mode 100644
index 0000000000..6505e34765
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/AudioControl.cpp
@@ -0,0 +1,60 @@
+#include "AudioControl.h"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "CloseHandle.h"
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+AudioControl::AudioControl() {}
+
+Return<sp<ICloseHandle>> AudioControl::registerFocusListener(const sp<IFocusListener>& listener) {
+ LOG(DEBUG) << "registering focus listener";
+ sp<ICloseHandle> closeHandle(nullptr);
+
+ if (listener) {
+ mFocusListener = listener;
+
+ closeHandle = new CloseHandle([this, listener]() {
+ if (mFocusListener == listener) {
+ mFocusListener = nullptr;
+ }
+ });
+ } else {
+ LOG(ERROR) << "Unexpected nullptr for listener resulting in no-op.";
+ }
+
+ return closeHandle;
+}
+
+Return<void> AudioControl::setBalanceTowardRight(float value) {
+ // For completeness, lets bounds check the input...
+ if (isValidValue(value)) {
+ LOG(ERROR) << "Balance value out of range -1 to 1 at " << value;
+ } else {
+ // Just log in this default mock implementation
+ LOG(INFO) << "Balance set to " << value;
+ }
+ return Void();
+}
+
+Return<void> AudioControl::setFadeTowardFront(float value) {
+ // For completeness, lets bounds check the input...
+ if (isValidValue(value)) {
+ LOG(ERROR) << "Fader value out of range -1 to 1 at " << value;
+ } else {
+ // Just log in this default mock implementation
+ LOG(INFO) << "Fader set to " << value;
+ }
+ return Void();
+}
+
+Return<void> AudioControl::onAudioFocusChange(hidl_bitfield<AudioUsage> usage, int zoneId,
+ hidl_bitfield<AudioFocusChange> focusChange) {
+ LOG(INFO) << "Focus changed: " << static_cast<int>(focusChange) << " for usage "
+ << static_cast<int>(usage) << " in zone " << zoneId;
+ return Void();
+}
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/automotive/audiocontrol/2.0/default/AudioControl.h b/automotive/audiocontrol/2.0/default/AudioControl.h
new file mode 100644
index 0000000000..475a693cb7
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/AudioControl.h
@@ -0,0 +1,49 @@
+/*
+ * 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 ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H
+
+#include <android/hardware/audio/common/6.0/types.h>
+#include <android/hardware/automotive/audiocontrol/2.0/IAudioControl.h>
+#include <android/hardware/automotive/audiocontrol/2.0/ICloseHandle.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+using android::hardware::audio::common::V6_0::AudioUsage;
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+class AudioControl : public IAudioControl {
+ public:
+ // Methods from ::android::hardware::automotive::audiocontrol::V2_0::IAudioControl follow.
+ Return<sp<ICloseHandle>> registerFocusListener(const sp<IFocusListener>& listener);
+ Return<void> onAudioFocusChange(hidl_bitfield<AudioUsage> usage, int zoneId,
+ hidl_bitfield<AudioFocusChange> focusChange);
+ Return<void> setBalanceTowardRight(float value) override;
+ Return<void> setFadeTowardFront(float value) override;
+
+ // Implementation details
+ AudioControl();
+
+ private:
+ sp<IFocusListener> mFocusListener;
+ static bool isValidValue(float value) { return (value > 1.0f) || (value < -1.0f); }
+};
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H
diff --git a/automotive/audiocontrol/2.0/default/CloseHandle.cpp b/automotive/audiocontrol/2.0/default/CloseHandle.cpp
new file mode 100644
index 0000000000..bc47931535
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/CloseHandle.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#include "CloseHandle.h"
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {}
+
+CloseHandle::~CloseHandle() {
+ close();
+}
+
+Return<void> CloseHandle::close() {
+ const auto wasClosed = mIsClosed.exchange(true);
+ if (wasClosed) return {};
+
+ if (mCallback) mCallback();
+ return {};
+}
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/automotive/audiocontrol/2.0/default/CloseHandle.h b/automotive/audiocontrol/2.0/default/CloseHandle.h
new file mode 100644
index 0000000000..6caf0bfa7e
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/CloseHandle.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android/hardware/automotive/audiocontrol/2.0/ICloseHandle.h>
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+/** Generic ICloseHandle implementation ignoring double-close events. */
+class CloseHandle : public ICloseHandle {
+ public:
+ using Callback = std::function<void()>;
+
+ /**
+ * Create a handle with a callback.
+ *
+ * The callback is guaranteed to be called exactly once.
+ *
+ * \param callback Called on the first close() call, or on destruction of the handle
+ */
+ CloseHandle(Callback callback = nullptr);
+ virtual ~CloseHandle();
+
+ Return<void> close() override;
+
+ private:
+ const Callback mCallback;
+ std::atomic<bool> mIsClosed = false;
+
+ DISALLOW_COPY_AND_ASSIGN(CloseHandle);
+};
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc b/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc
new file mode 100644
index 0000000000..81c9be4460
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.audiocontrol-hal-2.0 /vendor/bin/hw/android.hardware.automotive.audiocontrol@2.0-service
+ class hal
+ user audioserver
+ group system
diff --git a/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml b/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml
new file mode 100644
index 0000000000..42d23ed62e
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.automotive.audiocontrol</name>
+ <transport>hwbinder</transport>
+ <version>2.0</version>
+ <interface>
+ <name>IAudioControl</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest> \ No newline at end of file
diff --git a/automotive/audiocontrol/2.0/default/service.cpp b/automotive/audiocontrol/2.0/default/service.cpp
new file mode 100644
index 0000000000..dcc46c31aa
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/service.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "AudioControl.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::automotive::audiocontrol::V2_0::IAudioControl;
+
+// The namespace in which all our implementation code lives
+using namespace android::hardware::automotive::audiocontrol::V2_0::implementation;
+using namespace android;
+
+// Main service entry point
+int main() {
+ // Create an instance of our service class
+ android::sp<IAudioControl> service = new AudioControl();
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+ if (service->registerAsService() != OK) {
+ LOG(ERROR) << "registerAsService failed";
+ return 1;
+ }
+
+ // Join (forever) the thread pool we created for the service above
+ joinRpcThreadpool();
+
+ // We don't ever actually expect to return, so return an error if we do get here
+ return 2;
+} \ No newline at end of file
diff --git a/automotive/audiocontrol/2.0/types.hal b/automotive/audiocontrol/2.0/types.hal
new file mode 100644
index 0000000000..65b0988487
--- /dev/null
+++ b/automotive/audiocontrol/2.0/types.hal
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+/**
+ * Changes in audio focus that can be experienced
+ */
+enum AudioFocusChange : uint32_t {
+ NONE = 0,
+ GAIN = 1,
+ GAIN_TRANSIENT = 2,
+ GAIN_TRANSIENT_MAY_DUCK = 3,
+ GAIN_TRANSIENT_EXCLUSIVE = 4,
+ LOSS = -1 * GAIN,
+ LOSS_TRANSIENT = -1 * GAIN_TRANSIENT,
+ LOSS_TRANSIENT_CAN_DUCK = -1 * GAIN_TRANSIENT_MAY_DUCK,
+};
diff --git a/automotive/audiocontrol/2.0/vts/functional/Android.bp b/automotive/audiocontrol/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000000..520b042e37
--- /dev/null
+++ b/automotive/audiocontrol/2.0/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+//
+// 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.
+//
+
+cc_test {
+ name: "VtsHalAudioControlV2_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalAudioControlV2_0TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.automotive.audiocontrol@2.0",
+ "libgmock",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
new file mode 100644
index 0000000000..0c106647c5
--- /dev/null
+++ b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsHalAudioControlTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/ProcessState.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include <android/hardware/audio/common/6.0/types.h>
+#include <android/hardware/automotive/audiocontrol/2.0/IAudioControl.h>
+#include <android/hardware/automotive/audiocontrol/2.0/types.h>
+#include <android/log.h>
+
+using namespace ::android::hardware::automotive::audiocontrol::V2_0;
+using ::android::sp;
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V6_0::AudioUsage;
+
+// The main test class for the automotive AudioControl HAL
+class CarAudioControlHidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ // Make sure we can connect to the driver
+ pAudioControl = IAudioControl::getService(GetParam());
+ ASSERT_NE(pAudioControl.get(), nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+ protected:
+ sp<IAudioControl> pAudioControl; // Every test needs access to the service
+};
+
+//
+// Tests start here...
+//
+
+/*
+ * Fader exercise test. Note that only a subjective observer could determine if the
+ * fader actually works. The only thing we can do is exercise the HAL and if the HAL crashes,
+ * we _might_ get a test failure if that breaks the connection to the driver.
+ */
+TEST_P(CarAudioControlHidlTest, FaderExercise) {
+ ALOGI("Fader exercise test (silent)");
+
+ // Set the fader all the way to the back
+ pAudioControl->setFadeTowardFront(-1.0f);
+
+ // Set the fader all the way to the front
+ pAudioControl->setFadeTowardFront(1.0f);
+
+ // Set the fader part way toward the back
+ pAudioControl->setFadeTowardFront(-0.333f);
+
+ // Set the fader to a out of bounds value (driver should clamp)
+ pAudioControl->setFadeTowardFront(99999.9f);
+
+ // Set the fader back to the middle
+ pAudioControl->setFadeTowardFront(0.0f);
+}
+
+/*
+ * Balance exercise test.
+ */
+TEST_P(CarAudioControlHidlTest, BalanceExercise) {
+ ALOGI("Balance exercise test (silent)");
+
+ // Set the balance all the way to the left
+ pAudioControl->setBalanceTowardRight(-1.0f);
+
+ // Set the balance all the way to the right
+ pAudioControl->setBalanceTowardRight(1.0f);
+
+ // Set the balance part way toward the left
+ pAudioControl->setBalanceTowardRight(-0.333f);
+
+ // Set the balance to a out of bounds value (driver should clamp)
+ pAudioControl->setBalanceTowardRight(99999.9f);
+
+ // Set the balance back to the middle
+ pAudioControl->setBalanceTowardRight(0.0f);
+}
+
+struct FocusListenerMock : public IFocusListener {
+ MOCK_METHOD(Return<void>, requestAudioFocus,
+ (hidl_bitfield<AudioUsage> usage, int zoneId,
+ hidl_bitfield<AudioFocusChange> focusGain));
+ MOCK_METHOD(Return<void>, abandonAudioFocus, (hidl_bitfield<AudioUsage> usage, int zoneId));
+};
+
+/*
+ * Test focus listener registration.
+ *
+ * Verifies that:
+ * - registerFocusListener succeeds;
+ * - registering a second listener succeeds in replacing the first;
+ * - closing handle does not crash;
+ */
+TEST_P(CarAudioControlHidlTest, FocusListenerRegistration) {
+ ALOGI("Focus listener test");
+
+ sp<FocusListenerMock> listener = new FocusListenerMock();
+
+ auto hidlResult = pAudioControl->registerFocusListener(listener);
+ ASSERT_TRUE(hidlResult.isOk());
+
+ sp<FocusListenerMock> listener2 = new FocusListenerMock();
+
+ auto hidlResult2 = pAudioControl->registerFocusListener(listener2);
+ ASSERT_TRUE(hidlResult2.isOk());
+
+ const sp<ICloseHandle>& closeHandle = hidlResult2;
+ closeHandle->close();
+};
+
+TEST_P(CarAudioControlHidlTest, FocusChangeExercise) {
+ ALOGI("Focus Change test");
+
+ pAudioControl->onAudioFocusChange(AudioUsage::MEDIA | 0, 0,
+ AudioFocusChange::GAIN_TRANSIENT | 0);
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, CarAudioControlHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)),
+ android::hardware::PrintInstanceNameToString); \ No newline at end of file
diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal
index 1695821baa..7752b0e330 100644
--- a/automotive/evs/1.1/IEvsEnumerator.hal
+++ b/automotive/evs/1.1/IEvsEnumerator.hal
@@ -47,4 +47,11 @@ interface IEvsEnumerator extends @1.0::IEvsEnumerator {
* configured differently by another client.
*/
openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera);
+
+ /**
+ * Tells whether this is EVS manager or HAL implementation.
+ *
+ * @return result False for EVS manager implementations and true for all others.
+ */
+ isHardware() generates (bool result);
};
diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp
index 88fd6575ad..a7c7b4282b 100644
--- a/automotive/evs/1.1/default/Android.bp
+++ b/automotive/evs/1.1/default/Android.bp
@@ -41,7 +41,7 @@ cc_binary {
prebuilt_etc {
name: "evs_default_configuration.xml",
-
+ soc_specific: true,
src: "resources/evs_default_configuration.xml",
sub_dir: "automotive/evs",
}
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
index a010729ce6..cb7403a7da 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -42,7 +42,7 @@ EvsEnumerator::EvsEnumerator() {
// Add sample camera data to our list of cameras
// In a real driver, this would be expected to can the available hardware
sConfigManager =
- ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml");
+ ConfigManager::Create("/vendor/etc/automotive/evs/evs_default_configuration.xml");
for (auto v : sConfigManager->getCameraList()) {
sCameraList.emplace_back(v.c_str());
}
diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h
index 475ec76b93..ca35dc6f8a 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.h
+++ b/automotive/evs/1.1/default/EvsEnumerator.h
@@ -59,6 +59,7 @@ public:
Return<void> getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override;
Return<sp<IEvsCamera_1_1>> openCamera_1_1(const hidl_string& cameraId,
const Stream& streamCfg) override;
+ Return<bool> isHardware() override { return true; }
// Implementation details
EvsEnumerator();
diff --git a/automotive/evs/1.1/default/ServiceNames.h b/automotive/evs/1.1/default/ServiceNames.h
index 1178da5a9c..84b1697d0f 100644
--- a/automotive/evs/1.1/default/ServiceNames.h
+++ b/automotive/evs/1.1/default/ServiceNames.h
@@ -14,4 +14,4 @@
* limitations under the License.
*/
-const static char kEnumeratorServiceName[] = "EvsEnumeratorHw";
+const static char kEnumeratorServiceName[] = "hw/0";
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 4fc4e4c144..1a622452da 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -117,7 +117,7 @@ public:
pEnumerator = getService<IEvsEnumerator>(service_name);
ASSERT_NE(pEnumerator.get(), nullptr);
- mIsHwModule = !service_name.compare(kEnumeratorName);
+ mIsHwModule = pEnumerator->isHardware();
}
virtual void TearDown() override {
diff --git a/automotive/evs/1.1/vts/fuzzing/Android.bp b/automotive/evs/1.1/vts/fuzzing/Android.bp
new file mode 100644
index 0000000000..48427ee532
--- /dev/null
+++ b/automotive/evs/1.1/vts/fuzzing/Android.bp
@@ -0,0 +1,50 @@
+//
+// Copyright 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.
+//
+
+cc_defaults {
+ name: "android.hardware.automotive.evs@fuzz-defaults",
+ defaults: ["VtsHalTargetTestDefaults"],
+ shared_libs: [
+ "libui",
+ "libcamera_metadata",
+ ],
+ static_libs: [
+ "android.hardware.automotive.evs@1.0",
+ "android.hardware.automotive.evs@1.1",
+ "android.hardware.automotive.evs@common-default-lib",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.camera.device@3.2",
+ ],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
+
+cc_fuzz {
+ name: "VtsHalEvsV1_1CameraOpenFuzz",
+ defaults: ["android.hardware.automotive.evs@fuzz-defaults"],
+ srcs: [
+ "VtsHalEvsV1_1CameraOpenFuzz.cpp",
+ ],
+ fuzz_config: {
+ // wait for Haiku device ready
+ fuzz_on_haiku_device: false,
+ fuzz_on_haiku_host: false,
+ },
+}
diff --git a/automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp b/automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp
new file mode 100644
index 0000000000..4f05d21e69
--- /dev/null
+++ b/automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 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.
+ */
+
+#include "common.h"
+
+using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
+using ::android::hardware::camera::device::V3_2::Stream;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
+ UNUSED(argc);
+ UNUSED(argv);
+ pEnumerator = IEvsEnumerator::getService(kEnumeratorName);
+ sp<EvsDeathRecipient> dr = new EvsDeathRecipient();
+
+ pEnumerator->linkToDeath(dr, 0);
+
+ loadCameraList();
+ return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+
+ std::vector<sp<IEvsCamera_1_1>> camList;
+ Stream nullCfg = {};
+
+ while (fdp.remaining_bytes() > 4) {
+ switch (fdp.ConsumeIntegralInRange<uint32_t>(0, 3)) {
+ case 0: // open camera
+ {
+ uint32_t whichCam = fdp.ConsumeIntegralInRange<uint32_t>(0, cameraInfo.size() - 1);
+ sp<IEvsCamera_1_1> pCam =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(
+ cameraInfo[whichCam].v1.cameraId, nullCfg))
+ .withDefault(nullptr);
+ camList.emplace_back(pCam);
+ break;
+ }
+ case 1: // close camera
+ {
+ if (!camList.empty()) {
+ uint32_t whichCam = fdp.ConsumeIntegralInRange<uint32_t>(0, camList.size() - 1);
+ pEnumerator->closeCamera(camList[whichCam]);
+ }
+ break;
+ }
+ case 2: // get camera info
+ {
+ if (!camList.empty()) {
+ uint32_t whichCam = fdp.ConsumeIntegralInRange<uint32_t>(0, camList.size() - 1);
+ camList[whichCam]->getCameraInfo_1_1([](CameraDesc desc) { UNUSED(desc); });
+ }
+ break;
+ }
+ case 3: // setMaxFramesInFlight
+ {
+ if (!camList.empty()) {
+ uint32_t whichCam = fdp.ConsumeIntegralInRange<uint32_t>(0, camList.size() - 1);
+ int32_t numFrames = fdp.ConsumeIntegral<int32_t>();
+ camList[whichCam]->setMaxFramesInFlight(numFrames);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/automotive/evs/1.1/vts/fuzzing/common.h b/automotive/evs/1.1/vts/fuzzing/common.h
new file mode 100644
index 0000000000..af6fd545ea
--- /dev/null
+++ b/automotive/evs/1.1/vts/fuzzing/common.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "VtsHalEvsTest"
+#define UNUSED(x) (void)(x)
+
+const static char kEnumeratorName[] = "EvsEnumeratorHw";
+
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/StrongPointer.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+
+using ::android::sp;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_vec;
+
+static sp<IEvsEnumerator> pEnumerator;
+static std::vector<CameraDesc> cameraInfo;
+
+class EvsDeathRecipient : public hidl_death_recipient {
+ public:
+ void serviceDied(uint64_t /*cookie*/,
+ const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) override {
+ abort();
+ }
+};
+
+void loadCameraList() {
+ // SetUp() must run first!
+ assert(pEnumerator != nullptr);
+
+ // Get the camera list
+ pEnumerator->getCameraList_1_1([](hidl_vec<CameraDesc> cameraList) {
+ ALOGI("Camera list callback received %zu cameras", cameraList.size());
+ cameraInfo.reserve(cameraList.size());
+ for (auto&& cam : cameraList) {
+ ALOGI("Found camera %s", cam.v1.cameraId.c_str());
+ cameraInfo.push_back(cam);
+ }
+ });
+}
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 2050038d62..a94a37e0f1 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -82,6 +82,20 @@ cc_library_static {
],
}
+// VHal virtualization utils
+cc_library_static {
+ name: "android.hardware.automotive.vehicle@2.0-virtualization-utils",
+ vendor: true,
+ defaults: ["vhal_v2_0_defaults"],
+ srcs: [
+ "impl/vhal_v2_0/virtualization/Utils.cpp",
+ ],
+ export_include_dirs: ["impl"],
+ shared_libs: [
+ "libbase",
+ ],
+}
+
cc_test {
name: "android.hardware.automotive.vehicle@2.0-manager-unit-tests",
vendor: true,
@@ -133,3 +147,59 @@ cc_binary {
"libqemu_pipe",
],
}
+
+cc_binary {
+ name: "android.hardware.automotive.vehicle@2.0-virtualization-service",
+ defaults: ["vhal_v2_0_defaults"],
+ init_rc: ["android.hardware.automotive.vehicle@2.0-virtualization-service.rc"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp",
+ "VirtualizedVehicleService.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libjsoncpp",
+ "libprotobuf-cpp-full",
+ "libgrpc++",
+ ],
+ static_libs: [
+ "android.hardware.automotive.vehicle@2.0-manager-lib",
+ "android.hardware.automotive.vehicle@2.0-default-impl-lib",
+ "android.hardware.automotive.vehicle@2.0-grpc",
+ "android.hardware.automotive.vehicle@2.0-virtualization-utils",
+ "libqemu_pipe",
+ ],
+ cflags: [
+ "-Wno-unused-parameter"
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.automotive.vehicle@2.0-virtualization-grpc-server",
+ init_rc: ["android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc"],
+ defaults: ["vhal_v2_0_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp",
+ "VirtualizationGrpcServer.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libjsoncpp",
+ "libprotobuf-cpp-full",
+ "libgrpc++",
+ ],
+ static_libs: [
+ "android.hardware.automotive.vehicle@2.0-manager-lib",
+ "android.hardware.automotive.vehicle@2.0-default-impl-lib",
+ "android.hardware.automotive.vehicle@2.0-grpc",
+ "android.hardware.automotive.vehicle@2.0-virtualization-utils",
+ ],
+ cflags: [
+ "-Wno-unused-parameter"
+ ],
+}
diff --git a/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp b/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp
new file mode 100644
index 0000000000..fb02c58952
--- /dev/null
+++ b/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp
@@ -0,0 +1,15 @@
+#include <android-base/logging.h>
+
+#include "vhal_v2_0/virtualization/GrpcVehicleServer.h"
+#include "vhal_v2_0/virtualization/Utils.h"
+
+int main(int argc, char* argv[]) {
+ namespace vhal_impl = android::hardware::automotive::vehicle::V2_0::impl;
+
+ auto serverInfo = vhal_impl::VsockServerInfo::fromCommandLine(argc, argv);
+ CHECK(serverInfo.has_value()) << "Invalid server CID/port combination";
+
+ auto server = vhal_impl::makeGrpcVehicleServer(serverInfo->toUri());
+ server->Start();
+ return 0;
+}
diff --git a/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp b/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp
new file mode 100644
index 0000000000..68813c9035
--- /dev/null
+++ b/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 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 <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <vhal_v2_0/EmulatedVehicleConnector.h>
+#include <vhal_v2_0/EmulatedVehicleHal.h>
+#include <vhal_v2_0/VehicleHalManager.h>
+#include <vhal_v2_0/virtualization/GrpcVehicleClient.h>
+#include <vhal_v2_0/virtualization/Utils.h>
+
+using namespace android;
+using namespace android::hardware;
+using namespace android::hardware::automotive::vehicle::V2_0;
+
+int main(int argc, char* argv[]) {
+ namespace vhal_impl = android::hardware::automotive::vehicle::V2_0::impl;
+
+ auto serverInfo = vhal_impl::VsockServerInfo::fromRoPropertyStore();
+ CHECK(serverInfo.has_value()) << "Invalid server CID/port combination";
+
+ auto store = std::make_unique<VehiclePropertyStore>();
+ auto connector = impl::makeGrpcVehicleClient(serverInfo->toUri());
+ auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get());
+ auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
+ auto service = std::make_unique<VehicleHalManager>(hal.get());
+
+ configureRpcThreadpool(4, true /* callerWillJoin */);
+
+ LOG(INFO) << "Registering as service...";
+ status_t status = service->registerAsService();
+
+ if (status != OK) {
+ LOG(ERROR) << "Unable to register vehicle service (" << status << ")";
+ return 1;
+ }
+
+ LOG(INFO) << "Ready";
+ joinRpcThreadpool();
+
+ return 1;
+}
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc
new file mode 100644
index 0000000000..1101b087eb
--- /dev/null
+++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc
@@ -0,0 +1,10 @@
+# It is an interim state to run GRPC server as an Android service.
+# Eventually it will run outside of Android (e.g., AGL),
+# so the command line arguments are expected, though not conventionally used in Android
+service vendor.vehicle-hal-2.0-server \
+ /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server \
+ -server_cid ${ro.vendor.vehiclehal.server.cid:-pleaseconfigurethis} \
+ -server_port ${ro.vendor.vehiclehal.server.port:-pleaseconfigurethis}
+ class hal
+ user vehicle_network
+ group system inet
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc
new file mode 100644
index 0000000000..234de591cc
--- /dev/null
+++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc
@@ -0,0 +1,4 @@
+service vendor.vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-virtualization-service
+ class hal
+ user vehicle_network
+ group system inet
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
index 2cc6595248..6f71d654a7 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
@@ -35,13 +35,23 @@ message VehicleHalCallStatus {
VehicleHalStatusCode status_code = 1;
}
+message WrappedVehiclePropValue {
+ VehiclePropValue value = 1;
+ // An indicator on whether we should update the status of the property
+ // - true: if the value is generated by (emulated/real) car, or;
+ // if the value is injected to 'fake' a on car event (for debugging purpose)
+ // - false: if the value is set by VHal (public interface), since Android
+ // cannot change status of property on a real car
+ bool update_status = 2;
+}
+
service VehicleServer {
rpc GetAllPropertyConfig(google.protobuf.Empty) returns (stream VehiclePropConfig) {}
// Change the property value of the vehicle
- rpc SetProperty(VehiclePropValue) returns (VehicleHalCallStatus) {}
+ rpc SetProperty(WrappedVehiclePropValue) returns (VehicleHalCallStatus) {}
// Start a vehicle property value stream
- rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValue) {}
+ rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream WrappedVehiclePropValue) {}
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp
new file mode 100644
index 0000000000..e329c5be01
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2019 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 "GrpcVehicleClient.h"
+
+#include <condition_variable>
+#include <mutex>
+
+#include <android-base/logging.h>
+#include <grpc++/grpc++.h>
+
+#include "VehicleServer.grpc.pb.h"
+#include "VehicleServer.pb.h"
+#include "vhal_v2_0/ProtoMessageConverter.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
+ // TODO(chenhaosjtuacm): get secured credentials here
+ return ::grpc::InsecureChannelCredentials();
+}
+
+class GrpcVehicleClientImpl : public EmulatedVehicleClient {
+ public:
+ GrpcVehicleClientImpl(const std::string& addr)
+ : mServiceAddr(addr),
+ mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())),
+ mGrpcStub(vhal_proto::VehicleServer::NewStub(mGrpcChannel)) {
+ StartValuePollingThread();
+ }
+
+ ~GrpcVehicleClientImpl() {
+ mShuttingDownFlag.store(true);
+ mShutdownCV.notify_all();
+ if (mPollingThread.joinable()) {
+ mPollingThread.join();
+ }
+ }
+
+ // methods from IVehicleClient
+
+ std::vector<VehiclePropConfig> getAllPropertyConfig() const override;
+
+ StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override;
+
+ private:
+ void StartValuePollingThread();
+
+ // private data members
+
+ std::string mServiceAddr;
+ std::shared_ptr<::grpc::Channel> mGrpcChannel;
+ std::unique_ptr<vhal_proto::VehicleServer::Stub> mGrpcStub;
+ std::thread mPollingThread;
+
+ std::mutex mShutdownMutex;
+ std::condition_variable mShutdownCV;
+ std::atomic<bool> mShuttingDownFlag{false};
+};
+
+std::unique_ptr<EmulatedVehicleClient> makeGrpcVehicleClient(const std::string& addr) {
+ return std::make_unique<GrpcVehicleClientImpl>(addr);
+}
+
+std::vector<VehiclePropConfig> GrpcVehicleClientImpl::getAllPropertyConfig() const {
+ std::vector<VehiclePropConfig> configs;
+ ::grpc::ClientContext context;
+ auto config_stream = mGrpcStub->GetAllPropertyConfig(&context, ::google::protobuf::Empty());
+ vhal_proto::VehiclePropConfig protoConfig;
+ while (config_stream->Read(&protoConfig)) {
+ VehiclePropConfig config;
+ proto_msg_converter::fromProto(&config, protoConfig);
+ configs.emplace_back(std::move(config));
+ }
+ auto grpc_status = config_stream->Finish();
+ if (!grpc_status.ok()) {
+ LOG(ERROR) << __func__
+ << ": GRPC GetAllPropertyConfig Failed: " << grpc_status.error_message();
+ configs.clear();
+ }
+
+ return configs;
+}
+
+StatusCode GrpcVehicleClientImpl::setProperty(const VehiclePropValue& value, bool updateStatus) {
+ ::grpc::ClientContext context;
+ vhal_proto::WrappedVehiclePropValue wrappedProtoValue;
+ vhal_proto::VehicleHalCallStatus vhal_status;
+ proto_msg_converter::toProto(wrappedProtoValue.mutable_value(), value);
+ wrappedProtoValue.set_update_status(updateStatus);
+
+ auto grpc_status = mGrpcStub->SetProperty(&context, wrappedProtoValue, &vhal_status);
+ if (!grpc_status.ok()) {
+ LOG(ERROR) << __func__ << ": GRPC SetProperty Failed: " << grpc_status.error_message();
+ return StatusCode::INTERNAL_ERROR;
+ }
+
+ return static_cast<StatusCode>(vhal_status.status_code());
+}
+
+void GrpcVehicleClientImpl::StartValuePollingThread() {
+ mPollingThread = std::thread([this]() {
+ while (!mShuttingDownFlag.load()) {
+ ::grpc::ClientContext context;
+
+ std::atomic<bool> rpc_ok{true};
+ std::thread shuttingdown_watcher([this, &rpc_ok, &context]() {
+ std::unique_lock<std::mutex> shutdownLock(mShutdownMutex);
+ mShutdownCV.wait(shutdownLock, [this, &rpc_ok]() {
+ return !rpc_ok.load() || mShuttingDownFlag.load();
+ });
+ context.TryCancel();
+ });
+
+ auto value_stream =
+ mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty());
+ vhal_proto::WrappedVehiclePropValue wrappedProtoValue;
+ while (!mShuttingDownFlag.load() && value_stream->Read(&wrappedProtoValue)) {
+ VehiclePropValue value;
+ proto_msg_converter::fromProto(&value, wrappedProtoValue.value());
+ onPropertyValue(value, wrappedProtoValue.update_status());
+ }
+
+ rpc_ok.store(false);
+ mShutdownCV.notify_all();
+ shuttingdown_watcher.join();
+
+ auto grpc_status = value_stream->Finish();
+ // never reach here until connection lost
+ LOG(ERROR) << __func__
+ << ": GRPC Value Streaming Failed: " << grpc_status.error_message();
+
+ // try to reconnect
+ }
+ });
+}
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h
new file mode 100644
index 0000000000..14eae7f057
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 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 android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_
+
+#include "vhal_v2_0/EmulatedVehicleConnector.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+std::unique_ptr<EmulatedVehicleClient> makeGrpcVehicleClient(const std::string& addr);
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp
new file mode 100644
index 0000000000..e30b3bec54
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2019 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 "GrpcVehicleServer.h"
+
+#include <condition_variable>
+#include <mutex>
+#include <shared_mutex>
+
+#include <android-base/logging.h>
+#include <grpc++/grpc++.h>
+
+#include "VehicleServer.grpc.pb.h"
+#include "VehicleServer.pb.h"
+#include "vhal_v2_0/ProtoMessageConverter.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+class GrpcVehicleServerImpl : public GrpcVehicleServer, public vhal_proto::VehicleServer::Service {
+ public:
+ GrpcVehicleServerImpl(const std::string& addr) : mServiceAddr(addr) {
+ setValuePool(&mValueObjectPool);
+ }
+
+ // method from GrpcVehicleServer
+ void Start() override;
+
+ // method from IVehicleServer
+ void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override;
+
+ // methods from vhal_proto::VehicleServer::Service
+
+ ::grpc::Status GetAllPropertyConfig(
+ ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::grpc::ServerWriter<vhal_proto::VehiclePropConfig>* stream) override;
+
+ ::grpc::Status SetProperty(::grpc::ServerContext* context,
+ const vhal_proto::WrappedVehiclePropValue* wrappedPropValue,
+ vhal_proto::VehicleHalCallStatus* status) override;
+
+ ::grpc::Status StartPropertyValuesStream(
+ ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::grpc::ServerWriter<vhal_proto::WrappedVehiclePropValue>* stream) override;
+
+ private:
+ // We keep long-lasting connection for streaming the prop values.
+ // For us, each connection can be represented as a function to send the new value, and
+ // an ID to identify this connection
+ struct ConnectionDescriptor {
+ using ValueWriterType = std::function<bool(const vhal_proto::WrappedVehiclePropValue&)>;
+
+ ConnectionDescriptor(ValueWriterType&& value_writer)
+ : mValueWriter(std::move(value_writer)),
+ mConnectionID(CONNECTION_ID_COUNTER.fetch_add(1)) {}
+
+ ConnectionDescriptor(const ConnectionDescriptor&) = delete;
+
+ ConnectionDescriptor& operator=(const ConnectionDescriptor&) = delete;
+
+ // This move constructor is NOT THREAD-SAFE, which means it cannot be moved
+ // while using. Since the connection descriptors are pretected by mConnectionMutex
+ // then we are fine here
+ ConnectionDescriptor(ConnectionDescriptor&& cd)
+ : mValueWriter(std::move(cd.mValueWriter)),
+ mConnectionID(cd.mConnectionID),
+ mIsAlive(cd.mIsAlive.load()) {
+ cd.mIsAlive.store(false);
+ }
+
+ ValueWriterType mValueWriter;
+ uint64_t mConnectionID;
+ std::atomic<bool> mIsAlive{true};
+
+ static std::atomic<uint64_t> CONNECTION_ID_COUNTER;
+ };
+
+ std::string mServiceAddr;
+ VehiclePropValuePool mValueObjectPool;
+ mutable std::shared_mutex mConnectionMutex;
+ mutable std::shared_mutex mWriterMutex;
+ std::list<ConnectionDescriptor> mValueStreamingConnections;
+};
+
+std::atomic<uint64_t> GrpcVehicleServerImpl::ConnectionDescriptor::CONNECTION_ID_COUNTER = 0;
+
+static std::shared_ptr<::grpc::ServerCredentials> getServerCredentials() {
+ // TODO(chenhaosjtuacm): get secured credentials here
+ return ::grpc::InsecureServerCredentials();
+}
+
+GrpcVehicleServerPtr makeGrpcVehicleServer(const std::string& addr) {
+ return std::make_unique<GrpcVehicleServerImpl>(addr);
+}
+
+void GrpcVehicleServerImpl::Start() {
+ ::grpc::ServerBuilder builder;
+ builder.RegisterService(this);
+ builder.AddListeningPort(mServiceAddr, getServerCredentials());
+ std::unique_ptr<::grpc::Server> server(builder.BuildAndStart());
+
+ server->Wait();
+}
+
+void GrpcVehicleServerImpl::onPropertyValueFromCar(const VehiclePropValue& value,
+ bool updateStatus) {
+ vhal_proto::WrappedVehiclePropValue wrappedPropValue;
+ proto_msg_converter::toProto(wrappedPropValue.mutable_value(), value);
+ wrappedPropValue.set_update_status(updateStatus);
+ std::shared_lock read_lock(mConnectionMutex);
+
+ bool has_terminated_connections = 0;
+
+ for (auto& connection : mValueStreamingConnections) {
+ auto writeOK = connection.mValueWriter(wrappedPropValue);
+ if (!writeOK) {
+ LOG(ERROR) << __func__ << ": Server Write failed, connection lost. ID: "
+ << connection.mConnectionID;
+ has_terminated_connections = true;
+ connection.mIsAlive.store(false);
+ }
+ }
+
+ if (!has_terminated_connections) {
+ return;
+ }
+
+ read_lock.unlock();
+
+ std::unique_lock write_lock(mConnectionMutex);
+
+ for (auto itr = mValueStreamingConnections.begin(); itr != mValueStreamingConnections.end();) {
+ if (!itr->mIsAlive.load()) {
+ itr = mValueStreamingConnections.erase(itr);
+ } else {
+ ++itr;
+ }
+ }
+}
+
+::grpc::Status GrpcVehicleServerImpl::GetAllPropertyConfig(
+ ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::grpc::ServerWriter<vhal_proto::VehiclePropConfig>* stream) {
+ auto configs = onGetAllPropertyConfig();
+ for (auto& config : configs) {
+ vhal_proto::VehiclePropConfig protoConfig;
+ proto_msg_converter::toProto(&protoConfig, config);
+ if (!stream->Write(protoConfig)) {
+ return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost.");
+ }
+ }
+
+ return ::grpc::Status::OK;
+}
+
+::grpc::Status GrpcVehicleServerImpl::SetProperty(
+ ::grpc::ServerContext* context, const vhal_proto::WrappedVehiclePropValue* wrappedPropValue,
+ vhal_proto::VehicleHalCallStatus* status) {
+ VehiclePropValue value;
+ proto_msg_converter::fromProto(&value, wrappedPropValue->value());
+
+ auto set_status = static_cast<int32_t>(onSetProperty(value, wrappedPropValue->update_status()));
+ if (!vhal_proto::VehicleHalStatusCode_IsValid(set_status)) {
+ return ::grpc::Status(::grpc::StatusCode::INTERNAL, "Unknown status code");
+ }
+
+ status->set_status_code(static_cast<vhal_proto::VehicleHalStatusCode>(set_status));
+
+ return ::grpc::Status::OK;
+}
+
+::grpc::Status GrpcVehicleServerImpl::StartPropertyValuesStream(
+ ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::grpc::ServerWriter<vhal_proto::WrappedVehiclePropValue>* stream) {
+ std::mutex terminateMutex;
+ std::condition_variable terminateCV;
+ std::unique_lock<std::mutex> terminateLock(terminateMutex);
+ bool terminated{false};
+
+ auto callBack = [stream, &terminateMutex, &terminateCV, &terminated,
+ this](const vhal_proto::WrappedVehiclePropValue& value) {
+ std::unique_lock lock(mWriterMutex);
+ if (!stream->Write(value)) {
+ std::unique_lock<std::mutex> terminateLock(terminateMutex);
+ terminated = true;
+ terminateLock.unlock();
+ terminateCV.notify_all();
+ return false;
+ }
+ return true;
+ };
+
+ // Register connection
+ std::unique_lock lock(mConnectionMutex);
+ auto& conn = mValueStreamingConnections.emplace_back(std::move(callBack));
+ lock.unlock();
+
+ // Never stop until connection lost
+ terminateCV.wait(terminateLock, [&terminated]() { return terminated; });
+
+ LOG(ERROR) << __func__ << ": Stream lost, ID : " << conn.mConnectionID;
+
+ return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost.");
+}
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h
new file mode 100644
index 0000000000..32f4eb203a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 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 android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_
+
+#include "vhal_v2_0/EmulatedVehicleConnector.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+// Connect to the Vehicle Client via GRPC
+class GrpcVehicleServer : public EmulatedVehicleServer {
+ public:
+ // Start listening incoming calls, should never return if working normally
+ virtual void Start() = 0;
+};
+
+using GrpcVehicleServerPtr = std::unique_ptr<GrpcVehicleServer>;
+
+GrpcVehicleServerPtr makeGrpcVehicleServer(const std::string& addr);
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp
new file mode 100644
index 0000000000..184d8a47f7
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 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 "Utils.h"
+
+#include <cutils/properties.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sstream>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace impl {
+
+std::string VsockServerInfo::toUri() {
+ std::stringstream uri_stream;
+ uri_stream << "vsock:" << serverCid << ":" << serverPort;
+ return uri_stream.str();
+}
+
+static std::optional<unsigned> parseUnsignedIntFromString(const char* optarg, const char* name) {
+ auto v = strtoul(optarg, nullptr, 0);
+ if (((v == ULONG_MAX) && (errno == ERANGE)) || (v > UINT_MAX)) {
+ LOG(WARNING) << name << " value is out of range: " << optarg;
+ } else if (v != 0) {
+ return v;
+ } else {
+ LOG(WARNING) << name << " value is invalid or missing: " << optarg;
+ }
+
+ return std::nullopt;
+}
+
+static std::optional<unsigned> getNumberFromProperty(const char* key) {
+ auto value = property_get_int64(key, -1);
+ if ((value <= 0) || (value > UINT_MAX)) {
+ LOG(WARNING) << key << " is missing or out of bounds";
+ return std::nullopt;
+ }
+
+ return static_cast<unsigned int>(value);
+};
+
+std::optional<VsockServerInfo> VsockServerInfo::fromCommandLine(int argc, char* argv[]) {
+ std::optional<unsigned int> cid;
+ std::optional<unsigned int> port;
+
+ // unique values to identify the options
+ constexpr int OPT_VHAL_SERVER_CID = 1001;
+ constexpr int OPT_VHAL_SERVER_PORT_NUMBER = 1002;
+
+ struct option longOptions[] = {
+ {"server_cid", 1, 0, OPT_VHAL_SERVER_CID},
+ {"server_port", 1, 0, OPT_VHAL_SERVER_PORT_NUMBER},
+ {},
+ };
+
+ int optValue;
+ while ((optValue = getopt_long_only(argc, argv, ":", longOptions, 0)) != -1) {
+ switch (optValue) {
+ case OPT_VHAL_SERVER_CID:
+ cid = parseUnsignedIntFromString(optarg, "cid");
+ break;
+ case OPT_VHAL_SERVER_PORT_NUMBER:
+ port = parseUnsignedIntFromString(optarg, "port");
+ break;
+ default:
+ // ignore other options
+ break;
+ }
+ }
+
+ if (cid && port) {
+ return VsockServerInfo{*cid, *port};
+ }
+ return std::nullopt;
+}
+
+std::optional<VsockServerInfo> VsockServerInfo::fromRoPropertyStore() {
+ constexpr const char* VHAL_SERVER_CID_PROPERTY_KEY = "ro.vendor.vehiclehal.server.cid";
+ constexpr const char* VHAL_SERVER_PORT_PROPERTY_KEY = "ro.vendor.vehiclehal.server.port";
+
+ const auto cid = getNumberFromProperty(VHAL_SERVER_CID_PROPERTY_KEY);
+ const auto port = getNumberFromProperty(VHAL_SERVER_PORT_PROPERTY_KEY);
+
+ if (cid && port) {
+ return VsockServerInfo{*cid, *port};
+ }
+ return std::nullopt;
+}
+
+} // namespace impl
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h
new file mode 100644
index 0000000000..8a8bce7c7a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 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 android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_
+
+#include <optional>
+#include <string>
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace impl {
+
+struct VsockServerInfo {
+ unsigned int serverCid{0};
+ unsigned int serverPort{0};
+
+ static std::optional<VsockServerInfo> fromCommandLine(int argc, char* argv[]);
+ static std::optional<VsockServerInfo> fromRoPropertyStore();
+
+ std::string toUri();
+};
+
+} // namespace impl
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 6145ea2710..a91bd885b3 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -2438,6 +2438,217 @@ enum VehicleProperty : int32_t {
| VehiclePropertyType:STRING
| VehicleArea:GLOBAL),
+ /**
+ * Defines the initial Android user to be used during initialization.
+ *
+ * This property is called by the Android system when it initializes and it lets the HAL
+ * define which Android user should be started.
+ *
+ * This request is made by setting a VehiclePropValue (defined by InitialUserInfoRequest),
+ * and the HAL must respond with a property change event (defined by InitialUserInfoResponse).
+ * If the HAL doesn't respond after some time (defined by the Android system), the Android
+ * system will proceed as if HAL returned a response of action
+ * InitialUserInfoResponseAction:DEFAULT.
+ *
+ * For example, on first boot, the request could be:
+ *
+ * int32[0]: 42 // request id (arbitrary number set by Android system)
+ * int32[1]: 1 // InitialUserInfoRequestType::FIRST_BOOT
+ * int32[2]: 0 // id of current user (usersInfo.currentUser.userId)
+ * int32[3]: 1 // flag of current user (usersInfo.currentUser.flags = SYSTEM)
+ * int32[4]: 1 // number of existing users (usersInfo.numberUsers);
+ * int32[5]: 0 // user #0 (usersInfo.existingUsers[0].userId)
+ * int32[6]: 1 // flags of user #0 (usersInfo.existingUsers[0].flags)
+ *
+ * And if the HAL want to respond with the creation of an admin user called "Admin", the
+ * response would be:
+ *
+ * int32[0]: 42 // must match the request id from the request
+ * int32[1]: 2 // action = InitialUserInfoResponseAction::CREATE
+ * int32[2]: -1 // userToSwitchOrCreate.userId (not used as user will be created)
+ * int32[3]: 8 // userToSwitchOrCreate.flags = ADMIN
+ * string: "Admin" // userNameToCreate
+ *
+ * NOTE: if the HAL doesn't support user management, then it should not define this property,
+ * which in turn would disable the other user-related properties (for example, the Android
+ * system would never issue them and user-related requests from the HAL layer would be ignored
+ * by the Android System). But if it supports user management, then it must support all
+ * user-related properties (INITIAL_USER_INFO, SWITCH_USER, TODO(b/146207078):others).
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ INITIAL_USER_INFO = (
+ 0x0F07
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:MIXED
+ | VehicleArea:GLOBAL),
+
+ /**
+ * Defines a request to switch the foreground Android user.
+ *
+ * This property is used primarily by the Android System to inform the HAL that the
+ * current foreground Android user is switching, but it could also be used by the HAL to request
+ * the Android system to switch users - the
+ *
+ * When the request is made by Android, it sets a VehiclePropValue and the HAL must responde
+ * with a property change event; when the HAL is making the request, it must also do it through
+ * a property change event (the main difference is that the request id will be positive in the
+ * former case, and negative in the latter; the SwitchUserMessageType will also be different).
+ *
+ * The format of both request is defined by SwitchUserRequest and the format of the response
+ * (when needed) is defined by SwitchUserResponse. How the HAL (or Android System) should
+ * proceed depends on the message type (which is defined by the SwitchUserMessageType
+ * parameter), as defined below.
+ *
+ * 1.LEGACY_ANDROID_SWITCH
+ * -----------------------
+ *
+ * Called by the Android System to indicate the Android user is about to change, when the change
+ * request was made in a way that is not integrated with the HAL (for example, through
+ * adb shell am switch-user).
+ *
+ * The HAL can switch its internal user once it receives this request, but it doesn't need to
+ * reply back to the Android System. If its internal user cannot be changed for some reason,
+ * then it must wait for the SWITCH_USER(type=ANDROID_POST_SWITCH) call to recover
+ * (for example, it could issue a SWITCH_USER(type=VEHICLE_REQUEST) to switch back to
+ * the previous user), but ideally it should never fail (as switching back could result in a
+ * confusing experience for the end user).
+ *
+ * For example, if the system have users (0, 10, 11) and it's switching from 0 to 11 (where none
+ * of them have any special flag), the request would be:
+ *
+ * int32[0]: 42 // request id
+ * int32[1]: 1 // SwitchUserMessageType::LEGACY_ANDROID_SWITCH
+ * int32[2]: 11 // target user id
+ * int32[3]: 0 // target user flags (none)
+ * int32[4]: 10 // current user
+ * int32[5]: 0 // current user flags (none)
+ * int32[6]: 3 // number of users
+ * int32[7]: 0 // user #0 (Android user id 0)
+ * int32[8]: 0 // flags of user #0 (none)
+ * int32[9]: 10 // user #1 (Android user id 10)
+ * int32[10]: 0 // flags of user #1 (none)
+ * int32[11]: 11 // user #2 (Android user id 11)
+ * int32[12]: 0 // flags of user #2 (none)
+ *
+ * 2.ANDROID_SWITCH
+ * ----------------
+ * Called by the Android System to indicate the Android user is about to change, but Android
+ * will wait for the HAL's response (up to some time) before proceeding.
+ *
+ * The HAL must switch its internal user once it receives this request, then respond back to
+ * Android with a SWITCH_USER(type=VEHICLE_RESPONSE) indicating whether its internal
+ * user was switched or not (through the SwitchUserStatus enum).
+ *
+ * For example, if Android has users (0, 10, 11) and it's switching from 10 to 11 (where
+ * none of them have any special flag), the request would be:
+ *
+ * int32[0]: 42 // request id
+ * int32[1]: 2 // SwitchUserMessageType::ANDROID_SWITCH
+ * int32[2]: 11 // target user id
+ * int32[3]: 0 // target user flags (none)
+ * int32[4]: 10 // current user
+ * int32[5]: 0 // current user flags (none)
+ * int32[6]: 3 // number of users
+ * int32[7]: 0 // 1st user (user 0)
+ * int32[8]: 0 // 1st user flags (none)
+ * int32[9]: 10 // 2nd user (user 10)
+ * int32[10]: 0 // 2nd user flags (none)
+ * int32[11]: 11 // 3rd user (user 11)
+ * int32[12]: 0 // 3rd user flags (none)
+ *
+ * If the request succeeded, the HAL must update the propery with:
+ *
+ * int32[0]: 42 // request id
+ * int32[1]: 3 // messageType = SwitchUserMessageType::VEHICLE_RESPONSE
+ * int32[2]: 1 // status = SwitchUserStatus::SUCCESS
+ *
+ * But if it failed, the response would be something like:
+ *
+ * int32[0]: 42 // request id
+ * int32[1]: 3 // messageType = SwitchUserMessageType::VEHICLE_RESPONSE
+ * int32[2]: 2 // status = SwitchUserStatus::FAILURE
+ * string: "108-D'OH!" // OEM-spefic error message
+ *
+ * 3.VEHICLE_RESPONSE
+ * ------------------
+ * Called by the HAL to indicate whether a request of type ANDROID_SWITCH should proceed or
+ * abort - see the ANDROID_SWITCH section above for more info.
+ *
+ * 4.VEHICLE_REQUEST
+ * ------------------
+ * Called by the HAL to request that the current foreground Android user is switched.
+ *
+ * This is useful in situations where Android started as one user, but the vehicle identified
+ * the driver as another user. For example, user A unlocked the car using the key fob of user B;
+ * the INITIAL_USER_INFO request returned user B, but then a face recognition subsubsystem
+ * identified the user as A.
+ *
+ * The HAL makes this request by a property change event (passing a negative request id), and
+ * the Android system will response by issuye an ANDROID_POST_SWITCH call which the same
+ * request id.
+ *
+ * For example, if the current foreground Android user is 10 and the HAL asked it to switch to
+ * 11, the request would be:
+ *
+ * int32[0]: -108 // request id
+ * int32[1]: 4 // messageType = SwitchUserMessageType::VEHICLE_REQUEST
+ * int32[2]: 11 // Android user id
+ *
+ * If the request succeeded and Android has 3 users (0, 10, 11), the response would be:
+ *
+ * int32[0]: -108 // request id
+ * int32[1]: 5 // messageType = SwitchUserMessageType::ANDROID_SWITCH
+ * int32[2]: 11 // target user id
+ * int32[3]: 11 // target user id flags (none)
+ * int32[4]: 11 // current user
+ * int32[5]: 0 // current user flags (none)
+ * int32[6]: 3 // number of users
+ * int32[7]: 0 // 1st user (user 0)
+ * int32[8]: 0 // 1st user flags (none)
+ * int32[9]: 10 // 2nd user (user 10)
+ * int32[10]: 4 // 2nd user flags (none)
+ * int32[11]: 11 // 3rd user (user 11)
+ * int32[12]: 3 // 3rd user flags (none)
+ *
+ * Notice that both the current and target user ids are the same - if the request failed, then
+ * they would be different (i.e, target user would be 11, but current user would still be 10).
+ *
+ * 5.ANDROID_POST_SWITCH
+ * ---------------------
+ * Called by the Android System after a request to switch a user was made
+ *
+ * This property is called after switch requests of any type (i.e., LEGACY_ANDROID_SWITCH,
+ * ANDROID_SWITCH, or VEHICLE_REQUEST) and can be used to determine if the request succeeded or
+ * failed:
+ *
+ * 1. When it succeeded, it's called when the Android user is in the boot locked state and the
+ * value of the current and target users ids in the response are different. This would be
+ * equivalent to receiving an Intent.ACTION_LOCKED_BOOT_COMPLETED in an Android app.
+ * 2. When it failed it's called right away and the value of the current and target users ids
+ * in the response are the same.
+ *
+ * The HAL can update its internal state once it receives this request, but it doesn't need to
+ * reply back to the Android System.
+ *
+ * Request: the first N values as defined by INITIAL_USER_INFO (where the request-specific
+ * value at index 1 is SwitchUserMessageType::ANDROID_POST_SWITCH), then 2 more values for the
+ * target user id (i.e., the Android user id that was requested to be switched to) and its flags
+ * (as defined by UserFlags).
+ *
+ * Response: none.
+ *
+ * Example: see VEHICLE_REQUEST section above.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SWITCH_USER = (
+ 0x0F08
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:MIXED
+ | VehicleArea:GLOBAL),
};
/**
@@ -3733,3 +3944,258 @@ enum VmsAvailabilityStateIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex {
enum VmsPublisherInformationIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex {
PUBLISHER_ID = 1,
};
+
+/**
+ * Information about a specific Android user.
+ */
+struct UserInfo {
+
+ UserId userId;
+
+ UserFlags flags;
+};
+
+/**
+ * Id of an Android user.
+ *
+ * Must be > 0 for valid ids, or -1 when it's not used.
+ */
+typedef int32_t UserId;
+
+/**
+ * Flags used to define the characteristics of an Android user.
+ */
+enum UserFlags: int32_t {
+ /**
+ * No flags.
+ */
+ NONE = 0x0,
+
+ /**
+ * System user.
+ * On automotive, that user is always running, although never on foreground (except during
+ * boot or exceptional circumstances).
+ */
+ SYSTEM = 0x01,
+
+ /**
+ * Guest users have restrictions.
+ */
+ GUEST = 0x02,
+
+ /**
+ * Ephemeral users have non-persistent state.
+ */
+ EPHEMERAL = 0x04,
+
+ /**
+ * Admin users have additional privileges such as permission to create other users.
+ */
+ ADMIN = 0x08,
+};
+
+/**
+ * Information about all Android users.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it's part of other structs, which
+ * in turn are converted to a VehiclePropValue.RawValue through libraries provided by the default
+ * Vehicle HAL implementation.
+ */
+struct UsersInfo {
+
+ /** The current foreground user. */
+ UserInfo currentUser;
+
+ /** Number of existing users (includes the current user). */
+ int32_t numberUsers;
+
+ /** List of existing users (includes the current user). */
+ vec<UserInfo> existingUsers;
+ };
+
+/**
+ * Id of a request related to user management.
+ *
+ * This id can be used by the Android system to map responses sent by the HAL, and vice-versa.
+ *
+ * For requests originated by Android, the value is positive (> 0), while for requests originated by
+ * the HAL it must be negative (< 0).
+ */
+typedef int32_t UserRequestId;
+
+/**
+ * Defines the format of a INITIAL_USER_INFO request made by the Android system.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct InitialUserInfoRequest {
+ /**
+ * Arbitrary id used to map the HAL response to the request.
+ */
+ UserRequestId requestId;
+
+ /**
+ * Type of request.
+ */
+ InitialUserInfoRequestType requestType;
+
+ /**
+ * Information about the current state of the Android system.
+ */
+ UsersInfo usersInfo;
+};
+
+/**
+ * Defines when a INITIAL_USER_INFO request was made.
+ */
+enum InitialUserInfoRequestType : int32_t {
+ /** At the first time Android was booted (or after a factory reset). */
+ FIRST_BOOT = 1,
+
+ /** At the first time Android was booted after the system was updated. */
+ FIRST_BOOT_AFTER_OTA = 2,
+
+ /** When Android was booted "from scratch". */
+ COLD_BOOT = 3,
+
+ /** When Android was resumed after the system was suspended to memory. */
+ RESUME = 4,
+};
+
+/**
+ * Defines the format of a HAL response to a INITIAL_USER_INFO request.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct InitialUserInfoResponse {
+ /**
+ * Id of the request being responded.
+ */
+ UserRequestId requestId;
+
+ /**
+ * which action the Android system should take.
+ */
+ InitialUserInfoResponseAction action;
+
+ /**
+ * Information about the user that should be switched to or created.
+ */
+ UserInfo userToSwitchOrCreate;
+
+ /**
+ * Name of the user that should be created.
+ */
+ string userNameToCreate;
+};
+
+/**
+ * Defines which action the Android system should take in an INITIAL_USER_INFO request.
+ */
+enum InitialUserInfoResponseAction : int32_t {
+ /**
+ * Let the Android System decide what to do.
+ *
+ * For example, it might create a new user on first boot, and switch to the last
+ * active user afterwards.
+ */
+ DEFAULT = 0,
+
+ /**
+ * Switch to an existing Android user.
+ */
+ SWITCH = 1,
+
+ /**
+ * Create a new Android user (and switch to it).
+ */
+ CREATE = 2,
+};
+
+/**
+ * Defines the format of a SWITCH_USER property.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct SwitchUserRequest {
+ /**
+ * Arbitrary id used to map the response to the request.
+ */
+ UserRequestId requestId;
+
+ /**
+ * Type of message.
+ */
+ SwitchUserMessageType messageType;
+
+ /**
+ * Information about the Android user being switched to.
+ *
+ * Only the user id (but not the flags) should be set when the request is made by HAL.
+ */
+ UserInfo targetUser;
+
+ /**
+ * Information about the current state of the Android system.
+ *
+ * Should not be set when the request is made by HAL.
+ */
+ UsersInfo usersInfo;
+};
+
+/**
+ * Defines the reason a SWITCH_USER call was made.
+ *
+ * The meaning of each constant is explained in that property.
+ */
+enum SwitchUserMessageType: int32_t {
+ LEGACY_ANDROID_SWITCH = 1,
+ ANDROID_SWITCH = 2,
+ VEHICLE_RESPONSE = 3,
+ VEHICLE_REQUEST = 4,
+ ANDROID_POST_SWITCH = 5,
+};
+
+/**
+ * Defines the result of a SwitchUserRequest.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct SwitchUserResponse {
+ /**
+ * Id of the request being responded.
+ */
+ UserRequestId requestId;
+
+ /**
+ * Type of message.
+ */
+ SwitchUserMessageType messageType;
+
+ /**
+ * Status of the request.
+ */
+ SwitchUserStatus status;
+
+ /**
+ * HAL-specific error message.
+ *
+ * This argument is optional, and when defined (and the status is FAILURE), it's passed "as-is"
+ * to the caller. It could be used to show custom error messages to the end user.
+ */
+ string failureMessage;
+};
+
+/**
+ * Status of the response to a SwitchUserRequest.
+ */
+enum SwitchUserStatus : int32_t {
+ /** The request succeeded and the HAL user was switched. */
+ SUCCESS = 1,
+ /** The request failed and the HAL user remained the same. */
+ FAILURE = 2,
+};
diff --git a/biometrics/face/1.1/Android.bp b/biometrics/face/1.1/Android.bp
new file mode 100644
index 0000000000..2206597dec
--- /dev/null
+++ b/biometrics/face/1.1/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.biometrics.face@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "IBiometricsFace.hal",
+ ],
+ interfaces: [
+ "android.hardware.biometrics.face@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/biometrics/face/1.1/IBiometricsFace.hal b/biometrics/face/1.1/IBiometricsFace.hal
new file mode 100644
index 0000000000..84e7443c9c
--- /dev/null
+++ b/biometrics/face/1.1/IBiometricsFace.hal
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 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 android.hardware.biometrics.face@1.1;
+
+import @1.0::IBiometricsFace;
+import @1.0::Status;
+import @1.0::Feature;
+
+/**
+ * The HAL interface for biometric face authentication.
+ */
+interface IBiometricsFace extends @1.0::IBiometricsFace {
+ /**
+ * Enrolls a user's face for a remote client, for example Android Auto.
+ *
+ * The HAL implementation is responsible for creating a secure communication
+ * channel and receiving the enrollment images from a mobile device with
+ * face authentication hardware.
+ *
+ * Note that the Hardware Authentication Token must be valid for the
+ * duration of enrollment and thus should be explicitly invalidated by a
+ * call to revokeChallenge() when enrollment is complete, to reduce the
+ * window of opportunity to re-use the challenge and HAT. For example,
+ * Settings calls generateChallenge() once to allow the user to enroll one
+ * or more faces or toggle secure settings without having to re-enter the
+ * PIN/pattern/password. Once the user completes the operation, Settings
+ * invokes revokeChallenge() to close the transaction. If the HAT is expired,
+ * the implementation must invoke onError with UNABLE_TO_PROCESS.
+ *
+ * Requirements for using this API:
+ * - Mobile devices MUST NOT delegate enrollment to another device by calling
+ * this API. This feature is intended only to allow enrollment on devices
+ * where it is impossible to enroll locally on the device.
+ * - The path MUST be protected by a secret key with rollback protection.
+ * - Synchronizing between devices MUST be accomplished by having both
+ * devices agree on a secret PIN entered by the user (similar to BT
+ * pairing procedure) and use a salted version of that PIN plus other secret
+ * to encrypt traffic.
+ * - All communication to/from the remote device MUST be encrypted and signed
+ * to prevent image injection and other man-in-the-middle type attacks.
+ * - generateChallenge() and revokeChallenge() MUST be implemented on both
+ * remote and local host (e.g. hash the result of the remote host with a
+ * local secret before responding to the API call) and any transmission of
+ * the challenge between hosts MUST be signed to prevent man-in-the-middle
+ * attacks.
+ * - In the event of a lost connection, the result of the last
+ * generateChallenge() MUST be invalidated and the process started over.
+ * - Both the remote and local host MUST honor the timeout and invalidate the
+ * challenge.
+ *
+ * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+ * method.
+ *
+ * @param hat A valid Hardware Authentication Token, generated as a result
+ * of a generateChallenge() challenge being wrapped by the gatekeeper
+ * after a successful strong authentication request.
+ * @param timeoutSec A timeout in seconds, after which this enroll
+ * attempt is cancelled. Note that the framework can continue
+ * enrollment by calling this again with a valid HAT. This timeout is
+ * expected to be used to limit power usage if the device becomes idle
+ * during enrollment. The implementation is expected to send
+ * ERROR_TIMEOUT if this happens.
+ * @param disabledFeatures A list of features to be disabled during
+ * enrollment. Note that all features are enabled by default.
+ * @return status The status of this method call.
+ */
+ enrollRemotely(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures)
+ generates (Status status);
+
+ /**
+ * Enrolls a user's face.
+ *
+ * Note that the Hardware Authentication Token must be valid for the
+ * duration of enrollment and thus should be explicitly invalidated by a
+ * call to revokeChallenge() when enrollment is complete, to reduce the
+ * window of opportunity to re-use the challenge and HAT. For example,
+ * Settings calls generateChallenge() once to allow the user to enroll one
+ * or more faces or toggle secure settings without having to re-enter the
+ * PIN/pattern/password. Once the user completes the operation, Settings
+ * invokes revokeChallenge() to close the transaction. If the HAT is expired,
+ * the implementation must invoke onError with UNABLE_TO_PROCESS.
+ *
+ * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+ * method.
+ *
+ * @param hat A valid Hardware Authentication Token, generated as a result
+ * of a generateChallenge() challenge being wrapped by the gatekeeper
+ * after a successful strong authentication request.
+ * @param timeoutSec A timeout in seconds, after which this enroll
+ * attempt is cancelled. Note that the framework can continue
+ * enrollment by calling this again with a valid HAT. This timeout is
+ * expected to be used to limit power usage if the device becomes idle
+ * during enrollment. The implementation is expected to send
+ * ERROR_TIMEOUT if this happens.
+ * @param disabledFeatures A list of features to be disabled during
+ * enrollment. Note that all features are enabled by default.
+ * @param windowId optional ID of a camera preview window for a
+ * single-camera device. Must be null if not used.
+ * @return status The status of this method call.
+ */
+ enroll_1_1(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures,
+ handle windowId) generates (Status status);
+};
diff --git a/biometrics/face/1.1/default/Android.bp b/biometrics/face/1.1/default/Android.bp
new file mode 100644
index 0000000000..360071f3dd
--- /dev/null
+++ b/biometrics/face/1.1/default/Android.bp
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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.
+ */
+
+cc_binary {
+ name: "android.hardware.biometrics.face@1.1-service.example",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ init_rc: ["android.hardware.biometrics.face@1.1-service.rc"],
+ vintf_fragments: ["manifest_face_default.xml"],
+ relative_install_path: "hw",
+ proprietary: true,
+ srcs: [
+ "BiometricsFace.cpp",
+ "service.cpp",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "libutils",
+ "liblog",
+ "android.hardware.biometrics.face@1.0",
+ "android.hardware.biometrics.face@1.1",
+ ],
+}
diff --git a/biometrics/face/1.1/default/BiometricsFace.cpp b/biometrics/face/1.1/default/BiometricsFace.cpp
new file mode 100644
index 0000000000..2143880514
--- /dev/null
+++ b/biometrics/face/1.1/default/BiometricsFace.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright 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.
+ */
+
+#include "BiometricsFace.h"
+
+namespace android::hardware::biometrics::face::implementation {
+using android::hardware::biometrics::face::V1_0::FaceError;
+using android::hardware::biometrics::face::V1_0::OptionalUint64;
+
+// Arbitrary value.
+constexpr uint64_t kDeviceId = 123;
+// Arbitrary value.
+constexpr uint64_t kAuthenticatorId = 987;
+// Arbitrary value.
+constexpr uint64_t kLockoutDuration = 555;
+
+BiometricsFace::BiometricsFace() : mRandom(std::mt19937::default_seed) {}
+
+// Methods from IBiometricsFace follow.
+Return<void> BiometricsFace::setCallback(const sp<IBiometricsFaceClientCallback>& clientCallback,
+ setCallback_cb _hidl_cb) {
+ mClientCallback = clientCallback;
+ _hidl_cb({Status::OK, kDeviceId});
+ return Void();
+}
+
+Return<Status> BiometricsFace::setActiveUser(int32_t userId, const hidl_string& storePath) {
+ if (userId < 0 || storePath.empty() || std::string(storePath).find("/data") != 0) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ mUserId = userId;
+ mClientCallback->onLockoutChanged(kLockoutDuration);
+ return Status::OK;
+}
+
+Return<void> BiometricsFace::generateChallenge(uint32_t /* challengeTimeoutSec */,
+ generateChallenge_cb _hidl_cb) {
+ std::uniform_int_distribution<uint64_t> dist;
+ _hidl_cb({Status::OK, dist(mRandom)});
+ return Void();
+}
+
+Return<Status> BiometricsFace::enroll(const hidl_vec<uint8_t>& /* hat */, uint32_t /* timeoutSec */,
+ const hidl_vec<Feature>& /* disabledFeatures */) {
+ // hat can never be valid in this implementation.
+ mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::revokeChallenge() {
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::setFeature(Feature /* feature */, bool /* enabled */,
+ const hidl_vec<uint8_t>& /* hat */,
+ uint32_t /* faceId */) {
+ // hat can never be valid in this implementation.
+ return Status::ILLEGAL_ARGUMENT;
+}
+
+Return<void> BiometricsFace::getFeature(Feature /* feature */, uint32_t /* faceId */,
+ getFeature_cb _hidl_cb) {
+ // hat can never be valid in this implementation.
+ _hidl_cb({Status::ILLEGAL_ARGUMENT, false});
+ return Void();
+}
+
+Return<void> BiometricsFace::getAuthenticatorId(getAuthenticatorId_cb _hidl_cb) {
+ _hidl_cb({Status::OK, kAuthenticatorId});
+ return Void();
+}
+
+Return<Status> BiometricsFace::cancel() {
+ mClientCallback->onError(kDeviceId, mUserId, FaceError::CANCELED, 0 /* vendorCode */);
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::enumerate() {
+ mClientCallback->onEnumerate(kDeviceId, {}, mUserId);
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::remove(uint32_t /* faceId */) {
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::authenticate(uint64_t /* operationId */) {
+ mClientCallback->onError(kDeviceId, mUserId, FaceError::HW_UNAVAILABLE, 0 /* vendorCode */);
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::userActivity() {
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::resetLockout(const hidl_vec<uint8_t>& /* hat */) {
+ return Status::OK;
+}
+
+// Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow.
+Return<Status> BiometricsFace::enroll_1_1(const hidl_vec<uint8_t>& /* hat */,
+ uint32_t /* timeoutSec */,
+ const hidl_vec<Feature>& /* disabledFeatures */,
+ const hidl_handle& /* windowId */) {
+ mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::enrollRemotely(const hidl_vec<uint8_t>& /* hat */,
+ uint32_t /* timeoutSec */,
+ const hidl_vec<Feature>& /* disabledFeatures */) {
+ mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ return Status::OK;
+}
+
+} // namespace android::hardware::biometrics::face::implementation
diff --git a/biometrics/face/1.1/default/BiometricsFace.h b/biometrics/face/1.1/default/BiometricsFace.h
new file mode 100644
index 0000000000..5ce5771eae
--- /dev/null
+++ b/biometrics/face/1.1/default/BiometricsFace.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <random>
+
+namespace android::hardware::biometrics::face::implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::biometrics::face::V1_0::Feature;
+using ::android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
+using ::android::hardware::biometrics::face::V1_0::Status;
+
+class BiometricsFace : public V1_1::IBiometricsFace {
+ public:
+ BiometricsFace();
+
+ // Methods from ::android::hardware::biometrics::face::V1_0::IBiometricsFace follow.
+ Return<void> setCallback(const sp<IBiometricsFaceClientCallback>& clientCallback,
+ setCallback_cb _hidl_cb) override;
+
+ Return<Status> setActiveUser(int32_t userId, const hidl_string& storePath) override;
+
+ Return<void> generateChallenge(uint32_t challengeTimeoutSec,
+ generateChallenge_cb _hidl_cb) override;
+
+ Return<Status> enroll(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+ const hidl_vec<Feature>& disabledFeatures) override;
+
+ Return<Status> revokeChallenge() override;
+
+ Return<Status> setFeature(Feature feature, bool enabled, const hidl_vec<uint8_t>& hat,
+ uint32_t faceId) override;
+
+ Return<void> getFeature(Feature feature, uint32_t faceId, getFeature_cb _hidl_cb) override;
+
+ Return<void> getAuthenticatorId(getAuthenticatorId_cb _hidl_cb) override;
+
+ Return<Status> cancel() override;
+
+ Return<Status> enumerate() override;
+
+ Return<Status> remove(uint32_t faceId) override;
+
+ Return<Status> authenticate(uint64_t operationId) override;
+
+ Return<Status> userActivity() override;
+
+ Return<Status> resetLockout(const hidl_vec<uint8_t>& hat) override;
+
+ // Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow.
+ Return<Status> enroll_1_1(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+ const hidl_vec<Feature>& disabledFeatures,
+ const hidl_handle& windowId) override;
+
+ Return<Status> enrollRemotely(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+ const hidl_vec<Feature>& disabledFeatures) override;
+
+ private:
+ std::mt19937 mRandom;
+ int32_t mUserId;
+ sp<IBiometricsFaceClientCallback> mClientCallback;
+};
+
+} // namespace android::hardware::biometrics::face::implementation
diff --git a/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc b/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
new file mode 100644
index 0000000000..687e2d8c86
--- /dev/null
+++ b/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
@@ -0,0 +1,10 @@
+service vendor.face-hal-1-1-default /vendor/bin/hw/android.hardware.biometrics.face@1.1-service.example
+ # "class hal" causes a race condition on some devices due to files created
+ # in /data. As a workaround, postpone startup until later in boot once
+ # /data is mounted.
+ class late_start
+ user system
+ group system
+ writepid /dev/cpuset/foreground/tasks
+ capabilities SYS_NICE
+ rlimit rtprio 10 10
diff --git a/biometrics/face/1.1/default/manifest_face_default.xml b/biometrics/face/1.1/default/manifest_face_default.xml
new file mode 100644
index 0000000000..ec71d9c92b
--- /dev/null
+++ b/biometrics/face/1.1/default/manifest_face_default.xml
@@ -0,0 +1,11 @@
+<manifest version="2.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.biometrics.face</name>
+ <transport>hwbinder</transport>
+ <version>1.1</version>
+ <interface>
+ <name>IBiometricsFace</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/biometrics/face/1.1/default/service.cpp b/biometrics/face/1.1/default/service.cpp
new file mode 100644
index 0000000000..344bdb99b4
--- /dev/null
+++ b/biometrics/face/1.1/default/service.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.biometrics.face@1.1-service"
+
+#include <android/hardware/biometrics/face/1.0/types.h>
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
+#include <android/log.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include "BiometricsFace.h"
+
+using android::sp;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::biometrics::face::implementation::BiometricsFace;
+using android::hardware::biometrics::face::V1_1::IBiometricsFace;
+
+int main() {
+ ALOGI("BiometricsFace HAL is being started.");
+
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+ android::sp<IBiometricsFace> face = new BiometricsFace();
+ const android::status_t status = face->registerAsService();
+
+ if (status != android::OK) {
+ ALOGE("Error starting the BiometricsFace HAL.");
+ return 1;
+ }
+
+ ALOGI("BiometricsFace HAL has started successfully.");
+ joinRpcThreadpool();
+
+ ALOGI("BiometricsFace HAL is terminating.");
+ return 1; // should never get here
+}
diff --git a/biometrics/face/1.1/vts/functional/Android.bp b/biometrics/face/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000000..ccbb3994e1
--- /dev/null
+++ b/biometrics/face/1.1/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 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.
+ */
+
+cc_test {
+ name: "VtsHalBiometricsFaceV1_1TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalBiometricsFaceV1_1TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.biometrics.face@1.0",
+ "android.hardware.biometrics.face@1.1",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
new file mode 100644
index 0000000000..6ada44231f
--- /dev/null
+++ b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "biometrics_face_hidl_hal_test"
+
+#include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <chrono>
+#include <cstdint>
+#include <random>
+
+using android::sp;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo;
+using android::hardware::biometrics::face::V1_0::FaceError;
+using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
+using android::hardware::biometrics::face::V1_0::OptionalUint64;
+using android::hardware::biometrics::face::V1_0::Status;
+using android::hardware::biometrics::face::V1_1::IBiometricsFace;
+
+namespace {
+
+// Arbitrary, nonexistent userId
+constexpr uint32_t kUserId = 9;
+constexpr uint32_t kTimeoutSec = 3;
+constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
+constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata";
+constexpr char kCallbackNameOnError[] = "onError";
+
+// Callback arguments that need to be captured for the tests.
+struct FaceCallbackArgs {
+ // The error passed to the last onError() callback.
+ FaceError error;
+
+ // The userId passed to the last callback.
+ int32_t userId;
+};
+
+// Test callback class for the BiometricsFace HAL.
+// The HAL will call these callback methods to notify about completed operations
+// or encountered errors.
+class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase<FaceCallbackArgs>,
+ public IBiometricsFaceClientCallback {
+ public:
+ Return<void> onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override { return Void(); }
+
+ Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
+ return Void();
+ }
+
+ Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
+ return Void();
+ }
+
+ Return<void> onError(uint64_t, int32_t userId, FaceError error, int32_t) override {
+ FaceCallbackArgs args = {};
+ args.error = error;
+ args.userId = userId;
+ NotifyFromCallback(kCallbackNameOnError, args);
+ return Void();
+ }
+
+ Return<void> onRemoved(uint64_t, const hidl_vec<uint32_t>&, int32_t) override { return Void(); }
+
+ Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
+ return Void();
+ }
+
+ Return<void> onLockoutChanged(uint64_t) override { return Void(); }
+};
+
+// Test class for the BiometricsFace HAL.
+class FaceHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ mService = IBiometricsFace::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ mCallback = new FaceCallback();
+ mCallback->SetWaitTimeoutDefault(kTimeout);
+ Return<void> ret1 = mService->setCallback(mCallback, [](const OptionalUint64& res) {
+ ASSERT_EQ(Status::OK, res.status);
+ // Makes sure the "deviceId" represented by "res.value" is not 0.
+ // 0 would mean the HIDL is not available.
+ ASSERT_NE(0UL, res.value);
+ });
+ ASSERT_TRUE(ret1.isOk());
+ Return<Status> ret2 = mService->setActiveUser(kUserId, kFacedataDir);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret2));
+ }
+
+ void TearDown() override {}
+
+ sp<IBiometricsFace> mService;
+ sp<FaceCallback> mCallback;
+};
+
+// enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FaceHidlTest, Enroll2_2ZeroHatTest) {
+ // Filling HAT with zeros
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; i++) {
+ token[i] = 0;
+ }
+
+ hidl_handle windowId = nullptr;
+ Return<Status> ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid HAT should fail.
+TEST_P(FaceHidlTest, Enroll2_2GarbageHatTest) {
+ // Filling HAT with pseudorandom invalid data.
+ // Using default seed to make the test reproducible.
+ std::mt19937 gen(std::mt19937::default_seed);
+ std::uniform_int_distribution<uint8_t> dist;
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; ++i) {
+ token[i] = dist(gen);
+ }
+
+ hidl_handle windowId = nullptr;
+ Return<Status> ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FaceHidlTest, EnrollRemotelyZeroHatTest) {
+ // Filling HAT with zeros
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; i++) {
+ token[i] = 0;
+ }
+
+ Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid HAT should fail.
+TEST_P(FaceHidlTest, EnrollRemotelyGarbageHatTest) {
+ // Filling HAT with pseudorandom invalid data.
+ // Using default seed to make the test reproducible.
+ std::mt19937 gen(std::mt19937::default_seed);
+ std::uniform_int_distribution<uint8_t> dist;
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; ++i) {
+ token[i] = dist(gen);
+ }
+
+ Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+} // anonymous namespace
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, FaceHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBiometricsFace::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/biometrics/fingerprint/2.2/Android.bp b/biometrics/fingerprint/2.2/Android.bp
new file mode 100644
index 0000000000..6c769ac22e
--- /dev/null
+++ b/biometrics/fingerprint/2.2/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.biometrics.fingerprint@2.2",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IBiometricsFingerprint.hal",
+ "IBiometricsFingerprintClientCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.biometrics.fingerprint@2.1",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal
new file mode 100644
index 0000000000..06510344ef
--- /dev/null
+++ b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal
@@ -0,0 +1,58 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.biometrics.fingerprint@2.2;
+
+import @2.1::IBiometricsFingerprint;
+import @2.1::RequestStatus;
+
+interface IBiometricsFingerprint extends @2.1::IBiometricsFingerprint {
+ /**
+ * Fingerprint enroll request:
+ * Switches the HAL state machine to collect and store a new fingerprint
+ * template. Switches back as soon as enroll is complete, signalled by
+ * (fingerprintMsg.type == FINGERPRINT_TEMPLATE_ENROLLING &&
+ * fingerprintMsg.data.enroll.samplesRemaining == 0)
+ * or after timeoutSec seconds.
+ * The fingerprint template must be assigned to the group gid.
+ *
+ * @param hat a valid Hardware Authentication Token (HAT), generated
+ * as a result of a preEnroll() call.
+ * @param gid a framework defined fingerprint set (group) id.
+ * @param timeoutSec a timeout in seconds.
+ * @param windowId optional ID of an illumination window for optical under
+ * display fingerprint sensors. Must contain a null pointer if not used.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ *
+ * A notify() function may be called with a more detailed error structure.
+ */
+ enroll_2_2(vec<uint8_t> hat, uint32_t gid, uint32_t timeoutSec, handle windowId)
+ generates (RequestStatus debugErrno);
+
+ /**
+ * Authenticates an operation identified by operationId
+ *
+ * @param operationId operation id.
+ * @param gid fingerprint group id.
+ * @param windowId optional ID of an illumination window for optical under
+ * display fingerprint sensors. Must contain a null pointer if not used.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ */
+ authenticate_2_2(uint64_t operationId, uint32_t gid, handle windowId)
+ generates (RequestStatus debugErrno);
+};
diff --git a/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal b/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal
new file mode 100644
index 0000000000..14c2b12b76
--- /dev/null
+++ b/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.biometrics.fingerprint@2.2;
+
+import @2.1::IBiometricsFingerprintClientCallback;
+
+/*
+ * This HAL interface communicates asynchronous results from the
+ * fingerprint driver in response to user actions on the fingerprint sensor
+ */
+interface IBiometricsFingerprintClientCallback extends @2.1::IBiometricsFingerprintClientCallback {
+ /**
+ * Sent when a fingerprint image is acquired by the sensor
+ * @param deviceId the instance of this fingerprint device
+ * @param acquiredInfo a message about the quality of the acquired image
+ * @param vendorCode a vendor-specific message about the quality of the image. Only
+ * valid when acquiredInfo == ACQUIRED_VENDOR
+ */
+ oneway onAcquired_2_2(uint64_t deviceId, FingerprintAcquiredInfo acquiredInfo,
+ int32_t vendorCode);
+};
diff --git a/biometrics/fingerprint/2.2/types.hal b/biometrics/fingerprint/2.2/types.hal
new file mode 100644
index 0000000000..2c1d3f374c
--- /dev/null
+++ b/biometrics/fingerprint/2.2/types.hal
@@ -0,0 +1,42 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.biometrics.fingerprint@2.2;
+
+import @2.1::FingerprintAcquiredInfo;
+
+/**
+ * Fingerprint acquisition info is meant as feedback for the current operation.
+ * Anything but START and ACQUIRED_GOOD must be shown to the user as feedback on
+ * how to take action on the current operation. For example,
+ * ACQUIRED_IMAGER_DIRTY may be used to tell the user to clean the sensor if it
+ * is detected to be dirty.
+ * If this causes the current operation to fail, an additional ERROR_CANCELED
+ * must be sent to stop the operation in progress (e.g. enrollment).
+ * In general, these messages will result in a "Try again" message.
+ */
+enum FingerprintAcquiredInfo : @2.1::FingerprintAcquiredInfo {
+ /**
+ * This message represents the earliest message sent at the beginning of the
+ * authentication pipeline. It is expected to be used to measure latency. For
+ * example, in a camera-based authentication system it's expected to be sent
+ * prior to camera initialization. Note this should be sent whenever
+ * authentication is restarted (see IBiometricsFace#userActivity).
+ * The framework will measure latency based on the time between the last START
+ * message and the onAuthenticated callback.
+ */
+ START = 7,
+};
diff --git a/biometrics/fingerprint/2.2/vts/functional/Android.bp b/biometrics/fingerprint/2.2/vts/functional/Android.bp
new file mode 100644
index 0000000000..496570c64c
--- /dev/null
+++ b/biometrics/fingerprint/2.2/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 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.
+ */
+
+cc_test {
+ name: "VtsHalBiometricsFingerprintV2_2TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalBiometricsFingerprintV2_2TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.biometrics.fingerprint@2.1",
+ "android.hardware.biometrics.fingerprint@2.2",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
new file mode 100644
index 0000000000..50bd4ab5e0
--- /dev/null
+++ b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "fingerprint_hidl_hal_test"
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/properties.h>
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h>
+#include <android/hardware/biometrics/fingerprint/2.2/IBiometricsFingerprint.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+
+#include <cinttypes>
+#include <random>
+
+using android::sp;
+using android::base::GetUintProperty;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::biometrics::fingerprint::V2_1::FingerprintAcquiredInfo;
+using android::hardware::biometrics::fingerprint::V2_1::FingerprintError;
+using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
+using android::hardware::biometrics::fingerprint::V2_1::RequestStatus;
+using android::hardware::biometrics::fingerprint::V2_2::IBiometricsFingerprint;
+
+namespace {
+
+constexpr uint32_t kTimeoutSec = 3;
+constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
+constexpr uint32_t kGroupId = 99;
+constexpr char kCallbackNameOnError[] = "onError";
+
+// Callback arguments that need to be captured for the tests.
+struct FingerprintCallbackArgs {
+ // The error passed to the last onError() callback.
+ FingerprintError error;
+
+ // The deviceId passed to the last callback.
+ uint64_t deviceId;
+};
+
+// Test callback class for the BiometricsFingerprint HAL.
+// The HAL will call these callback methods to notify about completed operations
+// or encountered errors.
+class FingerprintCallback : public ::testing::VtsHalHidlTargetCallbackBase<FingerprintCallbackArgs>,
+ public IBiometricsFingerprintClientCallback {
+ public:
+ Return<void> onEnrollResult(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+
+ Return<void> onAcquired(uint64_t, FingerprintAcquiredInfo, int32_t) override { return Void(); }
+
+ Return<void> onAuthenticated(uint64_t, uint32_t, uint32_t, const hidl_vec<uint8_t>&) override {
+ return Void();
+ }
+
+ Return<void> onError(uint64_t deviceId, FingerprintError error, int32_t) override {
+ FingerprintCallbackArgs args = {};
+ args.error = error;
+ args.deviceId = deviceId;
+ NotifyFromCallback(kCallbackNameOnError, args);
+ return Void();
+ }
+
+ Return<void> onRemoved(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+
+ Return<void> onEnumerate(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+};
+
+class FingerprintHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ mService = IBiometricsFingerprint::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ mCallback = new FingerprintCallback();
+ mCallback->SetWaitTimeoutDefault(kTimeout);
+ Return<uint64_t> ret1 = mService->setNotify(mCallback);
+ ASSERT_NE(0UL, static_cast<uint64_t>(ret1));
+
+ /*
+ * Devices shipped from now on will instead store
+ * fingerprint data under /data/vendor_de/<user-id>/fpdata.
+ * Support for /data/vendor_de and /data/vendor_ce has been added to vold.
+ */
+
+ auto api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+ if (api_level == 0) {
+ api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
+ }
+ ASSERT_NE(api_level, 0);
+
+ // 27 is the API number for O-MR1
+ string tmpDir;
+ if (api_level <= 27) {
+ tmpDir = "/data/system/users/0/fpdata/";
+ } else {
+ tmpDir = "/data/vendor_de/0/fpdata/";
+ }
+
+ Return<RequestStatus> res = mService->setActiveGroup(kGroupId, tmpDir);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ }
+
+ sp<IBiometricsFingerprint> mService;
+ sp<FingerprintCallback> mCallback;
+};
+
+// Enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FingerprintHidlTest, EnrollZeroHatTest) {
+ // Filling HAT with zeros
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; i++) {
+ token[i] = 0;
+ }
+
+ hidl_handle windowId = nullptr;
+ Return<RequestStatus> ret = mService->enroll_2_2(token, kGroupId, kTimeoutSec, windowId);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(ret));
+
+ // At least one call to onError should occur
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ ASSERT_NE(FingerprintError::ERROR_NO_ERROR, res.args->error);
+}
+
+// Enroll with an invalid (null) HAT should fail.
+TEST_P(FingerprintHidlTest, EnrollGarbageHatTest) {
+ // Filling HAT with pseudorandom invalid data.
+ // Using default seed to make the test reproducible.
+ std::mt19937 gen(std::mt19937::default_seed);
+ std::uniform_int_distribution<uint8_t> dist;
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; ++i) {
+ token[i] = dist(gen);
+ }
+
+ hidl_handle windowId = nullptr;
+ Return<RequestStatus> ret = mService->enroll_2_2(token, kGroupId, kTimeoutSec, windowId);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(ret));
+
+ // At least one call to onError should occur
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ ASSERT_NE(FingerprintError::ERROR_NO_ERROR, res.args->error);
+}
+
+} // anonymous namespace
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, FingerprintHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ IBiometricsFingerprint::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 9ff0d74687..5f8674219c 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -81,8 +81,6 @@ bool tryLock(std::mutex& mutex)
return locked;
}
-buffer_handle_t sEmptyBuffer = nullptr;
-
} // Anonymous namespace
// Static instances
@@ -119,8 +117,8 @@ bool ExternalCameraDeviceSession::initialize() {
std::string make, model;
if (ret < 0) {
ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__);
- make = "Generic UVC webcam";
- model = "Generic UVC webcam";
+ mExifMake = "Generic UVC webcam";
+ mExifModel = "Generic UVC webcam";
} else {
// capability.card is UTF-8 encoded
char card[32];
@@ -134,11 +132,11 @@ bool ExternalCameraDeviceSession::initialize() {
}
}
if (j == 0 || card[j - 1] != '\0') {
- make = "Generic UVC webcam";
- model = "Generic UVC webcam";
+ mExifMake = "Generic UVC webcam";
+ mExifModel = "Generic UVC webcam";
} else {
- make = card;
- model = card;
+ mExifMake = card;
+ mExifModel = card;
}
}
@@ -147,7 +145,7 @@ bool ExternalCameraDeviceSession::initialize() {
ALOGE("%s: init OutputThread failed!", __FUNCTION__);
return true;
}
- mOutputThread->setExifMakeModel(make, model);
+ mOutputThread->setExifMakeModel(mExifMake, mExifModel);
status_t status = initDefaultRequests();
if (status != OK) {
@@ -161,7 +159,7 @@ bool ExternalCameraDeviceSession::initialize() {
ALOGE("%s: invalid request fmq", __FUNCTION__);
return true;
}
- mResultMetadataQueue = std::make_shared<RequestMetadataQueue>(
+ mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
kMetadataMsgQueueSize, false /* non blocking */);
if (!mResultMetadataQueue->isValid()) {
ALOGE("%s: invalid result fmq", __FUNCTION__);
@@ -183,7 +181,7 @@ bool ExternalCameraDeviceSession::isInitFailed() {
}
void ExternalCameraDeviceSession::initOutputThread() {
- mOutputThread = new OutputThread(this, mCroppingType);
+ mOutputThread = new OutputThread(this, mCroppingType, mCameraCharacteristics);
}
void ExternalCameraDeviceSession::closeOutputThread() {
@@ -518,35 +516,9 @@ Status ExternalCameraDeviceSession::importBufferLocked(int32_t streamId,
uint64_t bufId, buffer_handle_t buf,
/*out*/buffer_handle_t** outBufPtr,
bool allowEmptyBuf) {
-
- if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
- if (allowEmptyBuf) {
- *outBufPtr = &sEmptyBuffer;
- return Status::OK;
- } else {
- ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
- return Status::ILLEGAL_ARGUMENT;
- }
- }
-
- CirculatingBuffers& cbs = mCirculatingBuffers[streamId];
- if (cbs.count(bufId) == 0) {
- if (buf == nullptr) {
- ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
- return Status::ILLEGAL_ARGUMENT;
- }
- // Register a newly seen buffer
- buffer_handle_t importedBuf = buf;
- sHandleImporter.importBuffer(importedBuf);
- if (importedBuf == nullptr) {
- ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
- return Status::INTERNAL_ERROR;
- } else {
- cbs[bufId] = importedBuf;
- }
- }
- *outBufPtr = &cbs[bufId];
- return Status::OK;
+ return importBufferImpl(
+ mCirculatingBuffers, sHandleImporter, streamId,
+ bufId, buf, outBufPtr, allowEmptyBuf);
}
Status ExternalCameraDeviceSession::importRequestLockedImpl(
@@ -791,15 +763,32 @@ void ExternalCameraDeviceSession::notifyError(
//TODO: refactor with processCaptureResult
Status ExternalCameraDeviceSession::processCaptureRequestError(
- const std::shared_ptr<HalRequest>& req) {
+ const std::shared_ptr<HalRequest>& req,
+ /*out*/std::vector<NotifyMsg>* outMsgs,
+ /*out*/std::vector<CaptureResult>* outResults) {
ATRACE_CALL();
// Return V4L2 buffer to V4L2 buffer queue
- enqueueV4l2Frame(req->frameIn);
+ sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+ static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
+ enqueueV4l2Frame(v4l2Frame);
- // NotifyShutter
- notifyShutter(req->frameNumber, req->shutterTs);
+ if (outMsgs == nullptr) {
+ notifyShutter(req->frameNumber, req->shutterTs);
+ notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+ } else {
+ NotifyMsg shutter;
+ shutter.type = MsgType::SHUTTER;
+ shutter.msg.shutter.frameNumber = req->frameNumber;
+ shutter.msg.shutter.timestamp = req->shutterTs;
- notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+ NotifyMsg error;
+ error.type = MsgType::ERROR;
+ error.msg.error.frameNumber = req->frameNumber;
+ error.msg.error.errorStreamId = -1;
+ error.msg.error.errorCode = ErrorCode::ERROR_REQUEST;
+ outMsgs->push_back(shutter);
+ outMsgs->push_back(error);
+ }
// Fill output buffers
hidl_vec<CaptureResult> results;
@@ -826,16 +815,22 @@ Status ExternalCameraDeviceSession::processCaptureRequestError(
mInflightFrames.erase(req->frameNumber);
}
- // Callback into framework
- invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
- freeReleaseFences(results);
+ if (outResults == nullptr) {
+ // Callback into framework
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+ freeReleaseFences(results);
+ } else {
+ outResults->push_back(result);
+ }
return Status::OK;
}
Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
ATRACE_CALL();
// Return V4L2 buffer to V4L2 buffer queue
- enqueueV4l2Frame(req->frameIn);
+ sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+ static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
+ enqueueV4l2Frame(v4l2Frame);
// NotifyShutter
notifyShutter(req->frameNumber, req->shutterTs);
@@ -923,29 +918,10 @@ void ExternalCameraDeviceSession::invokeProcessCaptureResultCallback(
mProcessCaptureResultLock.unlock();
}
-void ExternalCameraDeviceSession::freeReleaseFences(hidl_vec<CaptureResult>& results) {
- for (auto& result : results) {
- if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
- native_handle_t* handle = const_cast<native_handle_t*>(
- result.inputBuffer.releaseFence.getNativeHandle());
- native_handle_close(handle);
- native_handle_delete(handle);
- }
- for (auto& buf : result.outputBuffers) {
- if (buf.releaseFence.getNativeHandle() != nullptr) {
- native_handle_t* handle = const_cast<native_handle_t*>(
- buf.releaseFence.getNativeHandle());
- native_handle_close(handle);
- native_handle_delete(handle);
- }
- }
- }
- return;
-}
-
ExternalCameraDeviceSession::OutputThread::OutputThread(
- wp<ExternalCameraDeviceSession> parent,
- CroppingType ct) : mParent(parent), mCroppingType(ct) {}
+ wp<OutputThreadInterface> parent, CroppingType ct,
+ const common::V1_0::helper::CameraMetadata& chars) :
+ mParent(parent), mCroppingType(ct), mCameraCharacteristics(chars) {}
ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
@@ -955,88 +931,6 @@ void ExternalCameraDeviceSession::OutputThread::setExifMakeModel(
mExifModel = model;
}
-uint32_t ExternalCameraDeviceSession::OutputThread::getFourCcFromLayout(
- const YCbCrLayout& layout) {
- intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
- intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
- if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
- // Interleaved format
- if (layout.cb > layout.cr) {
- return V4L2_PIX_FMT_NV21;
- } else {
- return V4L2_PIX_FMT_NV12;
- }
- } else if (layout.chromaStep == 1) {
- // Planar format
- if (layout.cb > layout.cr) {
- return V4L2_PIX_FMT_YVU420; // YV12
- } else {
- return V4L2_PIX_FMT_YUV420; // YU12
- }
- } else {
- return FLEX_YUV_GENERIC;
- }
-}
-
-int ExternalCameraDeviceSession::OutputThread::getCropRect(
- CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
- if (out == nullptr) {
- ALOGE("%s: out is null", __FUNCTION__);
- return -1;
- }
-
- uint32_t inW = inSize.width;
- uint32_t inH = inSize.height;
- uint32_t outW = outSize.width;
- uint32_t outH = outSize.height;
-
- // Handle special case where aspect ratio is close to input but scaled
- // dimension is slightly larger than input
- float arIn = ASPECT_RATIO(inSize);
- float arOut = ASPECT_RATIO(outSize);
- if (isAspectRatioClose(arIn, arOut)) {
- out->left = 0;
- out->top = 0;
- out->width = inW;
- out->height = inH;
- return 0;
- }
-
- if (ct == VERTICAL) {
- uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
- if (scaledOutH > inH) {
- ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
- __FUNCTION__, outW, outH, inW, inH);
- return -1;
- }
- scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
-
- out->left = 0;
- out->top = ((inH - scaledOutH) / 2) & ~0x1;
- out->width = inW;
- out->height = static_cast<int32_t>(scaledOutH);
- ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
- __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
- } else {
- uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
- if (scaledOutW > inW) {
- ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
- __FUNCTION__, outW, outH, inW, inH);
- return -1;
- }
- scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
-
- out->left = ((inW - scaledOutW) / 2) & ~0x1;
- out->top = 0;
- out->width = static_cast<int32_t>(scaledOutW);
- out->height = inH;
- ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
- __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
- }
-
- return 0;
-}
-
int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked(
sp<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
Size inSz = {in->mWidth, in->mHeight};
@@ -1274,265 +1168,6 @@ int ExternalCameraDeviceSession::OutputThread::cropAndScaleThumbLocked(
return 0;
}
-int ExternalCameraDeviceSession::OutputThread::formatConvertLocked(
- const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
- int ret = 0;
- switch (format) {
- case V4L2_PIX_FMT_NV21:
- ret = libyuv::I420ToNV21(
- static_cast<uint8_t*>(in.y),
- in.yStride,
- static_cast<uint8_t*>(in.cb),
- in.cStride,
- static_cast<uint8_t*>(in.cr),
- in.cStride,
- static_cast<uint8_t*>(out.y),
- out.yStride,
- static_cast<uint8_t*>(out.cr),
- out.cStride,
- sz.width,
- sz.height);
- if (ret != 0) {
- ALOGE("%s: convert to NV21 buffer failed! ret %d",
- __FUNCTION__, ret);
- return ret;
- }
- break;
- case V4L2_PIX_FMT_NV12:
- ret = libyuv::I420ToNV12(
- static_cast<uint8_t*>(in.y),
- in.yStride,
- static_cast<uint8_t*>(in.cb),
- in.cStride,
- static_cast<uint8_t*>(in.cr),
- in.cStride,
- static_cast<uint8_t*>(out.y),
- out.yStride,
- static_cast<uint8_t*>(out.cb),
- out.cStride,
- sz.width,
- sz.height);
- if (ret != 0) {
- ALOGE("%s: convert to NV12 buffer failed! ret %d",
- __FUNCTION__, ret);
- return ret;
- }
- break;
- case V4L2_PIX_FMT_YVU420: // YV12
- case V4L2_PIX_FMT_YUV420: // YU12
- // TODO: maybe we can speed up here by somehow save this copy?
- ret = libyuv::I420Copy(
- static_cast<uint8_t*>(in.y),
- in.yStride,
- static_cast<uint8_t*>(in.cb),
- in.cStride,
- static_cast<uint8_t*>(in.cr),
- in.cStride,
- static_cast<uint8_t*>(out.y),
- out.yStride,
- static_cast<uint8_t*>(out.cb),
- out.cStride,
- static_cast<uint8_t*>(out.cr),
- out.cStride,
- sz.width,
- sz.height);
- if (ret != 0) {
- ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
- __FUNCTION__, ret);
- return ret;
- }
- break;
- case FLEX_YUV_GENERIC:
- // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
- ALOGE("%s: unsupported flexible yuv layout"
- " y %p cb %p cr %p y_str %d c_str %d c_step %d",
- __FUNCTION__, out.y, out.cb, out.cr,
- out.yStride, out.cStride, out.chromaStep);
- return -1;
- default:
- ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
- return -1;
- }
- return 0;
-}
-
-int ExternalCameraDeviceSession::OutputThread::encodeJpegYU12(
- const Size & inSz, const YCbCrLayout& inLayout,
- int jpegQuality, const void *app1Buffer, size_t app1Size,
- void *out, const size_t maxOutSize, size_t &actualCodeSize)
-{
- /* libjpeg is a C library so we use C-style "inheritance" by
- * putting libjpeg's jpeg_destination_mgr first in our custom
- * struct. This allows us to cast jpeg_destination_mgr* to
- * CustomJpegDestMgr* when we get it passed to us in a callback */
- struct CustomJpegDestMgr {
- struct jpeg_destination_mgr mgr;
- JOCTET *mBuffer;
- size_t mBufferSize;
- size_t mEncodedSize;
- bool mSuccess;
- } dmgr;
-
- jpeg_compress_struct cinfo = {};
- jpeg_error_mgr jerr;
-
- /* Initialize error handling with standard callbacks, but
- * then override output_message (to print to ALOG) and
- * error_exit to set a flag and print a message instead
- * of killing the whole process */
- cinfo.err = jpeg_std_error(&jerr);
-
- cinfo.err->output_message = [](j_common_ptr cinfo) {
- char buffer[JMSG_LENGTH_MAX];
-
- /* Create the message */
- (*cinfo->err->format_message)(cinfo, buffer);
- ALOGE("libjpeg error: %s", buffer);
- };
- cinfo.err->error_exit = [](j_common_ptr cinfo) {
- (*cinfo->err->output_message)(cinfo);
- if(cinfo->client_data) {
- auto & dmgr =
- *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
- dmgr.mSuccess = false;
- }
- };
- /* Now that we initialized some callbacks, let's create our compressor */
- jpeg_create_compress(&cinfo);
-
- /* Initialize our destination manager */
- dmgr.mBuffer = static_cast<JOCTET*>(out);
- dmgr.mBufferSize = maxOutSize;
- dmgr.mEncodedSize = 0;
- dmgr.mSuccess = true;
- cinfo.client_data = static_cast<void*>(&dmgr);
-
- /* These lambdas become C-style function pointers and as per C++11 spec
- * may not capture anything */
- dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
- auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
- dmgr.mgr.next_output_byte = dmgr.mBuffer;
- dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
- ALOGV("%s:%d jpeg start: %p [%zu]",
- __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
- };
-
- dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
- ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
- return 0;
- };
-
- dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
- auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
- dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
- ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
- };
- cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
-
- /* We are going to be using JPEG in raw data mode, so we are passing
- * straight subsampled planar YCbCr and it will not touch our pixel
- * data or do any scaling or anything */
- cinfo.image_width = inSz.width;
- cinfo.image_height = inSz.height;
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_YCbCr;
-
- /* Initialize defaults and then override what we want */
- jpeg_set_defaults(&cinfo);
-
- jpeg_set_quality(&cinfo, jpegQuality, 1);
- jpeg_set_colorspace(&cinfo, JCS_YCbCr);
- cinfo.raw_data_in = 1;
- cinfo.dct_method = JDCT_IFAST;
-
- /* Configure sampling factors. The sampling factor is JPEG subsampling 420
- * because the source format is YUV420. Note that libjpeg sampling factors
- * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
- * 1 V value for each 2 Y values */
- cinfo.comp_info[0].h_samp_factor = 2;
- cinfo.comp_info[0].v_samp_factor = 2;
- cinfo.comp_info[1].h_samp_factor = 1;
- cinfo.comp_info[1].v_samp_factor = 1;
- cinfo.comp_info[2].h_samp_factor = 1;
- cinfo.comp_info[2].v_samp_factor = 1;
-
- /* Let's not hardcode YUV420 in 6 places... 5 was enough */
- int maxVSampFactor = std::max( {
- cinfo.comp_info[0].v_samp_factor,
- cinfo.comp_info[1].v_samp_factor,
- cinfo.comp_info[2].v_samp_factor
- });
- int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
- cinfo.comp_info[1].v_samp_factor;
-
- /* Start the compressor */
- jpeg_start_compress(&cinfo, TRUE);
-
- /* Compute our macroblock height, so we can pad our input to be vertically
- * macroblock aligned.
- * TODO: Does it need to be horizontally MCU aligned too? */
-
- size_t mcuV = DCTSIZE*maxVSampFactor;
- size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
-
- /* libjpeg uses arrays of row pointers, which makes it really easy to pad
- * data vertically (unfortunately doesn't help horizontally) */
- std::vector<JSAMPROW> yLines (paddedHeight);
- std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
- std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
-
- uint8_t *py = static_cast<uint8_t*>(inLayout.y);
- uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
- uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
-
- for(uint32_t i = 0; i < paddedHeight; i++)
- {
- /* Once we are in the padding territory we still point to the last line
- * effectively replicating it several times ~ CLAMP_TO_EDGE */
- int li = std::min(i, inSz.height - 1);
- yLines[i] = static_cast<JSAMPROW>(py + li * inLayout.yStride);
- if(i < paddedHeight / cVSubSampling)
- {
- crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
- cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
- }
- }
-
- /* If APP1 data was passed in, use it */
- if(app1Buffer && app1Size)
- {
- jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
- static_cast<const JOCTET*>(app1Buffer), app1Size);
- }
-
- /* While we still have padded height left to go, keep giving it one
- * macroblock at a time. */
- while (cinfo.next_scanline < cinfo.image_height) {
- const uint32_t batchSize = DCTSIZE * maxVSampFactor;
- const uint32_t nl = cinfo.next_scanline;
- JSAMPARRAY planes[3]{ &yLines[nl],
- &cbLines[nl/cVSubSampling],
- &crLines[nl/cVSubSampling] };
-
- uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
-
- if (done != batchSize) {
- ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
- __FUNCTION__, done, batchSize, cinfo.next_scanline,
- cinfo.image_height);
- return -1;
- }
- }
-
- /* This will flush everything */
- jpeg_finish_compress(&cinfo);
-
- /* Grab the actual code size and set it */
- actualCodeSize = dmgr.mEncodedSize;
-
- return 0;
-}
-
/*
* TODO: There needs to be a mechanism to discover allocated buffer size
* in the HAL.
@@ -1555,25 +1190,9 @@ Size ExternalCameraDeviceSession::getMaxJpegResolution() const {
}
Size ExternalCameraDeviceSession::getMaxThumbResolution() const {
- Size thumbSize { 0, 0 };
- camera_metadata_ro_entry entry =
- mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
- for(uint32_t i = 0; i < entry.count; i += 2) {
- Size sz { static_cast<uint32_t>(entry.data.i32[i]),
- static_cast<uint32_t>(entry.data.i32[i+1]) };
- if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
- thumbSize = sz;
- }
- }
-
- if (thumbSize.width * thumbSize.height == 0) {
- ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
- }
-
- return thumbSize;
+ return getMaxThumbnailResolution(mCameraCharacteristics);
}
-
ssize_t ExternalCameraDeviceSession::getJpegBufferSize(
uint32_t width, uint32_t height) const {
// Constant from camera3.h
@@ -1616,7 +1235,7 @@ ssize_t ExternalCameraDeviceSession::getJpegBufferSize(
int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
HalStreamBuffer &halBuf,
- const std::shared_ptr<HalRequest>& req)
+ const common::V1_0::helper::CameraMetadata& setting)
{
ATRACE_CALL();
int ret;
@@ -1645,17 +1264,17 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
Size thumbSize;
bool outputThumbnail = true;
- if (req->setting.exists(ANDROID_JPEG_QUALITY)) {
- camera_metadata_entry entry =
- req->setting.find(ANDROID_JPEG_QUALITY);
+ if (setting.exists(ANDROID_JPEG_QUALITY)) {
+ camera_metadata_ro_entry entry =
+ setting.find(ANDROID_JPEG_QUALITY);
jpegQuality = entry.data.u8[0];
} else {
return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__);
}
- if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
- camera_metadata_entry entry =
- req->setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
+ if (setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
+ camera_metadata_ro_entry entry =
+ setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
thumbQuality = entry.data.u8[0];
} else {
return lfail(
@@ -1663,9 +1282,9 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
__FUNCTION__);
}
- if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
- camera_metadata_entry entry =
- req->setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
+ if (setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
+ camera_metadata_ro_entry entry =
+ setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
thumbSize = Size { static_cast<uint32_t>(entry.data.i32[0]),
static_cast<uint32_t>(entry.data.i32[1])
};
@@ -1732,8 +1351,8 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
/* Combine camera characteristics with request settings to form EXIF
* metadata */
- common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics);
- meta.append(req->setting);
+ common::V1_0::helper::CameraMetadata meta(mCameraCharacteristics);
+ meta.append(setting);
/* Generate EXIF object */
std::unique_ptr<ExifUtils> utils(ExifUtils::create());
@@ -1838,7 +1457,7 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() {
// TODO: see if we can save some computation by converting to YV12 here
uint8_t* inData;
size_t inDataSize;
- if (req->frameIn->map(&inData, &inDataSize) != 0) {
+ if (req->frameIn->getData(&inData, &inDataSize) != 0) {
lk.unlock();
return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
}
@@ -1899,7 +1518,7 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() {
// Gralloc lockYCbCr the buffer
switch (halBuf.format) {
case PixelFormat::BLOB: {
- int ret = createJpegLocked(halBuf, req);
+ int ret = createJpegLocked(halBuf, req->setting);
if(ret != 0) {
lk.unlock();
@@ -1949,8 +1568,8 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() {
}
Size sz {halBuf.width, halBuf.height};
- ATRACE_BEGIN("formatConvertLocked");
- ret = formatConvertLocked(cropAndScaled, outLayout, sz, outputFourcc);
+ ATRACE_BEGIN("formatConvert");
+ ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
ATRACE_END();
if (ret != 0) {
lk.unlock();
@@ -2055,6 +1674,14 @@ Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers(
return Status::OK;
}
+void ExternalCameraDeviceSession::OutputThread::clearIntermediateBuffers() {
+ std::lock_guard<std::mutex> lk(mBufferLock);
+ mYu12Frame.clear();
+ mYu12ThumbFrame.clear();
+ mIntermediateBuffers.clear();
+ mBlobBufferSize = 0;
+}
+
Status ExternalCameraDeviceSession::OutputThread::submitRequest(
const std::shared_ptr<HalRequest>& req) {
std::unique_lock<std::mutex> lk(mRequestListLock);
@@ -2090,6 +1717,32 @@ void ExternalCameraDeviceSession::OutputThread::flush() {
}
}
+std::list<std::shared_ptr<HalRequest>>
+ExternalCameraDeviceSession::OutputThread::switchToOffline() {
+ ATRACE_CALL();
+ std::list<std::shared_ptr<HalRequest>> emptyList;
+ auto parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return emptyList;
+ }
+
+ std::unique_lock<std::mutex> lk(mRequestListLock);
+ std::list<std::shared_ptr<HalRequest>> reqs = std::move(mRequestList);
+ mRequestList.clear();
+ if (mProcessingRequest) {
+ std::chrono::seconds timeout = std::chrono::seconds(kFlushWaitTimeoutSec);
+ auto st = mRequestDoneCond.wait_for(lk, timeout);
+ if (st == std::cv_status::timeout) {
+ ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__);
+ }
+ }
+ lk.unlock();
+ clearIntermediateBuffers();
+ ALOGV("%s: returning %zu request for offline processing", __FUNCTION__, reqs.size());
+ return reqs;
+}
+
void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(
std::shared_ptr<HalRequest>* out) {
ATRACE_CALL();
@@ -2733,6 +2386,7 @@ Status ExternalCameraDeviceSession::configureStreams(
return Status::INTERNAL_ERROR;
}
+ mBlobBufferSize = blobBufferSize;
status = mOutputThread->allocateIntermediateBuffers(v4lSize,
mMaxThumbResolution, config.streams, blobBufferSize);
if (status != Status::OK) {
@@ -2916,16 +2570,6 @@ status_t ExternalCameraDeviceSession::initDefaultRequests() {
status_t ExternalCameraDeviceSession::fillCaptureResult(
common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
- // android.control
- // For USB camera, we don't know the AE state. Set the state to converged to
- // indicate the frame should be good to use. Then apps don't have to wait the
- // AE state.
- const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
- UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
-
- const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
- UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
-
bool afTrigger = false;
{
std::lock_guard<std::mutex> lk(mAfTriggerLock);
@@ -2951,46 +2595,10 @@ status_t ExternalCameraDeviceSession::fillCaptureResult(
}
UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
- // Set AWB state to converged to indicate the frame should be good to use.
- const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
- UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
-
- const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
- UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
-
- camera_metadata_ro_entry active_array_size =
- mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ camera_metadata_ro_entry activeArraySize =
+ mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
- if (active_array_size.count == 0) {
- ALOGE("%s: cannot find active array size!", __FUNCTION__);
- return -EINVAL;
- }
-
- const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
- UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
-
- // This means pipeline latency of X frame intervals. The maximum number is 4.
- const uint8_t requestPipelineMaxDepth = 4;
- UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
-
- // android.scaler
- const int32_t crop_region[] = {
- active_array_size.data.i32[0], active_array_size.data.i32[1],
- active_array_size.data.i32[2], active_array_size.data.i32[3],
- };
- UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
-
- // android.sensor
- UPDATE(md, ANDROID_SENSOR_TIMESTAMP, &timestamp, 1);
-
- // android.statistics
- const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
- UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
-
- const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
- UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
-
- return OK;
+ return fillCaptureResultCommon(md, timestamp, activeArraySize);
}
#undef ARRAY_SIZE
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index e25deff797..4a6381ea7b 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -18,10 +18,23 @@
#include <log/log.h>
#include <cmath>
+#include <cstring>
#include <sys/mman.h>
#include <linux/videodev2.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <jpeglib.h>
+
#include "ExternalCameraUtils.h"
+namespace {
+
+buffer_handle_t sEmptyBuffer = nullptr;
+
+} // Anonymous namespace
+
namespace android {
namespace hardware {
namespace camera {
@@ -29,10 +42,13 @@ namespace device {
namespace V3_4 {
namespace implementation {
+Frame::Frame(uint32_t width, uint32_t height, uint32_t fourcc) :
+ mWidth(width), mHeight(height), mFourcc(fourcc) {}
+
V4L2Frame::V4L2Frame(
uint32_t w, uint32_t h, uint32_t fourcc,
int bufIdx, int fd, uint32_t dataSize, uint64_t offset) :
- mWidth(w), mHeight(h), mFourcc(fourcc),
+ Frame(w, h, fourcc),
mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize), mOffset(offset) {}
int V4L2Frame::map(uint8_t** data, size_t* dataSize) {
@@ -75,9 +91,13 @@ V4L2Frame::~V4L2Frame() {
unmap();
}
+int V4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+ return map(outData, dataSize);
+}
+
AllocatedFrame::AllocatedFrame(
uint32_t w, uint32_t h) :
- mWidth(w), mHeight(h), mFourcc(V4L2_PIX_FMT_YUV420) {};
+ Frame(w, h, V4L2_PIX_FMT_YUV420) {};
AllocatedFrame::~AllocatedFrame() {}
@@ -106,6 +126,17 @@ int AllocatedFrame::allocate(YCbCrLayout* out) {
return 0;
}
+int AllocatedFrame::getData(uint8_t** outData, size_t* dataSize) {
+ YCbCrLayout layout;
+ int ret = allocate(&layout);
+ if (ret != 0) {
+ return ret;
+ }
+ *outData = mData.data();
+ *dataSize = mData.size();
+ return 0;
+}
+
int AllocatedFrame::getLayout(YCbCrLayout* out) {
IMapper::Rect noCrop = {0, 0,
static_cast<int32_t>(mWidth),
@@ -150,8 +181,520 @@ double SupportedV4L2Format::FrameRate::getDouble() const {
return durationDenominator / static_cast<double>(durationNumerator);
}
+::android::hardware::camera::common::V1_0::Status importBufferImpl(
+ /*inout*/std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*inout*/HandleImporter& handleImporter,
+ int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf) {
+ using ::android::hardware::camera::common::V1_0::Status;
+ if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
+ if (allowEmptyBuf) {
+ *outBufPtr = &sEmptyBuffer;
+ return Status::OK;
+ } else {
+ ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ }
+
+ CirculatingBuffers& cbs = circulatingBuffers[streamId];
+ if (cbs.count(bufId) == 0) {
+ if (buf == nullptr) {
+ ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ // Register a newly seen buffer
+ buffer_handle_t importedBuf = buf;
+ handleImporter.importBuffer(importedBuf);
+ if (importedBuf == nullptr) {
+ ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
+ return Status::INTERNAL_ERROR;
+ } else {
+ cbs[bufId] = importedBuf;
+ }
+ }
+ *outBufPtr = &cbs[bufId];
+ return Status::OK;
+}
+
+uint32_t getFourCcFromLayout(const YCbCrLayout& layout) {
+ intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
+ intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
+ if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
+ // Interleaved format
+ if (layout.cb > layout.cr) {
+ return V4L2_PIX_FMT_NV21;
+ } else {
+ return V4L2_PIX_FMT_NV12;
+ }
+ } else if (layout.chromaStep == 1) {
+ // Planar format
+ if (layout.cb > layout.cr) {
+ return V4L2_PIX_FMT_YVU420; // YV12
+ } else {
+ return V4L2_PIX_FMT_YUV420; // YU12
+ }
+ } else {
+ return FLEX_YUV_GENERIC;
+ }
+}
+
+int getCropRect(
+ CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
+ if (out == nullptr) {
+ ALOGE("%s: out is null", __FUNCTION__);
+ return -1;
+ }
+
+ uint32_t inW = inSize.width;
+ uint32_t inH = inSize.height;
+ uint32_t outW = outSize.width;
+ uint32_t outH = outSize.height;
+
+ // Handle special case where aspect ratio is close to input but scaled
+ // dimension is slightly larger than input
+ float arIn = ASPECT_RATIO(inSize);
+ float arOut = ASPECT_RATIO(outSize);
+ if (isAspectRatioClose(arIn, arOut)) {
+ out->left = 0;
+ out->top = 0;
+ out->width = inW;
+ out->height = inH;
+ return 0;
+ }
+
+ if (ct == VERTICAL) {
+ uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
+ if (scaledOutH > inH) {
+ ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
+ __FUNCTION__, outW, outH, inW, inH);
+ return -1;
+ }
+ scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
+
+ out->left = 0;
+ out->top = ((inH - scaledOutH) / 2) & ~0x1;
+ out->width = inW;
+ out->height = static_cast<int32_t>(scaledOutH);
+ ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
+ __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
+ } else {
+ uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
+ if (scaledOutW > inW) {
+ ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
+ __FUNCTION__, outW, outH, inW, inH);
+ return -1;
+ }
+ scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
+
+ out->left = ((inW - scaledOutW) / 2) & ~0x1;
+ out->top = 0;
+ out->width = static_cast<int32_t>(scaledOutW);
+ out->height = inH;
+ ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
+ __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
+ }
+
+ return 0;
+}
+
+int formatConvert(
+ const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
+ int ret = 0;
+ switch (format) {
+ case V4L2_PIX_FMT_NV21:
+ ret = libyuv::I420ToNV21(
+ static_cast<uint8_t*>(in.y),
+ in.yStride,
+ static_cast<uint8_t*>(in.cb),
+ in.cStride,
+ static_cast<uint8_t*>(in.cr),
+ in.cStride,
+ static_cast<uint8_t*>(out.y),
+ out.yStride,
+ static_cast<uint8_t*>(out.cr),
+ out.cStride,
+ sz.width,
+ sz.height);
+ if (ret != 0) {
+ ALOGE("%s: convert to NV21 buffer failed! ret %d",
+ __FUNCTION__, ret);
+ return ret;
+ }
+ break;
+ case V4L2_PIX_FMT_NV12:
+ ret = libyuv::I420ToNV12(
+ static_cast<uint8_t*>(in.y),
+ in.yStride,
+ static_cast<uint8_t*>(in.cb),
+ in.cStride,
+ static_cast<uint8_t*>(in.cr),
+ in.cStride,
+ static_cast<uint8_t*>(out.y),
+ out.yStride,
+ static_cast<uint8_t*>(out.cb),
+ out.cStride,
+ sz.width,
+ sz.height);
+ if (ret != 0) {
+ ALOGE("%s: convert to NV12 buffer failed! ret %d",
+ __FUNCTION__, ret);
+ return ret;
+ }
+ break;
+ case V4L2_PIX_FMT_YVU420: // YV12
+ case V4L2_PIX_FMT_YUV420: // YU12
+ // TODO: maybe we can speed up here by somehow save this copy?
+ ret = libyuv::I420Copy(
+ static_cast<uint8_t*>(in.y),
+ in.yStride,
+ static_cast<uint8_t*>(in.cb),
+ in.cStride,
+ static_cast<uint8_t*>(in.cr),
+ in.cStride,
+ static_cast<uint8_t*>(out.y),
+ out.yStride,
+ static_cast<uint8_t*>(out.cb),
+ out.cStride,
+ static_cast<uint8_t*>(out.cr),
+ out.cStride,
+ sz.width,
+ sz.height);
+ if (ret != 0) {
+ ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
+ __FUNCTION__, ret);
+ return ret;
+ }
+ break;
+ case FLEX_YUV_GENERIC:
+ // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
+ ALOGE("%s: unsupported flexible yuv layout"
+ " y %p cb %p cr %p y_str %d c_str %d c_step %d",
+ __FUNCTION__, out.y, out.cb, out.cr,
+ out.yStride, out.cStride, out.chromaStep);
+ return -1;
+ default:
+ ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
+ return -1;
+ }
+ return 0;
+}
+
+int encodeJpegYU12(
+ const Size & inSz, const YCbCrLayout& inLayout,
+ int jpegQuality, const void *app1Buffer, size_t app1Size,
+ void *out, const size_t maxOutSize, size_t &actualCodeSize)
+{
+ /* libjpeg is a C library so we use C-style "inheritance" by
+ * putting libjpeg's jpeg_destination_mgr first in our custom
+ * struct. This allows us to cast jpeg_destination_mgr* to
+ * CustomJpegDestMgr* when we get it passed to us in a callback */
+ struct CustomJpegDestMgr {
+ struct jpeg_destination_mgr mgr;
+ JOCTET *mBuffer;
+ size_t mBufferSize;
+ size_t mEncodedSize;
+ bool mSuccess;
+ } dmgr;
+
+ jpeg_compress_struct cinfo = {};
+ jpeg_error_mgr jerr;
+
+ /* Initialize error handling with standard callbacks, but
+ * then override output_message (to print to ALOG) and
+ * error_exit to set a flag and print a message instead
+ * of killing the whole process */
+ cinfo.err = jpeg_std_error(&jerr);
+
+ cinfo.err->output_message = [](j_common_ptr cinfo) {
+ char buffer[JMSG_LENGTH_MAX];
+
+ /* Create the message */
+ (*cinfo->err->format_message)(cinfo, buffer);
+ ALOGE("libjpeg error: %s", buffer);
+ };
+ cinfo.err->error_exit = [](j_common_ptr cinfo) {
+ (*cinfo->err->output_message)(cinfo);
+ if(cinfo->client_data) {
+ auto & dmgr =
+ *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
+ dmgr.mSuccess = false;
+ }
+ };
+ /* Now that we initialized some callbacks, let's create our compressor */
+ jpeg_create_compress(&cinfo);
+
+ /* Initialize our destination manager */
+ dmgr.mBuffer = static_cast<JOCTET*>(out);
+ dmgr.mBufferSize = maxOutSize;
+ dmgr.mEncodedSize = 0;
+ dmgr.mSuccess = true;
+ cinfo.client_data = static_cast<void*>(&dmgr);
+
+ /* These lambdas become C-style function pointers and as per C++11 spec
+ * may not capture anything */
+ dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
+ auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+ dmgr.mgr.next_output_byte = dmgr.mBuffer;
+ dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
+ ALOGV("%s:%d jpeg start: %p [%zu]",
+ __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
+ };
+
+ dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
+ ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
+ return 0;
+ };
+
+ dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
+ auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+ dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
+ ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
+ };
+ cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
+
+ /* We are going to be using JPEG in raw data mode, so we are passing
+ * straight subsampled planar YCbCr and it will not touch our pixel
+ * data or do any scaling or anything */
+ cinfo.image_width = inSz.width;
+ cinfo.image_height = inSz.height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_YCbCr;
+
+ /* Initialize defaults and then override what we want */
+ jpeg_set_defaults(&cinfo);
+
+ jpeg_set_quality(&cinfo, jpegQuality, 1);
+ jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+ cinfo.raw_data_in = 1;
+ cinfo.dct_method = JDCT_IFAST;
+
+ /* Configure sampling factors. The sampling factor is JPEG subsampling 420
+ * because the source format is YUV420. Note that libjpeg sampling factors
+ * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
+ * 1 V value for each 2 Y values */
+ cinfo.comp_info[0].h_samp_factor = 2;
+ cinfo.comp_info[0].v_samp_factor = 2;
+ cinfo.comp_info[1].h_samp_factor = 1;
+ cinfo.comp_info[1].v_samp_factor = 1;
+ cinfo.comp_info[2].h_samp_factor = 1;
+ cinfo.comp_info[2].v_samp_factor = 1;
+
+ /* Let's not hardcode YUV420 in 6 places... 5 was enough */
+ int maxVSampFactor = std::max( {
+ cinfo.comp_info[0].v_samp_factor,
+ cinfo.comp_info[1].v_samp_factor,
+ cinfo.comp_info[2].v_samp_factor
+ });
+ int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
+ cinfo.comp_info[1].v_samp_factor;
+
+ /* Start the compressor */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Compute our macroblock height, so we can pad our input to be vertically
+ * macroblock aligned.
+ * TODO: Does it need to be horizontally MCU aligned too? */
+
+ size_t mcuV = DCTSIZE*maxVSampFactor;
+ size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
+
+ /* libjpeg uses arrays of row pointers, which makes it really easy to pad
+ * data vertically (unfortunately doesn't help horizontally) */
+ std::vector<JSAMPROW> yLines (paddedHeight);
+ std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
+ std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
+
+ uint8_t *py = static_cast<uint8_t*>(inLayout.y);
+ uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
+ uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
+
+ for(uint32_t i = 0; i < paddedHeight; i++)
+ {
+ /* Once we are in the padding territory we still point to the last line
+ * effectively replicating it several times ~ CLAMP_TO_EDGE */
+ int li = std::min(i, inSz.height - 1);
+ yLines[i] = static_cast<JSAMPROW>(py + li * inLayout.yStride);
+ if(i < paddedHeight / cVSubSampling)
+ {
+ crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
+ cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
+ }
+ }
+
+ /* If APP1 data was passed in, use it */
+ if(app1Buffer && app1Size)
+ {
+ jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
+ static_cast<const JOCTET*>(app1Buffer), app1Size);
+ }
+
+ /* While we still have padded height left to go, keep giving it one
+ * macroblock at a time. */
+ while (cinfo.next_scanline < cinfo.image_height) {
+ const uint32_t batchSize = DCTSIZE * maxVSampFactor;
+ const uint32_t nl = cinfo.next_scanline;
+ JSAMPARRAY planes[3]{ &yLines[nl],
+ &cbLines[nl/cVSubSampling],
+ &crLines[nl/cVSubSampling] };
+
+ uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
+
+ if (done != batchSize) {
+ ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
+ __FUNCTION__, done, batchSize, cinfo.next_scanline,
+ cinfo.image_height);
+ return -1;
+ }
+ }
+
+ /* This will flush everything */
+ jpeg_finish_compress(&cinfo);
+
+ /* Grab the actual code size and set it */
+ actualCodeSize = dmgr.mEncodedSize;
+
+ return 0;
+}
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata& chars) {
+ Size thumbSize { 0, 0 };
+ camera_metadata_ro_entry entry =
+ chars.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+ for(uint32_t i = 0; i < entry.count; i += 2) {
+ Size sz { static_cast<uint32_t>(entry.data.i32[i]),
+ static_cast<uint32_t>(entry.data.i32[i+1]) };
+ if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
+ thumbSize = sz;
+ }
+ }
+
+ if (thumbSize.width * thumbSize.height == 0) {
+ ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
+ }
+
+ return thumbSize;
+}
+
+void freeReleaseFences(hidl_vec<V3_2::CaptureResult>& results) {
+ for (auto& result : results) {
+ if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
+ native_handle_t* handle = const_cast<native_handle_t*>(
+ result.inputBuffer.releaseFence.getNativeHandle());
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ }
+ for (auto& buf : result.outputBuffers) {
+ if (buf.releaseFence.getNativeHandle() != nullptr) {
+ native_handle_t* handle = const_cast<native_handle_t*>(
+ buf.releaseFence.getNativeHandle());
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ }
+ }
+ }
+ return;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define UPDATE(md, tag, data, size) \
+do { \
+ if ((md).update((tag), (data), (size))) { \
+ ALOGE("Update " #tag " failed!"); \
+ return BAD_VALUE; \
+ } \
+} while (0)
+
+status_t fillCaptureResultCommon(
+ common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp,
+ camera_metadata_ro_entry& activeArraySize) {
+ if (activeArraySize.count < 4) {
+ ALOGE("%s: cannot find active array size!", __FUNCTION__);
+ return -EINVAL;
+ }
+ // android.control
+ // For USB camera, we don't know the AE state. Set the state to converged to
+ // indicate the frame should be good to use. Then apps don't have to wait the
+ // AE state.
+ const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
+ UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
+
+ const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
+ UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
+
+ // Set AWB state to converged to indicate the frame should be good to use.
+ const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
+ UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+
+ const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
+ UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
+
+ const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
+ UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
+
+ // This means pipeline latency of X frame intervals. The maximum number is 4.
+ const uint8_t requestPipelineMaxDepth = 4;
+ UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
+
+ // android.scaler
+ const int32_t crop_region[] = {
+ activeArraySize.data.i32[0], activeArraySize.data.i32[1],
+ activeArraySize.data.i32[2], activeArraySize.data.i32[3],
+ };
+ UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
+
+ // android.sensor
+ UPDATE(md, ANDROID_SENSOR_TIMESTAMP, &timestamp, 1);
+
+ // android.statistics
+ const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+ UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
+
+ const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
+ UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
+
+ return OK;
+}
+
+#undef ARRAY_SIZE
+#undef UPDATE
+
} // namespace implementation
} // namespace V3_4
+
+namespace V3_6 {
+namespace implementation {
+
+AllocatedV4L2Frame::AllocatedV4L2Frame(sp<V3_4::implementation::V4L2Frame> frameIn) :
+ Frame(frameIn->mWidth, frameIn->mHeight, frameIn->mFourcc) {
+ uint8_t* dataIn;
+ size_t dataSize;
+ if (frameIn->getData(&dataIn, &dataSize) != 0) {
+ ALOGE("%s: map input V4L2 frame failed!", __FUNCTION__);
+ return;
+ }
+
+ mData.resize(dataSize);
+ std::memcpy(mData.data(), dataIn, dataSize);
+}
+
+int AllocatedV4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+ if (outData == nullptr || dataSize == nullptr) {
+ ALOGE("%s: outData(%p)/dataSize(%p) must not be null", __FUNCTION__, outData, dataSize);
+ return -1;
+ }
+
+ *outData = mData.data();
+ *dataSize = mData.size();
+ return 0;
+}
+
+AllocatedV4L2Frame::~AllocatedV4L2Frame() {}
+
+} // namespace implementation
+} // namespace V3_6
} // namespace device
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index 71b7c17dd6..ecab9cfa03 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
-#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
@@ -84,7 +84,8 @@ using ::android::sp;
using ::android::Mutex;
using ::android::base::unique_fd;
-struct ExternalCameraDeviceSession : public virtual RefBase {
+struct ExternalCameraDeviceSession : public virtual RefBase,
+ public virtual OutputThreadInterface {
ExternalCameraDeviceSession(const sp<ICameraDeviceCallback>&,
const ExternalCameraConfig& cfg,
@@ -110,6 +111,82 @@ struct ExternalCameraDeviceSession : public virtual RefBase {
static const int kMaxStallStream = 1;
static const uint32_t kMaxBytesPerPixel = 2;
+ class OutputThread : public android::Thread {
+ public:
+ OutputThread(wp<OutputThreadInterface> parent, CroppingType,
+ const common::V1_0::helper::CameraMetadata&);
+ virtual ~OutputThread();
+
+ Status allocateIntermediateBuffers(
+ const Size& v4lSize, const Size& thumbSize,
+ const hidl_vec<Stream>& streams,
+ uint32_t blobBufferSize);
+ Status submitRequest(const std::shared_ptr<HalRequest>&);
+ void flush();
+ void dump(int fd);
+ virtual bool threadLoop() override;
+
+ void setExifMakeModel(const std::string& make, const std::string& model);
+
+ // The remaining request list is returned for offline processing
+ std::list<std::shared_ptr<HalRequest>> switchToOffline();
+
+ protected:
+ // Methods to request output buffer in parallel
+ // No-op for device@3.4. Implemented in device@3.5
+ virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
+ virtual int waitForBufferRequestDone(
+ /*out*/std::vector<HalStreamBuffer>*) { return 0; }
+
+ static const int kFlushWaitTimeoutSec = 3; // 3 sec
+ static const int kReqWaitTimeoutMs = 33; // 33ms
+ static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec
+
+ void waitForNextRequest(std::shared_ptr<HalRequest>* out);
+ void signalRequestDone();
+
+ int cropAndScaleLocked(
+ sp<AllocatedFrame>& in, const Size& outSize,
+ YCbCrLayout* out);
+
+ int cropAndScaleThumbLocked(
+ sp<AllocatedFrame>& in, const Size& outSize,
+ YCbCrLayout* out);
+
+ int createJpegLocked(HalStreamBuffer &halBuf,
+ const common::V1_0::helper::CameraMetadata& settings);
+
+ void clearIntermediateBuffers();
+
+ const wp<OutputThreadInterface> mParent;
+ const CroppingType mCroppingType;
+ const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+
+ mutable std::mutex mRequestListLock; // Protect acccess to mRequestList,
+ // mProcessingRequest and mProcessingFrameNumer
+ std::condition_variable mRequestCond; // signaled when a new request is submitted
+ std::condition_variable mRequestDoneCond; // signaled when a request is done processing
+ std::list<std::shared_ptr<HalRequest>> mRequestList;
+ bool mProcessingRequest = false;
+ uint32_t mProcessingFrameNumer = 0;
+
+ // V4L2 frameIn
+ // (MJPG decode)-> mYu12Frame
+ // (Scale)-> mScaledYu12Frames
+ // (Format convert) -> output gralloc frames
+ mutable std::mutex mBufferLock; // Protect access to intermediate buffers
+ sp<AllocatedFrame> mYu12Frame;
+ sp<AllocatedFrame> mYu12ThumbFrame;
+ std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
+ std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
+ YCbCrLayout mYu12FrameLayout;
+ YCbCrLayout mYu12ThumbFrameLayout;
+ uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
+
+ std::string mExifMake;
+ std::string mExifModel;
+ };
+
protected:
// Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow
@@ -150,27 +227,22 @@ protected:
ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb);
protected:
- struct HalStreamBuffer {
- int32_t streamId;
- uint64_t bufferId;
- uint32_t width;
- uint32_t height;
- PixelFormat format;
- V3_2::BufferUsageFlags usage;
- buffer_handle_t* bufPtr;
- int acquireFence;
- bool fenceTimeout;
- };
+ // Methods from OutputThreadInterface
+ virtual Status importBuffer(int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf) override;
- struct HalRequest {
- uint32_t frameNumber;
- common::V1_0::helper::CameraMetadata setting;
- sp<V4L2Frame> frameIn;
- nsecs_t shutterTs;
- std::vector<HalStreamBuffer> buffers;
- };
+ virtual Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
+
+ virtual Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+ /*out*/std::vector<NotifyMsg>* msgs = nullptr,
+ /*out*/std::vector<CaptureResult>* results = nullptr) override;
- static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+ virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
+
+ virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+ // End of OutputThreadInterface methods
Status constructDefaultRequestSettingsRaw(RequestTemplate type,
V3_2::CameraMetadata *outMetadata);
@@ -219,11 +291,6 @@ protected:
// Optional argument for ICameraDeviceSession@3.5 impl
bool allowEmptyBuf = false);
- Status importBuffer(int32_t streamId,
- uint64_t bufId, buffer_handle_t buf,
- /*out*/buffer_handle_t** outBufPtr,
- bool allowEmptyBuf);
-
Status importBufferLocked(int32_t streamId,
uint64_t bufId, buffer_handle_t buf,
/*out*/buffer_handle_t** outBufPtr,
@@ -236,106 +303,15 @@ protected:
Status processOneCaptureRequest(const CaptureRequest& request);
- Status processCaptureResult(std::shared_ptr<HalRequest>&);
- Status processCaptureRequestError(const std::shared_ptr<HalRequest>&);
void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs);
- void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec);
void invokeProcessCaptureResultCallback(
hidl_vec<CaptureResult> &results, bool tryWriteFmq);
- static void freeReleaseFences(hidl_vec<CaptureResult>&);
Size getMaxJpegResolution() const;
Size getMaxThumbResolution() const;
- ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
-
int waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk);
- class OutputThread : public android::Thread {
- public:
- OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType);
- virtual ~OutputThread();
-
- Status allocateIntermediateBuffers(
- const Size& v4lSize, const Size& thumbSize,
- const hidl_vec<Stream>& streams,
- uint32_t blobBufferSize);
- Status submitRequest(const std::shared_ptr<HalRequest>&);
- void flush();
- void dump(int fd);
- virtual bool threadLoop() override;
-
- void setExifMakeModel(const std::string& make, const std::string& model);
-
- protected:
- // Methods to request output buffer in parallel
- // No-op for device@3.4. Implemented in device@3.5
- virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
- virtual int waitForBufferRequestDone(
- /*out*/std::vector<HalStreamBuffer>*) { return 0; }
-
- static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
- static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
- static_cast<uint32_t>('X') << 24;
- // returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
- static uint32_t getFourCcFromLayout(const YCbCrLayout&);
- static int getCropRect(
- CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out);
-
- static const int kFlushWaitTimeoutSec = 3; // 3 sec
- static const int kReqWaitTimeoutMs = 33; // 33ms
- static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec
-
- void waitForNextRequest(std::shared_ptr<HalRequest>* out);
- void signalRequestDone();
-
- int cropAndScaleLocked(
- sp<AllocatedFrame>& in, const Size& outSize,
- YCbCrLayout* out);
-
- int cropAndScaleThumbLocked(
- sp<AllocatedFrame>& in, const Size& outSize,
- YCbCrLayout* out);
-
- int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out,
- Size sz, uint32_t format);
-
- static int encodeJpegYU12(const Size &inSz,
- const YCbCrLayout& inLayout, int jpegQuality,
- const void *app1Buffer, size_t app1Size,
- void *out, size_t maxOutSize,
- size_t &actualCodeSize);
-
- int createJpegLocked(HalStreamBuffer &halBuf, const std::shared_ptr<HalRequest>& req);
-
- const wp<ExternalCameraDeviceSession> mParent;
- const CroppingType mCroppingType;
-
- mutable std::mutex mRequestListLock; // Protect acccess to mRequestList,
- // mProcessingRequest and mProcessingFrameNumer
- std::condition_variable mRequestCond; // signaled when a new request is submitted
- std::condition_variable mRequestDoneCond; // signaled when a request is done processing
- std::list<std::shared_ptr<HalRequest>> mRequestList;
- bool mProcessingRequest = false;
- uint32_t mProcessingFrameNumer = 0;
-
- // V4L2 frameIn
- // (MJPG decode)-> mYu12Frame
- // (Scale)-> mScaledYu12Frames
- // (Format convert) -> output gralloc frames
- mutable std::mutex mBufferLock; // Protect access to intermediate buffers
- sp<AllocatedFrame> mYu12Frame;
- sp<AllocatedFrame> mYu12ThumbFrame;
- std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
- std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
- YCbCrLayout mYu12FrameLayout;
- YCbCrLayout mYu12ThumbFrameLayout;
- uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
-
- std::string mExifMake;
- std::string mExifModel;
- };
-
// Protect (most of) HIDL interface methods from synchronized-entering
mutable Mutex mInterfaceLock;
@@ -381,12 +357,6 @@ protected:
std::mutex mInflightFramesLock; // protect mInflightFrames
std::unordered_set<uint32_t> mInflightFrames;
- // buffers currently circulating between HAL and camera service
- // key: bufferId sent via HIDL interface
- // value: imported buffer_handle_t
- // Buffer will be imported during processCaptureRequest and will be freed
- // when the its stream is deleted or camera device session is closed
- typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
// Stream ID -> circulating buffers map
std::map<int, CirculatingBuffers> mCirculatingBuffers;
// Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
@@ -395,6 +365,8 @@ protected:
std::mutex mAfTriggerLock; // protect mAfTrigger
bool mAfTrigger = false;
+ uint32_t mBlobBufferSize = 0;
+
static HandleImporter sHandleImporter;
/* Beginning of members not changed after initialize() */
@@ -410,6 +382,9 @@ protected:
const Size mMaxThumbResolution;
const Size mMaxJpegResolution;
+
+ std::string mExifMake;
+ std::string mExifModel;
/* End of members not changed after initialize() */
private:
@@ -484,4 +459,4 @@ private:
} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index bd7980780b..1958fcbab5 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -105,7 +105,7 @@ protected:
// Calls into virtual member function. Do not use it in constructor
status_t initCameraCharacteristics();
// Init available capabilities keys
- status_t initAvailableCapabilities(
+ virtual status_t initAvailableCapabilities(
::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
// Init non-device dependent keys
virtual status_t initDefaultCharsKeys(
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
index 341c62218d..74f75eb246 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -17,16 +17,27 @@
#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
+#include <android/hardware/camera/common/1.0/types.h>
+#include <android/hardware/camera/device/3.2/types.h>
+#include <android/hardware/graphics/common/1.0/types.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <inttypes.h>
#include <mutex>
+#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "tinyxml2.h" // XML parsing
#include "utils/LightRefBase.h"
+#include "utils/Timers.h"
+#include <CameraMetadata.h>
+#include <HandleImporter.h>
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+
+using ::android::hardware::graphics::mapper::V2_0::IMapper;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
namespace android {
namespace hardware {
@@ -113,16 +124,28 @@ struct SupportedV4L2Format {
std::vector<FrameRate> frameRates;
};
+// A Base class with basic information about a frame
+struct Frame : public VirtualLightRefBase {
+public:
+ Frame(uint32_t width, uint32_t height, uint32_t fourcc);
+ const uint32_t mWidth;
+ const uint32_t mHeight;
+ const uint32_t mFourcc;
+
+ // getData might involve map/allocation
+ virtual int getData(uint8_t** outData, size_t* dataSize) = 0;
+};
+
// A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
// Also contains necessary information to enqueue the buffer back to V4L2 buffer queue
-class V4L2Frame : public virtual VirtualLightRefBase {
+class V4L2Frame : public Frame {
public:
V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd,
uint32_t dataSize, uint64_t offset);
~V4L2Frame() override;
- const uint32_t mWidth;
- const uint32_t mHeight;
- const uint32_t mFourcc;
+
+ virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
const int mBufferIndex; // for later enqueue
int map(uint8_t** data, size_t* dataSize);
int unmap();
@@ -137,13 +160,13 @@ private:
// A RAII class representing a CPU allocated YUV frame used as intermeidate buffers
// when generating output images.
-class AllocatedFrame : public virtual VirtualLightRefBase {
+class AllocatedFrame : public Frame {
public:
- AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size?
+ AllocatedFrame(uint32_t w, uint32_t h); // only support V4L2_PIX_FMT_YUV420 for now
~AllocatedFrame() override;
- const uint32_t mWidth;
- const uint32_t mHeight;
- const uint32_t mFourcc; // Only support YU12 format for now
+
+ virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
int allocate(YCbCrLayout* out = nullptr);
int getLayout(YCbCrLayout* out);
int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input
@@ -165,8 +188,110 @@ const float kMinAspectRatio = 1.f;
bool isAspectRatioClose(float ar1, float ar2);
+struct HalStreamBuffer {
+ int32_t streamId;
+ uint64_t bufferId;
+ uint32_t width;
+ uint32_t height;
+ ::android::hardware::graphics::common::V1_0::PixelFormat format;
+ ::android::hardware::camera::device::V3_2::BufferUsageFlags usage;
+ buffer_handle_t* bufPtr;
+ int acquireFence;
+ bool fenceTimeout;
+};
+
+struct HalRequest {
+ uint32_t frameNumber;
+ common::V1_0::helper::CameraMetadata setting;
+ sp<Frame> frameIn;
+ nsecs_t shutterTs;
+ std::vector<HalStreamBuffer> buffers;
+};
+
+static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+
+// buffers currently circulating between HAL and camera service
+// key: bufferId sent via HIDL interface
+// value: imported buffer_handle_t
+// Buffer will be imported during processCaptureRequest (or requestStreamBuffer
+// in the case of HAL buffer manager is enabled) and will be freed
+// when the stream is deleted or camera device session is closed
+typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
+
+::android::hardware::camera::common::V1_0::Status importBufferImpl(
+ /*inout*/std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*inout*/HandleImporter& handleImporter,
+ int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf);
+
+static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
+ static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
+ static_cast<uint32_t>('X') << 24;
+
+// returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
+uint32_t getFourCcFromLayout(const YCbCrLayout&);
+
+using ::android::hardware::camera::external::common::Size;
+int getCropRect(CroppingType ct, const Size& inSize,
+ const Size& outSize, IMapper::Rect* out);
+
+int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format);
+
+int encodeJpegYU12(const Size &inSz,
+ const YCbCrLayout& inLayout, int jpegQuality,
+ const void *app1Buffer, size_t app1Size,
+ void *out, size_t maxOutSize,
+ size_t &actualCodeSize);
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata&);
+
+void freeReleaseFences(hidl_vec<V3_2::CaptureResult>&);
+
+status_t fillCaptureResultCommon(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp,
+ camera_metadata_ro_entry& activeArraySize);
+
+// Interface for OutputThread calling back to parent
+struct OutputThreadInterface : public virtual RefBase {
+ virtual ::android::hardware::camera::common::V1_0::Status importBuffer(
+ int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr, bool allowEmptyBuf) = 0;
+
+ virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) = 0;
+
+ // Callbacks are fired within the method if msgs/results are nullptr.
+ // Otherwise the callbacks will be returned and caller is responsible to
+ // fire the callback later
+ virtual ::android::hardware::camera::common::V1_0::Status processCaptureRequestError(
+ const std::shared_ptr<HalRequest>&,
+ /*out*/std::vector<V3_2::NotifyMsg>* msgs = nullptr,
+ /*out*/std::vector<V3_2::CaptureResult>* results = nullptr) = 0;
+
+ virtual ::android::hardware::camera::common::V1_0::Status processCaptureResult(
+ std::shared_ptr<HalRequest>&) = 0;
+
+ virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0;
+};
+
} // namespace implementation
} // namespace V3_4
+
+namespace V3_6 {
+namespace implementation {
+
+// A CPU copy of a mapped V4L2Frame. Will map the input V4L2 frame.
+class AllocatedV4L2Frame : public V3_4::implementation::Frame {
+public:
+ AllocatedV4L2Frame(sp<V3_4::implementation::V4L2Frame> frameIn);
+ ~AllocatedV4L2Frame() override;
+ virtual int getData(uint8_t** outData, size_t* dataSize) override;
+private:
+ std::vector<uint8_t> mData;
+};
+
+} // namespace implementation
+} // namespace V3_6
} // namespace device
} // namespace camera
} // namespace hardware
diff --git a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
index 00c1d0de39..287ac324ec 100644
--- a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
@@ -80,7 +80,7 @@ Status ExternalCameraDeviceSession::importRequestLocked(
ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread(
- wp<ExternalCameraDeviceSession> parent,
+ wp<OutputThreadInterface> parent,
sp<V3_5::ICameraDeviceCallback> callbacks) :
mParent(parent),
mCallbacks(callbacks) {}
@@ -254,7 +254,8 @@ void ExternalCameraDeviceSession::initOutputThread() {
mBufferRequestThread = new BufferRequestThread(this, mCallback_3_5);
mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
}
- mOutputThread = new OutputThread(this, mCroppingType, mBufferRequestThread);
+ mOutputThread = new OutputThread(
+ this, mCroppingType, mCameraCharacteristics, mBufferRequestThread);
}
void ExternalCameraDeviceSession::closeOutputThreadImpl() {
@@ -271,10 +272,11 @@ void ExternalCameraDeviceSession::closeOutputThread() {
}
ExternalCameraDeviceSession::OutputThread::OutputThread(
- wp<ExternalCameraDeviceSession> parent,
+ wp<OutputThreadInterface> parent,
CroppingType ct,
+ const common::V1_0::helper::CameraMetadata& chars,
sp<BufferRequestThread> bufReqThread) :
- V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct),
+ V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct, chars),
mBufferRequestThread(bufReqThread) {}
ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
index 281f93a13b..e89ef45f52 100644
--- a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
-#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
@@ -72,6 +72,7 @@ using ::android::base::unique_fd;
using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+using ::android::hardware::camera::device::V3_4::implementation::HalStreamBuffer;
struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCameraDeviceSession {
@@ -97,33 +98,10 @@ struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCamera
config, supportedFormats, devCfg);
}
-protected:
- // Methods from v3.4 and earlier will trampoline to inherited implementation
- Return<void> configureStreams_3_5(
- const StreamConfiguration& requestedConfiguration,
- ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb);
-
- Return<void> signalStreamFlush(
- const hidl_vec<int32_t>& requests,
- uint32_t streamConfigCounter);
-
- Return<void> isReconfigurationRequired(const V3_2::CameraMetadata& oldSessionParams,
- const V3_2::CameraMetadata& newSessionParams,
- ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb);
-
- virtual void initOutputThread() override;
- virtual void closeOutputThread() override;
- void closeOutputThreadImpl();
-
- virtual Status importRequestLocked(
- const CaptureRequest& request,
- hidl_vec<buffer_handle_t*>& allBufPtrs,
- hidl_vec<int>& allFences) override;
-
class BufferRequestThread : public android::Thread {
public:
BufferRequestThread(
- wp<ExternalCameraDeviceSession> parent,
+ wp<OutputThreadInterface> parent,
sp<V3_5::ICameraDeviceCallback> callbacks);
int requestBufferStart(const std::vector<HalStreamBuffer>&);
@@ -135,7 +113,7 @@ protected:
private:
void waitForNextRequest();
- const wp<ExternalCameraDeviceSession> mParent;
+ const wp<OutputThreadInterface> mParent;
const sp<V3_5::ICameraDeviceCallback> mCallbacks;
std::mutex mLock;
@@ -158,13 +136,12 @@ protected:
std::condition_variable mRequestDoneCond; // signaled when a request is done
};
- sp<BufferRequestThread> mBufferRequestThread;
-
class OutputThread :
public V3_4::implementation::ExternalCameraDeviceSession::OutputThread {
public:
// TODO: pass buffer request thread to OutputThread ctor
- OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType,
+ OutputThread(wp<OutputThreadInterface> parent, CroppingType,
+ const common::V1_0::helper::CameraMetadata&,
sp<BufferRequestThread> bufReqThread);
virtual ~OutputThread();
@@ -177,6 +154,31 @@ protected:
const sp<BufferRequestThread> mBufferRequestThread;
};
+protected:
+ // Methods from v3.4 and earlier will trampoline to inherited implementation
+ Return<void> configureStreams_3_5(
+ const StreamConfiguration& requestedConfiguration,
+ ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb);
+
+ Return<void> signalStreamFlush(
+ const hidl_vec<int32_t>& requests,
+ uint32_t streamConfigCounter);
+
+ Return<void> isReconfigurationRequired(const V3_2::CameraMetadata& oldSessionParams,
+ const V3_2::CameraMetadata& newSessionParams,
+ ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb);
+
+ virtual void initOutputThread() override;
+ virtual void closeOutputThread() override;
+ void closeOutputThreadImpl();
+
+ virtual Status importRequestLocked(
+ const CaptureRequest& request,
+ hidl_vec<buffer_handle_t*>& allBufPtrs,
+ hidl_vec<int>& allFences) override;
+
+ sp<BufferRequestThread> mBufferRequestThread;
+
sp<V3_5::ICameraDeviceCallback> mCallback_3_5;
bool mSupportBufMgr;
@@ -270,4 +272,4 @@ private:
} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.6/default/Android.bp b/camera/device/3.6/default/Android.bp
new file mode 100644
index 0000000000..a2ddebdd24
--- /dev/null
+++ b/camera/device/3.6/default/Android.bp
@@ -0,0 +1,67 @@
+//
+// 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.
+//
+
+cc_library_headers {
+ name: "camera.device@3.6-external-impl_headers",
+ vendor: true,
+ export_include_dirs: ["include/ext_device_v3_6_impl"]
+}
+
+cc_library_shared {
+ name: "camera.device@3.6-external-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ vendor: true,
+ srcs: [
+ "ExternalCameraDevice.cpp",
+ "ExternalCameraDeviceSession.cpp",
+ "ExternalCameraOfflineSession.cpp",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "libutils",
+ "libcutils",
+ "camera.device@3.2-impl",
+ "camera.device@3.3-impl",
+ "camera.device@3.4-external-impl",
+ "camera.device@3.5-external-impl",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
+ "android.hardware.camera.device@3.4",
+ "android.hardware.camera.device@3.5",
+ "android.hardware.camera.device@3.6",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
+ "liblog",
+ "libhardware",
+ "libcamera_metadata",
+ "libfmq",
+ "libsync",
+ "libyuv",
+ "libjpeg",
+ "libexif",
+ "libtinyxml2"
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper",
+ ],
+ local_include_dirs: ["include/ext_device_v3_6_impl"],
+ export_shared_lib_headers: [
+ "libfmq",
+ ],
+}
diff --git a/camera/device/3.6/default/ExternalCameraDevice.cpp b/camera/device/3.6/default/ExternalCameraDevice.cpp
new file mode 100644
index 0000000000..244c7dd460
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraDevice.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ExtCamDev@3.6"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include "ExternalCameraDevice_3_6.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+ExternalCameraDevice::ExternalCameraDevice(
+ const std::string& cameraId, const ExternalCameraConfig& cfg) :
+ V3_5::implementation::ExternalCameraDevice(cameraId, cfg) {}
+
+ExternalCameraDevice::~ExternalCameraDevice() {}
+
+sp<V3_4::implementation::ExternalCameraDeviceSession> ExternalCameraDevice::createSession(
+ const sp<V3_2::ICameraDeviceCallback>& cb,
+ const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats,
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ unique_fd v4l2Fd) {
+ return new ExternalCameraDeviceSession(
+ cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd));
+}
+
+#define UPDATE(tag, data, size) \
+do { \
+ if (metadata->update((tag), (data), (size))) { \
+ ALOGE("Update " #tag " failed!"); \
+ return -EINVAL; \
+ } \
+} while (0)
+
+status_t ExternalCameraDevice::initAvailableCapabilities(
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+ status_t res =
+ V3_4::implementation::ExternalCameraDevice::initAvailableCapabilities(metadata);
+
+ if (res != OK) {
+ return res;
+ }
+
+ camera_metadata_entry caps = metadata->find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ std::vector<uint8_t> availableCapabilities;
+
+ for (size_t i = 0; i < caps.count; i++) {
+ uint8_t capability = caps.data.u8[i];
+ availableCapabilities.push_back(capability);
+ }
+
+ // Add OFFLINE_PROCESSING capability to device 3.6
+ availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING);
+
+ UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+ availableCapabilities.data(),
+ availableCapabilities.size());
+
+ return OK;
+}
+
+#undef UPDATE
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
new file mode 100644
index 0000000000..0cc81bbe9e
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
@@ -0,0 +1,357 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ExtCamDevSsn@3.6"
+#include <android/log.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+ExternalCameraDeviceSession::ExternalCameraDeviceSession(
+ const sp<V3_2::ICameraDeviceCallback>& callback,
+ const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats,
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ unique_fd v4l2Fd) :
+ V3_5::implementation::ExternalCameraDeviceSession(
+ callback, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)) {
+}
+
+ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {}
+
+
+Return<void> ExternalCameraDeviceSession::configureStreams_3_6(
+ const StreamConfiguration& requestedConfiguration,
+ ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb) {
+ V3_2::StreamConfiguration config_v32;
+ V3_3::HalStreamConfiguration outStreams_v33;
+ V3_6::HalStreamConfiguration outStreams;
+ const V3_4::StreamConfiguration& requestedConfiguration_3_4 = requestedConfiguration.v3_4;
+ Mutex::Autolock _il(mInterfaceLock);
+
+ config_v32.operationMode = requestedConfiguration_3_4.operationMode;
+ config_v32.streams.resize(requestedConfiguration_3_4.streams.size());
+ uint32_t blobBufferSize = 0;
+ int numStallStream = 0;
+ for (size_t i = 0; i < config_v32.streams.size(); i++) {
+ config_v32.streams[i] = requestedConfiguration_3_4.streams[i].v3_2;
+ if (config_v32.streams[i].format == PixelFormat::BLOB) {
+ blobBufferSize = requestedConfiguration_3_4.streams[i].bufferSize;
+ numStallStream++;
+ }
+ }
+
+ // Fail early if there are multiple BLOB streams
+ if (numStallStream > kMaxStallStream) {
+ ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__,
+ kMaxStallStream, numStallStream);
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, outStreams);
+ return Void();
+ }
+
+ Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize);
+
+ fillOutputStream3_6(outStreams_v33, &outStreams);
+
+ _hidl_cb(status, outStreams);
+ return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::switchToOffline(
+ const hidl_vec<int32_t>& streamsToKeep,
+ ICameraDeviceSession::switchToOffline_cb _hidl_cb) {
+ std::vector<NotifyMsg> msgs;
+ std::vector<CaptureResult> results;
+ CameraOfflineSessionInfo info;
+ sp<ICameraOfflineSession> session;
+
+ Status st = switchToOffline(streamsToKeep, &msgs, &results, &info, &session);
+
+ mCallback->notify(msgs);
+ hidl_vec<CaptureResult> hidlResults(std::move(results));
+ invokeProcessCaptureResultCallback(hidlResults, /* tryWriteFmq */true);
+ V3_4::implementation::freeReleaseFences(hidlResults);
+
+ _hidl_cb(st, info, session);
+ return Void();
+}
+
+void ExternalCameraDeviceSession::fillOutputStream3_6(
+ const V3_3::HalStreamConfiguration& outStreams_v33,
+ /*out*/V3_6::HalStreamConfiguration* outStreams_v36) {
+ if (outStreams_v36 == nullptr) {
+ ALOGE("%s: outStreams_v36 must not be null!", __FUNCTION__);
+ return;
+ }
+ Mutex::Autolock _l(mLock);
+ outStreams_v36->streams.resize(outStreams_v33.streams.size());
+ for (size_t i = 0; i < outStreams_v36->streams.size(); i++) {
+ outStreams_v36->streams[i].v3_4.v3_3 = outStreams_v33.streams[i];
+ outStreams_v36->streams[i].supportOffline =
+ supportOfflineLocked(outStreams_v33.streams[i].v3_2.id);
+ }
+}
+
+bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) {
+ const Stream& stream = mStreamMap[streamId];
+ if (stream.format == PixelFormat::BLOB &&
+ stream.dataSpace == static_cast<int32_t>(Dataspace::V0_JFIF)) {
+ return true;
+ }
+ // TODO: support YUV output stream?
+ return false;
+}
+
+bool ExternalCameraDeviceSession::canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+ std::shared_ptr<V3_4::implementation::HalRequest> halReq) {
+ for (const auto& buffer : halReq->buffers) {
+ for (auto offlineStreamId : offlineStreams) {
+ if (buffer.streamId == offlineStreamId) {
+ return false;
+ }
+ }
+ }
+ // Only drop a request completely if it has no offline output
+ return true;
+}
+
+void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*out*/CameraOfflineSessionInfo* info) {
+ if (info == nullptr) {
+ ALOGE("%s: output info must not be null!", __FUNCTION__);
+ return;
+ }
+
+ info->offlineStreams.resize(offlineStreams.size());
+ info->offlineRequests.resize(offlineReqs.size());
+
+ std::unordered_map<int32_t, uint32_t> outstandingBufs(offlineStreams.size());
+ for (const auto streamId : offlineStreams) {
+ outstandingBufs.insert({streamId, 0});
+ }
+ // Fill in offline reqs and count outstanding buffers
+ for (size_t i = 0; i < offlineReqs.size(); i++) {
+ info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber;
+ info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size());
+ for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) {
+ int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId;
+ info->offlineRequests[i].pendingStreams[bIdx] = streamId;
+ outstandingBufs[streamId]++;
+ }
+ }
+
+ for (size_t i = 0; i < offlineStreams.size(); i++) {
+ int32_t streamId = offlineStreams[i];
+ info->offlineStreams[i].id = streamId;
+ info->offlineStreams[i].numOutstandingBuffers = outstandingBufs[streamId];
+ const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId);
+ info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size());
+ size_t bIdx = 0;
+ for (const auto& pair : bufIdMap) {
+ // Fill in bufferId
+ info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first;
+ }
+
+ }
+}
+
+Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+ /*out*/std::vector<NotifyMsg>* msgs,
+ /*out*/std::vector<CaptureResult>* results,
+ /*out*/CameraOfflineSessionInfo* info,
+ /*out*/sp<ICameraOfflineSession>* session) {
+ ATRACE_CALL();
+ if (offlineStreams.size() > 1) {
+ ALOGE("%s: more than one offline stream is not supported", __FUNCTION__);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) {
+ ALOGE("%s: output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__,
+ msgs, results, info, session);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ msgs->clear();
+ results->clear();
+
+ Mutex::Autolock _il(mInterfaceLock);
+ Status status = initStatus();
+ if (status != Status::OK) {
+ return status;
+ }
+
+ Mutex::Autolock _l(mLock);
+ for (auto streamId : offlineStreams) {
+ if (!supportOfflineLocked(streamId)) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ }
+
+ // pause output thread and get all remaining inflight requests
+ auto remainingReqs = mOutputThread->switchToOffline();
+ std::vector<std::shared_ptr<V3_4::implementation::HalRequest>> halReqs;
+
+ // Send out buffer/request error for remaining requests and filter requests
+ // to be handled in offline mode
+ for (auto& halReq : remainingReqs) {
+ bool dropReq = canDropRequest(offlineStreams, halReq);
+ if (dropReq) {
+ // Request is dropped completely. Just send request error and
+ // there is no need to send the request to offline session
+ processCaptureRequestError(halReq, msgs, results);
+ continue;
+ }
+
+ // All requests reach here must have at least one offline stream output
+ NotifyMsg shutter;
+ shutter.type = MsgType::SHUTTER;
+ shutter.msg.shutter.frameNumber = halReq->frameNumber;
+ shutter.msg.shutter.timestamp = halReq->shutterTs;
+ msgs->push_back(shutter);
+
+ std::vector<V3_4::implementation::HalStreamBuffer> offlineBuffers;
+ for (const auto& buffer : halReq->buffers) {
+ bool dropBuffer = true;
+ for (auto offlineStreamId : offlineStreams) {
+ if (buffer.streamId == offlineStreamId) {
+ dropBuffer = false;
+ break;
+ }
+ }
+ if (dropBuffer) {
+ NotifyMsg error;
+ error.type = MsgType::ERROR;
+ error.msg.error.frameNumber = halReq->frameNumber;
+ error.msg.error.errorStreamId = buffer.streamId;
+ error.msg.error.errorCode = ErrorCode::ERROR_BUFFER;
+ msgs->push_back(error);
+
+ CaptureResult result;
+ result.frameNumber = halReq->frameNumber;
+ result.partialResult = 0; // buffer only result
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(1);
+ result.outputBuffers[0].streamId = buffer.streamId;
+ result.outputBuffers[0].bufferId = buffer.bufferId;
+ result.outputBuffers[0].status = BufferStatus::ERROR;
+ if (buffer.acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = buffer.acquireFence;
+ result.outputBuffers[0].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ results->push_back(result);
+ } else {
+ offlineBuffers.push_back(buffer);
+ }
+ }
+ halReq->buffers = offlineBuffers;
+ halReqs.push_back(halReq);
+ }
+
+ // convert hal requests to offline request
+ std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
+ for (auto& v4lReq : halReqs) {
+ std::shared_ptr<HalRequest> halReq = std::make_shared<HalRequest>();
+ halReq->frameNumber = v4lReq->frameNumber;
+ halReq->setting = v4lReq->setting;
+ halReq->shutterTs = v4lReq->shutterTs;
+ halReq->buffers = v4lReq->buffers;
+ sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+ static_cast<V3_4::implementation::V4L2Frame*>(v4lReq->frameIn.get());
+ halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame);
+ offlineReqs.push_back(halReq);
+ // enqueue V4L2 frame
+ enqueueV4l2Frame(v4l2Frame);
+ }
+
+ // Collect buffer caches/streams
+ hidl_vec<Stream> streamInfos;
+ streamInfos.resize(offlineStreams.size());
+ std::map<int, CirculatingBuffers> circulatingBuffers;
+ {
+ Mutex::Autolock _l(mCbsLock);
+ size_t idx = 0;
+ for(auto streamId : offlineStreams) {
+ circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId);
+ mCirculatingBuffers.erase(streamId);
+ streamInfos[idx++] = mStreamMap.at(streamId);
+ mStreamMap.erase(streamId);
+ }
+ }
+
+ fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info);
+
+ // create the offline session object
+ bool afTrigger;
+ {
+ std::lock_guard<std::mutex> lk(mAfTriggerLock);
+ afTrigger = mAfTrigger;
+ }
+ sp<ExternalCameraOfflineSession> sessionImpl = new ExternalCameraOfflineSession(
+ mCroppingType, mCameraCharacteristics, mCameraId,
+ mExifMake, mExifModel, mBlobBufferSize, afTrigger,
+ streamInfos, offlineReqs, circulatingBuffers);
+
+ bool initFailed = sessionImpl->initialize();
+ if (initFailed) {
+ ALOGE("%s: offline session initialize failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ // cleanup stream and buffer caches
+ {
+ Mutex::Autolock _l(mCbsLock);
+ for(auto pair : mStreamMap) {
+ cleanupBuffersLocked(/*Stream ID*/pair.first);
+ }
+ mCirculatingBuffers.clear();
+ }
+ mStreamMap.clear();
+
+ // update inflight records
+ {
+ std::lock_guard<std::mutex> lk(mInflightFramesLock);
+ mInflightFrames.clear();
+ }
+
+ // stop v4l2 streaming
+ if (v4l2StreamOffLocked() !=0) {
+ ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ *session = sessionImpl->getInterface();
+ return Status::OK;
+}
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
new file mode 100644
index 0000000000..e606fda832
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
@@ -0,0 +1,554 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ExtCamOfflnSsn@3.6"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+#include <android/log.h>
+
+#include <linux/videodev2.h>
+#include <sync/sync.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraOfflineSession.h"
+
+namespace {
+
+// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer.
+static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */;
+
+} // anonymous namespace
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+// static instance
+HandleImporter ExternalCameraOfflineSession::sHandleImporter;
+
+using V3_5::implementation::ExternalCameraDeviceSession;
+
+ExternalCameraOfflineSession::ExternalCameraOfflineSession(
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ const std::string& exifMake,
+ const std::string& exifModel,
+ const uint32_t blobBufferSize,
+ const bool afTrigger,
+ const hidl_vec<Stream>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers) :
+ mCroppingType(croppingType), mChars(chars), mCameraId(cameraId),
+ mExifMake(exifMake), mExifModel(exifModel), mBlobBufferSize(blobBufferSize),
+ mAfTrigger(afTrigger), mOfflineStreams(offlineStreams), mOfflineReqs(offlineReqs),
+ mCirculatingBuffers(circulatingBuffers) {}
+
+ExternalCameraOfflineSession::~ExternalCameraOfflineSession() {
+ close();
+}
+
+bool ExternalCameraOfflineSession::initialize() {
+ mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
+ kMetadataMsgQueueSize, false /* non blocking */);
+ if (!mResultMetadataQueue->isValid()) {
+ ALOGE("%s: invalid result fmq", __FUNCTION__);
+ return true;
+ }
+ return false;
+}
+
+void ExternalCameraOfflineSession::initOutputThread() {
+ if (mOutputThread != nullptr) {
+ ALOGE("%s: OutputThread already exist!", __FUNCTION__);
+ return;
+ }
+
+ mBufferRequestThread = new ExternalCameraDeviceSession::BufferRequestThread(
+ this, mCallback);
+ mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
+
+ mOutputThread = new OutputThread(this, mCroppingType, mChars,
+ mBufferRequestThread, mOfflineReqs);
+
+ mOutputThread->setExifMakeModel(mExifMake, mExifModel);
+
+ Size inputSize = { mOfflineReqs[0]->frameIn->mWidth, mOfflineReqs[0]->frameIn->mHeight};
+ Size maxThumbSize = V3_4::implementation::getMaxThumbnailResolution(mChars);
+ mOutputThread->allocateIntermediateBuffers(
+ inputSize, maxThumbSize, mOfflineStreams, mBlobBufferSize);
+
+ mOutputThread->run("ExtCamOfflnOut", PRIORITY_DISPLAY);
+}
+
+bool ExternalCameraOfflineSession::OutputThread::threadLoop() {
+ auto parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return false;
+ }
+
+ if (mOfflineReqs.empty()) {
+ ALOGI("%s: all offline requests are processed. Stopping.", __FUNCTION__);
+ return false;
+ }
+
+ std::shared_ptr<HalRequest> req = mOfflineReqs.front();
+ mOfflineReqs.pop_front();
+
+ auto onDeviceError = [&](auto... args) {
+ ALOGE(args...);
+ parent->notifyError(
+ req->frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+ signalRequestDone();
+ return false;
+ };
+
+ if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) {
+ return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
+ req->frameIn->mFourcc & 0xFF,
+ (req->frameIn->mFourcc >> 8) & 0xFF,
+ (req->frameIn->mFourcc >> 16) & 0xFF,
+ (req->frameIn->mFourcc >> 24) & 0xFF);
+ }
+
+ int res = requestBufferStart(req->buffers);
+ if (res != 0) {
+ ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res);
+ return onDeviceError("%s: failed to send buffer request!", __FUNCTION__);
+ }
+
+ std::unique_lock<std::mutex> lk(mBufferLock);
+ // Convert input V4L2 frame to YU12 of the same size
+ // TODO: see if we can save some computation by converting to YV12 here
+ uint8_t* inData;
+ size_t inDataSize;
+ if (req->frameIn->getData(&inData, &inDataSize) != 0) {
+ lk.unlock();
+ return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
+ }
+
+ // TODO: in some special case maybe we can decode jpg directly to gralloc output?
+ if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) {
+ ATRACE_BEGIN("MJPGtoI420");
+ int res = libyuv::MJPGToI420(
+ inData, inDataSize, static_cast<uint8_t*>(mYu12FrameLayout.y), mYu12FrameLayout.yStride,
+ static_cast<uint8_t*>(mYu12FrameLayout.cb), mYu12FrameLayout.cStride,
+ static_cast<uint8_t*>(mYu12FrameLayout.cr), mYu12FrameLayout.cStride,
+ mYu12Frame->mWidth, mYu12Frame->mHeight, mYu12Frame->mWidth, mYu12Frame->mHeight);
+ ATRACE_END();
+
+ if (res != 0) {
+ // For some webcam, the first few V4L2 frames might be malformed...
+ ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res);
+ lk.unlock();
+ Status st = parent->processCaptureRequestError(req);
+ if (st != Status::OK) {
+ return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
+ }
+ signalRequestDone();
+ return true;
+ }
+ }
+
+ ATRACE_BEGIN("Wait for BufferRequest done");
+ res = waitForBufferRequestDone(&req->buffers);
+ ATRACE_END();
+
+ if (res != 0) {
+ ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res);
+ lk.unlock();
+ return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__);
+ }
+
+ ALOGV("%s processing new request", __FUNCTION__);
+ const int kSyncWaitTimeoutMs = 500;
+ for (auto& halBuf : req->buffers) {
+ if (*(halBuf.bufPtr) == nullptr) {
+ ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId);
+ halBuf.fenceTimeout = true;
+ } else if (halBuf.acquireFence >= 0) {
+ int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
+ if (ret) {
+ halBuf.fenceTimeout = true;
+ } else {
+ ::close(halBuf.acquireFence);
+ halBuf.acquireFence = -1;
+ }
+ }
+
+ if (halBuf.fenceTimeout) {
+ continue;
+ }
+
+ // Gralloc lockYCbCr the buffer
+ switch (halBuf.format) {
+ case PixelFormat::BLOB: {
+ int ret = createJpegLocked(halBuf, req->setting);
+
+ if(ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: createJpegLocked failed with %d",
+ __FUNCTION__, ret);
+ }
+ } break;
+ case PixelFormat::Y16: {
+ void* outLayout = sHandleImporter.lock(*(halBuf.bufPtr), halBuf.usage, inDataSize);
+
+ std::memcpy(outLayout, inData, inDataSize);
+
+ int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+ if (relFence >= 0) {
+ halBuf.acquireFence = relFence;
+ }
+ } break;
+ case PixelFormat::YCBCR_420_888:
+ case PixelFormat::YV12: {
+ IMapper::Rect outRect {0, 0,
+ static_cast<int32_t>(halBuf.width),
+ static_cast<int32_t>(halBuf.height)};
+ YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+ *(halBuf.bufPtr), halBuf.usage, outRect);
+ ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d",
+ __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr,
+ outLayout.yStride, outLayout.cStride, outLayout.chromaStep);
+
+ // Convert to output buffer size/format
+ uint32_t outputFourcc = V3_4::implementation::getFourCcFromLayout(outLayout);
+ ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__,
+ outputFourcc & 0xFF,
+ (outputFourcc >> 8) & 0xFF,
+ (outputFourcc >> 16) & 0xFF,
+ (outputFourcc >> 24) & 0xFF);
+
+ YCbCrLayout cropAndScaled;
+ ATRACE_BEGIN("cropAndScaleLocked");
+ int ret = cropAndScaleLocked(
+ mYu12Frame,
+ Size { halBuf.width, halBuf.height },
+ &cropAndScaled);
+ ATRACE_END();
+ if (ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: crop and scale failed!", __FUNCTION__);
+ }
+
+ Size sz {halBuf.width, halBuf.height};
+ ATRACE_BEGIN("formatConvert");
+ ret = V3_4::implementation::formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
+ ATRACE_END();
+ if (ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: format coversion failed!", __FUNCTION__);
+ }
+ int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+ if (relFence >= 0) {
+ halBuf.acquireFence = relFence;
+ }
+ } break;
+ default:
+ lk.unlock();
+ return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format);
+ }
+ } // for each buffer
+ mScaledYu12Frames.clear();
+
+ // Don't hold the lock while calling back to parent
+ lk.unlock();
+ Status st = parent->processCaptureResult(req);
+ if (st != Status::OK) {
+ return onDeviceError("%s: failed to process capture result!", __FUNCTION__);
+ }
+ signalRequestDone();
+ return true;
+}
+
+Status ExternalCameraOfflineSession::importBuffer(int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf) {
+ Mutex::Autolock _l(mCbsLock);
+ return V3_4::implementation::importBufferImpl(
+ mCirculatingBuffers, sHandleImporter, streamId,
+ bufId, buf, outBufPtr, allowEmptyBuf);
+ return Status::OK;
+};
+
+#define UPDATE(md, tag, data, size) \
+do { \
+ if ((md).update((tag), (data), (size))) { \
+ ALOGE("Update " #tag " failed!"); \
+ return BAD_VALUE; \
+ } \
+} while (0)
+
+status_t ExternalCameraOfflineSession::fillCaptureResult(
+ common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
+ bool afTrigger = false;
+ {
+ std::lock_guard<std::mutex> lk(mAfTriggerLock);
+ afTrigger = mAfTrigger;
+ if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+ camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
+ if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
+ mAfTrigger = afTrigger = true;
+ } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
+ mAfTrigger = afTrigger = false;
+ }
+ }
+ }
+
+ // For USB camera, the USB camera handles everything and we don't have control
+ // over AF. We only simply fake the AF metadata based on the request
+ // received here.
+ uint8_t afState;
+ if (afTrigger) {
+ afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+ } else {
+ afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+ }
+ UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
+
+ camera_metadata_ro_entry activeArraySize =
+ mChars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+
+ return V3_4::implementation::fillCaptureResultCommon(md, timestamp, activeArraySize);
+}
+
+#undef UPDATE
+
+Status ExternalCameraOfflineSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
+ ATRACE_CALL();
+ // Fill output buffers
+ hidl_vec<CaptureResult> results;
+ results.resize(1);
+ CaptureResult& result = results[0];
+ result.frameNumber = req->frameNumber;
+ result.partialResult = 1;
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(req->buffers.size());
+ for (size_t i = 0; i < req->buffers.size(); i++) {
+ result.outputBuffers[i].streamId = req->buffers[i].streamId;
+ result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+ if (req->buffers[i].fenceTimeout) {
+ result.outputBuffers[i].status = BufferStatus::ERROR;
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
+ } else {
+ result.outputBuffers[i].status = BufferStatus::OK;
+ // TODO: refactor
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ }
+ }
+
+ // Fill capture result metadata
+ fillCaptureResult(req->setting, req->shutterTs);
+ const camera_metadata_t *rawResult = req->setting.getAndLock();
+ V3_2::implementation::convertToHidl(rawResult, &result.result);
+ req->setting.unlock(rawResult);
+
+ // Callback into framework
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+ V3_4::implementation::freeReleaseFences(results);
+ return Status::OK;
+};
+
+void ExternalCameraOfflineSession::invokeProcessCaptureResultCallback(
+ hidl_vec<CaptureResult> &results, bool tryWriteFmq) {
+ if (mProcessCaptureResultLock.tryLock() != OK) {
+ const nsecs_t NS_TO_SECOND = 1000000000;
+ ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+ if (mProcessCaptureResultLock.timedLock(/* 1s */NS_TO_SECOND) != OK) {
+ ALOGE("%s: cannot acquire lock in 1s, cannot proceed",
+ __FUNCTION__);
+ return;
+ }
+ }
+ if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+ for (CaptureResult &result : results) {
+ if (result.result.size() > 0) {
+ if (mResultMetadataQueue->write(result.result.data(), result.result.size())) {
+ result.fmqResultSize = result.result.size();
+ result.result.resize(0);
+ } else {
+ ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+ result.fmqResultSize = 0;
+ }
+ } else {
+ result.fmqResultSize = 0;
+ }
+ }
+ }
+ auto status = mCallback->processCaptureResult(results);
+ if (!status.isOk()) {
+ ALOGE("%s: processCaptureResult ERROR : %s", __FUNCTION__,
+ status.description().c_str());
+ }
+
+ mProcessCaptureResultLock.unlock();
+}
+
+Status ExternalCameraOfflineSession::processCaptureRequestError(
+ const std::shared_ptr<HalRequest>& req,
+ /*out*/std::vector<NotifyMsg>* outMsgs,
+ /*out*/std::vector<CaptureResult>* outResults) {
+ ATRACE_CALL();
+
+ if (outMsgs == nullptr) {
+ notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+ } else {
+ NotifyMsg shutter;
+ shutter.type = MsgType::SHUTTER;
+ shutter.msg.shutter.frameNumber = req->frameNumber;
+ shutter.msg.shutter.timestamp = req->shutterTs;
+
+ NotifyMsg error;
+ error.type = MsgType::ERROR;
+ error.msg.error.frameNumber = req->frameNumber;
+ error.msg.error.errorStreamId = -1;
+ error.msg.error.errorCode = ErrorCode::ERROR_REQUEST;
+ outMsgs->push_back(shutter);
+ outMsgs->push_back(error);
+ }
+
+ // Fill output buffers
+ hidl_vec<CaptureResult> results;
+ results.resize(1);
+ CaptureResult& result = results[0];
+ result.frameNumber = req->frameNumber;
+ result.partialResult = 1;
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(req->buffers.size());
+ for (size_t i = 0; i < req->buffers.size(); i++) {
+ result.outputBuffers[i].streamId = req->buffers[i].streamId;
+ result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+ result.outputBuffers[i].status = BufferStatus::ERROR;
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ }
+
+ if (outResults == nullptr) {
+ // Callback into framework
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+ V3_4::implementation::freeReleaseFences(results);
+ } else {
+ outResults->push_back(result);
+ }
+ return Status::OK;
+};
+
+ssize_t ExternalCameraOfflineSession::getJpegBufferSize(
+ uint32_t /*width*/, uint32_t /*height*/) const {
+ // Empty implementation here as the jpeg buffer size is passed in by ctor
+ return 0;
+};
+
+void ExternalCameraOfflineSession::notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) {
+ NotifyMsg msg;
+ msg.type = MsgType::ERROR;
+ msg.msg.error.frameNumber = frameNumber;
+ msg.msg.error.errorStreamId = streamId;
+ msg.msg.error.errorCode = ec;
+ mCallback->notify({msg});
+};
+
+Return<void> ExternalCameraOfflineSession::setCallback(const sp<ICameraDeviceCallback>& cb) {
+ Mutex::Autolock _il(mInterfaceLock);
+ if (mCallback != nullptr && cb != nullptr) {
+ ALOGE("%s: callback must not be set twice!", __FUNCTION__);
+ return Void();
+ }
+ mCallback = cb;
+
+ initOutputThread();
+
+ if (mOutputThread == nullptr) {
+ ALOGE("%s: init OutputThread failed!", __FUNCTION__);
+ }
+ return Void();
+}
+
+Return<void> ExternalCameraOfflineSession::getCaptureResultMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) {
+ Mutex::Autolock _il(mInterfaceLock);
+ _hidl_cb(*mResultMetadataQueue->getDesc());
+ return Void();
+}
+
+void ExternalCameraOfflineSession::cleanupBuffersLocked(int id) {
+ for (auto& pair : mCirculatingBuffers.at(id)) {
+ sHandleImporter.freeBuffer(pair.second);
+ }
+ mCirculatingBuffers[id].clear();
+ mCirculatingBuffers.erase(id);
+}
+
+Return<void> ExternalCameraOfflineSession::close() {
+ Mutex::Autolock _il(mInterfaceLock);
+ {
+ Mutex::Autolock _l(mLock);
+ if (mClosed) {
+ ALOGW("%s: offline session already closed!", __FUNCTION__);
+ return Void();
+ }
+ }
+ if (mBufferRequestThread) {
+ mBufferRequestThread->requestExit();
+ mBufferRequestThread->join();
+ mBufferRequestThread.clear();
+ }
+ if (mOutputThread) {
+ mOutputThread->flush();
+ mOutputThread->requestExit();
+ mOutputThread->join();
+ mOutputThread.clear();
+ }
+
+ Mutex::Autolock _l(mLock);
+ // free all buffers
+ {
+ Mutex::Autolock _cbl(mCbsLock);
+ for(auto stream : mOfflineStreams) {
+ cleanupBuffersLocked(stream.id);
+ }
+ }
+ mCallback.clear();
+ mClosed = true;
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.6/default/OWNERS b/camera/device/3.6/default/OWNERS
new file mode 100644
index 0000000000..f48a95c5b3
--- /dev/null
+++ b/camera/device/3.6/default/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
new file mode 100644
index 0000000000..db0d9a548b
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
@@ -0,0 +1,208 @@
+/*
+ * 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h>
+#include "ExternalCameraOfflineSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_6::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_6::ICameraOfflineSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
+using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+
+struct ExternalCameraDeviceSession : public V3_5::implementation::ExternalCameraDeviceSession {
+
+ ExternalCameraDeviceSession(const sp<V3_2::ICameraDeviceCallback>&,
+ const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats,
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ unique_fd v4l2Fd);
+ virtual ~ExternalCameraDeviceSession();
+
+ // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+ // dealing with minor version revs and simultaneous implementation and interface inheritance
+ virtual sp<V3_4::ICameraDeviceSession> getInterface() override {
+ return new TrampolineSessionInterface_3_6(this);
+ }
+
+protected:
+ // Methods from v3.5 and earlier will trampoline to inherited implementation
+ Return<void> configureStreams_3_6(
+ const StreamConfiguration& requestedConfiguration,
+ ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb);
+
+ Return<void> switchToOffline(
+ const hidl_vec<int32_t>& streamsToKeep,
+ ICameraDeviceSession::switchToOffline_cb _hidl_cb);
+
+ void fillOutputStream3_6(const V3_3::HalStreamConfiguration& outStreams_v33,
+ /*out*/V3_6::HalStreamConfiguration* outStreams_v36);
+ bool supportOfflineLocked(int32_t streamId);
+
+ // Main body of switchToOffline. This method does not invoke any callbacks
+ // but instead returns the necessary callbacks in output arguments so callers
+ // can callback later without holding any locks
+ Status switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+ /*out*/std::vector<NotifyMsg>* msgs,
+ /*out*/std::vector<CaptureResult>* results,
+ /*out*/CameraOfflineSessionInfo* info,
+ /*out*/sp<ICameraOfflineSession>* session);
+
+ // Whether a request can be completely dropped when switching to offline
+ bool canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+ std::shared_ptr<V3_4::implementation::HalRequest> halReq);
+
+ void fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*out*/CameraOfflineSessionInfo* info);
+
+private:
+
+ struct TrampolineSessionInterface_3_6 : public ICameraDeviceSession {
+ TrampolineSessionInterface_3_6(sp<ExternalCameraDeviceSession> parent) :
+ mParent(parent) {}
+
+ virtual Return<void> constructDefaultRequestSettings(
+ RequestTemplate type,
+ V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+ return mParent->constructDefaultRequestSettings(type, _hidl_cb);
+ }
+
+ virtual Return<void> configureStreams(
+ const V3_2::StreamConfiguration& requestedConfiguration,
+ V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
+ return mParent->configureStreams(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
+ const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+ V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
+ return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
+ }
+
+ virtual Return<void> getCaptureRequestMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override {
+ return mParent->getCaptureRequestMetadataQueue(_hidl_cb);
+ }
+
+ virtual Return<void> getCaptureResultMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override {
+ return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+ }
+
+ virtual Return<Status> flush() override {
+ return mParent->flush();
+ }
+
+ virtual Return<void> close() override {
+ return mParent->close();
+ }
+
+ virtual Return<void> configureStreams_3_3(
+ const V3_2::StreamConfiguration& requestedConfiguration,
+ configureStreams_3_3_cb _hidl_cb) override {
+ return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> configureStreams_3_4(
+ const V3_4::StreamConfiguration& requestedConfiguration,
+ configureStreams_3_4_cb _hidl_cb) override {
+ return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> processCaptureRequest_3_4(const hidl_vec<V3_4::CaptureRequest>& requests,
+ const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+ ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override {
+ return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
+ }
+
+ virtual Return<void> configureStreams_3_5(
+ const StreamConfiguration& requestedConfiguration,
+ configureStreams_3_5_cb _hidl_cb) override {
+ return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> signalStreamFlush(
+ const hidl_vec<int32_t>& requests,
+ uint32_t streamConfigCounter) override {
+ return mParent->signalStreamFlush(requests, streamConfigCounter);
+ }
+
+ virtual Return<void> isReconfigurationRequired(const V3_2::CameraMetadata& oldSessionParams,
+ const V3_2::CameraMetadata& newSessionParams,
+ ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) override {
+ return mParent->isReconfigurationRequired(oldSessionParams, newSessionParams, _hidl_cb);
+ }
+
+ virtual Return<void> configureStreams_3_6(
+ const StreamConfiguration& requestedConfiguration,
+ configureStreams_3_6_cb _hidl_cb) override {
+ return mParent->configureStreams_3_6(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> switchToOffline(
+ const hidl_vec<int32_t>& streamsToKeep,
+ switchToOffline_cb _hidl_cb) override {
+ return mParent->switchToOffline(streamsToKeep, _hidl_cb);
+ }
+
+ private:
+ sp<ExternalCameraDeviceSession> mParent;
+ };
+};
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h
new file mode 100644
index 0000000000..046c9d817e
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h
@@ -0,0 +1,77 @@
+/*
+ * 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
+
+#include "ExternalCameraDeviceSession.h"
+#include <../../../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::device::V3_5::ICameraDevice;
+using ::android::hardware::camera::common::V1_0::CameraResourceCost;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * The camera device HAL implementation is opened lazily (via the open call)
+ */
+struct ExternalCameraDevice : public V3_5::implementation::ExternalCameraDevice {
+
+ // Called by external camera provider HAL.
+ // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
+ // be multiple CameraDevice trying to access the same physical camera. Also, provider will have
+ // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
+ // camera is detached.
+ ExternalCameraDevice(const std::string& cameraId, const ExternalCameraConfig& cfg);
+ virtual ~ExternalCameraDevice();
+
+protected:
+ virtual sp<V3_4::implementation::ExternalCameraDeviceSession> createSession(
+ const sp<V3_2::ICameraDeviceCallback>&,
+ const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats,
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ unique_fd v4l2Fd) override;
+
+ virtual status_t initAvailableCapabilities(
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata*) override;
+};
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h
new file mode 100644
index 0000000000..230b67c43c
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h
@@ -0,0 +1,232 @@
+/*
+ * 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.6/ICameraOfflineSession.h>
+#include <android/hardware/camera/common/1.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <deque>
+#include <../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h>
+#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h>
+#include <HandleImporter.h>
+#include <Exif.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_5::BufferRequest;
+using ::android::hardware::camera::device::V3_5::BufferRequestStatus;
+using ::android::hardware::camera::device::V3_2::BufferStatus;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::MsgType;
+using ::android::hardware::camera::device::V3_2::NotifyMsg;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+using ::android::hardware::camera::device::V3_2::StreamType;
+using ::android::hardware::camera::device::V3_2::DataspaceFlags;
+using ::android::hardware::camera::device::V3_2::CameraBlob;
+using ::android::hardware::camera::device::V3_2::CameraBlobId;
+using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_6::ICameraOfflineSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::camera::external::common::SizeHasher;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
+using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+using ::android::hardware::camera::device::V3_4::implementation::CirculatingBuffers;
+using ::android::hardware::camera::device::V3_4::implementation::HalRequest;
+using ::android::hardware::camera::device::V3_4::implementation::OutputThreadInterface;
+
+struct ExternalCameraOfflineSession : public virtual RefBase,
+ public virtual OutputThreadInterface {
+
+ ExternalCameraOfflineSession(
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ const std::string& exifMake,
+ const std::string& exifModel,
+ uint32_t blobBufferSize,
+ bool afTrigger,
+ const hidl_vec<Stream>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers);
+
+ bool initialize();
+
+ virtual ~ExternalCameraOfflineSession();
+
+ // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+ // dealing with minor version revs and simultaneous implementation and interface inheritance
+ virtual sp<V3_6::ICameraOfflineSession> getInterface() {
+ return new TrampolineSessionInterface_3_6(this);
+ }
+
+protected:
+
+ // Methods from OutputThreadInterface
+ virtual Status importBuffer(int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf) override;
+
+ virtual Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
+
+ virtual Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+ /*out*/std::vector<NotifyMsg>* msgs = nullptr,
+ /*out*/std::vector<CaptureResult>* results = nullptr) override;
+
+ virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
+
+ virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+ // End of OutputThreadInterface methods
+
+ class OutputThread : public V3_5::implementation::ExternalCameraDeviceSession::OutputThread {
+ public:
+ OutputThread(
+ wp<OutputThreadInterface> parent, CroppingType ct,
+ const common::V1_0::helper::CameraMetadata& chars,
+ sp<V3_5::implementation::ExternalCameraDeviceSession::BufferRequestThread> bufReqThread,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs) :
+ V3_5::implementation::ExternalCameraDeviceSession::OutputThread(
+ parent, ct, chars, bufReqThread),
+ mOfflineReqs(offlineReqs) {}
+
+ virtual bool threadLoop() override;
+
+ protected:
+ std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+ }; // OutputThread
+
+
+ Return<void> setCallback(const sp<ICameraDeviceCallback>& cb);
+
+ Return<void> getCaptureResultMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb);
+
+ Return<void> close();
+
+ void initOutputThread();
+
+ void invokeProcessCaptureResultCallback(
+ hidl_vec<CaptureResult> &results, bool tryWriteFmq);
+
+ status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
+
+ void cleanupBuffersLocked(int id);
+
+ // Protect (most of) HIDL interface methods from synchronized-entering
+ mutable Mutex mInterfaceLock;
+
+ mutable Mutex mLock; // Protect all data members except otherwise noted
+
+ bool mClosed = false;
+ const CroppingType mCroppingType;
+ const common::V1_0::helper::CameraMetadata mChars;
+ const std::string mCameraId;
+ const std::string mExifMake;
+ const std::string mExifModel;
+ const uint32_t mBlobBufferSize;
+
+ std::mutex mAfTriggerLock; // protect mAfTrigger
+ bool mAfTrigger;
+
+ const hidl_vec<Stream> mOfflineStreams;
+ std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+
+ // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
+ mutable Mutex mCbsLock;
+ std::map<int, CirculatingBuffers> mCirculatingBuffers;
+
+ static HandleImporter sHandleImporter;
+
+ using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+ std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+ // Protect against invokeProcessCaptureResultCallback()
+ Mutex mProcessCaptureResultLock;
+
+ sp<ICameraDeviceCallback> mCallback;
+
+ sp<V3_5::implementation::ExternalCameraDeviceSession::BufferRequestThread> mBufferRequestThread;
+ sp<OutputThread> mOutputThread;
+private:
+
+ struct TrampolineSessionInterface_3_6 : public ICameraOfflineSession {
+ TrampolineSessionInterface_3_6(sp<ExternalCameraOfflineSession> parent) :
+ mParent(parent) {}
+
+ virtual Return<void> setCallback(const sp<ICameraDeviceCallback>& cb) override {
+ return mParent->setCallback(cb);
+ }
+
+ virtual Return<void> getCaptureResultMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override {
+ return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+ }
+
+ virtual Return<void> close() override {
+ return mParent->close();
+ }
+
+ private:
+ sp<ExternalCameraOfflineSession> mParent;
+ };
+};
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal
index 4c063dde75..4e2252cc5c 100644
--- a/camera/metadata/3.5/types.hal
+++ b/camera/metadata/3.5/types.hal
@@ -72,6 +72,23 @@ enum CameraMetadataTag : @3.4::CameraMetadataTag {
ANDROID_CONTROL_END_3_5,
+ /** android.scaler.availableRotateAndCropModes [static, byte[], public]
+ *
+ * <p>List of rotate-and-crop modes for ANDROID_SCALER_ROTATE_AND_CROP that are supported by this camera device.</p>
+ *
+ * @see ANDROID_SCALER_ROTATE_AND_CROP
+ */
+ ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_SCALER_END_3_4,
+
+ /** android.scaler.rotateAndCrop [dynamic, enum, public]
+ *
+ * <p>Whether a rotation-and-crop operation is applied to processed
+ * outputs from the camera.</p>
+ */
+ ANDROID_SCALER_ROTATE_AND_CROP,
+
+ ANDROID_SCALER_END_3_5,
+
};
/*
@@ -103,3 +120,14 @@ enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING,
};
+
+/** android.scaler.rotateAndCrop enumeration values
+ * @see ANDROID_SCALER_ROTATE_AND_CROP
+ */
+enum CameraMetadataEnumAndroidScalerRotateAndCrop : uint32_t {
+ ANDROID_SCALER_ROTATE_AND_CROP_NONE,
+ ANDROID_SCALER_ROTATE_AND_CROP_90,
+ ANDROID_SCALER_ROTATE_AND_CROP_180,
+ ANDROID_SCALER_ROTATE_AND_CROP_270,
+ ANDROID_SCALER_ROTATE_AND_CROP_AUTO,
+};
diff --git a/camera/provider/2.4/ICameraProvider.hal b/camera/provider/2.4/ICameraProvider.hal
index 74c3ff1693..105629dec3 100644
--- a/camera/provider/2.4/ICameraProvider.hal
+++ b/camera/provider/2.4/ICameraProvider.hal
@@ -115,7 +115,7 @@ interface ICameraProvider {
* INTERNAL_ERROR:
* A camera ID list cannot be created. This may be due to
* a failure to initialize the camera subsystem, for example.
- * @return cameraDeviceServiceNames The vector of internal camera device
+ * @return cameraDeviceNames The vector of internal camera device
* names known to this provider.
*/
getCameraIdList()
diff --git a/camera/provider/2.4/ICameraProviderCallback.hal b/camera/provider/2.4/ICameraProviderCallback.hal
index 63dd3c516f..8822305c3a 100644
--- a/camera/provider/2.4/ICameraProviderCallback.hal
+++ b/camera/provider/2.4/ICameraProviderCallback.hal
@@ -39,7 +39,7 @@ interface ICameraProviderCallback {
* are already present, as soon as the callbacks are available through
* setCallback.
*
- * @param cameraDeviceServiceName The name of the camera device that has a
+ * @param cameraDeviceName The name of the camera device that has a
* new status.
* @param newStatus The new status that device is in.
*
@@ -57,7 +57,7 @@ interface ICameraProviderCallback {
* android.flash.info.available is reported as true via the
* ICameraDevice::getCameraCharacteristics call.
*
- * @param cameraDeviceServiceName The name of the camera device that has a
+ * @param cameraDeviceName The name of the camera device that has a
* new status.
* @param newStatus The new status that device is in.
*
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index e38e0f7574..1c51d46fa0 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -50,6 +50,7 @@ cc_library_shared {
"android.hardware.camera.device@3.3",
"android.hardware.camera.device@3.4",
"android.hardware.camera.device@3.5",
+ "android.hardware.camera.device@3.6",
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
@@ -61,6 +62,7 @@ cc_library_shared {
"camera.device@3.4-impl",
"camera.device@3.5-external-impl",
"camera.device@3.5-impl",
+ "camera.device@3.6-external-impl",
"libcamera_metadata",
"libcutils",
"libhardware",
@@ -74,7 +76,8 @@ cc_library_shared {
],
header_libs: [
"camera.device@3.4-external-impl_headers",
- "camera.device@3.5-external-impl_headers"
+ "camera.device@3.5-external-impl_headers",
+ "camera.device@3.6-external-impl_headers"
],
export_include_dirs: ["."],
}
diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
index a6fd288125..2bfced2c62 100644
--- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
@@ -26,6 +26,7 @@
#include "ExternalCameraProviderImpl_2_4.h"
#include "ExternalCameraDevice_3_4.h"
#include "ExternalCameraDevice_3_5.h"
+#include "ExternalCameraDevice_3_6.h"
namespace android {
namespace hardware {
@@ -73,6 +74,7 @@ ExternalCameraProviderImpl_2_4::ExternalCameraProviderImpl_2_4() :
switch(mPreferredHal3MinorVersion) {
case 4:
case 5:
+ case 6:
// OK
break;
default:
@@ -171,6 +173,12 @@ Return<void> ExternalCameraProviderImpl_2_4::getCameraDeviceInterface_V3_x(
cameraId, mCfg);
break;
}
+ case 6: {
+ ALOGV("Constructing v3.6 external camera device");
+ deviceImpl = new device::V3_6::implementation::ExternalCameraDevice(
+ cameraId, mCfg);
+ break;
+ }
default:
ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion);
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
@@ -202,7 +210,9 @@ void ExternalCameraProviderImpl_2_4::addExternalCamera(const char* devName) {
ALOGI("ExtCam: adding %s to External Camera HAL!", devName);
Mutex::Autolock _l(mLock);
std::string deviceName;
- if (mPreferredHal3MinorVersion == 5) {
+ if (mPreferredHal3MinorVersion == 6) {
+ deviceName = std::string("device@3.6/external/") + devName;
+ } else if (mPreferredHal3MinorVersion == 5) {
deviceName = std::string("device@3.5/external/") + devName;
} else {
deviceName = std::string("device@3.4/external/") + devName;
@@ -249,7 +259,9 @@ void ExternalCameraProviderImpl_2_4::deviceAdded(const char* devName) {
void ExternalCameraProviderImpl_2_4::deviceRemoved(const char* devName) {
Mutex::Autolock _l(mLock);
std::string deviceName;
- if (mPreferredHal3MinorVersion == 5) {
+ if (mPreferredHal3MinorVersion == 6) {
+ deviceName = std::string("device@3.6/external/") + devName;
+ } else if (mPreferredHal3MinorVersion == 5) {
deviceName = std::string("device@3.5/external/") + devName;
} else {
deviceName = std::string("device@3.4/external/") + devName;
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index d14ccfaf2e..15f5c9ad4b 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -41,6 +41,7 @@ cc_test {
"android.hardware.camera.metadata@3.4",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
+ "android.hardware.camera.provider@2.6",
"android.hardware.graphics.common@1.0",
"android.hidl.allocator@1.0",
"libgrallocusage",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index c9f9bf6856..b4092ca211 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -40,15 +40,17 @@
#include <android/hardware/camera/metadata/3.4/types.h>
#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
+#include <android/hardware/camera/provider/2.6/ICameraProvider.h>
+#include <android/hardware/camera/provider/2.6/ICameraProviderCallback.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <binder/MemoryHeapBase.h>
#include <cutils/properties.h>
#include <fmq/MessageQueue.h>
#include <grallocusage/GrallocUsageConversion.h>
+#include <gtest/gtest.h>
#include <gui/BufferItemConsumer.h>
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
-#include <gtest/gtest.h>
#include <hardware/gralloc.h>
#include <hardware/gralloc1.h>
#include <hidl/GtestPrinter.h>
@@ -537,7 +539,7 @@ public:
uint32_t id;
ASSERT_TRUE(parseProviderName(service_name, &mProviderType, &id));
- castProvider(mProvider, &mProvider2_5);
+ castProvider(mProvider, &mProvider2_5, &mProvider2_6);
notifyDeviceState(provider::V2_5::DeviceState::NORMAL);
}
virtual void TearDown() override {}
@@ -709,8 +711,9 @@ public:
sp<ICameraDeviceSession> *session /*out*/,
camera_metadata_t **staticMeta /*out*/,
::android::sp<ICameraDevice> *device = nullptr/*out*/);
- void castProvider(const sp<provider::V2_4::ICameraProvider> &provider,
- sp<provider::V2_5::ICameraProvider> *provider2_5 /*out*/);
+ void castProvider(const sp<provider::V2_4::ICameraProvider>& provider,
+ sp<provider::V2_5::ICameraProvider>* provider2_5 /*out*/,
+ sp<provider::V2_6::ICameraProvider>* provider2_6 /*out*/);
void castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
@@ -937,6 +940,7 @@ protected:
// Camera provider service
sp<ICameraProvider> mProvider;
sp<::android::hardware::camera::provider::V2_5::ICameraProvider> mProvider2_5;
+ sp<::android::hardware::camera::provider::V2_6::ICameraProvider> mProvider2_6;
// Camera provider type.
std::string mProviderType;
@@ -1649,6 +1653,33 @@ TEST_P(CameraHidlTest, setCallback) {
return Void();
}
};
+
+ struct ProviderCb2_6
+ : public ::android::hardware::camera::provider::V2_6::ICameraProviderCallback {
+ virtual Return<void> cameraDeviceStatusChange(const hidl_string& cameraDeviceName,
+ CameraDeviceStatus newStatus) override {
+ ALOGI("camera device status callback name %s, status %d", cameraDeviceName.c_str(),
+ (int)newStatus);
+ return Void();
+ }
+
+ virtual Return<void> torchModeStatusChange(const hidl_string& cameraDeviceName,
+ TorchModeStatus newStatus) override {
+ ALOGI("Torch mode status callback name %s, status %d", cameraDeviceName.c_str(),
+ (int)newStatus);
+ return Void();
+ }
+
+ virtual Return<void> physicalCameraDeviceStatusChange(
+ const hidl_string& cameraDeviceName, const hidl_string& physicalCameraDeviceName,
+ CameraDeviceStatus newStatus) override {
+ ALOGI("physical camera device status callback name %s, physical camera name %s,"
+ " status %d",
+ cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(), (int)newStatus);
+ return Void();
+ }
+ };
+
sp<ProviderCb> cb = new ProviderCb;
auto status = mProvider->setCallback(cb);
ASSERT_TRUE(status.isOk());
@@ -1656,6 +1687,16 @@ TEST_P(CameraHidlTest, setCallback) {
status = mProvider->setCallback(nullptr);
ASSERT_TRUE(status.isOk());
ASSERT_EQ(Status::OK, status);
+
+ if (mProvider2_6.get() != nullptr) {
+ sp<ProviderCb2_6> cb = new ProviderCb2_6;
+ auto status = mProvider2_6->setCallback(cb);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_EQ(Status::OK, status);
+ status = mProvider2_6->setCallback(nullptr);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_EQ(Status::OK, status);
+ }
}
// Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device
@@ -5596,12 +5637,19 @@ void CameraHidlTest::castDevice(const sp<device::V3_2::ICameraDevice> &device,
}
//Cast camera provider to corresponding version if available
-void CameraHidlTest::castProvider(const sp<ICameraProvider> &provider,
- sp<provider::V2_5::ICameraProvider> *provider2_5 /*out*/) {
+void CameraHidlTest::castProvider(const sp<ICameraProvider>& provider,
+ sp<provider::V2_5::ICameraProvider>* provider2_5 /*out*/,
+ sp<provider::V2_6::ICameraProvider>* provider2_6 /*out*/) {
ASSERT_NE(nullptr, provider2_5);
- auto castResult = provider::V2_5::ICameraProvider::castFrom(provider);
- if (castResult.isOk()) {
- *provider2_5 = castResult;
+ auto castResult2_5 = provider::V2_5::ICameraProvider::castFrom(provider);
+ if (castResult2_5.isOk()) {
+ *provider2_5 = castResult2_5;
+ }
+
+ ASSERT_NE(nullptr, provider2_6);
+ auto castResult2_6 = provider::V2_6::ICameraProvider::castFrom(provider);
+ if (castResult2_6.isOk()) {
+ *provider2_6 = castResult2_6;
}
}
diff --git a/camera/provider/2.5/default/Android.bp b/camera/provider/2.5/default/Android.bp
index 4563362ddb..9ddf651440 100644
--- a/camera/provider/2.5/default/Android.bp
+++ b/camera/provider/2.5/default/Android.bp
@@ -52,6 +52,8 @@ cc_library_shared {
"android.hardware.camera.provider@2.4-external",
"android.hardware.camera.provider@2.5",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"camera.device@3.3-impl",
@@ -72,7 +74,8 @@ cc_library_shared {
],
header_libs: [
"camera.device@3.4-external-impl_headers",
- "camera.device@3.5-external-impl_headers"
+ "camera.device@3.5-external-impl_headers",
+ "camera.device@3.6-external-impl_headers"
],
export_include_dirs: ["."],
}
@@ -165,7 +168,10 @@ cc_binary {
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.5-external",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"libbinder",
+ "libcamera_metadata",
"libhidlbase",
"liblog",
"libtinyxml2",
@@ -179,5 +185,6 @@ cc_binary {
"camera.device@3.4-impl_headers",
"camera.device@3.5-external-impl_headers",
"camera.device@3.5-impl_headers",
+ "camera.device@3.6-external-impl_headers",
],
}
diff --git a/camera/provider/2.6/Android.bp b/camera/provider/2.6/Android.bp
new file mode 100644
index 0000000000..e69819c863
--- /dev/null
+++ b/camera/provider/2.6/Android.bp
@@ -0,0 +1,26 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.camera.provider@2.6",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "ICameraProvider.hal",
+ "ICameraProviderCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.camera.common@1.0",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
+ "android.hardware.camera.device@3.4",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.camera.provider@2.5",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal
new file mode 100644
index 0000000000..0948db6ea3
--- /dev/null
+++ b/camera/provider/2.6/ICameraProvider.hal
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+package android.hardware.camera.provider@2.6;
+
+import @2.5::ICameraProvider;
+import android.hardware.camera.common@1.0::Status;
+import android.hardware.camera.device@3.4::StreamConfiguration;
+
+/**
+ * Camera provider HAL
+ *
+ * @2.6::adds support for the getConcurrentStreamingCameraIds() and
+ * isConcurrentStreamCombinationSupported()
+ * @2.6::ICameraProviderCallback to receive physical camera availability
+ * callbacks for logical multi-cameras.
+ */
+interface ICameraProvider extends @2.5::ICameraProvider {
+ /**
+ * getConcurrentStreamingCameraIds
+ *
+ * Get a vector of combinations of camera device ids that are able to
+ * configure streams concurrently. Each camera device advertised in a
+ * combination MUST at the very least support the following streams while
+ * streaming concurrently with the other camera ids in the combination.
+ *
+ * Target 1 Target 2
+ * ---------------------------------------------
+ * | Type | Size | Type | Size |
+ * ---------------------------------------------
+ * | YUV | 1280 X 720 | |
+ * ---------------------------------------------
+ * | PRIV | 1280 X 720 | |
+ * ---------------------------------------------
+ * | YUV | 1280 X 720 | YUV |1280 X 720|
+ * ---------------------------------------------
+ * | PRIV | 1280 X 720 | PRIV |1280 X 720|
+ * ---------------------------------------------
+ * | PRIV | 1280 X 720 | YUV |1280 X 720|
+ * ---------------------------------------------
+
+ * @return status Status code for the operation
+ * @return cameraIds a list of camera id combinations that support
+ * concurrent stream configurations with the minimum guarantees
+ * specified.
+ */
+ getConcurrentStreamingCameraIds() generates (Status status, vec<vec<string>> cameraIds);
+
+ /**
+ * isConcurrentStreamCombinationSupported:
+ *
+ * Check for device support of specific camera stream combinations while
+ * streaming concurrently with other devices.
+ *
+ * The per device streamList must contain at least one output-capable stream, and may
+ * not contain more than one input-capable stream.
+ * In contrast to regular stream configuration the framework does not create
+ * or initialize any actual streams. This means that Hal must not use or
+ * consider the stream "id" value.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Preconditions:
+ *
+ * The framework can call this method at any time before, during and
+ * after active session configuration per device. This means that calls must not
+ * impact the performance of pending camera requests in any way. In
+ * particular there must not be any glitches or delays during normal
+ * camera streaming.
+ *
+ * The framework must not call this method with any combination of camera
+ * ids that is not a subset of the camera ids advertised by getConcurrentStreamingCameraIds of
+ * the same provider.
+ *
+ * Performance requirements:
+ * This call is expected to be significantly faster than stream
+ * configuration. In general HW and SW camera settings must not be
+ * changed and there must not be a user-visible impact on camera performance.
+ *
+ * @param configs a vector of camera ids and their corresponding stream
+ * configurations that need to be queried for support.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On successful stream combination query.
+ * METHOD_NOT_SUPPORTED:
+ * The camera provider does not support stream combination query.
+ * INTERNAL_ERROR:
+ * The stream combination query cannot complete due to internal
+ * error.
+ * @return true in case the stream combination is supported, false otherwise.
+ *
+ *
+ */
+ isConcurrentStreamCombinationSupported(vec<CameraIdAndStreamCombination> configs)
+ generates (Status status, bool queryStatus);
+};
diff --git a/camera/provider/2.6/ICameraProviderCallback.hal b/camera/provider/2.6/ICameraProviderCallback.hal
new file mode 100644
index 0000000000..42c1092676
--- /dev/null
+++ b/camera/provider/2.6/ICameraProviderCallback.hal
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package android.hardware.camera.provider@2.6;
+
+import android.hardware.camera.common@1.0::types;
+import android.hardware.camera.provider@2.4::ICameraProviderCallback;
+
+/**
+ * Callback functions for a camera provider HAL to use to inform the camera
+ * service of changes to the camera subsystem.
+ *
+ * Version 2.6 adds support for physical camera device status callback for
+ * multi-camera.
+ */
+interface ICameraProviderCallback extends @2.4::ICameraProviderCallback {
+
+ /**
+ * cameraPhysicalDeviceStatusChange:
+ *
+ * Callback to the camera service to indicate that the state of a physical
+ * camera device of a logical multi-camera has changed.
+ *
+ * On camera service startup, when ICameraProvider::setCallback is invoked,
+ * the camera service must assume that all physical devices backing internal
+ * multi-camera devices are in the CAMERA_DEVICE_STATUS_PRESENT state.
+ *
+ * The provider must call this method to inform the camera service of any
+ * initially NOT_PRESENT physical devices, as soon as the callbacks are available
+ * through setCallback.
+ *
+ * @param cameraDeviceName The name of the logical multi-camera whose
+ * physical camera has a new status.
+ * @param physicalCameraDeviceName The name of the physical camera device
+ * that has a new status.
+ * @param newStatus The new status that device is in.
+ *
+ */
+ physicalCameraDeviceStatusChange(string cameraDeviceName,
+ string physicalCameraDeviceName, CameraDeviceStatus newStatus);
+};
diff --git a/camera/provider/2.6/types.hal b/camera/provider/2.6/types.hal
new file mode 100644
index 0000000000..24c62aa24d
--- /dev/null
+++ b/camera/provider/2.6/types.hal
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package android.hardware.camera.provider@2.6;
+
+import android.hardware.camera.device@3.4::StreamConfiguration;
+
+/**
+ * CameraIdAndStreamCombination:
+ * Pairs the cameraId and the StreamConfiguration to be
+ * tested with other concurrent camera id and StreamConfigurations
+ */
+struct CameraIdAndStreamCombination {
+ string cameraId;
+
+ @3.4::StreamConfiguration streamConfiguration;
+};
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index 7c7f87f655..6d204cb952 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -115,27 +115,6 @@ LOCAL_MODULE := framework_compatibility_matrix.xml
LOCAL_REQUIRED_MODULES := $(my_framework_matrix_deps)
include $(BUILD_PHONY_PACKAGE)
-# Final Framework Compatibility Matrix for OTA
-include $(CLEAR_VARS)
-include $(LOCAL_PATH)/clear_vars.mk
-LOCAL_MODULE := verified_assembled_system_matrix.xml
-LOCAL_MODULE_PATH := $(PRODUCT_OUT)
-LOCAL_REQUIRED_MODULES := $(my_framework_matrix_deps)
-LOCAL_GENERATED_SOURCES := $(call module-installed-files,$(LOCAL_REQUIRED_MODULES))
-LOCAL_ADD_VBMETA_VERSION_OVERRIDE := true
-
-ifdef BUILT_VENDOR_MANIFEST
-LOCAL_GEN_FILE_DEPENDENCIES += $(BUILT_VENDOR_MANIFEST)
-LOCAL_ASSEMBLE_VINTF_FLAGS += -c "$(BUILT_VENDOR_MANIFEST)"
-endif
-
-ifneq ($(PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS),true)
-LOCAL_ASSEMBLE_VINTF_FLAGS += --no-kernel-requirements
-endif
-
-include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
-BUILT_SYSTEM_MATRIX := $(LOCAL_BUILT_MODULE)
-
my_system_matrix_deps :=
my_framework_matrix_deps :=
my_empty_manifest :=
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 24f114b811..9a8f336ff3 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -9,7 +9,6 @@
</hal>
<hal format="hidl" optional="false">
<name>android.hardware.audio</name>
- <version>5.0</version>
<version>6.0</version>
<interface>
<name>IDevicesFactory</name>
@@ -18,7 +17,6 @@
</hal>
<hal format="hidl" optional="false">
<name>android.hardware.audio.effect</name>
- <version>5.0</version>
<version>6.0</version>
<interface>
<name>IEffectsFactory</name>
@@ -47,6 +45,7 @@
<interface>
<name>IEvsEnumerator</name>
<instance>default</instance>
+ <regex-instance>[a-z]+/[0-9]+</regex-instance>
</interface>
</hal>
<hal format="aidl" optional="true">
@@ -66,7 +65,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.biometrics.face</name>
- <version>1.0</version>
+ <version>1.0-1</version>
<interface>
<name>IBiometricsFace</name>
<instance>default</instance>
@@ -122,7 +121,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.camera.provider</name>
- <version>2.4-5</version>
+ <version>2.4-6</version>
<interface>
<name>ICameraProvider</name>
<regex-instance>[^/]+/[0-9]+</regex-instance>
@@ -174,7 +173,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.dumpstate</name>
- <version>1.0</version>
+ <version>1.1</version>
<interface>
<name>IDumpstateDevice</name>
<instance>default</instance>
@@ -289,6 +288,13 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.light</name>
+ <interface>
+ <name>ILights</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.media.c2</name>
<version>1.0-1</version>
@@ -400,7 +406,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.secure_element</name>
- <version>1.0</version>
+ <version>1.0-2</version>
<interface>
<name>ISecureElement</name>
<regex-instance>eSE[1-9][0-9]*</regex-instance>
@@ -489,14 +495,6 @@
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.vibrator</name>
- <version>1.0-3</version>
- <interface>
- <name>IVibrator</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
<name>android.hardware.vr</name>
<version>1.0</version>
<interface>
diff --git a/current.txt b/current.txt
index 8724170496..3be26c2f74 100644
--- a/current.txt
+++ b/current.txt
@@ -451,9 +451,9 @@ ca15a738dedc2f4981925f7d7ff29c22bc3f8a848403dcf0c592c167de09d9af android.hardwar
443659bb9e27221e5da0d16c7a0ecb2dc3a9a03acc8a0b2196b47c50735e2d2e android.hardware.audio.effect@5.0::IVirtualizerEffect
78fed26a781cdca1b3bcb37520bff705d7764ee81db9cfd37014953c7ad2596e android.hardware.audio.effect@5.0::IVisualizerEffect
6385b6accab8a544e2ee54ba7bf5aa55dff6153bcedd80fdaae16fe9e0be7050 android.hardware.audio.effect@5.0::types
+95aa2f59e29e2f84d8e84320ace9b6682b426a16e897b4bd241375cbee0e07f3 android.hardware.biometrics.face@1.0::types
e18ff318f3fc43db37f554696dc4e551abb9b119bde53950f73e28ce33a97a40 android.hardware.biometrics.face@1.0::IBiometricsFace
b6e55d7795bbafd011fb95a3b6d3954bf66c349e14cf107f3b72032ce3ceb448 android.hardware.biometrics.face@1.0::IBiometricsFaceClientCallback
-95aa2f59e29e2f84d8e84320ace9b6682b426a16e897b4bd241375cbee0e07f3 android.hardware.biometrics.face@1.0::types
ecedc58dbcdb13503c19c0ab160ac1dd0530bb1471164149282dd1463c684185 android.hardware.bluetooth.audio@2.0::IBluetoothAudioPort
fb9c40e4deab40be5476477078fe3d8a4a4495fd9deef4321878d169d675c633 android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvider
f7431f3e3e4e3387fc6f27a6cf423eddcd824a395dc4349d302c995ab44a9895 android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory
@@ -587,6 +587,9 @@ d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardwar
2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types
cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types
a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types
+9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback
+bceee81ec1b59324abd05932b5620fda5a6589597c9cb3953ba7f3ea02cccd3e android.hardware.camera.provider@2.4::ICameraProvider
+2ce820dc4f3c6d85721b65150ed2157c6e2e2055f866fb6c6ba4790f14408d66 android.hardware.camera.provider@2.4::ICameraProviderCallback
b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
8eac60e1f724d141c71c69f06d4544acb720a55dfbbcd97fa01bb3d25ee4e2f5 android.hardware.neuralnetworks@1.0::types
@@ -597,6 +600,8 @@ fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardwar
a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types
1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
+ff5dd821c2c7a9c78607159c4d788960b725487263c49d956ca5fa3d37008b45 android.hardware.wifi@1.2::IWifiStaIface
+5751f230e86a36111e7c5b995577cbf89d8df76c8e6c7641199198f3db3a93f7 android.hardware.wifi@1.3::IWifiStaIface
# HALs released in Android R
e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types
@@ -623,21 +628,32 @@ dd377f404a8e71f6191d295e10067db629b0f0c28e594af906f2bea5d87fe2cc android.hardwar
5237c42d3913ef569f07bec802568084b615155d05a7951e75085da54856508c android.hardware.audio.effect@6.0::IPresetReverbEffect
282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect
0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect
+7e8e1c3d0173c5d503dd01cecff8e3864478557ca6b9e8cc2291598b1a4aea62 android.hardware.biometrics.face@1.1::IBiometricsFace
+ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types
+6828bbf18dc5d0f00c73341a10c8e4d574346c1abb1c2ed682ba5e9f8a3240d9 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint
+82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback
79e115c8f8970b8b914bafc66df5425e065fda4dcda97222966ef12451d2a1cc android.hardware.bluetooth@1.1::IBluetoothHci
40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks
07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
+e88840e0558439cb54837514ddccd43877094951758f367e9c638084eb7455a6 android.hardware.camera.provider@2.6::ICameraProvider
+8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback
c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas
9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener
f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService
4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types
66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory
994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory
-3dacec7801968e1e4479724dc0180442d9e915466bff051f80996266b1a51c2c android.hardware.gnss@2.1::IGnss
+881aa8720fb1d69aa9843bfab69d810ab7654a61d2f5ab5e2626cbf240f24eaf android.hardware.dumpstate@1.1::types
+13b33f623521ded51a6c0f7ea5b77e97066d0aa1e38a83c2873f08ad67294f89 android.hardware.dumpstate@1.1::IDumpstateDevice
+769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types
+88371e0edf69a1f72bfc45ecb2335e9b145e87339d3eecc92664a1fb200213ba android.hardware.gnss@2.1::IGnss
ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback
ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration
5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement
-0bfb291708dd4a7c6ec6b9883e2b8592357edde8d7e962ef83918e4a2154ce69 android.hardware.gnss@2.1::IGnssMeasurementCallback
+d7bf37660a0946de9599dcbae997b077ee3e604fc2044534d40d3da04297a5d3 android.hardware.gnss@2.1::IGnssMeasurementCallback
+6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections
+a3f439b782a6a92aaf3c0250f3526e94e8bf8844c3d578f0815e21b12c431346 android.hardware.gnss.measurement_corrections@1.1::types
ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types
@@ -647,15 +663,16 @@ bbeee9604128ede83ee755b67e73b5ad29e6e1dbac9ec41fea6ffe2745b0c50a android.hardwar
6e1e28a96c90ba78d47257faea3f3bb4e6360affbbfa5822f0dc31211f9266ff android.hardware.identity@1.0::IWritableIdentityCredential
27ae3724053940462114228872b3ffaf0b8e6177d5ba97f5a76339d12b8a99dd android.hardware.keymaster@4.1::IKeymasterDevice
adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation
-ac429fca0da4ce91218768ec31b64ded88251f8a26d8c4f27c06abdc5b1926d9 android.hardware.keymaster@4.1::types
+ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardware.keymaster@4.1::types
df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer
d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardware.neuralnetworks@1.3::IDevice
4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback
-7d23020248194abbee8091cc624f39a5a6d7ccba338b172d5d2d3df0cceffbee android.hardware.neuralnetworks@1.3::IPreparedModel
+2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
+237b23b126a66f3432658020fed78cdd06ba6297459436fe6bae0ba753370833 android.hardware.neuralnetworks@1.3::IPreparedModel
0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-ee65638f8af3f9f4f222e7208eaa9f1f8e7f8e0a21545846ba67d0e27624efa1 android.hardware.neuralnetworks@1.3::types
+3646950b10f7cacdafca13609b0e18496cea942f3bdfe920494661856eff48bb android.hardware.neuralnetworks@1.3::types
3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types
@@ -664,20 +681,14 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar
def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
62cf050c593c1ec34b49178b5bdde72dd9b80d9bad3eb184e4f0cd564d28678c android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types
-##
-# BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present
-##
-616456d7ce4435d88995f9fe0025a76bca14bd70799e4ca3ff4bae74d54d1166 android.hardware.radio@1.5::types
-c68f5bd87f747f8e7968ff66ecc548b2d26f8e186b7bb805c11d6c883a838fc6 android.hardware.radio@1.5::IRadio
+88fb40d98b89cfaafad33b06c95e5dcd51c4470962e8fbe80ed22884407f98a1 android.hardware.radio@1.5::types
+8062d0a1a03594dd8b448adcf6f08856b5720f7e33f9b785a21d3ef74a4f211d android.hardware.radio@1.5::IRadio
e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication
-9e962eff568dc8c712d83846f8c27460de5005ed9b836d3e08390e8aa56b5a46 android.hardware.radio@1.5::IRadioResponse
-5971a891d7d8843e9fb9f44583a9a0a265ec42fd5e4e1c95c9803454d21fabf7 android.hardware.radio.config@1.3::types
+7f2439b48bda2961c6d629d0415eee66d519142cf9537f05e9d285153c70ca85 android.hardware.radio@1.5::IRadioResponse
+dcc8872337f0135e81970e1d8d5fd7139160dc80e9be76f0ae05290fa7e472b8 android.hardware.radio.config@1.3::types
a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig
742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse
-##
-# END Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present
-##
-51d1c8d285e0456da2a3fdfbf4700c6277165d5e83219894d651c8ea0e39aa8b android.hardware.soundtrigger@2.3::types
+4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types
12d7533ff0754f45bf59ab300799074570a99a676545652c2c23abc73cb4515d android.hardware.soundtrigger@2.3::ISoundTriggerHw
7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget
diff --git a/drm/1.0/default/OWNERS b/drm/1.0/default/OWNERS
new file mode 100644
index 0000000000..ecb421cc1f
--- /dev/null
+++ b/drm/1.0/default/OWNERS
@@ -0,0 +1,6 @@
+edwinwong@google.com
+fredgc@google.com
+jtinker@google.com
+kylealexander@google.com
+rfrias@google.com
+robertshih@google.com
diff --git a/drm/1.0/vts/OWNERS b/drm/1.0/vts/OWNERS
new file mode 100644
index 0000000000..ecb421cc1f
--- /dev/null
+++ b/drm/1.0/vts/OWNERS
@@ -0,0 +1,6 @@
+edwinwong@google.com
+fredgc@google.com
+jtinker@google.com
+kylealexander@google.com
+rfrias@google.com
+robertshih@google.com
diff --git a/drm/1.0/vts/functional/Android.bp b/drm/1.0/vts/functional/Android.bp
index 4fbd54df50..235bfb406f 100644
--- a/drm/1.0/vts/functional/Android.bp
+++ b/drm/1.0/vts/functional/Android.bp
@@ -14,23 +14,75 @@
// limitations under the License.
//
-cc_test {
- name: "VtsHalDrmV1_0TargetTest",
+cc_library_static {
+ name: "libdrmvtshelper",
defaults: ["VtsHalTargetTestDefaults"],
+ local_include_dirs: [
+ "include",
+ ],
srcs: [
- "drm_hal_clearkey_test.cpp",
- "drm_hal_vendor_test.cpp",
"vendor_modules.cpp",
],
static_libs: [
+ "android.hardware.drm@1.0-helper",
+ ],
+ export_include_dirs: ["include"],
+}
+
+cc_library_static {
+ name: "android.hardware.drm@1.0-vts",
+ defaults: ["VtsHalTargetTestDefaults"],
+ local_include_dirs: [
+ "include",
+ ],
+ srcs: [
+ "drm_hal_clearkey_test.cpp",
+ "drm_hal_vendor_test.cpp",
+ ],
+ shared_libs: [
"android.hardware.drm@1.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlmemory",
+ "libnativehelper",
+ ],
+ static_libs: [
"android.hardware.drm@1.0-helper",
+ "libcrypto_static",
+ "libdrmvtshelper",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.drm@1.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlmemory",
+ "libnativehelper",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+}
+
+cc_test {
+ name: "VtsHalDrmV1_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "drm_hal_test_main.cpp",
+ ],
+ whole_static_libs: [
+ "android.hardware.drm@1.0-vts",
+ ],
+ shared_libs: [
+ "android.hardware.drm@1.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libhidlmemory",
"libnativehelper",
- "libssl",
+ ],
+ static_libs: [
+ "android.hardware.drm@1.0-helper",
"libcrypto_static",
+ "libdrmvtshelper",
],
test_suites: [
"general-tests",
diff --git a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
index 5713d2ef16..ebdc2d7350 100644
--- a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
+++ b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
@@ -16,127 +16,26 @@
#define LOG_TAG "drm_hal_clearkey_test@1.0"
-#include <android/hardware/drm/1.0/ICryptoFactory.h>
-#include <android/hardware/drm/1.0/ICryptoPlugin.h>
-#include <android/hardware/drm/1.0/IDrmFactory.h>
-#include <android/hardware/drm/1.0/IDrmPlugin.h>
-#include <android/hardware/drm/1.0/types.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/ServiceManagement.h>
-#include <hidlmemory/mapping.h>
-#include <log/log.h>
#include <openssl/aes.h>
-#include <memory>
#include <random>
-using ::android::hardware::drm::V1_0::BufferType;
-using ::android::hardware::drm::V1_0::DestinationBuffer;
-using ::android::hardware::drm::V1_0::ICryptoFactory;
-using ::android::hardware::drm::V1_0::ICryptoPlugin;
-using ::android::hardware::drm::V1_0::IDrmFactory;
-using ::android::hardware::drm::V1_0::IDrmPlugin;
-using ::android::hardware::drm::V1_0::KeyedVector;
-using ::android::hardware::drm::V1_0::KeyValue;
-using ::android::hardware::drm::V1_0::KeyRequestType;
-using ::android::hardware::drm::V1_0::KeyType;
-using ::android::hardware::drm::V1_0::Mode;
-using ::android::hardware::drm::V1_0::Pattern;
-using ::android::hardware::drm::V1_0::SecureStop;
-using ::android::hardware::drm::V1_0::SecureStopId;
-using ::android::hardware::drm::V1_0::SessionId;
-using ::android::hardware::drm::V1_0::SharedBuffer;
-using ::android::hardware::drm::V1_0::Status;
-using ::android::hardware::drm::V1_0::SubSample;
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
+#include "android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h"
using std::string;
-using std::unique_ptr;
using std::random_device;
using std::map;
using std::mt19937;
using std::vector;
-/**
- * These clearkey tests use white box knowledge of the legacy clearkey
- * plugin to verify that the HIDL HAL services and interfaces are working.
- * It is not intended to verify any vendor's HAL implementation. If you
- * are looking for vendor HAL tests, see drm_hal_vendor_test.cpp
- */
-#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
-#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
-
-static const uint8_t kCommonPsshBoxUUID[16] = {
- 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02,
- 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B};
-
-// To be used in mpd to specify drm scheme for players
-static const uint8_t kClearKeyUUID[16] = {
- 0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
- 0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E};
-
static const uint8_t kInvalidUUID[16] = {
0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
-class DrmHalClearkeyFactoryTest : public ::testing::TestWithParam<std::string> {
- public:
- void SetUp() override {
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
- ALOGD("Running test %s.%s", test_info->test_case_name(),
- test_info->name());
-
- const std::string instanceName = GetParam();
- drmFactory = IDrmFactory::getService(instanceName);
- ASSERT_NE(nullptr, drmFactory.get());
- cryptoFactory = ICryptoFactory::getService(instanceName);
- ASSERT_NE(nullptr, cryptoFactory.get());
-
- const bool drmClearKey = drmFactory->isCryptoSchemeSupported(kClearKeyUUID);
- const bool cryptoClearKey = cryptoFactory->isCryptoSchemeSupported(kClearKeyUUID);
- EXPECT_EQ(drmClearKey, cryptoClearKey);
- const bool supportsClearKey = drmClearKey && cryptoClearKey;
-
- const bool drmCommonPsshBox = drmFactory->isCryptoSchemeSupported(kCommonPsshBoxUUID);
- const bool cryptoCommonPsshBox = cryptoFactory->isCryptoSchemeSupported(kCommonPsshBoxUUID);
- EXPECT_EQ(drmCommonPsshBox, cryptoCommonPsshBox);
- const bool supportsCommonPsshBox = drmCommonPsshBox && cryptoCommonPsshBox;
-
- EXPECT_EQ(supportsClearKey, supportsCommonPsshBox);
- correspondsToThisTest = supportsClearKey && supportsCommonPsshBox;
-
- if (instanceName == "clearkey") {
- EXPECT_TRUE(correspondsToThisTest);
-
- // TODO(b/147449315)
- // Only the clearkey plugged into the "default" instance supports
- // this test. Currently the "clearkey" instance fails some tests
- // here.
- GTEST_SKIP() << "Clearkey tests don't work with 'clearkey' instance yet.";
- }
-
- if (!correspondsToThisTest) {
- GTEST_SKIP() << "Cannot test clearkey features on non-clearkey DRM modules";
- }
- }
-
- protected:
- sp<IDrmFactory> drmFactory;
- sp<ICryptoFactory> cryptoFactory;
-
- bool correspondsToThisTest;
-};
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace vts {
/**
* Ensure the factory doesn't support an invalid scheme UUID
@@ -264,48 +163,6 @@ TEST_P(DrmHalClearkeyFactoryTest, CreateInvalidCryptoPlugin) {
EXPECT_OK(res);
}
-class DrmHalClearkeyPluginTest : public DrmHalClearkeyFactoryTest {
- public:
- virtual void SetUp() override {
- // Create factories
- DrmHalClearkeyFactoryTest::SetUp();
-
- if (!correspondsToThisTest) {
- GTEST_SKIP() << "Cannot test clearkey features on non-clearkey DRM modules";
- }
-
- ASSERT_NE(nullptr, drmFactory.get());
- hidl_string packageName("android.hardware.drm.test");
- auto res = drmFactory->createPlugin(
- kClearKeyUUID, packageName,
- [this](Status status, const sp<IDrmPlugin>& plugin) {
- EXPECT_EQ(Status::OK, status);
- ASSERT_NE(nullptr, plugin.get());
- drmPlugin = plugin;
- });
- ASSERT_OK(res);
-
- hidl_vec<uint8_t> initVec;
- res = cryptoFactory->createPlugin(
- kClearKeyUUID, initVec,
- [this](Status status, const sp<ICryptoPlugin>& plugin) {
- EXPECT_EQ(Status::OK, status);
- ASSERT_NE(nullptr, plugin.get());
- cryptoPlugin = plugin;
- });
- ASSERT_OK(res);
- }
-
- SessionId openSession();
- void closeSession(const SessionId& sessionId);
- hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
- sp<IMemory> getDecryptMemory(size_t size, size_t index);
-
- protected:
- sp<IDrmPlugin> drmPlugin;
- sp<ICryptoPlugin> cryptoPlugin;
-};
-
/**
* DrmPlugin tests
*/
@@ -966,30 +823,6 @@ TEST_P(DrmHalClearkeyPluginTest, SetMediaDrmSessionEmptySession) {
* Decrypt tests
*/
-class DrmHalClearkeyDecryptTest : public DrmHalClearkeyPluginTest {
- public:
- void SetUp() override {
- DrmHalClearkeyPluginTest::SetUp();
-
- if (!correspondsToThisTest) {
- GTEST_SKIP() << "Cannot test clearkey features on non-clearkey DRM modules";
- }
- }
- void fillRandom(const sp<IMemory>& memory);
- hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
- EXPECT_EQ(16u, vec.size());
- return hidl_array<uint8_t, 16>(&vec[0]);
- }
- uint32_t decrypt(Mode mode, uint8_t* iv, const hidl_vec<SubSample>& subSamples,
- const Pattern& pattern, Status status);
- void aes_ctr_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
- const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
- void aes_cbc_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
- const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
- void decryptWithInvalidKeys(hidl_vec<uint8_t>& invalidResponse,
- vector<uint8_t>& iv, const Pattern& noPattern, const vector<SubSample>& subSamples);
-};
-
void DrmHalClearkeyDecryptTest::fillRandom(const sp<IMemory>& memory) {
random_device rd;
mt19937 rand(rd());
@@ -1300,20 +1133,8 @@ TEST_P(DrmHalClearkeyDecryptTest, DecryptWithKeyTooLong) {
decryptWithInvalidKeys(invalidResponse, iv, noPattern, subSamples);
}
-static const std::set<std::string> kAllInstances = [] {
- std::vector<std::string> drmInstances =
- android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
- std::vector<std::string> cryptoInstances =
- android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
- std::set<std::string> allInstances;
- allInstances.insert(drmInstances.begin(), drmInstances.end());
- allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
- return allInstances;
-}();
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyFactoryTest, testing::ValuesIn(kAllInstances),
- android::hardware::PrintInstanceNameToString);
-INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyPluginTest, testing::ValuesIn(kAllInstances),
- android::hardware::PrintInstanceNameToString);
-INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyDecryptTest, testing::ValuesIn(kAllInstances),
- android::hardware::PrintInstanceNameToString);
+} // namespace vts
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/1.0/vts/functional/drm_hal_test_main.cpp b/drm/1.0/vts/functional/drm_hal_test_main.cpp
new file mode 100644
index 0000000000..fd2538b051
--- /dev/null
+++ b/drm/1.0/vts/functional/drm_hal_test_main.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "drm_hal_vendor_test@1.0"
+
+#include "vendor_modules.h"
+#include "android/hardware/drm/1.0/vts/drm_hal_vendor_test.h"
+#include "android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h"
+
+using ::android::hardware::drm::V1_0::ICryptoFactory;
+using ::android::hardware::drm::V1_0::IDrmFactory;
+
+using ::android::hardware::drm::V1_0::vts::DrmHalClearkeyFactoryTest;
+using ::android::hardware::drm::V1_0::vts::DrmHalClearkeyPluginTest;
+using ::android::hardware::drm::V1_0::vts::DrmHalClearkeyDecryptTest;
+
+using ::android::hardware::drm::V1_0::vts::DrmHalVendorFactoryTest;
+using ::android::hardware::drm::V1_0::vts::DrmHalVendorPluginTest;
+using ::android::hardware::drm::V1_0::vts::DrmHalVendorDecryptTest;
+
+/**
+ * Instantiate the set of test cases for each vendor module
+ */
+
+static const std::vector<DrmHalTestParam> kAllInstances = [] {
+ std::vector<std::string> drmInstances =
+ android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
+ std::vector<std::string> cryptoInstances =
+ android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
+ std::set<std::string> allInstances;
+ allInstances.insert(drmInstances.begin(), drmInstances.end());
+ allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
+
+ std::vector<DrmHalTestParam> allInstanceUuidCombos;
+ auto noUUID = [](std::string s) { return DrmHalTestParam(s); };
+ std::transform(allInstances.begin(), allInstances.end(),
+ std::back_inserter(allInstanceUuidCombos), noUUID);
+ return allInstanceUuidCombos;
+}();
+
+INSTANTIATE_TEST_CASE_P(DrmHalVendorFactoryTestCases, DrmHalVendorFactoryTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_CASE_P(DrmHalVendorPluginTestCases, DrmHalVendorPluginTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_CASE_P(DrmHalVendorDecryptTestCases, DrmHalVendorDecryptTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyFactoryTest, testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyPluginTest, testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyDecryptTest, testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
diff --git a/drm/1.0/vts/functional/drm_hal_vendor_module_api.h b/drm/1.0/vts/functional/drm_hal_vendor_module_api.h
index b8b205265d..a8b5ade31c 100644..120000
--- a/drm/1.0/vts/functional/drm_hal_vendor_module_api.h
+++ b/drm/1.0/vts/functional/drm_hal_vendor_module_api.h
@@ -1,234 +1 @@
-/*
- * 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 DRM_HAL_VENDOR_MODULE_API_H
-#define DRM_HAL_VENDOR_MODULE_API_H
-
-#include <stdint.h>
-#include <map>
-#include <string>
-#include <vector>
-
-/**
- * The DRM and Crypto HALs interact with vendor-provided HAL implementations
- * that have DRM-specific capabilities. Since the VTS tests cannot contain
- * DRM-specific functionality, supporting modules are required to enable VTS
- * to validate HAL implementations in a generic way. If the vendor-specific
- * VTS module is not provided for a given drm HAL implementation, only very
- * small subset of functionality can be verified.
- *
- * As an example, a DRM HAL implementation interacts with a DRM-specific
- * license server to obtain licenses for decrypting content. The DRM HAL
- * implementation generates a key request message, delivers it to the server
- * and receives a key response message which is then loaded into the HAL. Once
- * the keys are loaded, the Crypto HAL decryption functionality and performance
- * and other associated APIs can be tested by the common VTS test suite.
- *
- * Vendor-specific VTS modules are shared libraries used by the DRM VTS test.
- * They provide a set of functions to support VTS testing of the DRM HAL module.
- *
- * The modules are placed in a common location on the file system. The VTS test
- * scans through all vendor-provided support libraries and runs the VTS test
- * suite on each library that is found.
- *
- * The vendor-specific module exposes an extern “C” vendorModuleFactory()
- * function that returns a DrmHalVTSVendorModule instance. DrmHalVTSVendorModule
- * instances are versioned, where each version is represented by subclass of
- * DrmHalVTSVendorModule that corresponds to the API version. For example, a
- * vendor-specific module that implements version 1 of the API would return a
- * DrmHalVTSVendorModule_V1 from the vendorModuleFactory() function.
- */
-
-class DrmHalVTSVendorModule;
-
-extern "C" {
-/**
- * The factory method for creating DrmHalVTSVendorModule instances. The returned
- * instance will be a subclass of DrmHalVTSVendorModule that corresponds to the
- * supported API version.
- */
-DrmHalVTSVendorModule* vendorModuleFactory();
-};
-
-class DrmHalVTSVendorModule {
- public:
- DrmHalVTSVendorModule() : installed(true) {}
- virtual ~DrmHalVTSVendorModule() {}
-
- /**
- * Return the vendor-specific module API version. The version is an integer
- * value with initial version 1. The API version indicates which subclass
- * version DrmHalVTSVendorModule this instance is.
- */
- virtual uint32_t getAPIVersion() const = 0;
-
- /**
- * Return the UUID for the DRM HAL implementation. Protection System
- * Specific
- * UUID (see http://dashif.org/identifiers/protection/)
- */
- virtual std::vector<uint8_t> getUUID() const = 0;
-
- /**
- * Return the service name for the DRM HAL implementation. If the hal is a
- * legacy
- * drm plugin, i.e. not running as a HIDL service, return the empty string.
- */
- virtual std::string getServiceName() const = 0;
-
- /**
- * Set a flag in the vendor module to indicate whether or not the drm
- * scheme corresponding to this module is installed on the device.
- */
- void setInstalled(bool flag) {installed = flag;}
- bool isInstalled() const {return installed;}
-
- private:
- bool installed;
- DrmHalVTSVendorModule(const DrmHalVTSVendorModule&) = delete;
- void operator=(const DrmHalVTSVendorModule&) = delete;
-};
-
-/**
- * API Version 1. This is the baseline version that supports a minimal set
- * of VTS tests.
- */
-class DrmHalVTSVendorModule_V1 : public DrmHalVTSVendorModule {
- public:
- DrmHalVTSVendorModule_V1() {}
- virtual ~DrmHalVTSVendorModule_V1() {}
-
- virtual uint32_t getAPIVersion() const { return 1; }
-
- /**
- * Handle a provisioning request. This function will be called if the HAL
- * module's getProvisionRequest returns a provision request. The vendor
- * module should process the provisioning request, either by sending it
- * to a provisioning server, or generating a mock response. The resulting
- * provisioning response is returned to the VTS test.
- *
- * @param provisioningRequest the provisioning request recieved from
- * the DRM HAL
- * @param url the default url the HAL implementation provided with the
- * provisioning request
- * @return the generated provisioning response
- */
- virtual std::vector<uint8_t> handleProvisioningRequest(
- const std::vector<uint8_t>& provisioningRequest,
- const std::string& url) = 0;
-
- /**
- * Content configuration specifies content-specific parameters associated
- * with a key request/response transaction. It allows the VTS test to
- * request keys and use them to perform decryption.
- */
- struct ContentConfiguration {
- /**
- * Assign a name for this configuration that will be referred to
- * in log messages.
- */
- const std::string name;
-
- /**
- * Server to use when requesting a key response. This url will be
- * passed as a parameter to the vendor vts module along with the
- * key request to perform the key request transaction.
- */
- const std::string serverUrl;
-
- /**
- * Initialization data provided to getKeyRequest, e.g. PSSH for CENC
- * content
- */
- const std::vector<uint8_t> initData;
-
- /**
- * Mime type provided to getKeyRequest, e.g. "video/mp4", or "cenc"
- */
- const std::string mimeType;
-
- /**
- * Optional parameters to be associated with the key request
- */
- const std::map<std::string, std::string> optionalParameters;
-
- /**
- * Define license policy attributes for the content configuration.
- * These attributes can affect which tests are able to be applied.
- */
- struct Policy {
- /**
- * Indicate if the license policy allows offline playback.
- * Content configurated with this policy supports KeyType::OFFLINE
- * key requests/responses. A vendor module should provide at least
- * one content configuration where allowOffline is true if the drm
- * scheme supports offline content.
- */
- bool allowOffline;
- } policy;
-
- /**
- * The keys that will be available once the keys are loaded
- */
- struct Key {
- /**
- * Indicate if the key content is configured to require secure
- * buffers, where the output buffers are protected and cannot be
- * accessed by the non-secure cpu. A vendor module should provide
- * at least one content configurations where isSecure is false, to
- * allow decrypt result verification tests to be run.
- */
- bool isSecure;
-
- /**
- * A key ID identifies a key to use for decryption
- */
- const std::vector<uint8_t> keyId;
-
- /**
- * The clear content key is provided to generate expected values for
- * validating decryption.
- */
- const std::vector<uint8_t> clearContentKey;
- };
- std::vector<Key> keys;
- };
-
- /**
- * Return a list of content configurations that can be exercised by the
- * VTS test.
- */
- virtual std::vector<ContentConfiguration>
- getContentConfigurations() const = 0;
-
- /**
- * Handle a key request. This function will be called if the HAL
- * module's getKeyRequest returns a key request. The vendor
- * module should process the key request, either by sending it
- * to a license server, or by generating a mock response. The resulting
- * key response is returned to the VTS test.
- *
- * @param keyRequest the key request recieved from the DRM HAL
- * @param serverUrl the url of the key server that was supplied
- * by the ContentConfiguration
- * @return the generated key response
- */
- virtual std::vector<uint8_t> handleKeyRequest(
- const std::vector<uint8_t>& keyRequest,
- const std::string& serverUrl) = 0;
-};
-
-#endif // DRM_HAL_VENDOR_MODULE_API_H
+include/drm_hal_vendor_module_api.h \ No newline at end of file
diff --git a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
index 2259985712..5c6c98b32f 100644
--- a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
+++ b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
@@ -16,138 +16,46 @@
#define LOG_TAG "drm_hal_vendor_test@1.0"
-#include <android/hardware/drm/1.0/ICryptoFactory.h>
-#include <android/hardware/drm/1.0/ICryptoPlugin.h>
-#include <android/hardware/drm/1.0/IDrmFactory.h>
-#include <android/hardware/drm/1.0/IDrmPlugin.h>
-#include <android/hardware/drm/1.0/IDrmPluginListener.h>
-#include <android/hardware/drm/1.0/types.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/ServiceManagement.h>
-#include <hidlmemory/mapping.h>
-#include <log/log.h>
#include <openssl/aes.h>
-#include <memory>
#include <random>
#include "drm_hal_vendor_module_api.h"
#include "vendor_modules.h"
#include <VtsHalHidlTargetCallbackBase.h>
-using ::android::hardware::drm::V1_0::BufferType;
-using ::android::hardware::drm::V1_0::DestinationBuffer;
-using ::android::hardware::drm::V1_0::EventType;
-using ::android::hardware::drm::V1_0::ICryptoFactory;
-using ::android::hardware::drm::V1_0::ICryptoPlugin;
-using ::android::hardware::drm::V1_0::IDrmFactory;
-using ::android::hardware::drm::V1_0::IDrmPlugin;
-using ::android::hardware::drm::V1_0::IDrmPluginListener;
-using ::android::hardware::drm::V1_0::KeyedVector;
-using ::android::hardware::drm::V1_0::KeyRequestType;
-using ::android::hardware::drm::V1_0::KeyStatus;
-using ::android::hardware::drm::V1_0::KeyStatusType;
-using ::android::hardware::drm::V1_0::KeyType;
-using ::android::hardware::drm::V1_0::KeyValue;
-using ::android::hardware::drm::V1_0::Mode;
-using ::android::hardware::drm::V1_0::Pattern;
-using ::android::hardware::drm::V1_0::SecureStop;
-using ::android::hardware::drm::V1_0::SecureStopId;
-using ::android::hardware::drm::V1_0::SessionId;
-using ::android::hardware::drm::V1_0::SharedBuffer;
-using ::android::hardware::drm::V1_0::Status;
-using ::android::hardware::drm::V1_0::SubSample;
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
-using std::string;
-using std::unique_ptr;
+#include "android/hardware/drm/1.0/vts/drm_hal_vendor_test.h"
+
using std::random_device;
-using std::map;
using std::mt19937;
-using std::vector;
-
-using ContentConfiguration = ::DrmHalVTSVendorModule_V1::ContentConfiguration;
-using Key = ::DrmHalVTSVendorModule_V1::ContentConfiguration::Key;
-
-#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
-#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
-
-#define RETURN_IF_SKIPPED \
- if (vendorModule == nullptr || !vendorModule->isInstalled()) { \
- GTEST_SKIP() << "This drm scheme not supported." \
- << " library:" << GetParam() << " service-name:" \
- << (vendorModule == nullptr ? "N/A" : vendorModule->getServiceName()) \
- << std::endl; \
- return; \
- }
static const uint8_t kInvalidUUID[16] = {
0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
};
-static drm_vts::VendorModules* gVendorModules = nullptr;
-
-class DrmHalVendorFactoryTest : public testing::TestWithParam<std::string> {
- public:
- DrmHalVendorFactoryTest()
- : vendorModule(
- static_cast<DrmHalVTSVendorModule_V1*>(gVendorModules->getModule(GetParam()))) {}
-
- virtual ~DrmHalVendorFactoryTest() {}
-
- virtual void SetUp() {
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
- ALOGD("Running test %s.%s from vendor module %s", test_info->test_case_name(),
- test_info->name(), GetParam().c_str());
-
- const std::string instance = GetParam();
- if (instance == "widevine") {
- ASSERT_NE(nullptr, vendorModule.get());
- }
-
- if (vendorModule == nullptr) {
- GTEST_SKIP() << "No vendor module available";
- } else {
- ASSERT_EQ(instance, vendorModule->getServiceName());
- contentConfigurations = vendorModule->getContentConfigurations();
- }
-
- drmFactory = IDrmFactory::getService(instance);
- ASSERT_NE(nullptr, drmFactory.get());
- cryptoFactory = ICryptoFactory::getService(instance);
- ASSERT_NE(nullptr, cryptoFactory.get());
-
- // If drm scheme not installed skip subsequent tests
- if (!drmFactory->isCryptoSchemeSupported(getVendorUUID())) {
- // no GTEST_SKIP since only some tests require the module
- vendorModule->setInstalled(false);
- }
- }
-
- protected:
- hidl_array<uint8_t, 16> getVendorUUID() {
- if (vendorModule == nullptr) return {};
- vector<uint8_t> uuid = vendorModule->getUUID();
- return hidl_array<uint8_t, 16>(&uuid[0]);
+static drm_vts::VendorModules* gVendorModules = [] {
+#if defined(__LP64__)
+ const char* kModulePath = "/data/local/tmp/64/lib";
+#else
+ const char* kModulePath = "/data/local/tmp/32/lib";
+#endif
+ auto modules = new drm_vts::VendorModules(kModulePath);
+ if (modules->getPathList().size() == 0) {
+ std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
+ ", all vendor tests will be skipped" << std::endl;
}
+ return modules;
+}();
- sp<IDrmFactory> drmFactory;
- sp<ICryptoFactory> cryptoFactory;
- unique_ptr<DrmHalVTSVendorModule_V1> vendorModule;
- vector<ContentConfiguration> contentConfigurations;
-};
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace vts {
+
+DrmHalVendorFactoryTest::DrmHalVendorFactoryTest()
+ : vendorModule(static_cast<DrmHalVTSVendorModule_V1*>(
+ gVendorModules->getModuleByName(GetParam().instance_))) {} // getModuleByName
TEST_P(DrmHalVendorFactoryTest, ValidateConfigurations) {
const char* kVendorStr = "Vendor module ";
@@ -195,8 +103,8 @@ TEST_P(DrmHalVendorFactoryTest, EmptyPluginUUIDNotSupported) {
*/
TEST_P(DrmHalVendorFactoryTest, PluginConfigUUIDSupported) {
RETURN_IF_SKIPPED;
- EXPECT_TRUE(drmFactory->isCryptoSchemeSupported(getVendorUUID()));
- EXPECT_TRUE(cryptoFactory->isCryptoSchemeSupported(getVendorUUID()));
+ EXPECT_TRUE(drmFactory->isCryptoSchemeSupported(getUUID()));
+ EXPECT_TRUE(cryptoFactory->isCryptoSchemeSupported(getUUID()));
}
/**
@@ -232,7 +140,7 @@ TEST_P(DrmHalVendorFactoryTest, CreateVendorDrmPlugin) {
RETURN_IF_SKIPPED;
hidl_string packageName("android.hardware.drm.test");
auto res = drmFactory->createPlugin(
- getVendorUUID(), packageName,
+ getUUID(), packageName,
[&](Status status, const sp<IDrmPlugin>& plugin) {
EXPECT_EQ(Status::OK, status);
EXPECT_NE(nullptr, plugin.get());
@@ -247,7 +155,7 @@ TEST_P(DrmHalVendorFactoryTest, CreateVendorCryptoPlugin) {
RETURN_IF_SKIPPED;
hidl_vec<uint8_t> initVec;
auto res = cryptoFactory->createPlugin(
- getVendorUUID(), initVec,
+ getUUID(), initVec,
[&](Status status, const sp<ICryptoPlugin>& plugin) {
EXPECT_EQ(Status::OK, status);
EXPECT_NE(nullptr, plugin.get());
@@ -285,50 +193,6 @@ TEST_P(DrmHalVendorFactoryTest, CreateInvalidCryptoPlugin) {
EXPECT_OK(res);
}
-class DrmHalVendorPluginTest : public DrmHalVendorFactoryTest {
- public:
- virtual ~DrmHalVendorPluginTest() {}
- virtual void SetUp() override {
- // Create factories
- DrmHalVendorFactoryTest::SetUp();
- RETURN_IF_SKIPPED;
-
- hidl_string packageName("android.hardware.drm.test");
- auto res = drmFactory->createPlugin(
- getVendorUUID(), packageName,
- [this](Status status, const sp<IDrmPlugin>& plugin) {
- EXPECT_EQ(Status::OK, status);
- ASSERT_NE(nullptr, plugin.get());
- drmPlugin = plugin;
- });
- ASSERT_OK(res);
-
- hidl_vec<uint8_t> initVec;
- res = cryptoFactory->createPlugin(
- getVendorUUID(), initVec,
- [this](Status status, const sp<ICryptoPlugin>& plugin) {
- EXPECT_EQ(Status::OK, status);
- ASSERT_NE(nullptr, plugin.get());
- cryptoPlugin = plugin;
- });
- ASSERT_OK(res);
- }
-
- virtual void TearDown() override {}
-
- SessionId openSession();
- void closeSession(const SessionId& sessionId);
- sp<IMemory> getDecryptMemory(size_t size, size_t index);
- KeyedVector toHidlKeyedVector(const map<string, string>& params);
- hidl_vec<uint8_t> loadKeys(const SessionId& sessionId,
- const ContentConfiguration& configuration,
- const KeyType& type);
-
- protected:
- sp<IDrmPlugin> drmPlugin;
- sp<ICryptoPlugin> cryptoPlugin;
-};
-
/**
* DrmPlugin tests
*/
@@ -1193,7 +1057,7 @@ sp<IMemory> DrmHalVendorPluginTest::getDecryptMemory(size_t size,
EXPECT_OK(res);
- sp<IMemory> mappedMemory = mapMemory(hidlMemory);
+ sp<IMemory> mappedMemory = android::hardware::mapMemory(hidlMemory);
EXPECT_NE(nullptr, mappedMemory.get());
res = cryptoPlugin->setSharedBufferBase(hidlMemory, index);
EXPECT_OK(res);
@@ -1237,29 +1101,6 @@ TEST_P(DrmHalVendorPluginTest, SetMediaDrmSessionEmptySession) {
* Decrypt tests
*/
-class DrmHalVendorDecryptTest : public DrmHalVendorPluginTest {
- public:
- DrmHalVendorDecryptTest() = default;
- virtual ~DrmHalVendorDecryptTest() {}
-
- protected:
- void fillRandom(const sp<IMemory>& memory);
- hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
- EXPECT_EQ(vec.size(), 16u);
- return hidl_array<uint8_t, 16>(&vec[0]);
- }
- hidl_vec<KeyValue> queryKeyStatus(SessionId sessionId);
- void removeKeys(SessionId sessionId);
- uint32_t decrypt(Mode mode, bool isSecure,
- const hidl_array<uint8_t, 16>& keyId, uint8_t* iv,
- const hidl_vec<SubSample>& subSamples, const Pattern& pattern,
- const vector<uint8_t>& key, Status expectedStatus);
- void aes_ctr_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
- const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
- void aes_cbc_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
- const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
-};
-
void DrmHalVendorDecryptTest::fillRandom(const sp<IMemory>& memory) {
random_device rd;
mt19937 rand(rd());
@@ -1566,47 +1407,8 @@ TEST_P(DrmHalVendorDecryptTest, AttemptDecryptWithKeysRemoved) {
}
}
-
-/**
- * Instantiate the set of test cases for each vendor module
- */
-
-static const std::set<std::string> kAllInstances = [] {
- std::vector<std::string> drmInstances =
- android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
- std::vector<std::string> cryptoInstances =
- android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
- std::set<std::string> allInstances;
- allInstances.insert(drmInstances.begin(), drmInstances.end());
- allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
- return allInstances;
-}();
-
-INSTANTIATE_TEST_CASE_P(DrmHalVendorFactoryTestCases, DrmHalVendorFactoryTest,
- testing::ValuesIn(kAllInstances),
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_CASE_P(DrmHalVendorPluginTestCases, DrmHalVendorPluginTest,
- testing::ValuesIn(kAllInstances),
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_CASE_P(DrmHalVendorDecryptTestCases, DrmHalVendorDecryptTest,
- testing::ValuesIn(kAllInstances),
- android::hardware::PrintInstanceNameToString);
-
-int main(int argc, char** argv) {
-#if defined(__LP64__)
- const char* kModulePath = "/data/local/tmp/64/lib";
-#else
- const char* kModulePath = "/data/local/tmp/32/lib";
-#endif
- gVendorModules = new drm_vts::VendorModules(kModulePath);
- if (gVendorModules->getPathList().size() == 0) {
- std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
- ", all vendor tests will be skipped" << std::endl;
- }
- ::testing::InitGoogleTest(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+} // namespace vts
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h b/drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h
new file mode 100644
index 0000000000..ca707b81fb
--- /dev/null
+++ b/drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h
@@ -0,0 +1,201 @@
+/*
+ * 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 DRM_HAL_CLEARKEY_TEST_H
+#define DRM_HAL_CLEARKEY_TEST_H
+
+#include <android/hardware/drm/1.0/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <hidlmemory/mapping.h>
+#include <log/log.h>
+
+#include "drm_vts_helper.h"
+
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+using ::drm_vts::DrmHalTestParam;
+using ::drm_vts::PrintParamInstanceToString;
+
+using std::string;
+using std::map;
+using std::vector;
+
+/**
+ * These clearkey tests use white box knowledge of the legacy clearkey
+ * plugin to verify that the HIDL HAL services and interfaces are working.
+ * It is not intended to verify any vendor's HAL implementation. If you
+ * are looking for vendor HAL tests, see drm_hal_vendor_test.cpp
+ */
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace vts {
+
+class DrmHalClearkeyFactoryTest : public ::testing::TestWithParam<DrmHalTestParam> {
+ public:
+ void SetUp() override {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("Running test %s.%s", test_info->test_case_name(),
+ test_info->name());
+
+ const std::string instanceName = GetParam().instance_;
+ drmFactory = IDrmFactory::getService(instanceName);
+ ASSERT_NE(nullptr, drmFactory.get());
+ cryptoFactory = ICryptoFactory::getService(instanceName);
+ ASSERT_NE(nullptr, cryptoFactory.get());
+
+ const bool drmClearKey = drmFactory->isCryptoSchemeSupported(kClearKeyUUID);
+ const bool cryptoClearKey = cryptoFactory->isCryptoSchemeSupported(kClearKeyUUID);
+ EXPECT_EQ(drmClearKey, cryptoClearKey);
+ const bool supportsClearKey = drmClearKey && cryptoClearKey;
+
+ const bool drmCommonPsshBox = drmFactory->isCryptoSchemeSupported(kCommonPsshBoxUUID);
+ const bool cryptoCommonPsshBox = cryptoFactory->isCryptoSchemeSupported(kCommonPsshBoxUUID);
+ EXPECT_EQ(drmCommonPsshBox, cryptoCommonPsshBox);
+ const bool supportsCommonPsshBox = drmCommonPsshBox && cryptoCommonPsshBox;
+
+ EXPECT_EQ(supportsClearKey, supportsCommonPsshBox);
+ correspondsToThisTest = supportsClearKey && supportsCommonPsshBox;
+
+ if (instanceName == "clearkey") {
+ EXPECT_TRUE(correspondsToThisTest);
+
+ // TODO(b/147449315)
+ // Only the clearkey plugged into the "default" instance supports
+ // this test. Currently the "clearkey" instance fails some tests
+ // here.
+ GTEST_SKIP() << "Clearkey tests don't work with 'clearkey' instance yet.";
+ }
+
+ if (!correspondsToThisTest) {
+ GTEST_SKIP() << "Cannot test clearkey features on non-clearkey DRM modules";
+ }
+ }
+
+ protected:
+ static constexpr uint8_t kCommonPsshBoxUUID[16] = {
+ 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02,
+ 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B};
+
+ // To be used in mpd to specify drm scheme for players
+ static constexpr uint8_t kClearKeyUUID[16] = {
+ 0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
+ 0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E};
+
+ sp<IDrmFactory> drmFactory;
+ sp<ICryptoFactory> cryptoFactory;
+
+ bool correspondsToThisTest;
+};
+
+class DrmHalClearkeyPluginTest : public DrmHalClearkeyFactoryTest {
+ public:
+ virtual void SetUp() override {
+ // Create factories
+ DrmHalClearkeyFactoryTest::SetUp();
+
+ if (!correspondsToThisTest) {
+ GTEST_SKIP() << "Cannot test clearkey features on non-clearkey DRM modules";
+ }
+
+ ASSERT_NE(nullptr, drmFactory.get());
+ hidl_string packageName("android.hardware.drm.test");
+ auto res = drmFactory->createPlugin(
+ getUUID(), packageName,
+ [this](Status status, const sp<IDrmPlugin>& plugin) {
+ EXPECT_EQ(Status::OK, status);
+ ASSERT_NE(nullptr, plugin.get());
+ drmPlugin = plugin;
+ });
+ ASSERT_OK(res);
+
+ hidl_vec<uint8_t> initVec;
+ res = cryptoFactory->createPlugin(
+ getUUID(), initVec,
+ [this](Status status, const sp<ICryptoPlugin>& plugin) {
+ EXPECT_EQ(Status::OK, status);
+ ASSERT_NE(nullptr, plugin.get());
+ cryptoPlugin = plugin;
+ });
+ ASSERT_OK(res);
+ }
+
+ SessionId openSession();
+ void closeSession(const SessionId& sessionId);
+ hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
+ sp<IMemory> getDecryptMemory(size_t size, size_t index);
+
+ protected:
+ hidl_array<uint8_t, 16> getUUID() {
+ if (GetParamUUID() == hidl_array<uint8_t, 16>()) {
+ return kClearKeyUUID;
+ }
+ return GetParamUUID();
+ }
+
+ hidl_array<uint8_t, 16> GetParamUUID() {
+ return GetParam().scheme_;
+ }
+
+ sp<IDrmPlugin> drmPlugin;
+ sp<ICryptoPlugin> cryptoPlugin;
+};
+
+class DrmHalClearkeyDecryptTest : public DrmHalClearkeyPluginTest {
+ public:
+ void SetUp() override {
+ DrmHalClearkeyPluginTest::SetUp();
+
+ if (!correspondsToThisTest) {
+ GTEST_SKIP() << "Cannot test clearkey features on non-clearkey DRM modules";
+ }
+ }
+ void fillRandom(const sp<IMemory>& memory);
+ hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
+ EXPECT_EQ(16u, vec.size());
+ return hidl_array<uint8_t, 16>(&vec[0]);
+ }
+ uint32_t decrypt(Mode mode, uint8_t* iv, const hidl_vec<SubSample>& subSamples,
+ const Pattern& pattern, Status status);
+ void aes_ctr_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
+ const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
+ void aes_cbc_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
+ const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
+ void decryptWithInvalidKeys(hidl_vec<uint8_t>& invalidResponse,
+ vector<uint8_t>& iv, const Pattern& noPattern, const vector<SubSample>& subSamples);
+};
+
+} // namespace vts
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // DRM_HAL_CLEARKEY_TEST_H
diff --git a/drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_vendor_test.h b/drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_vendor_test.h
new file mode 100644
index 0000000000..468d335df4
--- /dev/null
+++ b/drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_vendor_test.h
@@ -0,0 +1,209 @@
+/*
+ * 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 DRM_HAL_VENDOR_TEST_H
+#define DRM_HAL_VENDOR_TEST_H
+
+#include <android/hardware/drm/1.0/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.0/IDrmPluginListener.h>
+#include <android/hardware/drm/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <hidlmemory/mapping.h>
+#include <log/log.h>
+
+#include <memory>
+#include <set>
+#include <vector>
+
+#include "drm_hal_vendor_module_api.h"
+#include "drm_vts_helper.h"
+#include "vendor_modules.h"
+#include <VtsHalHidlTargetCallbackBase.h>
+
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+using ::drm_vts::DrmHalTestParam;
+using ::drm_vts::PrintParamInstanceToString;
+
+using std::string;
+using std::unique_ptr;
+using std::map;
+using std::vector;
+
+using ContentConfiguration = ::DrmHalVTSVendorModule_V1::ContentConfiguration;
+using Key = ::DrmHalVTSVendorModule_V1::ContentConfiguration::Key;
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+#define RETURN_IF_SKIPPED \
+ if (vendorModule == nullptr || !vendorModule->isInstalled()) { \
+ GTEST_SKIP() << "This drm scheme not supported." \
+ << " library:" << GetParam() << " service-name:" \
+ << (vendorModule == nullptr ? "N/A" : vendorModule->getServiceName()) \
+ << std::endl; \
+ return; \
+ }
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace vts {
+
+class DrmHalVendorFactoryTest : public testing::TestWithParam<DrmHalTestParam> {
+ public:
+ DrmHalVendorFactoryTest();
+ virtual ~DrmHalVendorFactoryTest() {}
+
+ virtual void SetUp() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("Running test %s.%s from vendor module %s", test_info->test_case_name(),
+ test_info->name(), GetParam().instance_.c_str());
+
+ const std::string instance = GetParam().instance_;
+ if (instance == "widevine") {
+ ASSERT_NE(nullptr, vendorModule.get());
+ }
+
+ if (vendorModule == nullptr) {
+ GTEST_SKIP() << "No vendor module available";
+ } else {
+ ASSERT_EQ(instance, vendorModule->getServiceName());
+ contentConfigurations = vendorModule->getContentConfigurations();
+ }
+
+ drmFactory = IDrmFactory::getService(instance);
+ ASSERT_NE(nullptr, drmFactory.get());
+ cryptoFactory = ICryptoFactory::getService(instance);
+ ASSERT_NE(nullptr, cryptoFactory.get());
+
+ // If drm scheme not installed skip subsequent tests
+ if (!drmFactory->isCryptoSchemeSupported(getUUID())) {
+ // no GTEST_SKIP since only some tests require the module
+ vendorModule->setInstalled(false);
+ hidl_array<uint8_t, 16> noUUID;
+ ASSERT_EQ(GetParamUUID(), noUUID) << "param uuid unsupported";
+ }
+ }
+
+ protected:
+ hidl_array<uint8_t, 16> getUUID() {
+ if (GetParamUUID() == hidl_array<uint8_t, 16>()) {
+ return getVendorUUID();
+ }
+ return GetParamUUID();
+ }
+
+ hidl_array<uint8_t, 16> getVendorUUID() {
+ if (vendorModule == nullptr) return {};
+ vector<uint8_t> uuid = vendorModule->getUUID();
+ return hidl_array<uint8_t, 16>(&uuid[0]);
+ }
+
+ hidl_array<uint8_t, 16> GetParamUUID() {
+ return GetParam().scheme_;
+ }
+
+ sp<IDrmFactory> drmFactory;
+ sp<ICryptoFactory> cryptoFactory;
+ unique_ptr<DrmHalVTSVendorModule_V1> vendorModule;
+ vector<ContentConfiguration> contentConfigurations;
+};
+
+class DrmHalVendorPluginTest : public DrmHalVendorFactoryTest {
+ public:
+ virtual ~DrmHalVendorPluginTest() {}
+ virtual void SetUp() override {
+ // Create factories
+ DrmHalVendorFactoryTest::SetUp();
+ RETURN_IF_SKIPPED;
+
+ hidl_string packageName("android.hardware.drm.test");
+ auto res = drmFactory->createPlugin(
+ getVendorUUID(), packageName,
+ [this](Status status, const sp<IDrmPlugin>& plugin) {
+ EXPECT_EQ(Status::OK, status);
+ ASSERT_NE(nullptr, plugin.get());
+ drmPlugin = plugin;
+ });
+ ASSERT_OK(res);
+
+ hidl_vec<uint8_t> initVec;
+ res = cryptoFactory->createPlugin(
+ getVendorUUID(), initVec,
+ [this](Status status, const sp<ICryptoPlugin>& plugin) {
+ EXPECT_EQ(Status::OK, status);
+ ASSERT_NE(nullptr, plugin.get());
+ cryptoPlugin = plugin;
+ });
+ ASSERT_OK(res);
+ }
+
+ virtual void TearDown() override {}
+
+ SessionId openSession();
+ void closeSession(const SessionId& sessionId);
+ sp<IMemory> getDecryptMemory(size_t size, size_t index);
+ KeyedVector toHidlKeyedVector(const map<string, string>& params);
+ hidl_vec<uint8_t> loadKeys(const SessionId& sessionId,
+ const ContentConfiguration& configuration,
+ const KeyType& type);
+
+ protected:
+ sp<IDrmPlugin> drmPlugin;
+ sp<ICryptoPlugin> cryptoPlugin;
+};
+
+class DrmHalVendorDecryptTest : public DrmHalVendorPluginTest {
+ public:
+ DrmHalVendorDecryptTest() = default;
+ virtual ~DrmHalVendorDecryptTest() {}
+
+ protected:
+ void fillRandom(const sp<IMemory>& memory);
+ hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
+ EXPECT_EQ(vec.size(), 16u);
+ return hidl_array<uint8_t, 16>(&vec[0]);
+ }
+ hidl_vec<KeyValue> queryKeyStatus(SessionId sessionId);
+ void removeKeys(SessionId sessionId);
+ uint32_t decrypt(Mode mode, bool isSecure,
+ const hidl_array<uint8_t, 16>& keyId, uint8_t* iv,
+ const hidl_vec<SubSample>& subSamples, const Pattern& pattern,
+ const vector<uint8_t>& key, Status expectedStatus);
+ void aes_ctr_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
+ const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
+ void aes_cbc_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
+ const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
+};
+
+} // namespace vts
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // DRM_HAL_VENDOR_TEST_H
diff --git a/drm/1.0/vts/functional/include/drm_hal_vendor_module_api.h b/drm/1.0/vts/functional/include/drm_hal_vendor_module_api.h
new file mode 100644
index 0000000000..b8b205265d
--- /dev/null
+++ b/drm/1.0/vts/functional/include/drm_hal_vendor_module_api.h
@@ -0,0 +1,234 @@
+/*
+ * 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 DRM_HAL_VENDOR_MODULE_API_H
+#define DRM_HAL_VENDOR_MODULE_API_H
+
+#include <stdint.h>
+#include <map>
+#include <string>
+#include <vector>
+
+/**
+ * The DRM and Crypto HALs interact with vendor-provided HAL implementations
+ * that have DRM-specific capabilities. Since the VTS tests cannot contain
+ * DRM-specific functionality, supporting modules are required to enable VTS
+ * to validate HAL implementations in a generic way. If the vendor-specific
+ * VTS module is not provided for a given drm HAL implementation, only very
+ * small subset of functionality can be verified.
+ *
+ * As an example, a DRM HAL implementation interacts with a DRM-specific
+ * license server to obtain licenses for decrypting content. The DRM HAL
+ * implementation generates a key request message, delivers it to the server
+ * and receives a key response message which is then loaded into the HAL. Once
+ * the keys are loaded, the Crypto HAL decryption functionality and performance
+ * and other associated APIs can be tested by the common VTS test suite.
+ *
+ * Vendor-specific VTS modules are shared libraries used by the DRM VTS test.
+ * They provide a set of functions to support VTS testing of the DRM HAL module.
+ *
+ * The modules are placed in a common location on the file system. The VTS test
+ * scans through all vendor-provided support libraries and runs the VTS test
+ * suite on each library that is found.
+ *
+ * The vendor-specific module exposes an extern “C” vendorModuleFactory()
+ * function that returns a DrmHalVTSVendorModule instance. DrmHalVTSVendorModule
+ * instances are versioned, where each version is represented by subclass of
+ * DrmHalVTSVendorModule that corresponds to the API version. For example, a
+ * vendor-specific module that implements version 1 of the API would return a
+ * DrmHalVTSVendorModule_V1 from the vendorModuleFactory() function.
+ */
+
+class DrmHalVTSVendorModule;
+
+extern "C" {
+/**
+ * The factory method for creating DrmHalVTSVendorModule instances. The returned
+ * instance will be a subclass of DrmHalVTSVendorModule that corresponds to the
+ * supported API version.
+ */
+DrmHalVTSVendorModule* vendorModuleFactory();
+};
+
+class DrmHalVTSVendorModule {
+ public:
+ DrmHalVTSVendorModule() : installed(true) {}
+ virtual ~DrmHalVTSVendorModule() {}
+
+ /**
+ * Return the vendor-specific module API version. The version is an integer
+ * value with initial version 1. The API version indicates which subclass
+ * version DrmHalVTSVendorModule this instance is.
+ */
+ virtual uint32_t getAPIVersion() const = 0;
+
+ /**
+ * Return the UUID for the DRM HAL implementation. Protection System
+ * Specific
+ * UUID (see http://dashif.org/identifiers/protection/)
+ */
+ virtual std::vector<uint8_t> getUUID() const = 0;
+
+ /**
+ * Return the service name for the DRM HAL implementation. If the hal is a
+ * legacy
+ * drm plugin, i.e. not running as a HIDL service, return the empty string.
+ */
+ virtual std::string getServiceName() const = 0;
+
+ /**
+ * Set a flag in the vendor module to indicate whether or not the drm
+ * scheme corresponding to this module is installed on the device.
+ */
+ void setInstalled(bool flag) {installed = flag;}
+ bool isInstalled() const {return installed;}
+
+ private:
+ bool installed;
+ DrmHalVTSVendorModule(const DrmHalVTSVendorModule&) = delete;
+ void operator=(const DrmHalVTSVendorModule&) = delete;
+};
+
+/**
+ * API Version 1. This is the baseline version that supports a minimal set
+ * of VTS tests.
+ */
+class DrmHalVTSVendorModule_V1 : public DrmHalVTSVendorModule {
+ public:
+ DrmHalVTSVendorModule_V1() {}
+ virtual ~DrmHalVTSVendorModule_V1() {}
+
+ virtual uint32_t getAPIVersion() const { return 1; }
+
+ /**
+ * Handle a provisioning request. This function will be called if the HAL
+ * module's getProvisionRequest returns a provision request. The vendor
+ * module should process the provisioning request, either by sending it
+ * to a provisioning server, or generating a mock response. The resulting
+ * provisioning response is returned to the VTS test.
+ *
+ * @param provisioningRequest the provisioning request recieved from
+ * the DRM HAL
+ * @param url the default url the HAL implementation provided with the
+ * provisioning request
+ * @return the generated provisioning response
+ */
+ virtual std::vector<uint8_t> handleProvisioningRequest(
+ const std::vector<uint8_t>& provisioningRequest,
+ const std::string& url) = 0;
+
+ /**
+ * Content configuration specifies content-specific parameters associated
+ * with a key request/response transaction. It allows the VTS test to
+ * request keys and use them to perform decryption.
+ */
+ struct ContentConfiguration {
+ /**
+ * Assign a name for this configuration that will be referred to
+ * in log messages.
+ */
+ const std::string name;
+
+ /**
+ * Server to use when requesting a key response. This url will be
+ * passed as a parameter to the vendor vts module along with the
+ * key request to perform the key request transaction.
+ */
+ const std::string serverUrl;
+
+ /**
+ * Initialization data provided to getKeyRequest, e.g. PSSH for CENC
+ * content
+ */
+ const std::vector<uint8_t> initData;
+
+ /**
+ * Mime type provided to getKeyRequest, e.g. "video/mp4", or "cenc"
+ */
+ const std::string mimeType;
+
+ /**
+ * Optional parameters to be associated with the key request
+ */
+ const std::map<std::string, std::string> optionalParameters;
+
+ /**
+ * Define license policy attributes for the content configuration.
+ * These attributes can affect which tests are able to be applied.
+ */
+ struct Policy {
+ /**
+ * Indicate if the license policy allows offline playback.
+ * Content configurated with this policy supports KeyType::OFFLINE
+ * key requests/responses. A vendor module should provide at least
+ * one content configuration where allowOffline is true if the drm
+ * scheme supports offline content.
+ */
+ bool allowOffline;
+ } policy;
+
+ /**
+ * The keys that will be available once the keys are loaded
+ */
+ struct Key {
+ /**
+ * Indicate if the key content is configured to require secure
+ * buffers, where the output buffers are protected and cannot be
+ * accessed by the non-secure cpu. A vendor module should provide
+ * at least one content configurations where isSecure is false, to
+ * allow decrypt result verification tests to be run.
+ */
+ bool isSecure;
+
+ /**
+ * A key ID identifies a key to use for decryption
+ */
+ const std::vector<uint8_t> keyId;
+
+ /**
+ * The clear content key is provided to generate expected values for
+ * validating decryption.
+ */
+ const std::vector<uint8_t> clearContentKey;
+ };
+ std::vector<Key> keys;
+ };
+
+ /**
+ * Return a list of content configurations that can be exercised by the
+ * VTS test.
+ */
+ virtual std::vector<ContentConfiguration>
+ getContentConfigurations() const = 0;
+
+ /**
+ * Handle a key request. This function will be called if the HAL
+ * module's getKeyRequest returns a key request. The vendor
+ * module should process the key request, either by sending it
+ * to a license server, or by generating a mock response. The resulting
+ * key response is returned to the VTS test.
+ *
+ * @param keyRequest the key request recieved from the DRM HAL
+ * @param serverUrl the url of the key server that was supplied
+ * by the ContentConfiguration
+ * @return the generated key response
+ */
+ virtual std::vector<uint8_t> handleKeyRequest(
+ const std::vector<uint8_t>& keyRequest,
+ const std::string& serverUrl) = 0;
+};
+
+#endif // DRM_HAL_VENDOR_MODULE_API_H
diff --git a/drm/1.0/vts/functional/include/drm_vts_helper.h b/drm/1.0/vts/functional/include/drm_vts_helper.h
new file mode 100644
index 0000000000..1f02af9460
--- /dev/null
+++ b/drm/1.0/vts/functional/include/drm_vts_helper.h
@@ -0,0 +1,58 @@
+/*
+ * 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 DRM_VTS_HELPER_H
+#define DRM_VTS_HELPER_H
+
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+
+#include <array>
+#include <chrono>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace drm_vts {
+
+using ::android::hardware::hidl_array;
+
+struct DrmHalTestParam {
+ const std::string instance_;
+ const hidl_array<uint8_t, 16> scheme_{};
+ DrmHalTestParam(const std::string& instance) : instance_(instance) {}
+ DrmHalTestParam(const std::string& instance, const hidl_array<uint8_t, 16>& scheme)
+ : instance_(instance), scheme_(scheme) {}
+};
+
+inline std::ostream& operator<<(std::ostream& stream, const DrmHalTestParam& val) {
+ stream << val.instance_ << ", " << android::hardware::toString(val.scheme_);
+ return stream;
+}
+
+inline std::string PrintParamInstanceToString(
+ const testing::TestParamInfo<DrmHalTestParam>& info) {
+ // test names need to be unique -> index prefix
+ std::string name = std::to_string(info.index) + "/" + info.param.instance_;
+ return android::hardware::Sanitize(name);
+};
+
+} // namespace drm_vts
+
+#endif // DRM_VTS_HELPER_H
diff --git a/drm/1.0/vts/functional/vendor_modules.h b/drm/1.0/vts/functional/include/vendor_modules.h
index 8330b0a1ff..3f6fa1573d 100644
--- a/drm/1.0/vts/functional/vendor_modules.h
+++ b/drm/1.0/vts/functional/include/vendor_modules.h
@@ -51,6 +51,11 @@ class VendorModules {
*/
std::vector<std::string> getPathList() const {return mPathList;}
+ /**
+ * Retrieve a DrmHalVTSVendorModule given a service name.
+ */
+ DrmHalVTSVendorModule* getModuleByName(const std::string& name);
+
private:
std::vector<std::string> mPathList;
std::map<std::string, std::unique_ptr<SharedLibrary>> mOpenLibraries;
diff --git a/drm/1.0/vts/functional/vendor_modules.cpp b/drm/1.0/vts/functional/vendor_modules.cpp
index 98430f550e..53927bd182 100644
--- a/drm/1.0/vts/functional/vendor_modules.cpp
+++ b/drm/1.0/vts/functional/vendor_modules.cpp
@@ -23,6 +23,7 @@
#include <utils/String8.h>
#include <SharedLibrary.h>
+#include "drm_hal_vendor_module_api.h"
#include "vendor_modules.h"
using std::string;
@@ -69,4 +70,15 @@ DrmHalVTSVendorModule* VendorModules::getModule(const string& path) {
ModuleFactory moduleFactory = reinterpret_cast<ModuleFactory>(symbol);
return (*moduleFactory)();
}
+
+DrmHalVTSVendorModule* VendorModules::getModuleByName(const string& name) {
+ for (const auto &path : mPathList) {
+ auto module = getModule(path);
+ if (module->getServiceName() == name) {
+ return module;
+ }
+
+ }
+ return NULL;
+}
};
diff --git a/drm/1.1/vts/OWNERS b/drm/1.1/vts/OWNERS
new file mode 100644
index 0000000000..ecb421cc1f
--- /dev/null
+++ b/drm/1.1/vts/OWNERS
@@ -0,0 +1,6 @@
+edwinwong@google.com
+fredgc@google.com
+jtinker@google.com
+kylealexander@google.com
+rfrias@google.com
+robertshih@google.com
diff --git a/drm/1.1/vts/functional/Android.bp b/drm/1.1/vts/functional/Android.bp
index fb09563ada..e08d760ea4 100644
--- a/drm/1.1/vts/functional/Android.bp
+++ b/drm/1.1/vts/functional/Android.bp
@@ -14,21 +14,56 @@
// limitations under the License.
//
-cc_test {
- name: "VtsHalDrmV1_1TargetTest",
+cc_library_static {
+ name: "android.hardware.drm@1.1-vts",
defaults: ["VtsHalTargetTestDefaults"],
+ include_dirs: [
+ "hardware/interfaces/drm/1.0/vts/functional",
+ ],
+ local_include_dirs: [
+ "include",
+ ],
srcs: [
"drm_hal_clearkey_test.cpp",
],
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlmemory",
+ "libnativehelper",
+ ],
static_libs: [
+ "libdrmvtshelper",
+ ],
+ export_shared_lib_headers: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
- "android.hardware.drm@1.0-helper",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libhidlmemory",
"libnativehelper",
- "libssl",
+ ],
+ export_static_lib_headers: [
+ "libdrmvtshelper",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+}
+
+cc_test {
+ name: "VtsHalDrmV1_1TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "drm_hal_test_main.cpp",
+ ],
+ whole_static_libs: [
+ "android.hardware.drm@1.1-vts"
+ ],
+ shared_libs: [
+ "android.hardware.drm@1.1",
],
test_suites: [
"general-tests",
diff --git a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
index bf99ef6cd8..fba973357d 100644
--- a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
+++ b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
@@ -16,205 +16,20 @@
#define LOG_TAG "drm_hal_clearkey_test@1.1"
-#include <android/hardware/drm/1.0/ICryptoPlugin.h>
-#include <android/hardware/drm/1.0/IDrmPlugin.h>
-#include <android/hardware/drm/1.0/types.h>
-#include <android/hardware/drm/1.1/ICryptoFactory.h>
-#include <android/hardware/drm/1.1/IDrmFactory.h>
-#include <android/hardware/drm/1.1/IDrmPlugin.h>
-#include <android/hardware/drm/1.1/types.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <android/hidl/manager/1.2/IServiceManager.h>
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/ServiceManagement.h>
-#include <hidlmemory/mapping.h>
#include <log/log.h>
-#include <openssl/aes.h>
-#include <memory>
-#include <random>
-
-namespace drm = ::android::hardware::drm;
-using ::android::hardware::drm::V1_0::BufferType;
-using ::android::hardware::drm::V1_0::DestinationBuffer;
-using ::android::hardware::drm::V1_0::ICryptoPlugin;
-using ::android::hardware::drm::V1_0::KeyedVector;
-using ::android::hardware::drm::V1_0::KeyValue;
-using ::android::hardware::drm::V1_0::KeyType;
-using ::android::hardware::drm::V1_0::Mode;
-using ::android::hardware::drm::V1_0::Pattern;
-using ::android::hardware::drm::V1_0::SecureStop;
-using ::android::hardware::drm::V1_0::SecureStopId;
-using ::android::hardware::drm::V1_0::SessionId;
-using ::android::hardware::drm::V1_0::SharedBuffer;
-using ::android::hardware::drm::V1_0::Status;
-using ::android::hardware::drm::V1_0::SubSample;
-using ::android::hardware::drm::V1_0::SubSample;
-
-using ::android::hardware::drm::V1_1::DrmMetricGroup;
-using ::android::hardware::drm::V1_1::HdcpLevel;
-using ::android::hardware::drm::V1_1::ICryptoFactory;
-using ::android::hardware::drm::V1_1::IDrmFactory;
-using ::android::hardware::drm::V1_1::IDrmPlugin;
-using ::android::hardware::drm::V1_1::KeyRequestType;
-using ::android::hardware::drm::V1_1::SecureStopRelease;
-using ::android::hardware::drm::V1_1::SecurityLevel;
-using ::android::hardware::drm::V1_1::SecurityLevel;
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
-using std::string;
-using std::unique_ptr;
-using std::random_device;
-using std::map;
-using std::mt19937;
-using std::vector;
-
-/**
- * These clearkey tests use white box knowledge of the legacy clearkey
- * plugin to verify that the HIDL HAL services and interfaces are working.
- * It is not intended to verify any vendor's HAL implementation. If you
- * are looking for vendor HAL tests, see drm_hal_vendor_test.cpp
- */
-#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
-#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
-
-// To be used in mpd to specify drm scheme for players
-static const uint8_t kClearKeyUUID[16] = {
+#include <vector>
+
+#include "android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace vts {
+
+const uint8_t kClearKeyUUID[16] = {
0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
- 0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E};
-
-class DrmHalClearkeyTest : public ::testing::TestWithParam<std::string> {
- public:
- void SetUp() override {
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
-
- ALOGD("DrmHalClearkeyTest: Running test %s.%s", test_info->test_case_name(),
- test_info->name());
-
- const std::string instance = GetParam();
-
- sp<IDrmFactory> drmFactory = IDrmFactory::getService(instance);
- drmPlugin = createDrmPlugin(drmFactory);
- sp<ICryptoFactory> cryptoFactory = ICryptoFactory::getService(instance);
- cryptoPlugin = createCryptoPlugin(cryptoFactory);
-
- if (drmPlugin == nullptr || cryptoPlugin == nullptr) {
- if (instance == "clearkey") {
- ASSERT_NE(nullptr, drmPlugin.get()) << "Can't get clearkey drm@1.1 plugin";
- ASSERT_NE(nullptr, cryptoPlugin.get()) << "Can't get clearkey crypto@1.1 plugin";
- }
- GTEST_SKIP() << "Instance does not support clearkey";
- }
- }
-
- SessionId openSession();
- SessionId openSession(SecurityLevel level);
- void closeSession(const SessionId& sessionId);
- hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
-
- private:
- sp<IDrmPlugin> createDrmPlugin(sp<IDrmFactory> drmFactory) {
- if (drmFactory == nullptr) {
- return nullptr;
- }
- sp<IDrmPlugin> plugin = nullptr;
- auto res = drmFactory->createPlugin(
- kClearKeyUUID, "", [&](Status status, const sp<drm::V1_0::IDrmPlugin>& pluginV1_0) {
- EXPECT_EQ(Status::OK == status, pluginV1_0 != nullptr);
- plugin = IDrmPlugin::castFrom(pluginV1_0);
- });
-
- if (!res.isOk()) {
- ALOGE("createDrmPlugin remote call failed");
- }
- return plugin;
- }
-
- sp<ICryptoPlugin> createCryptoPlugin(sp<ICryptoFactory> cryptoFactory) {
- if (cryptoFactory == nullptr) {
- return nullptr;
- }
- sp<ICryptoPlugin> plugin = nullptr;
- hidl_vec<uint8_t> initVec;
- auto res = cryptoFactory->createPlugin(
- kClearKeyUUID, initVec,
- [&](Status status, const sp<drm::V1_0::ICryptoPlugin>& pluginV1_0) {
- EXPECT_EQ(Status::OK == status, pluginV1_0 != nullptr);
- plugin = pluginV1_0;
- });
- if (!res.isOk()) {
- ALOGE("createCryptoPlugin remote call failed");
- }
- return plugin;
- }
-
-protected:
- template <typename CT>
- bool ValueEquals(DrmMetricGroup::ValueType type, const std::string& expected, const CT& actual) {
- return type == DrmMetricGroup::ValueType::STRING_TYPE && expected == actual.stringValue;
- }
-
- template <typename CT>
- bool ValueEquals(DrmMetricGroup::ValueType type, const int64_t expected, const CT& actual) {
- return type == DrmMetricGroup::ValueType::INT64_TYPE && expected == actual.int64Value;
- }
-
- template <typename CT>
- bool ValueEquals(DrmMetricGroup::ValueType type, const double expected, const CT& actual) {
- return type == DrmMetricGroup::ValueType::DOUBLE_TYPE && expected == actual.doubleValue;
- }
-
- template <typename AT, typename VT>
- bool ValidateMetricAttributeAndValue(const DrmMetricGroup::Metric& metric,
- const std::string& attributeName, const AT& attributeValue,
- const std::string& componentName, const VT& componentValue) {
- bool validAttribute = false;
- bool validComponent = false;
- for (const DrmMetricGroup::Attribute& attribute : metric.attributes) {
- if (attribute.name == attributeName &&
- ValueEquals(attribute.type, attributeValue, attribute)) {
- validAttribute = true;
- }
- }
- for (const DrmMetricGroup::Value& value : metric.values) {
- if (value.componentName == componentName &&
- ValueEquals(value.type, componentValue, value)) {
- validComponent = true;
- }
- }
- return validAttribute && validComponent;
- }
-
- template <typename AT, typename VT>
- bool ValidateMetricAttributeAndValue(const hidl_vec<DrmMetricGroup>& metricGroups,
- const std::string& metricName,
- const std::string& attributeName, const AT& attributeValue,
- const std::string& componentName, const VT& componentValue) {
- bool foundMetric = false;
- for (const auto& group : metricGroups) {
- for (const auto& metric : group.metrics) {
- if (metric.name == metricName) {
- foundMetric = foundMetric || ValidateMetricAttributeAndValue(
- metric, attributeName, attributeValue,
- componentName, componentValue);
- }
- }
- }
- return foundMetric;
- }
-
- sp<IDrmPlugin> drmPlugin;
- sp<ICryptoPlugin> cryptoPlugin;
+ 0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E
};
/**
@@ -812,16 +627,8 @@ TEST_P(DrmHalClearkeyTest, RemoveSecureStopById) {
EXPECT_OK(res);
}
-static const std::set<std::string> kAllInstances = [] {
- std::vector<std::string> drmInstances =
- android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
- std::vector<std::string> cryptoInstances =
- android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
- std::set<std::string> allInstances;
- allInstances.insert(drmInstances.begin(), drmInstances.end());
- allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
- return allInstances;
-}();
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyTest, testing::ValuesIn(kAllInstances),
- android::hardware::PrintInstanceNameToString);
+} // namespace vts
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/1.1/vts/functional/drm_hal_test_main.cpp b/drm/1.1/vts/functional/drm_hal_test_main.cpp
new file mode 100644
index 0000000000..c6965bdc39
--- /dev/null
+++ b/drm/1.1/vts/functional/drm_hal_test_main.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+
+#include <algorithm>
+#include <iterator>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h"
+
+using android::hardware::drm::V1_1::ICryptoFactory;
+using android::hardware::drm::V1_1::IDrmFactory;
+using android::hardware::drm::V1_1::vts::DrmHalClearkeyTest;
+using android::hardware::drm::V1_1::vts::kClearKeyUUID;
+
+static const std::vector<DrmHalTestParam> kAllInstances = [] {
+ std::vector<std::string> drmInstances =
+ android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
+ std::vector<std::string> cryptoInstances =
+ android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
+ std::set<std::string> allInstances;
+ allInstances.insert(drmInstances.begin(), drmInstances.end());
+ allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
+
+ std::vector<DrmHalTestParam> allInstancesWithClearKeyUuid;
+ std::transform(allInstances.begin(), allInstances.end(),
+ std::back_inserter(allInstancesWithClearKeyUuid),
+ [](std::string s) { return DrmHalTestParam(s, kClearKeyUUID); });
+ return allInstancesWithClearKeyUuid;
+}();
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyTest, testing::ValuesIn(kAllInstances),
+ PrintParamInstanceToString);
diff --git a/drm/1.1/vts/functional/include/android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h b/drm/1.1/vts/functional/include/android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h
new file mode 100644
index 0000000000..e21a2c135c
--- /dev/null
+++ b/drm/1.1/vts/functional/include/android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h
@@ -0,0 +1,209 @@
+/*
+ * 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 V1_1_DRM_HAL_CLEARKEY_TEST_H
+#define V1_1_DRM_HAL_CLEARKEY_TEST_H
+
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.0/types.h>
+#include <android/hardware/drm/1.1/ICryptoFactory.h>
+#include <android/hardware/drm/1.1/IDrmFactory.h>
+#include <android/hardware/drm/1.1/IDrmPlugin.h>
+#include <android/hardware/drm/1.1/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <string>
+
+#include "drm_vts_helper.h"
+
+namespace drm = ::android::hardware::drm;
+
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+using drm_vts::DrmHalTestParam;
+using drm_vts::PrintParamInstanceToString;
+
+/**
+ * These clearkey tests use white box knowledge of the legacy clearkey
+ * plugin to verify that the HIDL HAL services and interfaces are working.
+ * It is not intended to verify any vendor's HAL implementation. If you
+ * are looking for vendor HAL tests, see drm_hal_vendor_test.cpp
+ */
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace vts {
+
+using ::android::hardware::drm::V1_0::ICryptoPlugin;
+using ::android::hardware::drm::V1_0::KeyedVector;
+using ::android::hardware::drm::V1_0::KeyType;
+using ::android::hardware::drm::V1_0::Mode;
+using ::android::hardware::drm::V1_0::Pattern;
+using ::android::hardware::drm::V1_0::SecureStop;
+using ::android::hardware::drm::V1_0::SecureStopId;
+using ::android::hardware::drm::V1_0::SessionId;
+using ::android::hardware::drm::V1_0::Status;
+
+// To be used in mpd to specify drm scheme for players
+extern const uint8_t kClearKeyUUID[16];
+
+class DrmHalClearkeyTest : public ::testing::TestWithParam<DrmHalTestParam> {
+ public:
+ void SetUp() override {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ ALOGD("DrmHalClearkeyTest: Running test %s.%s", test_info->test_case_name(),
+ test_info->name());
+
+ const std::string instance = GetParam().instance_;
+
+ sp<IDrmFactory> drmFactory = IDrmFactory::getService(instance);
+ if (!drmFactory->isCryptoSchemeSupported(kClearKeyUUID)) {
+ GTEST_SKIP() << instance << " does not support clearkey";
+ }
+ drmPlugin = createDrmPlugin(drmFactory);
+ sp<ICryptoFactory> cryptoFactory = ICryptoFactory::getService(instance);
+ cryptoPlugin = createCryptoPlugin(cryptoFactory);
+
+ if (drmPlugin == nullptr || cryptoPlugin == nullptr) {
+ if (instance == "clearkey") {
+ ASSERT_NE(nullptr, drmPlugin.get()) << "Can't get clearkey drm@1.1 plugin";
+ ASSERT_NE(nullptr, cryptoPlugin.get()) << "Can't get clearkey crypto@1.1 plugin";
+ }
+ GTEST_SKIP() << "Instance does not support clearkey";
+ }
+ }
+
+ SessionId openSession();
+ SessionId openSession(SecurityLevel level);
+ void closeSession(const SessionId& sessionId);
+ hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
+
+ private:
+ sp<IDrmPlugin> createDrmPlugin(sp<IDrmFactory> drmFactory) {
+ if (drmFactory == nullptr) {
+ return nullptr;
+ }
+ sp<IDrmPlugin> plugin = nullptr;
+ auto res = drmFactory->createPlugin(GetParam().scheme_, "",
+ [&](Status status, const sp<drm::V1_0::IDrmPlugin>& pluginV1_0) {
+ EXPECT_EQ(Status::OK == status, pluginV1_0 != nullptr);
+ plugin = IDrmPlugin::castFrom(pluginV1_0);
+ });
+
+ if (!res.isOk()) {
+ ALOGE("createDrmPlugin remote call failed");
+ }
+ return plugin;
+ }
+
+ sp<ICryptoPlugin> createCryptoPlugin(sp<ICryptoFactory> cryptoFactory) {
+ if (cryptoFactory == nullptr) {
+ return nullptr;
+ }
+ sp<ICryptoPlugin> plugin = nullptr;
+ hidl_vec<uint8_t> initVec;
+ auto res = cryptoFactory->createPlugin(
+ GetParam().scheme_, initVec,
+ [&](Status status, const sp<drm::V1_0::ICryptoPlugin>& pluginV1_0) {
+ EXPECT_EQ(Status::OK == status, pluginV1_0 != nullptr);
+ plugin = pluginV1_0;
+ });
+ if (!res.isOk()) {
+ ALOGE("createCryptoPlugin remote call failed");
+ }
+ return plugin;
+ }
+
+protected:
+ template <typename CT>
+ bool ValueEquals(DrmMetricGroup::ValueType type, const std::string& expected, const CT& actual) {
+ return type == DrmMetricGroup::ValueType::STRING_TYPE && expected == actual.stringValue;
+ }
+
+ template <typename CT>
+ bool ValueEquals(DrmMetricGroup::ValueType type, const int64_t expected, const CT& actual) {
+ return type == DrmMetricGroup::ValueType::INT64_TYPE && expected == actual.int64Value;
+ }
+
+ template <typename CT>
+ bool ValueEquals(DrmMetricGroup::ValueType type, const double expected, const CT& actual) {
+ return type == DrmMetricGroup::ValueType::DOUBLE_TYPE && expected == actual.doubleValue;
+ }
+
+ template <typename AT, typename VT>
+ bool ValidateMetricAttributeAndValue(const DrmMetricGroup::Metric& metric,
+ const std::string& attributeName, const AT& attributeValue,
+ const std::string& componentName, const VT& componentValue) {
+ bool validAttribute = false;
+ bool validComponent = false;
+ for (const DrmMetricGroup::Attribute& attribute : metric.attributes) {
+ if (attribute.name == attributeName &&
+ ValueEquals(attribute.type, attributeValue, attribute)) {
+ validAttribute = true;
+ }
+ }
+ for (const DrmMetricGroup::Value& value : metric.values) {
+ if (value.componentName == componentName &&
+ ValueEquals(value.type, componentValue, value)) {
+ validComponent = true;
+ }
+ }
+ return validAttribute && validComponent;
+ }
+
+ template <typename AT, typename VT>
+ bool ValidateMetricAttributeAndValue(const hidl_vec<DrmMetricGroup>& metricGroups,
+ const std::string& metricName,
+ const std::string& attributeName, const AT& attributeValue,
+ const std::string& componentName, const VT& componentValue) {
+ bool foundMetric = false;
+ for (const auto& group : metricGroups) {
+ for (const auto& metric : group.metrics) {
+ if (metric.name == metricName) {
+ foundMetric = foundMetric || ValidateMetricAttributeAndValue(
+ metric, attributeName, attributeValue,
+ componentName, componentValue);
+ }
+ }
+ }
+ return foundMetric;
+ }
+
+ sp<IDrmPlugin> drmPlugin;
+ sp<ICryptoPlugin> cryptoPlugin;
+};
+
+} // namespace vts
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // V1_1_DRM_HAL_CLEARKEY_TEST_H
diff --git a/drm/1.2/vts/OWNERS b/drm/1.2/vts/OWNERS
new file mode 100644
index 0000000000..ecb421cc1f
--- /dev/null
+++ b/drm/1.2/vts/OWNERS
@@ -0,0 +1,6 @@
+edwinwong@google.com
+fredgc@google.com
+jtinker@google.com
+kylealexander@google.com
+rfrias@google.com
+robertshih@google.com
diff --git a/drm/1.2/vts/functional/Android.bp b/drm/1.2/vts/functional/Android.bp
index 83ea104579..ecc7d6c592 100644
--- a/drm/1.2/vts/functional/Android.bp
+++ b/drm/1.2/vts/functional/Android.bp
@@ -14,27 +14,61 @@
// limitations under the License.
//
-cc_test {
- name: "VtsHalDrmV1_2TargetTest",
+cc_library_static {
+ name: "android.hardware.drm@1.2-vts",
defaults: ["VtsHalTargetTestDefaults"],
- include_dirs: ["hardware/interfaces/drm/1.0/vts/functional"],
+ local_include_dirs: [
+ "include",
+ ],
srcs: [
"drm_hal_clearkey_module.cpp",
"drm_hal_common.cpp",
"drm_hal_test.cpp",
- "vendor_modules.cpp",
],
- static_libs: [
+ shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"android.hardware.drm@1.2",
- "android.hardware.drm@1.0-helper",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libhidlmemory",
"libnativehelper",
- "libssl",
+ ],
+ static_libs: [
+ "android.hardware.drm@1.0-helper",
+ "libcrypto_static",
+ "libdrmvtshelper",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.drm@1.2",
+ ],
+ export_static_lib_headers: [
+ "android.hardware.drm@1.0-helper",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+}
+
+cc_test {
+ name: "VtsHalDrmV1_2TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "drm_hal_test_main.cpp",
+ ],
+ whole_static_libs: [
+ "android.hardware.drm@1.2-vts",
+ ],
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.2",
+ "android.hidl.allocator@1.0",
+ "libhidlmemory",
+ ],
+ static_libs: [
+ "android.hardware.drm@1.0-helper",
"libcrypto_static",
+ "libdrmvtshelper",
],
test_suites: [
"general-tests",
diff --git a/drm/1.2/vts/functional/drm_hal_common.cpp b/drm/1.2/vts/functional/drm_hal_common.cpp
index 02aa3a99bc..d5e453c778 100644
--- a/drm/1.2/vts/functional/drm_hal_common.cpp
+++ b/drm/1.2/vts/functional/drm_hal_common.cpp
@@ -26,7 +26,7 @@
#include <random>
#include "drm_hal_clearkey_module.h"
-#include "drm_hal_common.h"
+#include "android/hardware/drm/1.2/vts/drm_hal_common.h"
using ::android::hardware::drm::V1_0::BufferType;
using ::android::hardware::drm::V1_0::DestinationBuffer;
@@ -87,14 +87,14 @@ static DrmHalVTSVendorModule_V1* getModuleForInstance(const std::string& instanc
return new DrmHalVTSClearkeyModule();
}
- return static_cast<DrmHalVTSVendorModule_V1*>(DrmHalTest::gVendorModules->getModule(instance));
+ return static_cast<DrmHalVTSVendorModule_V1*>(DrmHalTest::gVendorModules->getModuleByName(instance));
}
/**
* DrmHalTest
*/
-DrmHalTest::DrmHalTest() : vendorModule(getModuleForInstance(GetParam())) {}
+DrmHalTest::DrmHalTest() : vendorModule(getModuleForInstance(GetParamService())) {}
void DrmHalTest::SetUp() {
const ::testing::TestInfo* const test_info =
@@ -102,9 +102,9 @@ void DrmHalTest::SetUp() {
ALOGD("Running test %s.%s from (vendor) module %s",
test_info->test_case_name(), test_info->name(),
- GetParam().c_str());
+ GetParamService().c_str());
- const string instance = GetParam();
+ const string instance = GetParamService();
drmFactory = IDrmFactory::getService(instance);
ASSERT_NE(drmFactory, nullptr);
@@ -120,21 +120,16 @@ void DrmHalTest::SetUp() {
GTEST_SKIP() << "No vendor module installed";
}
- if (instance == "clearkey") {
- // TODO(b/147449315)
- // Only the clearkey plugged into the "default" instance supports
- // this test. Currently the "clearkey" instance fails some tests
- // here.
- GTEST_SKIP() << "Clearkey tests don't work with 'clearkey' instance yet.";
- }
-
ASSERT_EQ(instance, vendorModule->getServiceName());
contentConfigurations = vendorModule->getContentConfigurations();
// If drm scheme not installed skip subsequent tests
- if (drmFactory.get() == nullptr || !drmFactory->isCryptoSchemeSupported(getVendorUUID())) {
- vendorModule->setInstalled(false);
- return;
+ if (!drmFactory->isCryptoSchemeSupported(getUUID())) {
+ if (GetParamUUID() == hidl_array<uint8_t, 16>()) {
+ GTEST_SKIP() << "vendor module drm scheme not supported";
+ } else {
+ FAIL() << "param scheme must be supported: " << android::hardware::toString(GetParamUUID());
+ }
}
ASSERT_NE(nullptr, drmPlugin.get()) << "Can't find " << vendorModule->getServiceName() << " drm@1.2 plugin";
@@ -149,7 +144,7 @@ sp<IDrmPlugin> DrmHalTest::createDrmPlugin() {
sp<IDrmPlugin> plugin = nullptr;
hidl_string packageName("android.hardware.drm.test");
auto res =
- drmFactory->createPlugin(getVendorUUID(), packageName,
+ drmFactory->createPlugin(getUUID(), packageName,
[&](StatusV1_0 status, const sp<IDrmPluginV1_0>& pluginV1_0) {
EXPECT_EQ(StatusV1_0::OK == status, pluginV1_0 != nullptr);
plugin = IDrmPlugin::castFrom(pluginV1_0);
@@ -168,7 +163,7 @@ sp<ICryptoPlugin> DrmHalTest::createCryptoPlugin() {
sp<ICryptoPlugin> plugin = nullptr;
hidl_vec<uint8_t> initVec;
auto res = cryptoFactory->createPlugin(
- getVendorUUID(), initVec,
+ getUUID(), initVec,
[&](StatusV1_0 status, const sp<ICryptoPluginV1_0>& pluginV1_0) {
EXPECT_EQ(StatusV1_0::OK == status, pluginV1_0 != nullptr);
plugin = ICryptoPlugin::castFrom(pluginV1_0);
@@ -179,12 +174,63 @@ sp<ICryptoPlugin> DrmHalTest::createCryptoPlugin() {
return plugin;
}
+hidl_array<uint8_t, 16> DrmHalTest::getUUID() {
+ if (GetParamUUID() == hidl_array<uint8_t, 16>()) {
+ return getVendorUUID();
+ }
+ return GetParamUUID();
+}
+
hidl_array<uint8_t, 16> DrmHalTest::getVendorUUID() {
if (vendorModule == nullptr) return {};
vector<uint8_t> uuid = vendorModule->getUUID();
return hidl_array<uint8_t, 16>(&uuid[0]);
}
+void DrmHalTest::provision() {
+ hidl_string certificateType;
+ hidl_string certificateAuthority;
+ hidl_vec<uint8_t> provisionRequest;
+ hidl_string defaultUrl;
+ auto res = drmPlugin->getProvisionRequest_1_2(
+ certificateType, certificateAuthority,
+ [&](StatusV1_2 status, const hidl_vec<uint8_t>& request,
+ const hidl_string& url) {
+ if (status == StatusV1_2::OK) {
+ EXPECT_NE(request.size(), 0u);
+ provisionRequest = request;
+ defaultUrl = url;
+ } else if (status == StatusV1_2::ERROR_DRM_CANNOT_HANDLE) {
+ EXPECT_EQ(0u, request.size());
+ }
+ });
+ EXPECT_OK(res);
+
+ if (provisionRequest.size() > 0) {
+ vector<uint8_t> response = vendorModule->handleProvisioningRequest(
+ provisionRequest, defaultUrl);
+ ASSERT_NE(0u, response.size());
+
+ auto res = drmPlugin->provideProvisionResponse(
+ response, [&](StatusV1_0 status, const hidl_vec<uint8_t>&,
+ const hidl_vec<uint8_t>&) {
+ EXPECT_EQ(StatusV1_0::OK, status);
+ });
+ EXPECT_OK(res);
+ }
+}
+
+SessionId DrmHalTest::openSession(SecurityLevel level, StatusV1_0 *err) {
+ SessionId sessionId;
+ auto res = drmPlugin->openSession_1_1(level,
+ [&](StatusV1_0 status, const hidl_vec<unsigned char> &id) {
+ *err = status;
+ sessionId = id;
+ });
+ EXPECT_OK(res);
+ return sessionId;
+}
+
/**
* Helper method to open a session and verify that a non-empty
* session ID is returned
@@ -474,7 +520,7 @@ void DrmHalTest::aes_cbc_decrypt(uint8_t* dest, uint8_t* src,
/**
* Helper method to test decryption with invalid keys is returned
*/
-void DrmHalClearkeyTest::decryptWithInvalidKeys(
+void DrmHalClearkeyTestV1_2::decryptWithInvalidKeys(
hidl_vec<uint8_t>& invalidResponse,
vector<uint8_t>& iv,
const Pattern& noPattern,
diff --git a/drm/1.2/vts/functional/drm_hal_test.cpp b/drm/1.2/vts/functional/drm_hal_test.cpp
index 54c5751eab..0dfff26528 100644
--- a/drm/1.2/vts/functional/drm_hal_test.cpp
+++ b/drm/1.2/vts/functional/drm_hal_test.cpp
@@ -17,13 +17,13 @@
#define LOG_TAG "drm_hal_test@1.2"
#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
#include <hidl/HidlSupport.h>
#include <hidl/ServiceManagement.h>
#include <log/log.h>
#include <openssl/aes.h>
+#include <vector>
-#include "drm_hal_common.h"
+#include "android/hardware/drm/1.2/vts/drm_hal_common.h"
using ::android::hardware::drm::V1_0::Status;
using ::android::hardware::drm::V1_1::KeyRequestType;
@@ -34,12 +34,13 @@ using ::android::hardware::drm::V1_2::KeyStatus;
using ::android::hardware::drm::V1_2::KeyStatusType;
using ::android::hardware::drm::V1_2::OfflineLicenseState;
-using ::android::hardware::drm::V1_2::vts::DrmHalClearkeyTest;
+using ::android::hardware::drm::V1_2::vts::DrmHalClearkeyTestV1_2;
using ::android::hardware::drm::V1_2::vts::DrmHalPluginListener;
using ::android::hardware::drm::V1_2::vts::DrmHalTest;
using ::android::hardware::drm::V1_2::vts::kCallbackLostState;
using ::android::hardware::drm::V1_2::vts::kCallbackKeysChange;
+using ::android::hardware::hidl_array;
using ::android::hardware::hidl_string;
static const char* const kVideoMp4 = "video/mp4";
@@ -48,13 +49,13 @@ static const char* const kDrmErrorTestKey = "drmErrorTest";
static const char* const kDrmErrorInvalidState = "invalidState";
static const char* const kDrmErrorResourceContention = "resourceContention";
static const SecurityLevel kSwSecureCrypto = SecurityLevel::SW_SECURE_CRYPTO;
+static const SecurityLevel kHwSecureAll = SecurityLevel::HW_SECURE_ALL;
/**
* Ensure drm factory supports module UUID Scheme
*/
TEST_P(DrmHalTest, VendorUuidSupported) {
- RETURN_IF_SKIPPED;
- auto res = drmFactory->isCryptoSchemeSupported_1_2(getVendorUUID(), kVideoMp4, kSwSecureCrypto);
+ auto res = drmFactory->isCryptoSchemeSupported_1_2(getUUID(), kVideoMp4, kSwSecureCrypto);
ALOGI("kVideoMp4 = %s res %d", kVideoMp4, (bool)res);
EXPECT_TRUE(res);
}
@@ -63,7 +64,6 @@ TEST_P(DrmHalTest, VendorUuidSupported) {
* Ensure drm factory doesn't support an invalid scheme UUID
*/
TEST_P(DrmHalTest, InvalidPluginNotSupported) {
- RETURN_IF_SKIPPED;
const uint8_t kInvalidUUID[16] = {
0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
@@ -74,7 +74,6 @@ TEST_P(DrmHalTest, InvalidPluginNotSupported) {
* Ensure drm factory doesn't support an empty UUID
*/
TEST_P(DrmHalTest, EmptyPluginUUIDNotSupported) {
- RETURN_IF_SKIPPED;
hidl_array<uint8_t, 16> emptyUUID;
memset(emptyUUID.data(), 0, 16);
EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(emptyUUID, kVideoMp4, kSwSecureCrypto));
@@ -84,8 +83,7 @@ TEST_P(DrmHalTest, EmptyPluginUUIDNotSupported) {
* Ensure drm factory doesn't support an invalid mime type
*/
TEST_P(DrmHalTest, BadMimeNotSupported) {
- RETURN_IF_SKIPPED;
- EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(getVendorUUID(), kBadMime, kSwSecureCrypto));
+ EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(getUUID(), kBadMime, kSwSecureCrypto));
}
/**
@@ -101,36 +99,17 @@ TEST_P(DrmHalTest, BadMimeNotSupported) {
* that is delivered back to the HAL.
*/
TEST_P(DrmHalTest, DoProvisioning) {
- RETURN_IF_SKIPPED;
- hidl_string certificateType;
- hidl_string certificateAuthority;
- hidl_vec<uint8_t> provisionRequest;
- hidl_string defaultUrl;
- auto res = drmPlugin->getProvisionRequest_1_2(
- certificateType, certificateAuthority,
- [&](StatusV1_2 status, const hidl_vec<uint8_t>& request,
- const hidl_string& url) {
- if (status == StatusV1_2::OK) {
- EXPECT_NE(request.size(), 0u);
- provisionRequest = request;
- defaultUrl = url;
- } else if (status == StatusV1_2::ERROR_DRM_CANNOT_HANDLE) {
- EXPECT_EQ(0u, request.size());
- }
- });
- EXPECT_OK(res);
-
- if (provisionRequest.size() > 0) {
- vector<uint8_t> response = vendorModule->handleProvisioningRequest(
- provisionRequest, defaultUrl);
- ASSERT_NE(0u, response.size());
-
- auto res = drmPlugin->provideProvisionResponse(
- response, [&](Status status, const hidl_vec<uint8_t>&,
- const hidl_vec<uint8_t>&) {
- EXPECT_EQ(Status::OK, status);
- });
- EXPECT_OK(res);
+ for (auto level : {kHwSecureAll, kSwSecureCrypto}) {
+ StatusV1_0 err = StatusV1_0::OK;
+ auto sid = openSession(level, &err);
+ if (err == StatusV1_0::OK) {
+ closeSession(sid);
+ } else if (err == StatusV1_0::ERROR_DRM_CANNOT_HANDLE) {
+ continue;
+ } else {
+ EXPECT_EQ(StatusV1_0::ERROR_DRM_NOT_PROVISIONED, err);
+ provision();
+ }
}
}
@@ -138,7 +117,6 @@ TEST_P(DrmHalTest, DoProvisioning) {
* A get key request should fail if no sessionId is provided
*/
TEST_P(DrmHalTest, GetKeyRequestNoSession) {
- RETURN_IF_SKIPPED;
SessionId invalidSessionId;
hidl_vec<uint8_t> initData;
KeyedVector optionalParameters;
@@ -156,7 +134,6 @@ TEST_P(DrmHalTest, GetKeyRequestNoSession) {
* invalid mime type
*/
TEST_P(DrmHalTest, GetKeyRequestBadMime) {
- RETURN_IF_SKIPPED;
auto sessionId = openSession();
hidl_vec<uint8_t> initData;
KeyedVector optionalParameters;
@@ -193,7 +170,6 @@ void checkKeySetIdState(Status status, OfflineLicenseState state) {
* Test drm plugin offline key support
*/
TEST_P(DrmHalTest, OfflineLicenseTest) {
- RETURN_IF_SKIPPED;
auto sessionId = openSession();
hidl_vec<uint8_t> keySetId = loadKeys(sessionId, KeyType::OFFLINE);
@@ -233,7 +209,6 @@ TEST_P(DrmHalTest, OfflineLicenseTest) {
* Test drm plugin offline key state
*/
TEST_P(DrmHalTest, OfflineLicenseStateTest) {
- RETURN_IF_SKIPPED;
auto sessionId = openSession();
DrmHalVTSVendorModule_V1::ContentConfiguration content = getContent(KeyType::OFFLINE);
hidl_vec<uint8_t> keySetId = loadKeys(sessionId, content, KeyType::OFFLINE);
@@ -258,7 +233,6 @@ TEST_P(DrmHalTest, OfflineLicenseStateTest) {
* Negative offline license test. Remove empty keySetId
*/
TEST_P(DrmHalTest, RemoveEmptyKeySetId) {
- RETURN_IF_SKIPPED;
KeySetId emptyKeySetId;
Status err = drmPlugin->removeOfflineLicense(emptyKeySetId);
EXPECT_EQ(Status::BAD_VALUE, err);
@@ -268,7 +242,6 @@ TEST_P(DrmHalTest, RemoveEmptyKeySetId) {
* Negative offline license test. Get empty keySetId state
*/
TEST_P(DrmHalTest, GetEmptyKeySetIdState) {
- RETURN_IF_SKIPPED;
KeySetId emptyKeySetId;
auto res = drmPlugin->getOfflineLicenseState(emptyKeySetId, checkKeySetIdState<Status::BAD_VALUE, OfflineLicenseState::UNKNOWN>);
EXPECT_OK(res);
@@ -278,7 +251,6 @@ TEST_P(DrmHalTest, GetEmptyKeySetIdState) {
* Test that the plugin returns valid connected and max HDCP levels
*/
TEST_P(DrmHalTest, GetHdcpLevels) {
- RETURN_IF_SKIPPED;
auto res = drmPlugin->getHdcpLevels_1_2(
[&](StatusV1_2 status, const HdcpLevel &connectedLevel,
const HdcpLevel &maxLevel) {
@@ -294,7 +266,6 @@ TEST_P(DrmHalTest, GetHdcpLevels) {
* the listener gets them.
*/
TEST_P(DrmHalTest, ListenerKeysChange) {
- RETURN_IF_SKIPPED;
sp<DrmHalPluginListener> listener = new DrmHalPluginListener();
auto res = drmPlugin->setListener(listener);
EXPECT_OK(res);
@@ -326,7 +297,6 @@ TEST_P(DrmHalTest, ListenerKeysChange) {
* Positive decrypt test. "Decrypt" a single clear segment
*/
TEST_P(DrmHalTest, ClearSegmentTest) {
- RETURN_IF_SKIPPED;
for (const auto& config : contentConfigurations) {
for (const auto& key : config.keys) {
const size_t kSegmentSize = 1024;
@@ -354,7 +324,6 @@ TEST_P(DrmHalTest, ClearSegmentTest) {
* Verify data matches.
*/
TEST_P(DrmHalTest, EncryptedAesCtrSegmentTest) {
- RETURN_IF_SKIPPED;
for (const auto& config : contentConfigurations) {
for (const auto& key : config.keys) {
const size_t kSegmentSize = 1024;
@@ -381,7 +350,6 @@ TEST_P(DrmHalTest, EncryptedAesCtrSegmentTest) {
* Negative decrypt test. Decrypted frame too large to fit in output buffer
*/
TEST_P(DrmHalTest, ErrorFrameTooLarge) {
- RETURN_IF_SKIPPED;
for (const auto& config : contentConfigurations) {
for (const auto& key : config.keys) {
const size_t kSegmentSize = 1024;
@@ -407,7 +375,6 @@ TEST_P(DrmHalTest, ErrorFrameTooLarge) {
* Negative decrypt test. Decrypt without loading keys.
*/
TEST_P(DrmHalTest, EncryptedAesCtrSegmentTestNoKeys) {
- RETURN_IF_SKIPPED;
for (const auto& config : contentConfigurations) {
for (const auto& key : config.keys) {
vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
@@ -432,17 +399,14 @@ TEST_P(DrmHalTest, EncryptedAesCtrSegmentTestNoKeys) {
/**
* Ensure clearkey drm factory doesn't support security level higher than supported
*/
-TEST_P(DrmHalClearkeyTest, BadLevelNotSupported) {
- RETURN_IF_SKIPPED;
- const SecurityLevel kHwSecureAll = SecurityLevel::HW_SECURE_ALL;
- EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(getVendorUUID(), kVideoMp4, kHwSecureAll));
+TEST_P(DrmHalClearkeyTestV1_2, BadLevelNotSupported) {
+ EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(getUUID(), kVideoMp4, kHwSecureAll));
}
/**
* Test resource contention during attempt to generate key request
*/
-TEST_P(DrmHalClearkeyTest, GetKeyRequestResourceContention) {
- RETURN_IF_SKIPPED;
+TEST_P(DrmHalClearkeyTestV1_2, GetKeyRequestResourceContention) {
Status status = drmPlugin->setPropertyString(kDrmErrorTestKey, kDrmErrorResourceContention);
EXPECT_EQ(Status::OK, status);
auto sessionId = openSession();
@@ -463,8 +427,7 @@ TEST_P(DrmHalClearkeyTest, GetKeyRequestResourceContention) {
/**
* Test clearkey plugin offline key with mock error
*/
-TEST_P(DrmHalClearkeyTest, OfflineLicenseInvalidState) {
- RETURN_IF_SKIPPED;
+TEST_P(DrmHalClearkeyTestV1_2, OfflineLicenseInvalidState) {
auto sessionId = openSession();
hidl_vec<uint8_t> keySetId = loadKeys(sessionId, KeyType::OFFLINE);
Status status = drmPlugin->setPropertyString(kDrmErrorTestKey, kDrmErrorInvalidState);
@@ -485,8 +448,7 @@ TEST_P(DrmHalClearkeyTest, OfflineLicenseInvalidState) {
/**
* Test SessionLostState is triggered on error
*/
-TEST_P(DrmHalClearkeyTest, SessionLostState) {
- RETURN_IF_SKIPPED;
+TEST_P(DrmHalClearkeyTestV1_2, SessionLostState) {
sp<DrmHalPluginListener> listener = new DrmHalPluginListener();
auto res = drmPlugin->setListener(listener);
EXPECT_OK(res);
@@ -506,8 +468,7 @@ TEST_P(DrmHalClearkeyTest, SessionLostState) {
/**
* Negative decrypt test. Decrypt with invalid key.
*/
-TEST_P(DrmHalClearkeyTest, DecryptWithEmptyKey) {
- RETURN_IF_SKIPPED;
+TEST_P(DrmHalClearkeyTestV1_2, DecryptWithEmptyKey) {
vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
const Pattern noPattern = {0, 0};
const uint32_t kClearBytes = 512;
@@ -544,8 +505,7 @@ TEST_P(DrmHalClearkeyTest, DecryptWithEmptyKey) {
/**
* Negative decrypt test. Decrypt with a key exceeds AES_BLOCK_SIZE.
*/
-TEST_P(DrmHalClearkeyTest, DecryptWithKeyTooLong) {
- RETURN_IF_SKIPPED;
+TEST_P(DrmHalClearkeyTestV1_2, DecryptWithKeyTooLong) {
vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
const Pattern noPattern = {0, 0};
const uint32_t kClearBytes = 512;
@@ -572,43 +532,3 @@ TEST_P(DrmHalClearkeyTest, DecryptWithKeyTooLong) {
memcpy(invalidResponse.data(), keyTooLongResponse.c_str(), kKeyTooLongResponseSize);
decryptWithInvalidKeys(invalidResponse, iv, noPattern, subSamples);
}
-
-/**
- * Instantiate the set of test cases for each vendor module
- */
-
-static const std::set<std::string> kAllInstances = [] {
- using ::android::hardware::drm::V1_2::ICryptoFactory;
- using ::android::hardware::drm::V1_2::IDrmFactory;
-
- std::vector<std::string> drmInstances =
- android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
- std::vector<std::string> cryptoInstances =
- android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
- std::set<std::string> allInstances;
- allInstances.insert(drmInstances.begin(), drmInstances.end());
- allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
- return allInstances;
-}();
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalTest, testing::ValuesIn(kAllInstances),
- android::hardware::PrintInstanceNameToString);
-INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyTest, testing::ValuesIn(kAllInstances),
- android::hardware::PrintInstanceNameToString);
-
-int main(int argc, char** argv) {
-#if defined(__LP64__)
- const char* kModulePath = "/data/local/tmp/64/lib";
-#else
- const char* kModulePath = "/data/local/tmp/32/lib";
-#endif
- DrmHalTest::gVendorModules = new drm_vts::VendorModules(kModulePath);
- if (DrmHalTest::gVendorModules->getPathList().size() == 0) {
- std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
- ", all vendor tests will be skipped" << std::endl;
- }
- ::testing::InitGoogleTest(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
diff --git a/drm/1.2/vts/functional/drm_hal_test_main.cpp b/drm/1.2/vts/functional/drm_hal_test_main.cpp
new file mode 100644
index 0000000000..ea6e63df6e
--- /dev/null
+++ b/drm/1.2/vts/functional/drm_hal_test_main.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/**
+ * Instantiate the set of test cases for each vendor module
+ */
+
+#define LOG_TAG "drm_hal_test@1.2"
+
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "android/hardware/drm/1.2/vts/drm_hal_common.h"
+
+using android::hardware::drm::V1_2::vts::DrmHalTest;
+using android::hardware::drm::V1_2::vts::DrmHalClearkeyTestV1_2;
+using drm_vts::DrmHalTestParam;
+using drm_vts::PrintParamInstanceToString;
+
+static const std::vector<DrmHalTestParam> kAllInstances = [] {
+ using ::android::hardware::drm::V1_2::ICryptoFactory;
+ using ::android::hardware::drm::V1_2::IDrmFactory;
+
+ std::vector<std::string> drmInstances =
+ android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
+ std::vector<std::string> cryptoInstances =
+ android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
+ std::set<std::string> allInstances;
+ allInstances.insert(drmInstances.begin(), drmInstances.end());
+ allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
+
+ std::vector<DrmHalTestParam> allInstanceUuidCombos;
+ auto noUUID = [](std::string s) { return DrmHalTestParam(s); };
+ std::transform(allInstances.begin(), allInstances.end(),
+ std::back_inserter(allInstanceUuidCombos), noUUID);
+ return allInstanceUuidCombos;
+}();
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalTest, testing::ValuesIn(kAllInstances),
+ PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyTestV1_2, testing::ValuesIn(kAllInstances),
+ PrintParamInstanceToString);
+
+int main(int argc, char** argv) {
+#if defined(__LP64__)
+ const char* kModulePath = "/data/local/tmp/64/lib";
+#else
+ const char* kModulePath = "/data/local/tmp/32/lib";
+#endif
+ DrmHalTest::gVendorModules = new drm_vts::VendorModules(kModulePath);
+ if (DrmHalTest::gVendorModules->getPathList().size() == 0) {
+ std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
+ ", all vendor tests will be skipped" << std::endl;
+ }
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/drm/1.2/vts/functional/drm_hal_common.h b/drm/1.2/vts/functional/include/android/hardware/drm/1.2/vts/drm_hal_common.h
index b2d654c604..6fee6f4631 100644
--- a/drm/1.2/vts/functional/drm_hal_common.h
+++ b/drm/1.2/vts/functional/include/android/hardware/drm/1.2/vts/drm_hal_common.h
@@ -23,28 +23,33 @@
#include <android/hardware/drm/1.2/IDrmPlugin.h>
#include <android/hardware/drm/1.2/IDrmPluginListener.h>
#include <android/hardware/drm/1.2/types.h>
+#include <hidl/HidlSupport.h>
+#include <array>
#include <chrono>
+# include <iostream>
#include <map>
#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include "drm_hal_vendor_module_api.h"
+#include "drm_vts_helper.h"
#include "vendor_modules.h"
#include "VtsHalHidlTargetCallbackBase.h"
using ::android::hardware::drm::V1_0::EventType;
using ::android::hardware::drm::V1_0::KeyedVector;
-using KeyStatusV1_0 = ::android::hardware::drm::V1_0::KeyStatus;
using ::android::hardware::drm::V1_0::KeyType;
using ::android::hardware::drm::V1_0::Mode;
using ::android::hardware::drm::V1_0::Pattern;
using ::android::hardware::drm::V1_0::SessionId;
using ::android::hardware::drm::V1_0::SubSample;
+using ::android::hardware::drm::V1_1::SecurityLevel;
-using ::android::hardware::drm::V1_1::ICryptoFactory;
-
+using KeyStatusV1_0 = ::android::hardware::drm::V1_0::KeyStatus;
+using StatusV1_0 = ::android::hardware::drm::V1_0::Status;
using StatusV1_2 = ::android::hardware::drm::V1_2::Status;
using ::android::hardware::hidl_array;
@@ -55,28 +60,24 @@ using ::android::hardware::Void;
using ::android::hidl::memory::V1_0::IMemory;
using ::android::sp;
+using drm_vts::DrmHalTestParam;
+
+using std::array;
using std::map;
+using std::pair;
using std::string;
using std::unique_ptr;
using std::vector;
#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
-#define RETURN_IF_SKIPPED \
- if (!vendorModule->isInstalled()) { \
- GTEST_SKIP() << "This drm scheme not supported." \
- << " library:" << GetParam() \
- << " service-name:" << vendorModule->getServiceName() << std::endl; \
- return; \
- }
-
namespace android {
namespace hardware {
namespace drm {
namespace V1_2 {
namespace vts {
-class DrmHalTest : public ::testing::TestWithParam<std::string> {
+class DrmHalTest : public ::testing::TestWithParam<DrmHalTestParam> {
public:
static drm_vts::VendorModules* gVendorModules;
DrmHalTest();
@@ -84,7 +85,12 @@ class DrmHalTest : public ::testing::TestWithParam<std::string> {
virtual void TearDown() override {}
protected:
+ hidl_array<uint8_t, 16> getUUID();
hidl_array<uint8_t, 16> getVendorUUID();
+ hidl_array<uint8_t, 16> GetParamUUID() { return GetParam().scheme_; }
+ string GetParamService() { return GetParam().instance_; }
+ void provision();
+ SessionId openSession(SecurityLevel level, StatusV1_0* err);
SessionId openSession();
void closeSession(const SessionId& sessionId);
hidl_vec<uint8_t> loadKeys(const SessionId& sessionId,
@@ -127,13 +133,15 @@ class DrmHalTest : public ::testing::TestWithParam<std::string> {
};
-class DrmHalClearkeyTest : public DrmHalTest {
+class DrmHalClearkeyTestV1_2 : public DrmHalTest {
public:
virtual void SetUp() override {
DrmHalTest::SetUp();
-
- if (vendorModule == nullptr) {
- GTEST_SKIP() << "Instance not supported";
+ const uint8_t kClearKeyUUID[16] = {
+ 0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
+ 0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E};
+ if (!drmFactory->isCryptoSchemeSupported(kClearKeyUUID)) {
+ GTEST_SKIP() << "ClearKey not supported by " << GetParamService();
}
}
virtual void TearDown() override {}
diff --git a/drm/1.2/vts/functional/vendor_modules.cpp b/drm/1.2/vts/functional/vendor_modules.cpp
deleted file mode 100644
index efcb90a91a..0000000000
--- a/drm/1.2/vts/functional/vendor_modules.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#define LOG_TAG "drm-vts-vendor-modules"
-
-#include <dirent.h>
-#include <dlfcn.h>
-#include <log/log.h>
-#include <memory>
-#include <utils/String8.h>
-#include <SharedLibrary.h>
-
-#include "vendor_modules.h"
-
-using std::string;
-using std::vector;
-using std::unique_ptr;
-using ::android::String8;
-using ::android::hardware::drm::V1_0::helper::SharedLibrary;
-
-namespace drm_vts {
-void VendorModules::scanModules(const std::string &directory) {
- DIR* dir = opendir(directory.c_str());
- if (dir == NULL) {
- ALOGE("Unable to open drm VTS vendor directory %s", directory.c_str());
- } else {
- struct dirent* entry;
- while ((entry = readdir(dir))) {
- ALOGD("checking file %s", entry->d_name);
- string fullpath = directory + "/" + entry->d_name;
- if (endsWith(fullpath, ".so")) {
- mPathList.push_back(fullpath);
- }
- }
- closedir(dir);
- }
-}
-
-DrmHalVTSVendorModule* VendorModules::getModule(const string& path) {
- if (mOpenLibraries.find(path) == mOpenLibraries.end()) {
- auto library = std::make_unique<SharedLibrary>(String8(path.c_str()));
- if (!library) {
- ALOGE("failed to map shared library %s", path.c_str());
- return NULL;
- }
- mOpenLibraries[path] = std::move(library);
- }
- const unique_ptr<SharedLibrary>& library = mOpenLibraries[path];
- void* symbol = library->lookup("vendorModuleFactory");
- if (symbol == NULL) {
- ALOGE("getVendorModule failed to lookup 'vendorModuleFactory' in %s: "
- "%s", path.c_str(), library->lastError());
- return NULL;
- }
- typedef DrmHalVTSVendorModule* (*ModuleFactory)();
- ModuleFactory moduleFactory = reinterpret_cast<ModuleFactory>(symbol);
- return (*moduleFactory)();
-}
-};
diff --git a/drm/1.2/vts/functional/vendor_modules.h b/drm/1.2/vts/functional/vendor_modules.h
deleted file mode 100644
index 9b730adcd9..0000000000
--- a/drm/1.2/vts/functional/vendor_modules.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2019 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 VENDOR_MODULES_H
-#define VENDOR_MODULES_H
-
-#include <map>
-#include <vector>
-#include <string>
-
-#include <SharedLibrary.h>
-
-using ::android::hardware::drm::V1_0::helper::SharedLibrary;
-
-class DrmHalVTSVendorModule;
-
-namespace drm_vts {
-class VendorModules {
- public:
- /**
- * Initialize with a file system path where the shared libraries
- * are to be found.
- */
- explicit VendorModules(const std::string& dir) {
- scanModules(dir);
- }
- ~VendorModules() {}
-
- /**
- * Retrieve a DrmHalVTSVendorModule given its full path. The
- * getAPIVersion method can be used to determine the versioned
- * subclass type.
- */
- DrmHalVTSVendorModule* getModule(const std::string& path);
-
- /**
- * Return the list of paths to available vendor modules.
- */
- std::vector<std::string> getPathList() const {return mPathList;}
-
- private:
- std::vector<std::string> mPathList;
- std::map<std::string, std::unique_ptr<SharedLibrary>> mOpenLibraries;
-
- /**
- * Scan the list of paths to available vendor modules.
- */
- void scanModules(const std::string& dir);
-
- inline bool endsWith(const std::string& str, const std::string& suffix) const {
- if (suffix.size() > str.size()) return false;
- return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin());
- }
-
- VendorModules(const VendorModules&) = delete;
- void operator=(const VendorModules&) = delete;
-};
-};
-
-#endif // VENDOR_MODULES_H
diff --git a/drm/1.3/vts/OWNERS b/drm/1.3/vts/OWNERS
new file mode 100644
index 0000000000..3a0672e5c6
--- /dev/null
+++ b/drm/1.3/vts/OWNERS
@@ -0,0 +1,9 @@
+conglin@google.com
+edwinwong@google.com
+fredgc@google.com
+jtinker@google.com
+juce@google.com
+kylealexander@google.com
+rfrias@google.com
+robertshih@google.com
+sigquit@google.com
diff --git a/drm/1.3/vts/functional/Android.bp b/drm/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000000..4be157584b
--- /dev/null
+++ b/drm/1.3/vts/functional/Android.bp
@@ -0,0 +1,78 @@
+//
+// 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.
+//
+
+cc_library_static {
+ name: "android.hardware.drm@1.3-vts",
+ defaults: ["VtsHalTargetTestDefaults"],
+ local_include_dirs: [
+ "include",
+ ],
+ srcs: [
+ "drm_hal_test.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "android.hardware.drm@1.2",
+ "android.hardware.drm@1.3",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlmemory",
+ "libnativehelper",
+ ],
+ static_libs: [
+ "android.hardware.drm@1.0-helper",
+ "libcrypto_static",
+ "libdrmvtshelper",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+}
+
+cc_test {
+ name: "VtsHalDrmV1_3TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ include_dirs: ["hardware/interfaces/drm/1.0/vts/functional"],
+ srcs: [
+ "drm_hal_test_main.cpp",
+ ],
+ whole_static_libs: [
+ "android.hardware.drm@1.0-vts",
+ "android.hardware.drm@1.1-vts",
+ "android.hardware.drm@1.2-vts",
+ "android.hardware.drm@1.3-vts",
+ ],
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "android.hardware.drm@1.2",
+ "android.hardware.drm@1.3",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlmemory",
+ "libnativehelper",
+ ],
+ static_libs: [
+ "android.hardware.drm@1.0-helper",
+ "libcrypto_static",
+ "libdrmvtshelper",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/drm/1.3/vts/functional/drm_hal_test.cpp b/drm/1.3/vts/functional/drm_hal_test.cpp
new file mode 100644
index 0000000000..738f5b28f6
--- /dev/null
+++ b/drm/1.3/vts/functional/drm_hal_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "drm_hal_test@1.3"
+
+#include "android/hardware/drm/1.3/vts/drm_hal_test.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_3 {
+namespace vts {
+
+TEST_P(DrmHalTestV1_3, SchemeSupported) {
+ EXPECT_TRUE(drmFactory_->isCryptoSchemeSupported(GetParam().scheme_));
+}
+
+TEST_P(DrmHalTestV1_3, SignRsaNotAllowed) {
+ hidl_array<uint8_t, 16> kWidevineUUID ({
+ 0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE,
+ 0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED
+ });
+
+ if (!drmFactory_->isCryptoSchemeSupported(kWidevineUUID)) {
+ GTEST_SKIP() << "Widevine only test";
+ }
+
+ // signRSA
+ const hidl_vec<uint8_t>& sessionId{};
+ const hidl_string& algorithm{};
+ const hidl_vec<uint8_t>& message{};
+ const hidl_vec<uint8_t>& wrappedKey{};
+ auto res = drmPlugin_->signRSA(
+ sessionId, algorithm, message, wrappedKey,
+ [&](StatusV1_0 status, const hidl_vec<uint8_t>& signature) {
+ EXPECT_EQ(status, StatusV1_0::ERROR_DRM_UNKNOWN);
+ EXPECT_EQ(signature.size(), 0);
+ }
+ );
+ EXPECT_TRUE(res.isOk());
+}
+
+} // namespace vts
+} // namespace V1_3
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/1.3/vts/functional/drm_hal_test_main.cpp b/drm/1.3/vts/functional/drm_hal_test_main.cpp
new file mode 100644
index 0000000000..02b45ea6b9
--- /dev/null
+++ b/drm/1.3/vts/functional/drm_hal_test_main.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+/**
+ * Instantiate the set of test cases for each vendor module
+ */
+
+#define LOG_TAG "drm_hal_test@1.3"
+
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h" // V1_0 tests
+#include "android/hardware/drm/1.0/vts/drm_hal_vendor_test.h" // V1_0 tests
+#include "android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h" // V1_1 tests
+#include "android/hardware/drm/1.2/vts/drm_hal_common.h" // V1_2 tests
+#include "android/hardware/drm/1.3/vts/drm_hal_test.h" // V1_3 tests
+
+using drm_vts::DrmHalTestParam;
+using drm_vts::PrintParamInstanceToString;
+
+using android::hardware::drm::V1_0::vts::DrmHalVendorFactoryTest;
+using android::hardware::drm::V1_0::vts::DrmHalVendorPluginTest;
+using android::hardware::drm::V1_0::vts::DrmHalVendorDecryptTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyFactoryTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyPluginTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyDecryptTest;
+using android::hardware::drm::V1_1::vts::DrmHalClearkeyTest;
+using android::hardware::drm::V1_2::vts::DrmHalTest;
+using android::hardware::drm::V1_2::vts::DrmHalClearkeyTestV1_2;
+using android::hardware::drm::V1_3::vts::DrmHalTestV1_3;
+
+static const std::vector<DrmHalTestParam> kAllInstances = [] {
+ using ::android::hardware::drm::V1_3::ICryptoFactory;
+ using ::android::hardware::drm::V1_3::IDrmFactory;
+
+ std::vector<std::string> drmInstances =
+ android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
+ std::vector<std::string> cryptoInstances =
+ android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
+ std::set<std::string> allInstances;
+ allInstances.insert(drmInstances.begin(), drmInstances.end());
+ allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
+
+ std::vector<DrmHalTestParam> allInstanceUuidCombos;
+ for (const auto &instance : allInstances) {
+ auto drmFactory = IDrmFactory::getService(instance);
+ if (drmFactory == nullptr) {
+ continue;
+ }
+ drmFactory->getSupportedCryptoSchemes(
+ [&](const hidl_vec<hidl_array<uint8_t, 16>>& schemes) {
+ for (const auto &scheme : schemes) {
+ allInstanceUuidCombos.push_back(DrmHalTestParam(instance, scheme));
+ }
+ });
+ }
+ return allInstanceUuidCombos;
+}();
+
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorFactoryTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorPluginTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorDecryptTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyFactoryTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyPluginTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyDecryptTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_1, DrmHalClearkeyTest,
+ testing::ValuesIn(kAllInstances),
+ PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalTest,
+ testing::ValuesIn(kAllInstances),
+ PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalClearkeyTestV1_2,
+ testing::ValuesIn(kAllInstances),
+ PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_3, DrmHalTestV1_3,
+ testing::ValuesIn(kAllInstances),
+ PrintParamInstanceToString);
+
+int main(int argc, char** argv) {
+#if defined(__LP64__)
+ const char* kModulePath = "/data/local/tmp/64/lib";
+#else
+ const char* kModulePath = "/data/local/tmp/32/lib";
+#endif
+ DrmHalTest::gVendorModules = new drm_vts::VendorModules(kModulePath);
+ if (DrmHalTest::gVendorModules->getPathList().size() == 0) {
+ std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
+ ", all vendor tests will be skipped" << std::endl;
+ }
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h b/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h
new file mode 100644
index 0000000000..d8f527764b
--- /dev/null
+++ b/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h
@@ -0,0 +1,86 @@
+/*
+ * 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 DRM_HAL_TEST_V1_3_H
+#define DRM_HAL_TEST_V1_3_H
+
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "drm_hal_vendor_module_api.h"
+#include "drm_vts_helper.h"
+#include "vendor_modules.h"
+#include "VtsHalHidlTargetCallbackBase.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_3 {
+namespace vts {
+
+using android::hardware::hidl_array;
+using android::hardware::hidl_string;
+
+using drm_vts::DrmHalTestParam;
+
+using IDrmFactoryV1_3 = android::hardware::drm::V1_3::IDrmFactory;
+using IDrmPluginV1_0 = android::hardware::drm::V1_0::IDrmPlugin;
+using StatusV1_0 = android::hardware::drm::V1_0::Status;
+
+class DrmHalTestV1_3 : public ::testing::TestWithParam<DrmHalTestParam> {
+public:
+ DrmHalTestV1_3()
+ : drmFactory_(IDrmFactoryV1_3::getService(GetParam().instance_)) {}
+
+ virtual void SetUp() override {
+ ASSERT_NE(drmFactory_, nullptr);
+
+ // create plugin
+ hidl_string packageName("android.hardware.drm.V1_3.vts");
+ auto res = drmFactory_->createPlugin(
+ GetParam().scheme_, packageName,
+ [&](StatusV1_0 status, const sp<IDrmPluginV1_0>& pluginV1_0) {
+ EXPECT_EQ(StatusV1_0::OK, status);
+ drmPlugin_ = pluginV1_0;
+ });
+ EXPECT_TRUE(res.isOk());
+ ASSERT_NE(drmPlugin_, nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+protected:
+ sp<IDrmFactoryV1_3> drmFactory_;
+ sp<IDrmPluginV1_0> drmPlugin_;
+};
+
+} // namespace vts
+} // namespace V1_3
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // DRM_HAL_TEST_V1_3_H
diff --git a/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp b/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
index 96b13c5c38..343d4c9bcf 100644
--- a/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
+++ b/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
@@ -78,6 +78,7 @@ TEST_P(DumpstateHidlTest, TestOk) {
ASSERT_EQ(1, read(fds[0], &buff, 1)) << "dumped nothing";
native_handle_close(handle);
+ native_handle_delete(handle);
}
// Positive test: make sure dumpstateBoard() doesn't crash with two FDs.
@@ -96,6 +97,7 @@ TEST_P(DumpstateHidlTest, TestHandleWithTwoFds) {
ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
native_handle_close(handle);
+ native_handle_delete(handle);
}
INSTANTIATE_TEST_SUITE_P(
diff --git a/dumpstate/1.1/Android.bp b/dumpstate/1.1/Android.bp
new file mode 100644
index 0000000000..2aa8c82dc7
--- /dev/null
+++ b/dumpstate/1.1/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.dumpstate@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IDumpstateDevice.hal",
+ ],
+ interfaces: [
+ "android.hardware.dumpstate@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/dumpstate/1.1/IDumpstateDevice.hal b/dumpstate/1.1/IDumpstateDevice.hal
new file mode 100644
index 0000000000..24831b37b2
--- /dev/null
+++ b/dumpstate/1.1/IDumpstateDevice.hal
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+package android.hardware.dumpstate@1.1;
+
+import @1.0::IDumpstateDevice;
+
+interface IDumpstateDevice extends @1.0::IDumpstateDevice {
+ /**
+ * Extension of dumpstateBoard which also accepts a mode parameter to limit dumped data.
+ *
+ * For an example of when this is relevant, consider a bug report being generated with
+ * DumpstateMode::CONNECTIVITY - there is no reason to include camera or USB logs in this type
+ * of report.
+ *
+ * The 1.0 version of #dumpstateBoard(handle) should just delegate to this new method and pass
+ * DumpstateMode::DEFAULT and a timeout of 30,000ms (30 seconds).
+ *
+ * @param h A native handle with one or two valid file descriptors. The first FD is for text
+ * output, the second (if present) is for binary output.
+ * @param mode A mode value to restrict dumped content.
+ * @param timeoutMillis An approximate "budget" for how much time this call has been allotted.
+ * If execution runs longer than this, the IDumpstateDevice service may be killed and only
+ * partial information will be included in the report.
+ */
+ dumpstateBoard_1_1(handle h, DumpstateMode mode, uint64_t timeoutMillis);
+
+ /**
+ * Turns device vendor logging on or off.
+ *
+ * The setting should be persistent across reboots. Underlying implementations may need to start
+ * vendor logging daemons, set system properties, or change logging masks, for example. Given
+ * that many vendor logs contain significant amounts of private information and may come with
+ * memory/storage/battery impacts, calling this method on a user build should only be done after
+ * user consent has been obtained, e.g. from a toggle in developer settings.
+ *
+ * @param enable Whether to enable or disable device vendor logging.
+ * @return success Whether or not the change took effect.
+ */
+ setDeviceLoggingEnabled(bool enable) generates (bool success);
+};
diff --git a/dumpstate/1.1/types.hal b/dumpstate/1.1/types.hal
new file mode 100644
index 0000000000..a6f391aded
--- /dev/null
+++ b/dumpstate/1.1/types.hal
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+package android.hardware.dumpstate@1.1;
+
+/**
+ * Constants that define the type of bug report being taken to restrict content appropriately.
+ */
+enum DumpstateMode : uint32_t {
+ /**
+ * Takes a bug report without user interference.
+ */
+ FULL = 0,
+
+ /**
+ * Interactive bug report, i.e. triggered by the user.
+ */
+ INTERACTIVE = 1,
+
+ /**
+ * Remote bug report triggered by DevicePolicyManager, for example.
+ */
+ REMOTE = 2,
+
+ /**
+ * Bug report triggered on a wear device.
+ */
+ WEAR = 3,
+
+ /**
+ * Bug report limited to only connectivity info (cellular, wifi, and networking). Sometimes
+ * called "telephony" in legacy contexts.
+ *
+ * All reported information MUST directly relate to connectivity debugging or customer support
+ * and MUST NOT contain unrelated private information. This information MUST NOT identify
+ * user-installed packages (UIDs are OK, package names are not), and MUST NOT contain logs of
+ * user application traffic.
+ */
+ CONNECTIVITY = 4,
+
+ /**
+ * Bug report limited to only wifi info.
+ */
+ WIFI = 5,
+
+ /**
+ * Default mode.
+ */
+ DEFAULT = 6
+};
diff --git a/dumpstate/1.1/vts/functional/Android.bp b/dumpstate/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000000..5267706c0b
--- /dev/null
+++ b/dumpstate/1.1/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+//
+// 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.
+//
+
+cc_test {
+ name: "VtsHalDumpstateV1_1TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalDumpstateV1_1TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.dumpstate@1.0",
+ "android.hardware.dumpstate@1.1",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
new file mode 100644
index 0000000000..583efbf722
--- /dev/null
+++ b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "dumpstate_1_1_hidl_hal_test"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
+#include <android/hardware/dumpstate/1.1/types.h>
+#include <cutils/native_handle.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+namespace {
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::dumpstate::V1_1::DumpstateMode;
+using ::android::hardware::dumpstate::V1_1::IDumpstateDevice;
+
+class DumpstateHidl1_1Test : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ dumpstate = IDumpstateDevice::getService(GetParam());
+ ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance";
+ }
+
+ sp<IDumpstateDevice> dumpstate;
+};
+
+#define TEST_FOR_DUMPSTATE_MODE(name, body, mode) \
+ TEST_P(DumpstateHidl1_1Test, name##_##mode) { body(DumpstateMode::mode); }
+
+#define TEST_FOR_ALL_DUMPSTATE_MODES(name, body) \
+ TEST_FOR_DUMPSTATE_MODE(name, body, FULL); \
+ TEST_FOR_DUMPSTATE_MODE(name, body, INTERACTIVE); \
+ TEST_FOR_DUMPSTATE_MODE(name, body, REMOTE); \
+ TEST_FOR_DUMPSTATE_MODE(name, body, WEAR); \
+ TEST_FOR_DUMPSTATE_MODE(name, body, CONNECTIVITY); \
+ TEST_FOR_DUMPSTATE_MODE(name, body, WIFI); \
+ TEST_FOR_DUMPSTATE_MODE(name, body, DEFAULT);
+
+constexpr uint64_t kDefaultTimeoutMillis = 30 * 1000; // 30 seconds
+
+// Negative test: make sure dumpstateBoard() doesn't crash when passed a null pointer.
+TEST_FOR_ALL_DUMPSTATE_MODES(TestNullHandle, [this](DumpstateMode mode) {
+ Return<void> status = dumpstate->dumpstateBoard_1_1(nullptr, mode, kDefaultTimeoutMillis);
+
+ ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+});
+
+// Negative test: make sure dumpstateBoard() ignores a handle with no FD.
+TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithNoFd, [this](DumpstateMode mode) {
+ native_handle_t* handle = native_handle_create(0, 0);
+ ASSERT_NE(handle, nullptr) << "Could not create native_handle";
+
+ Return<void> status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+
+ ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+
+ native_handle_close(handle);
+ native_handle_delete(handle);
+});
+
+// Positive test: make sure dumpstateBoard() writes something to the FD.
+TEST_FOR_ALL_DUMPSTATE_MODES(TestOk, [this](DumpstateMode mode) {
+ // Index 0 corresponds to the read end of the pipe; 1 to the write end.
+ int fds[2];
+ ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+ native_handle_t* handle = native_handle_create(1, 0);
+ ASSERT_NE(handle, nullptr) << "Could not create native_handle";
+ handle->data[0] = fds[1];
+
+ Return<void> status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+ ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+
+ // Check that at least one byte was written
+ char buff;
+ ASSERT_EQ(1, read(fds[0], &buff, 1)) << "dumped nothing";
+
+ native_handle_close(handle);
+ native_handle_delete(handle);
+});
+
+// Positive test: make sure dumpstateBoard() doesn't crash with two FDs.
+TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithTwoFds, [this](DumpstateMode mode) {
+ int fds1[2];
+ int fds2[2];
+ ASSERT_EQ(0, pipe2(fds1, O_NONBLOCK)) << errno;
+ ASSERT_EQ(0, pipe2(fds2, O_NONBLOCK)) << errno;
+
+ native_handle_t* handle = native_handle_create(2, 0);
+ ASSERT_NE(handle, nullptr) << "Could not create native_handle";
+ handle->data[0] = fds1[1];
+ handle->data[1] = fds2[1];
+
+ Return<void> status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+ ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+
+ native_handle_close(handle);
+ native_handle_delete(handle);
+});
+
+// Make sure dumpstateBoard_1_1 actually validates its arguments.
+TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Negative) {
+ int fds[2];
+ ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+ native_handle_t* handle = native_handle_create(1, 0);
+ ASSERT_NE(handle, nullptr) << "Could not create native_handle";
+ handle->data[0] = fds[1];
+
+ Return<void> status = dumpstate->dumpstateBoard_1_1(handle, static_cast<DumpstateMode>(-100),
+ kDefaultTimeoutMillis);
+ ASSERT_FALSE(status.isOk()) << "Status should not be ok with invalid mode param: "
+ << status.description();
+
+ native_handle_close(handle);
+ native_handle_delete(handle);
+}
+
+TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Undefined) {
+ int fds[2];
+ ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+ native_handle_t* handle = native_handle_create(1, 0);
+ ASSERT_NE(handle, nullptr) << "Could not create native_handle";
+ handle->data[0] = fds[1];
+
+ Return<void> status = dumpstate->dumpstateBoard_1_1(handle, static_cast<DumpstateMode>(9001),
+ kDefaultTimeoutMillis);
+ ASSERT_FALSE(status.isOk()) << "Status should not be ok with invalid mode param: "
+ << status.description();
+
+ native_handle_close(handle);
+ native_handle_delete(handle);
+}
+
+// Make sure toggling device logging doesn't crash.
+TEST_P(DumpstateHidl1_1Test, TestEnableDeviceLogging) {
+ Return<bool> status = dumpstate->setDeviceLoggingEnabled(true);
+
+ ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+}
+
+TEST_P(DumpstateHidl1_1Test, TestDisableDeviceLogging) {
+ Return<bool> status = dumpstate->setDeviceLoggingEnabled(false);
+
+ ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, DumpstateHidl1_1Test,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IDumpstateDevice::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
+} // namespace
diff --git a/gnss/1.0/IGnssCallback.hal b/gnss/1.0/IGnssCallback.hal
index d62676fb5e..311ab2166c 100644
--- a/gnss/1.0/IGnssCallback.hal
+++ b/gnss/1.0/IGnssCallback.hal
@@ -90,6 +90,7 @@ interface IGnssCallback {
* - QZSS: 193-200
* - Galileo: 1-36
* - Beidou: 1-37
+ * - IRNSS: 1-14
*/
int16_t svid;
diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
index 6183a1ae28..c04b4d0df2 100644
--- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -26,6 +26,8 @@
#include <condition_variable>
#include <mutex>
+#include <cutils/properties.h>
+
using android::hardware::Return;
using android::hardware::Void;
@@ -37,6 +39,12 @@ using android::hardware::gnss::V1_0::IGnssDebug;
using android::hardware::gnss::V1_0::IGnssMeasurement;
using android::sp;
+static bool IsAutomotiveDevice() {
+ char buffer[PROPERTY_VALUE_MAX] = {0};
+ property_get("ro.hardware.type", buffer, "");
+ return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
+}
+
#define TIMEOUT_SEC 2 // for basic commands/responses
// for command line argument on how strictly to run the test
@@ -473,9 +481,9 @@ TEST_P(GnssHalTest, GetAllExtensions) {
auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
ASSERT_TRUE(gnssDebug.isOk());
- if (info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
- sp<IGnssDebug> iGnssDebug = gnssDebug;
- EXPECT_NE(iGnssDebug, nullptr);
+ if (!IsAutomotiveDevice() && info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
+ sp<IGnssDebug> iGnssDebug = gnssDebug;
+ EXPECT_NE(iGnssDebug, nullptr);
}
}
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index bdd02d2e6e..369a89da39 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -29,6 +29,10 @@ cc_test {
],
shared_libs: [
"android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss.measurement_corrections@1.1",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
],
- test_suites: ["general-tests", "vts-core"],
}
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index e0d8b54525..8530ffb08e 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -19,6 +19,7 @@
#include <gnss_hal_test.h>
#include <android/hardware/gnss/1.1/IGnssConfiguration.h>
+#include <cutils/properties.h>
#include <gtest/gtest.h>
using android::hardware::hidl_vec;
@@ -32,6 +33,12 @@ using android::hardware::gnss::V1_0::IGnssDebug;
using android::hardware::gnss::V1_1::IGnssConfiguration;
using android::hardware::gnss::V1_1::IGnssMeasurement;
+static bool IsAutomotiveDevice() {
+ char buffer[PROPERTY_VALUE_MAX] = {0};
+ property_get("ro.hardware.type", buffer, "");
+ return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
+}
+
/*
* SetupTeardownCreateCleanup:
* Requests the gnss HAL then calls cleanup
@@ -524,7 +531,8 @@ TEST_P(GnssHalTest, InjectBestLocation) {
TEST_P(GnssHalTest, GnssDebugValuesSanityTest) {
auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
ASSERT_TRUE(gnssDebug.isOk());
- if (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017) {
+ if (!IsAutomotiveDevice() && gnss_cb_->info_cbq_.calledCount() > 0 &&
+ gnss_cb_->last_info_.yearOfHw >= 2017) {
sp<IGnssDebug> iGnssDebug = gnssDebug;
EXPECT_NE(iGnssDebug, nullptr);
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index 0fa08b903e..53f5b9e283 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -296,6 +296,12 @@ TEST_P(GnssHalTest, TestGnssVisibilityControlExtension) {
* capability flag is set.
*/
TEST_P(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) {
+ if (!IsGnssHalVersion_2_0()) {
+ ALOGI("Test GnssMeasurementCorrectionsCapabilities skipped. GNSS HAL version is greater "
+ "than 2.0.");
+ return;
+ }
+
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) {
return;
}
diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp
index 8b0c374469..7efc4a60aa 100644
--- a/gnss/2.1/Android.bp
+++ b/gnss/2.1/Android.bp
@@ -7,6 +7,7 @@ hidl_interface {
enabled: true,
},
srcs: [
+ "types.hal",
"IGnss.hal",
"IGnssCallback.hal",
"IGnssMeasurement.hal",
@@ -14,6 +15,7 @@ hidl_interface {
"IGnssConfiguration.hal",
],
interfaces: [
+ "android.hardware.gnss.measurement_corrections@1.1",
"android.hardware.gnss.measurement_corrections@1.0",
"android.hardware.gnss.visibility_control@1.0",
"android.hardware.gnss@1.0",
diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal
index 2d633928dd..ce37647868 100644
--- a/gnss/2.1/IGnss.hal
+++ b/gnss/2.1/IGnss.hal
@@ -16,6 +16,7 @@
package android.hardware.gnss@2.1;
+import android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections;
import @2.0::IGnss;
import IGnssCallback;
@@ -62,4 +63,14 @@ interface IGnss extends @2.0::IGnss {
* @return gnssConfigurationIface Handle to the IGnssConfiguration interface.
*/
getExtensionGnssConfiguration_2_1() generates (IGnssConfiguration gnssConfigurationIface);
+
+ /**
+ * This method returns the IMeasurementCorrections interface.
+ *
+ * Both getExtensionMeasurementCorrections and getExtensionMeasurementCorrections_1_1 must
+ * return non-null. Both methods can return the same V1.1 IMeasurementCorrections object.
+ *
+ * @return measurementCorrectionsIface Handle to the IMeasurementCorrections interface.
+ */
+ getExtensionMeasurementCorrections_1_1() generates (IMeasurementCorrections measurementCorrectionsIface);
}; \ No newline at end of file
diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal
index ca6175f508..0385abd467 100644
--- a/gnss/2.1/IGnssMeasurementCallback.hal
+++ b/gnss/2.1/IGnssMeasurementCallback.hal
@@ -17,24 +17,115 @@
package android.hardware.gnss@2.1;
import @1.0::IGnssMeasurementCallback;
-import @1.1::IGnssMeasurementCallback;
import @2.0::IGnssMeasurementCallback;
import @2.0::ElapsedRealtime;
+import GnssSignalType;
/** The callback interface to report measurements from the HAL. */
interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback {
/**
- * Extends a GNSS Measurement, adding a basebandCN0DbHz.
+ * Flags to indicate what fields in GnssMeasurement are valid.
+ */
+ enum GnssMeasurementFlags : uint32_t {
+ /** A valid 'snr' is stored in the data structure. */
+ HAS_SNR = 1 << 0,
+ /** A valid 'carrier frequency' is stored in the data structure. */
+ HAS_CARRIER_FREQUENCY = 1 << 9,
+ /** A valid 'carrier cycles' is stored in the data structure. */
+ HAS_CARRIER_CYCLES = 1 << 10,
+ /** A valid 'carrier phase' is stored in the data structure. */
+ HAS_CARRIER_PHASE = 1 << 11,
+ /** A valid 'carrier phase uncertainty' is stored in the data structure. */
+ HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12,
+ /** A valid automatic gain control is stored in the data structure. */
+ HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13,
+ /** A valid receiver inter-signal bias is stored in the data structure. */
+ HAS_RECEIVER_ISB = 1 << 16,
+ /** A valid receiver inter-signal bias uncertainty is stored in the data structure. */
+ HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17,
+ /** A valid satellite inter-signal bias is stored in the data structure. */
+ HAS_SATELLITE_ISB = 1 << 18,
+ /** A valid satellite inter-signal bias uncertainty is stored in the data structure. */
+ HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19
+ };
+
+
+ /**
+ * Extends a GNSS Measurement, adding basebandCN0DbHz, GnssMeasurementFlags,
+ * receiverInterSignalBiasNs, receiverInterSignalBiasUncertaintyNs, satelliteInterSignalBiasNs
+ * and satelliteInterSignalBiasUncertaintyNs.
*/
struct GnssMeasurement {
/**
* GNSS measurement information for a single satellite and frequency, as in the 2.0 version
* of the HAL.
+ *
+ * In this version of the HAL, the field 'flags' in the v2_0.v1_1.v1_0 struct is deprecated,
+ * and is no longer used by the framework. The GNSS measurement flags are instead reported
+ * in @2.1::IGnssMeasurementCallback.GnssMeasurement.flags.
+ *
*/
@2.0::IGnssMeasurementCallback.GnssMeasurement v2_0;
/**
+ * A set of flags indicating the validity of the fields in this data
+ * structure.
+ *
+ * Fields for which there is no corresponding flag must be filled in
+ * with a valid value. For convenience, these are marked as mandatory.
+ *
+ * Others fields may have invalid information in them, if not marked as
+ * valid by the corresponding bit in flags.
+ */
+ bitfield<GnssMeasurementFlags> flags;
+
+ /**
+ * The receiver inter-signal bias (ISB) in nanoseconds.
+ *
+ * This value is the estimated receiver-side inter-system (different from the constellation
+ * in GnssClock.referenceSignalForIsb) bias and inter-frequency (different from the carrier
+ * frequency in GnssClock.referenceSignalForIsb) bias. The reported receiver ISB
+ * must include signal delays caused by
+ *
+ * - Receiver inter-constellation bias
+ * - Receiver inter-frequency bias
+ * - Receiver inter-code bias
+ *
+ * The value does not include the inter-frequency Ionospheric bias.
+ *
+ * The receiver ISB of GnssClock.referenceSignalForIsb is defined to be 0.0 nanoseconds.
+ */
+ double receiverInterSignalBiasNs;
+
+ /**
+ * 1-sigma uncertainty associated with the receiver inter-signal bias in nanoseconds.
+ */
+ double receiverInterSignalBiasUncertaintyNs;
+
+ /**
+ * The satellite inter-signal bias in nanoseconds.
+ *
+ * This value is the satellite-and-control-segment-side inter-system (different from the
+ * constellation in GnssClock.referenceSignalForIsb) bias and inter-frequency (different
+ * from the carrier frequency in GnssClock.referenceSignalForIsb) bias, including:
+ *
+ * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPT-UTC Time Offset (TauGps),
+ * BDS-GLO Time Offset (BGTO))
+ * - Group delay (e.g., Total Group Delay (TGD))
+ * - Satellite inter-signal bias, which includes satellite inter-frequency bias (GLO only),
+ * and satellite inter-code bias (e.g., Differential Code Bias (DCB)).
+ *
+ * The receiver ISB of GnssClock.referenceSignalForIsb is defined to be 0.0 nanoseconds.
+ */
+ double satelliteInterSignalBiasNs;
+
+ /**
+ * 1-sigma uncertainty associated with the satellite inter-signal bias in nanoseconds.
+ */
+ double satelliteInterSignalBiasUncertaintyNs;
+
+ /**
* Baseband Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. It contains
* the measured C/N0 value for the signal measured at the baseband.
*
@@ -51,8 +142,22 @@ interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback {
};
/**
- * Complete set of GNSS Measurement data, same as 2.0 with additional double (i.e.,
- * basebandCN0DbHz) in measurements.
+ * Extends a GNSS clock time, adding a referenceSignalTypeForIsb.
+ */
+ struct GnssClock {
+ /**
+ * GNSS clock time information, as in the 1.0 version of the HAL.
+ */
+ @1.0::IGnssMeasurementCallback.GnssClock v1_0;
+
+ /**
+ * Reference GNSS signal type for inter-signal bias.
+ */
+ GnssSignalType referenceSignalTypeForIsb;
+ };
+
+ /**
+ * Complete set of GNSS Measurement data, same as 2.0 with additional fields in measurements.
*/
struct GnssData {
/** The full set of satellite measurement observations. */
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
index 834847e91e..1f1078e398 100644
--- a/gnss/2.1/default/Android.bp
+++ b/gnss/2.1/default/Android.bp
@@ -32,6 +32,7 @@ cc_binary {
"libhidlbase",
"libutils",
"liblog",
+ "android.hardware.gnss.measurement_corrections@1.1",
"android.hardware.gnss.measurement_corrections@1.0",
"android.hardware.gnss.visibility_control@1.0",
"android.hardware.gnss@2.1",
diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp
index 7db86897f9..679eb35804 100644
--- a/gnss/2.1/default/Gnss.cpp
+++ b/gnss/2.1/default/Gnss.cpp
@@ -25,7 +25,7 @@
#include <log/log.h>
using ::android::hardware::gnss::common::Utils;
-using ::android::hardware::gnss::measurement_corrections::V1_0::implementation::
+using ::android::hardware::gnss::measurement_corrections::V1_1::implementation::
GnssMeasurementCorrections;
namespace android {
@@ -368,6 +368,12 @@ Return<sp<V2_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_1() {
return mGnssConfiguration;
}
+Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
+Gnss::getExtensionMeasurementCorrections_1_1() {
+ ALOGD("Gnss::getExtensionMeasurementCorrections_1_1()");
+ return new GnssMeasurementCorrections();
+}
+
void Gnss::reportSvStatus(const hidl_vec<GnssSvInfo>& svInfoList) const {
std::unique_lock<std::mutex> lock(mMutex);
// TODO(skz): update this to call 2_0 callback if non-null
diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h
index 7a2a2c953a..c47206a7a4 100644
--- a/gnss/2.1/default/Gnss.h
+++ b/gnss/2.1/default/Gnss.h
@@ -89,6 +89,8 @@ struct Gnss : public IGnss {
Return<bool> setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) override;
Return<sp<V2_1::IGnssMeasurement>> getExtensionGnssMeasurement_2_1() override;
Return<sp<V2_1::IGnssConfiguration>> getExtensionGnssConfiguration_2_1() override;
+ Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
+ getExtensionMeasurementCorrections_1_1() override;
private:
void reportLocation(const V2_0::GnssLocation&) const;
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.cpp b/gnss/2.1/default/GnssMeasurementCorrections.cpp
index 2bf5601820..9dedbf6747 100644
--- a/gnss/2.1/default/GnssMeasurementCorrections.cpp
+++ b/gnss/2.1/default/GnssMeasurementCorrections.cpp
@@ -23,11 +23,12 @@ namespace android {
namespace hardware {
namespace gnss {
namespace measurement_corrections {
-namespace V1_0 {
+namespace V1_1 {
namespace implementation {
// Methods from V1_0::IMeasurementCorrections follow.
-Return<bool> GnssMeasurementCorrections::setCorrections(const MeasurementCorrections& corrections) {
+Return<bool> GnssMeasurementCorrections::setCorrections(
+ const V1_0::MeasurementCorrections& corrections) {
ALOGD("setCorrections");
ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu, "
"satCorrections.size: %d",
@@ -67,8 +68,40 @@ Return<bool> GnssMeasurementCorrections::setCallback(
return true;
}
+// Methods from V1_1::IMeasurementCorrections follow.
+Return<bool> GnssMeasurementCorrections::setCorrections_1_1(
+ const V1_1::MeasurementCorrections& corrections) {
+ ALOGD("setCorrections_1_1");
+ ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu,"
+ "satCorrections.size: %d, hasEnvironmentBearing: %d, environmentBearingDeg: %f,"
+ "environmentBearingUncDeg: %f",
+ corrections.v1_0.latitudeDegrees, corrections.v1_0.longitudeDegrees,
+ corrections.v1_0.altitudeMeters, corrections.v1_0.horizontalPositionUncertaintyMeters,
+ corrections.v1_0.verticalPositionUncertaintyMeters,
+ static_cast<unsigned long long>(corrections.v1_0.toaGpsNanosecondsOfWeek),
+ static_cast<int>(corrections.v1_0.satCorrections.size()),
+ corrections.hasEnvironmentBearing, corrections.environmentBearingDegrees,
+ corrections.environmentBearingUncertaintyDegrees);
+ for (auto singleSatCorrection : corrections.v1_0.satCorrections) {
+ ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d, cfHz: %f, probLos: %f,"
+ " epl: %f, eplUnc: %f",
+ static_cast<int>(singleSatCorrection.singleSatCorrectionFlags),
+ static_cast<int>(singleSatCorrection.constellation),
+ static_cast<int>(singleSatCorrection.svid), singleSatCorrection.carrierFrequencyHz,
+ singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters,
+ singleSatCorrection.excessPathLengthUncertaintyMeters);
+ ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
+ singleSatCorrection.reflectingPlane.latitudeDegrees,
+ singleSatCorrection.reflectingPlane.longitudeDegrees,
+ singleSatCorrection.reflectingPlane.altitudeMeters,
+ singleSatCorrection.reflectingPlane.azimuthDegrees);
+ }
+
+ return true;
+}
+
} // namespace implementation
-} // namespace V1_0
+} // namespace V1_1
} // namespace measurement_corrections
} // namespace gnss
} // namespace hardware
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.h b/gnss/2.1/default/GnssMeasurementCorrections.h
index 4339bed55d..036e855586 100644
--- a/gnss/2.1/default/GnssMeasurementCorrections.h
+++ b/gnss/2.1/default/GnssMeasurementCorrections.h
@@ -16,7 +16,7 @@
#pragma once
-#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
@@ -24,7 +24,7 @@ namespace android {
namespace hardware {
namespace gnss {
namespace measurement_corrections {
-namespace V1_0 {
+namespace V1_1 {
namespace implementation {
using ::android::sp;
@@ -37,12 +37,15 @@ using ::android::hardware::Void;
struct GnssMeasurementCorrections : public IMeasurementCorrections {
// Methods from V1_0::IMeasurementCorrections follow.
- Return<bool> setCorrections(const MeasurementCorrections& corrections) override;
+ Return<bool> setCorrections(const V1_0::MeasurementCorrections& corrections) override;
Return<bool> setCallback(const sp<V1_0::IMeasurementCorrectionsCallback>& callback) override;
+
+ // Methods from V1_1::IMeasurementCorrections follow.
+ Return<bool> setCorrections_1_1(const V1_1::MeasurementCorrections& corrections) override;
};
} // namespace implementation
-} // namespace V1_0
+} // namespace V1_1
} // namespace measurement_corrections
} // namespace gnss
} // namespace hardware
diff --git a/gnss/2.1/types.hal b/gnss/2.1/types.hal
new file mode 100644
index 0000000000..e4484c15f3
--- /dev/null
+++ b/gnss/2.1/types.hal
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 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 android.hardware.gnss@2.1;
+
+import @2.0::GnssConstellationType;
+
+/**
+ * Represents a GNSS signal type.
+ */
+struct GnssSignalType {
+ /**
+ * Constellation type of the SV that transmits the signal.
+ */
+ GnssConstellationType constellation;
+
+ /**
+ * Carrier frequency in Hz of the signal.
+ */
+ double carrierFrequencyHz;
+
+ /**
+ * The type of code of the GNSS signal.
+ *
+ * This is used to specify the observation descriptor defined in GNSS Observation Data File
+ * Header Section Description in the RINEX standard (Version 3.XX). In RINEX Version 3.03,
+ * in Appendix Table A2 Attributes are listed as uppercase letters (for instance, "A" for
+ * "A channel").
+ *
+ * See the comment of @2.0::IGnssMeasurementCallback.GnssMeasurement.codeType for more details.
+ */
+ string codeType;
+};
diff --git a/gnss/2.1/vts/functional/Android.bp b/gnss/2.1/vts/functional/Android.bp
index 83404992de..f008a26f1f 100644
--- a/gnss/2.1/vts/functional/Android.bp
+++ b/gnss/2.1/vts/functional/Android.bp
@@ -24,6 +24,7 @@ cc_test {
],
static_libs: [
"android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss.measurement_corrections@1.1",
"android.hardware.gnss.visibility_control@1.0",
"android.hardware.gnss@1.0",
"android.hardware.gnss@1.1",
@@ -31,5 +32,8 @@ cc_test {
"android.hardware.gnss@2.1",
"android.hardware.gnss@common-vts-lib",
],
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp
index 22268f676d..93f89f54e0 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp
@@ -256,3 +256,10 @@ Return<void> GnssHalTest::GnssMeasurementCallback::gnssMeasurementCb_2_1(
measurement_cbq_.store(data);
return Void();
}
+
+Return<void> GnssHalTest::GnssMeasurementCorrectionsCallback::setCapabilitiesCb(
+ uint32_t capabilities) {
+ ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities);
+ capabilities_cbq_.store(capabilities);
+ return Void();
+} \ No newline at end of file
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h
index 6b67e139c3..b99cf2322a 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test.h
+++ b/gnss/2.1/vts/functional/gnss_hal_test.h
@@ -27,6 +27,7 @@ using android::hardware::Return;
using android::hardware::Void;
using android::hardware::gnss::common::GnssCallbackEventQueue;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
using android::hardware::gnss::V1_0::GnssLocationFlags;
using android::hardware::gnss::V2_0::GnssConstellationType;
using android::hardware::gnss::V2_1::IGnss;
@@ -138,6 +139,19 @@ class GnssHalTest : public testing::TestWithParam<std::string> {
Return<void> gnssMeasurementCb_2_1(const IGnssMeasurementCallback_2_1::GnssData&) override;
};
+ /* Callback class for GnssMeasurementCorrections. */
+ class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
+ public:
+ uint32_t last_capabilities_;
+ GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+
+ GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){};
+ virtual ~GnssMeasurementCorrectionsCallback() = default;
+
+ // Methods from V1_0::IMeasurementCorrectionsCallback follow.
+ Return<void> setCapabilitiesCb(uint32_t capabilities) override;
+ };
+
/*
* SetUpGnssCallback:
* Set GnssCallback and verify the result.
diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
index 2c51717665..9ac9436b0d 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "GnssHalTestCases"
#include <gnss_hal_test.h>
+#include <cmath>
#include "Utils.h"
#include <gtest/gtest.h>
@@ -30,6 +31,7 @@ using IGnssMeasurement_2_1 = android::hardware::gnss::V2_1::IGnssMeasurement;
using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
+
using IGnssConfiguration_2_1 = android::hardware::gnss::V2_1::IGnssConfiguration;
using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
@@ -38,6 +40,10 @@ using IGnssConfiguration_1_0 = android::hardware::gnss::V1_0::IGnssConfiguration
using android::hardware::gnss::V2_0::GnssConstellationType;
using android::hardware::gnss::V2_1::IGnssConfiguration;
+using GnssMeasurementFlags = IGnssMeasurementCallback_2_1::GnssMeasurementFlags;
+using IMeasurementCorrections_1_1 =
+ android::hardware::gnss::measurement_corrections::V1_1::IMeasurementCorrections;
+
/*
* SetupTeardownCreateCleanup:
* Requests the gnss HAL then calls cleanup
@@ -92,6 +98,7 @@ TEST_P(GnssHalTest, TestGnssConfigurationExtension) {
* TestGnssMeasurementFields:
* Sets a GnssMeasurementCallback, waits for a measurement, and verifies
* 1. basebandCN0DbHz is valid
+ * 2. ISB fields are valid if HAS_INTER_SIGNAL_BIAS is true.
*/
TEST_P(GnssHalTest, TestGnssMeasurementFields) {
const int kFirstGnssMeasurementTimeoutSeconds = 10;
@@ -118,6 +125,29 @@ TEST_P(GnssHalTest, TestGnssMeasurementFields) {
for (auto measurement : lastMeasurement.measurements) {
// Verify basebandCn0DbHz is valid.
ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
+
+ if (((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_ISB) > 0) &&
+ ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_ISB_UNCERTAINTY) >
+ 0) &&
+ ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB) > 0) &&
+ ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB_UNCERTAINTY) >
+ 0)) {
+ GnssConstellationType referenceConstellation =
+ lastMeasurement.clock.referenceSignalTypeForIsb.constellation;
+ double carrierFrequencyHz =
+ lastMeasurement.clock.referenceSignalTypeForIsb.carrierFrequencyHz;
+ std::string codeType = lastMeasurement.clock.referenceSignalTypeForIsb.codeType;
+
+ ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN &&
+ referenceConstellation >= GnssConstellationType::IRNSS);
+ ASSERT_TRUE(carrierFrequencyHz > 0);
+ ASSERT_TRUE(codeType != "");
+
+ ASSERT_TRUE(std::abs(measurement.receiverInterSignalBiasNs) < 1.0e6);
+ ASSERT_TRUE(measurement.receiverInterSignalBiasUncertaintyNs >= 0);
+ ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
+ ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
+ }
}
iGnssMeasurement->close();
@@ -533,4 +563,36 @@ TEST_P(GnssHalTest, BlacklistConstellationLocationOn) {
result = gnss_configuration_hal->setBlacklist_2_1(sources);
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
+}
+
+/*
+ * TestGnssMeasurementCorrections:
+ * If measurement corrections capability is supported, verifies that it supports the
+ * gnss.measurement_corrections@1.1::IMeasurementCorrections interface by invoking a method.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementCorrections) {
+ if (!(gnss_cb_->last_capabilities_ &
+ IGnssCallback_2_1::Capabilities::MEASUREMENT_CORRECTIONS)) {
+ return;
+ }
+
+ // Verify IMeasurementCorrections is supported.
+ auto measurementCorrections = gnss_hal_->getExtensionMeasurementCorrections_1_1();
+ ASSERT_TRUE(measurementCorrections.isOk());
+ sp<IMeasurementCorrections_1_1> iMeasurementCorrections = measurementCorrections;
+ ASSERT_NE(iMeasurementCorrections, nullptr);
+
+ sp<GnssMeasurementCorrectionsCallback> callback = new GnssMeasurementCorrectionsCallback();
+ iMeasurementCorrections->setCallback(callback);
+
+ const int kMeasurementCorrectionsCapabilitiesTimeoutSeconds = 5;
+ callback->capabilities_cbq_.retrieve(callback->last_capabilities_,
+ kMeasurementCorrectionsCapabilitiesTimeoutSeconds);
+ ASSERT_TRUE(callback->capabilities_cbq_.calledCount() > 0);
+
+ // Set a mock MeasurementCorrections.
+ auto result =
+ iMeasurementCorrections->setCorrections_1_1(Utils::getMockMeasurementCorrections_1_1());
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
} \ No newline at end of file
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index ccb91b100f..0cdc865849 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -24,24 +24,45 @@ namespace gnss {
namespace common {
using GnssSvFlags = V1_0::IGnssCallback::GnssSvFlags;
-using GnssMeasurementFlags = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags;
+using GnssMeasurementFlagsV1_0 = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags;
+using GnssMeasurementFlagsV2_1 = V2_1::IGnssMeasurementCallback::GnssMeasurementFlags;
using GnssMeasurementStateV2_0 = V2_0::IGnssMeasurementCallback::GnssMeasurementState;
using ElapsedRealtime = V2_0::ElapsedRealtime;
using ElapsedRealtimeFlags = V2_0::ElapsedRealtimeFlags;
using GnssConstellationTypeV2_0 = V2_0::GnssConstellationType;
using IGnssMeasurementCallbackV2_0 = V2_0::IGnssMeasurementCallback;
+using GnssSignalType = V2_1::GnssSignalType;
GnssDataV2_1 Utils::getMockMeasurementV2_1() {
GnssDataV2_0 gnssDataV2_0 = Utils::getMockMeasurementV2_0();
V2_1::IGnssMeasurementCallback::GnssMeasurement gnssMeasurementV2_1 = {
.v2_0 = gnssDataV2_0.measurements[0],
+ .flags = (uint32_t)(GnssMeasurementFlagsV2_1::HAS_CARRIER_FREQUENCY |
+ GnssMeasurementFlagsV2_1::HAS_CARRIER_PHASE |
+ GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB |
+ GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB_UNCERTAINTY |
+ GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB |
+ GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB_UNCERTAINTY),
+ .receiverInterSignalBiasNs = 10.0,
+ .receiverInterSignalBiasUncertaintyNs = 100.0,
+ .satelliteInterSignalBiasNs = 20.0,
+ .satelliteInterSignalBiasUncertaintyNs = 150.0,
.basebandCN0DbHz = 25.0,
};
+ GnssSignalType referenceSignalTypeForIsb = {
+ .constellation = GnssConstellationTypeV2_0::GPS,
+ .carrierFrequencyHz = 1.59975e+09,
+ .codeType = "C",
+ };
+ V2_1::IGnssMeasurementCallback::GnssClock gnssClockV2_1 = {
+ .v1_0 = gnssDataV2_0.clock,
+ .referenceSignalTypeForIsb = referenceSignalTypeForIsb,
+ };
hidl_vec<V2_1::IGnssMeasurementCallback::GnssMeasurement> measurements(1);
measurements[0] = gnssMeasurementV2_1;
GnssDataV2_1 gnssDataV2_1 = {
.measurements = measurements,
- .clock = gnssDataV2_0.clock,
+ .clock = gnssClockV2_1,
.elapsedRealtime = gnssDataV2_0.elapsedRealtime,
};
return gnssDataV2_1;
@@ -49,7 +70,7 @@ GnssDataV2_1 Utils::getMockMeasurementV2_1() {
GnssDataV2_0 Utils::getMockMeasurementV2_0() {
V1_0::IGnssMeasurementCallback::GnssMeasurement measurement_1_0 = {
- .flags = (uint32_t)GnssMeasurementFlags::HAS_CARRIER_FREQUENCY,
+ .flags = (uint32_t)GnssMeasurementFlagsV1_0::HAS_CARRIER_FREQUENCY,
.svid = (int16_t)6,
.constellation = V1_0::GnssConstellationType::UNKNOWN,
.timeOffsetNs = 0.0,
diff --git a/gnss/common/utils/vts/Android.bp b/gnss/common/utils/vts/Android.bp
index 1988171979..fd9613b02a 100644
--- a/gnss/common/utils/vts/Android.bp
+++ b/gnss/common/utils/vts/Android.bp
@@ -30,6 +30,7 @@ cc_library_static {
shared_libs: [
"android.hardware.gnss@1.0",
"android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss.measurement_corrections@1.1",
],
static_libs: [
"libgtest",
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index 51d3ea18d5..b6c3f5eccf 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -92,7 +92,7 @@ void Utils::checkLocation(const GnssLocation& location, bool check_speed,
EXPECT_GT(location.timestamp, 1.48e12);
}
-const MeasurementCorrections Utils::getMockMeasurementCorrections() {
+const MeasurementCorrections_1_0 Utils::getMockMeasurementCorrections() {
ReflectingPlane reflectingPlane = {
.latitudeDegrees = 37.4220039,
.longitudeDegrees = -122.0840991,
@@ -127,7 +127,7 @@ const MeasurementCorrections Utils::getMockMeasurementCorrections() {
hidl_vec<SingleSatCorrection> singleSatCorrections = {singleSatCorrection1,
singleSatCorrection2};
- MeasurementCorrections mockCorrections = {
+ MeasurementCorrections_1_0 mockCorrections = {
.latitudeDegrees = 37.4219999,
.longitudeDegrees = -122.0840575,
.altitudeMeters = 30.60062531,
@@ -139,6 +139,18 @@ const MeasurementCorrections Utils::getMockMeasurementCorrections() {
return mockCorrections;
}
+const MeasurementCorrections_1_1 Utils::getMockMeasurementCorrections_1_1() {
+ MeasurementCorrections_1_0 mockCorrections_1_0 = getMockMeasurementCorrections();
+
+ MeasurementCorrections_1_1 mockCorrections_1_1 = {
+ .v1_0 = mockCorrections_1_0,
+ .hasEnvironmentBearing = true,
+ .environmentBearingDegrees = 45.0,
+ .environmentBearingUncertaintyDegrees = 4.0,
+ };
+ return mockCorrections_1_1;
+}
+
} // namespace common
} // namespace gnss
} // namespace hardware
diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h
index dce4c7b323..781ad428eb 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -19,10 +19,16 @@
#include <android/hardware/gnss/1.0/IGnss.h>
#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation;
using namespace android::hardware::gnss::measurement_corrections::V1_0;
+using MeasurementCorrections_1_0 =
+ android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
+using MeasurementCorrections_1_1 =
+ android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections;
+
namespace android {
namespace hardware {
namespace gnss {
@@ -31,7 +37,8 @@ namespace common {
struct Utils {
static void checkLocation(const GnssLocation& location, bool check_speed,
bool check_more_accuracies);
- static const MeasurementCorrections getMockMeasurementCorrections();
+ static const MeasurementCorrections_1_0 getMockMeasurementCorrections();
+ static const MeasurementCorrections_1_1 getMockMeasurementCorrections_1_1();
};
} // namespace common
diff --git a/gnss/measurement_corrections/1.1/Android.bp b/gnss/measurement_corrections/1.1/Android.bp
new file mode 100644
index 0000000000..1d69f20866
--- /dev/null
+++ b/gnss/measurement_corrections/1.1/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.gnss.measurement_corrections@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IMeasurementCorrections.hal",
+ ],
+ interfaces: [
+ "android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/gnss/measurement_corrections/1.1/IMeasurementCorrections.hal b/gnss/measurement_corrections/1.1/IMeasurementCorrections.hal
new file mode 100644
index 0000000000..9461a5e445
--- /dev/null
+++ b/gnss/measurement_corrections/1.1/IMeasurementCorrections.hal
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package android.hardware.gnss.measurement_corrections@1.1;
+
+import @1.0::IMeasurementCorrections;
+
+/**
+ * Interface for measurement corrections support.
+ */
+interface IMeasurementCorrections extends @1.0::IMeasurementCorrections {
+ /**
+ * Injects measurement corrections to be used by the HAL to improve the GNSS location output.
+ *
+ * These are NOT to be used to adjust the IGnssMeasurementCallback output values -
+ * those remain raw, uncorrected measurements.
+ *
+ * In general, these are injected when conditions defined by the platform are met, such as when
+ * GNSS Location is being requested at a sufficiently high accuracy, based on the capabilities
+ * of the GNSS chipset as reported in the IGnssCallback.
+ *
+ * @param corrections The computed corrections to be used by the HAL.
+ *
+ * @return success Whether the HAL can accept & use these corrections.
+ */
+ setCorrections_1_1(MeasurementCorrections corrections) generates (bool success);
+}; \ No newline at end of file
diff --git a/gnss/measurement_corrections/1.1/types.hal b/gnss/measurement_corrections/1.1/types.hal
new file mode 100644
index 0000000000..40b6f52b7d
--- /dev/null
+++ b/gnss/measurement_corrections/1.1/types.hal
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+package android.hardware.gnss.measurement_corrections@1.1;
+
+import @1.0::MeasurementCorrections;
+
+/**
+ * A struct containing a set of measurement corrections for all used GNSS satellites at the location
+ * specified by latitudeDegrees, longitudeDegrees, altitudeMeters and at the time of week specified
+ * toaGpsNanosecondsOfWeek
+ */
+struct MeasurementCorrections {
+ @1.0::MeasurementCorrections v1_0;
+
+ /**
+ * Boolean indicating if environment bearing is available.
+ */
+ bool hasEnvironmentBearing;
+
+ /**
+ * Environment bearing in degrees clockwise from true North (0.0 to 360.0], in direction of
+ * user motion. Environment bearing is provided when it is known with high probability that
+ * velocity is aligned with an environment feature, such as a building or road.
+ *
+ * If user speed is zero, environmentBearingDegrees represents bearing of most recent speed
+ * that was > 0.
+ *
+ * As position approaches another road, environmentBearingUncertaintyDegrees will grow, and at
+ * some stage hasEnvironmentBearing = false.
+ *
+ * As position moves towards an open area, environmentBearingUncertaintyDegrees will grow, and
+ * at some stage hasEnvironmentBearing = false.
+ *
+ * If the road is curved in the vicinity of the user location, then
+ * environmentBearingUncertaintyDegrees will include the amount by which the road direction
+ * changes in the area of position uncertainty.
+ */
+ float environmentBearingDegrees;
+
+ /**
+ * Bearing uncertainty [0 to 180].
+ */
+ float environmentBearingUncertaintyDegrees;
+}; \ No newline at end of file
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
index 43cf6722dd..7b46688d9f 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -280,7 +280,7 @@ enum StandardMetadataType {
*
* The default blend mode is INVALID. If the BlendMode is set to any
* valid value other than INVALID, this BlendMode overrides all other
- * dataspaces. For a longer description of this behavior see MetadataType::DATASPACE.
+ * blend modes. For a longer description of this behavior see MetadataType::DATASPACE.
*
* The blend mode is a stable aidl android.hardware.graphics.common.BlendMode.
*
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index cdc0f35a41..3b0911f923 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -23,14 +23,13 @@ cc_library_static {
"TestCommandReader.cpp",
],
static_libs: [
- "VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@3.0-vts",
"android.hardware.graphics.mapper@4.0-vts",
+ "libgtest",
],
export_static_lib_headers: [
- "VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@3.0-vts",
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index a8e1480d4f..4b6b7c86b8 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -16,8 +16,6 @@
#include <composer-vts/2.1/ComposerVts.h>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace android {
namespace hardware {
namespace graphics {
@@ -25,11 +23,6 @@ namespace composer {
namespace V2_1 {
namespace vts {
-Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
-
-Composer::Composer(const std::string& name)
- : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
-
Composer::Composer(const sp<IComposer>& composer) : mComposer(composer) {
// ASSERT_* can only be used in functions returning void.
[this] {
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index 5432882bea..a8bb1a22cb 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -26,11 +26,11 @@ cc_library_static {
"libui",
],
static_libs: [
- "VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.mapper@2.1-vts",
"libarect",
+ "libgtest",
"libmath",
"libnativewindow",
"librenderengine",
@@ -40,7 +40,6 @@ cc_library_static {
"android.hardware.graphics.mapper@4.0-vts",
],
export_static_lib_headers: [
- "VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.mapper@2.1-vts",
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index 93b67f0fcc..a526137c41 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -16,7 +16,6 @@
#include <composer-vts/2.2/ComposerVts.h>
-#include <VtsHalHidlTargetTestBase.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
#include <hidl/HidlTransportUtils.h>
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index e2f267012f..a23d72c949 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -57,7 +57,15 @@ void TestRenderEngine::initGraphicBuffer(uint32_t width, uint32_t height, uint32
void TestRenderEngine::drawLayers() {
base::unique_fd bufferFence;
base::unique_fd readyFence;
- mRenderEngine->drawLayers(mDisplaySettings, mCompositionLayers,
+
+ std::vector<const renderengine::LayerSettings*> compositionLayerPointers;
+ compositionLayerPointers.reserve(mCompositionLayers.size());
+ std::transform(mCompositionLayers.begin(), mCompositionLayers.end(),
+ std::back_insert_iterator(compositionLayerPointers),
+ [](renderengine::LayerSettings& settings) -> renderengine::LayerSettings* {
+ return &settings;
+ });
+ mRenderEngine->drawLayers(mDisplaySettings, compositionLayerPointers,
mGraphicBuffer->getNativeBuffer(), true, std::move(bufferFence),
&readyFence);
int fd = readyFence.release();
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 5d22305020..6bc2732d7d 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -22,7 +22,6 @@
#include <unordered_set>
#include <vector>
-#include <VtsHalHidlTargetTestBase.h>
#include <android/hardware/graphics/composer/2.2/IComposer.h>
#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
index 7519a64b4f..d5eedf122c 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
@@ -142,7 +142,7 @@ class TestBufferLayer : public TestLayer {
const native_handle_t* mBufferHandle = nullptr;
};
-class ReadbackHelper : public ::testing::VtsHalHidlTargetTestBase {
+class ReadbackHelper {
public:
static std::string getColorModeString(ColorMode mode);
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
index b936cabb1e..4eb4bb7179 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
@@ -24,8 +24,6 @@
#include <ui/Rect.h>
#include <ui/Region.h>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace android {
namespace hardware {
namespace graphics {
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index f987516a33..e38af00a38 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -19,7 +19,7 @@ cc_test {
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
- "VtsHalGraphicsComposerV2_2TargetTest.cpp"
+ "VtsHalGraphicsComposerV2_2TargetTest.cpp",
],
// TODO(b/64437680): Assume these libs are always available on the device.
@@ -51,12 +51,16 @@ cc_test {
"android.hardware.graphics.mapper@3.0-vts",
"android.hardware.graphics.mapper@4.0",
"android.hardware.graphics.mapper@4.0-vts",
- "librenderengine"
+ "libgtest",
+ "librenderengine",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
],
disable_framework: true,
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index 044bd9640e..cb43e64c81 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -932,7 +932,7 @@ TEST_P(GraphicsCompositionTest, SetLayerZOrder) {
class GraphicsBlendModeCompositionTest
: public GraphicsCompositionTestBase,
- public testing::WithParamInterface<std::tuple<string, string>> {
+ public testing::WithParamInterface<std::tuple<std::string, std::string>> {
public:
void SetUp() override {
SetUpBase(std::get<0>(GetParam()));
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
index f65a9c41ae..3d81e8f647 100644
--- a/graphics/composer/2.3/utils/vts/Android.bp
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -23,6 +23,7 @@ cc_library_static {
static_libs: [
"android.hardware.graphics.composer@2.2-vts",
"android.hardware.graphics.composer@2.3",
+ "libgtest",
],
export_static_lib_headers: [
"android.hardware.graphics.composer@2.2-vts",
diff --git a/graphics/composer/2.3/utils/vts/ComposerVts.cpp b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
index d4f5b3a4de..d73a3b08b9 100644
--- a/graphics/composer/2.3/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
@@ -16,8 +16,6 @@
#include <composer-vts/2.3/ComposerVts.h>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace android {
namespace hardware {
namespace graphics {
@@ -27,11 +25,6 @@ namespace vts {
using V2_1::Error;
-Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
-
-Composer::Composer(const std::string& name)
- : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
-
Composer::Composer(const sp<IComposer>& composer)
: V2_2::vts::Composer(composer), mComposer(composer) {}
diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
index e5ac842262..dae9ab42a2 100644
--- a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
+++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
@@ -19,7 +19,6 @@
#include <memory>
#include <vector>
-#include <VtsHalHidlTargetTestBase.h>
#include <android/hardware/graphics/composer/2.3/IComposer.h>
#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
#include <composer-vts/2.2/ComposerVts.h>
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
index 7e0c33ce97..9e3cf0e083 100644
--- a/graphics/composer/2.4/IComposerClient.hal
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -71,6 +71,51 @@ interface IComposerClient extends @2.3::IComposerClient {
* setClientTargetProperty(ClientTargetProperty clientTargetProperty);
*/
SET_CLIENT_TARGET_PROPERTY = 0x105 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+
+ /**
+ * SET_LAYER_GENERIC_METADATA has this pseudo prototype
+ *
+ * setLayerGenericMetadata(string key, bool mandatory, vec<uint8_t> value);
+ *
+ * Sets a piece of generic metadata for the given layer. If this
+ * function is called twice with the same key but different values, the
+ * newer value must override the older one. Calling this function with a
+ * 0-length value must reset that key's metadata as if it had not been
+ * set.
+ *
+ * A given piece of metadata may either be mandatory or a hint
+ * (non-mandatory) as indicated by the second parameter. Mandatory
+ * metadata may affect the composition result, which is to say that it
+ * may cause a visible change in the final image. By contrast, hints may
+ * only affect the composition strategy, such as which layers are
+ * composited by the client, but must not cause a visible change in the
+ * final image. The value of the mandatory flag shall match the value
+ * returned from getLayerGenericMetadataKeys for the given key.
+ *
+ * Only keys which have been returned from getLayerGenericMetadataKeys()
+ * shall be accepted. Any other keys must result in an UNSUPPORTED error.
+ *
+ * The value passed into this function shall be the binary
+ * representation of a HIDL type corresponding to the given key. For
+ * example, a key of 'com.example.V1_3.Foo' shall be paired with a
+ * value of type com.example@1.3::Foo, which would be defined in a
+ * vendor HAL extension.
+ *
+ * This function will be encoded in the command buffer in this order:
+ * 1) The key length, stored as a uint32_t
+ * 2) The key itself, padded to a uint32_t boundary if necessary
+ * 3) The mandatory flag, stored as a uint32_t
+ * 4) The value length in bytes, stored as a uint32_t
+ * 5) The value itself, padded to a uint32_t boundary if necessary
+ *
+ * @param key indicates which metadata value should be set on this layer
+ * @param mandatory indicates whether this particular key represents
+ * mandatory metadata or a hint (non-mandatory metadata), as
+ * described above
+ * @param value is a binary representation of a HIDL struct
+ * corresponding to the key as described above
+ */
+ SET_LAYER_GENERIC_METADATA = 0x40e << @2.1::IComposerClient.Command:OPCODE_SHIFT,
};
/**
@@ -271,4 +316,33 @@ interface IComposerClient extends @2.3::IComposerClient {
*/
setContentType(Display display, ContentType type)
generates (Error error);
+
+ struct LayerGenericMetadataKey {
+ /**
+ * Key names must comply with the requirements specified for
+ * getLayerGenericMetadataKeys below
+ */
+ string name;
+
+ /**
+ * The mandatory flag is defined in the description of
+ * setLayerGenericMetadata above
+ */
+ bool mandatory;
+ };
+
+ /**
+ * Retrieves the set of keys that may be passed into setLayerGenericMetadata
+ *
+ * Key names must meet the following requirements:
+ * - Must be specified in reverse domain name notation
+ * - Must not start with 'com.android' or 'android'
+ * - Must be unique within the returned vector
+ * - Must correspond to a matching HIDL struct type, which defines the
+ * structure of its values. For example, the key 'com.example.V1-3.Foo'
+ * should correspond to a value of type com.example@1.3::Foo, which is
+ * defined in a vendor HAL extension
+ */
+ getLayerGenericMetadataKeys()
+ generates(Error error, vec<LayerGenericMetadataKey> keys);
};
diff --git a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
index e84779ecbb..eb35e5cb9e 100644
--- a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
+++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
@@ -53,6 +53,27 @@ class CommandWriterBase : public V2_3::CommandWriterBase {
writeSigned(static_cast<int32_t>(clientTargetProperty.dataspace));
endCommand();
}
+
+ void setLayerGenericMetadata(const hidl_string& key, const bool mandatory,
+ const hidl_vec<uint8_t>& value) {
+ const size_t commandSize = 3 + sizeToElements(key.size()) + sizeToElements(value.size());
+ if (commandSize > std::numeric_limits<uint16_t>::max()) {
+ LOG_FATAL("Too much generic metadata (%zu elements)", commandSize);
+ return;
+ }
+
+ beginCommand(IComposerClient::Command::SET_LAYER_GENERIC_METADATA,
+ static_cast<uint16_t>(commandSize));
+ write(key.size());
+ writeBlob(key.size(), reinterpret_cast<const unsigned char*>(key.c_str()));
+ write(mandatory);
+ write(value.size());
+ writeBlob(value.size(), value.data());
+ endCommand();
+ }
+
+ protected:
+ uint32_t sizeToElements(uint32_t size) { return (size + 3) / 4; }
};
// This class helps parse a command queue. Note that all sizes/lengths are in
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
index c864ce6961..c889069143 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -164,6 +164,14 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl<Interfac
return mHal->setContentType(display, contentType);
}
+ Return<void> getLayerGenericMetadataKeys(
+ IComposerClient::getLayerGenericMetadataKeys_cb hidl_cb) override {
+ std::vector<IComposerClient::LayerGenericMetadataKey> keys;
+ Error error = mHal->getLayerGenericMetadataKeys(&keys);
+ hidl_cb(error, keys);
+ return Void();
+ }
+
static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
auto client = std::make_unique<ComposerClientImpl>(hal);
return client->init() ? std::move(client) : nullptr;
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
index e0153ceb81..697d6b8a6b 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
@@ -74,6 +74,43 @@ class ComposerCommandEngine : public V2_3::hal::ComposerCommandEngine {
CommandWriterBase* getWriter() { return static_cast<CommandWriterBase*>(mWriter.get()); }
+ bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
+ switch (static_cast<IComposerClient::Command>(command)) {
+ case IComposerClient::Command::SET_LAYER_GENERIC_METADATA:
+ return executeSetLayerGenericMetadata(length);
+ default:
+ return BaseType2_3::executeCommand(command, length);
+ }
+ }
+
+ bool executeSetLayerGenericMetadata(uint16_t length) {
+ // We expect at least two buffer lengths and a mandatory flag
+ if (length < 3) {
+ return false;
+ }
+
+ const uint32_t keySize = read();
+ std::string key;
+ key.resize(keySize);
+ readBlob(keySize, key.data());
+
+ const bool mandatory = read();
+
+ const uint32_t valueSize = read();
+ std::vector<uint8_t> value(valueSize);
+ readBlob(valueSize, value.data());
+
+ auto error = mHal->setLayerGenericMetadata(mCurrentDisplay, mCurrentLayer, key, mandatory,
+ value);
+ if (error != Error::NONE) {
+ // The error cast is safe because setLayerGenericMetadata doesn't
+ // return any of the new values added in V2_4::Error
+ mWriter->setError(getCommandLoc(), static_cast<V2_1::Error>(error));
+ }
+
+ return true;
+ }
+
ComposerHal* mHal;
};
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
index 277055c0c6..58991c1d8d 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
@@ -79,6 +79,10 @@ class ComposerHal : public V2_3::hal::ComposerHal {
uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
std::vector<uint32_t>* outRequestMasks,
IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0;
+ virtual Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+ bool mandatory, const std::vector<uint8_t>& value) = 0;
+ virtual Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
};
} // namespace hal
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
index 616852a71b..d28e00625f 100644
--- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -245,6 +245,61 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
return err;
}
+ Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+ bool mandatory, const std::vector<uint8_t>& value) override {
+ if (!mDispatch.setLayerGenericMetadata) {
+ return Error::UNSUPPORTED;
+ }
+
+ if (key.size() > std::numeric_limits<uint32_t>::max()) {
+ return Error::BAD_PARAMETER;
+ }
+
+ if (value.size() > std::numeric_limits<uint32_t>::max()) {
+ return Error::BAD_PARAMETER;
+ }
+
+ int32_t error = mDispatch.setLayerGenericMetadata(
+ mDevice, display, layer, static_cast<uint32_t>(key.size()), key.c_str(), mandatory,
+ static_cast<uint32_t>(value.size()), value.data());
+ return static_cast<Error>(error);
+ }
+
+ Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override {
+ if (!mDispatch.getLayerGenericMetadataKey) {
+ return Error::UNSUPPORTED;
+ }
+
+ std::vector<IComposerClient::LayerGenericMetadataKey> keys;
+
+ uint32_t index = 0;
+ uint32_t keyLength = 0;
+ while (true) {
+ mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, nullptr, nullptr);
+ if (keyLength == 0) {
+ break;
+ }
+
+ IComposerClient::LayerGenericMetadataKey key;
+ std::string keyName;
+ keyName.resize(keyLength);
+ mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, keyName.data(),
+ &key.mandatory);
+ key.name = keyName;
+ keys.emplace_back(std::move(key));
+
+ // Only attempt to load the first 100 keys to avoid an infinite loop
+ // if something goes wrong
+ if (++index > 100) {
+ break;
+ }
+ }
+
+ *outKeys = std::move(keys);
+ return Error::NONE;
+ }
+
protected:
bool initDispatch() override {
if (!BaseType2_3::initDispatch()) {
@@ -267,6 +322,11 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType);
this->initOptionalDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_PROPERTY,
&mDispatch.getClientTargetProperty);
+ this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_GENERIC_METADATA,
+ &mDispatch.setLayerGenericMetadata);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_LAYER_GENERIC_METADATA_KEY,
+ &mDispatch.getLayerGenericMetadataKey);
+
return true;
}
@@ -319,6 +379,8 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes;
HWC2_PFN_SET_CONTENT_TYPE setContentType;
HWC2_PFN_GET_CLIENT_TARGET_PROPERTY getClientTargetProperty;
+ HWC2_PFN_SET_LAYER_GENERIC_METADATA setLayerGenericMetadata;
+ HWC2_PFN_GET_LAYER_GENERIC_METADATA_KEY getLayerGenericMetadataKey;
} mDispatch = {};
hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr;
diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp
index 673c15eb28..e42223d6eb 100644
--- a/graphics/composer/2.4/utils/vts/Android.bp
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -22,12 +22,12 @@ cc_library_static {
"GraphicsComposerCallback.cpp",
],
static_libs: [
- "VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3-vts",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
+ "libgtest",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
index 8a9c00608d..c5f3b5ed2f 100644
--- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -16,8 +16,6 @@
#include <composer-vts/2.4/ComposerVts.h>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace android {
namespace hardware {
namespace graphics {
@@ -27,11 +25,6 @@ namespace vts {
using V2_4::Error;
-Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
-
-Composer::Composer(const std::string& name)
- : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
-
Composer::Composer(const sp<IComposer>& composer)
: V2_3::vts::Composer(composer), mComposer(composer) {}
@@ -129,6 +122,16 @@ Error ComposerClient::setContentType(Display display, IComposerClient::ContentTy
return mClient->setContentType(display, contentType);
}
+Error ComposerClient::getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) {
+ Error error = Error::NONE;
+ mClient->getLayerGenericMetadataKeys([&](const auto tmpError, const auto& tmpKeys) {
+ error = tmpError;
+ *outKeys = tmpKeys;
+ });
+ return error;
+}
+
} // namespace vts
} // namespace V2_4
} // namespace composer
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
index df75a48655..fd59eb93cd 100644
--- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
@@ -19,7 +19,6 @@
#include <memory>
#include <vector>
-#include <VtsHalHidlTargetTestBase.h>
#include <android/hardware/graphics/composer/2.4/IComposer.h>
#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
#include <composer-vts/2.3/ComposerVts.h>
@@ -93,6 +92,9 @@ class ComposerClient : public V2_3::vts::ComposerClient {
Error setContentType(Display display, IComposerClient::ContentType contentType);
+ Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys);
+
private:
const sp<IComposerClient> mClient;
};
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index 800ff08a17..a7c3fd7b0c 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "graphics_composer_hidl_hal_test@2.4"
#include <algorithm>
+#include <regex>
#include <thread>
#include <android-base/logging.h>
@@ -41,6 +42,8 @@ namespace V2_4 {
namespace vts {
namespace {
+using namespace std::chrono_literals;
+
using common::V1_0::BufferUsage;
using common::V1_1::RenderIntent;
using common::V1_2::ColorMode;
@@ -525,7 +528,7 @@ TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyMode) {
EXPECT_EQ(Error::UNSUPPORTED,
mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false));
GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display "
- << to_string(display) << ", skipping test";
+ << std::to_string(display) << ", skipping test";
return;
}
@@ -579,7 +582,7 @@ void GraphicsComposerHidlTest::Test_setContentTypeForDisplay(
if (!contentTypeSupport) {
EXPECT_EQ(Error::UNSUPPORTED, mComposerClient->setContentType(display, contentType));
GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display "
- << to_string(display) << ", skipping test";
+ << std::to_string(display) << ", skipping test";
return;
}
@@ -625,6 +628,28 @@ INSTANTIATE_TEST_SUITE_P(
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
android::hardware::PrintInstanceNameToString);
+TEST_P(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) {
+ std::vector<IComposerClient::LayerGenericMetadataKey> keys;
+ mComposerClient->getLayerGenericMetadataKeys(&keys);
+
+ std::regex reverseDomainName("^[a-zA-Z-]{2,}(\\.[a-zA-Z0-9-]+)+$");
+ std::unordered_set<std::string> uniqueNames;
+ for (const auto& key : keys) {
+ std::string name(key.name.c_str());
+
+ // Keys must not start with 'android' or 'com.android'
+ ASSERT_FALSE(name.find("android") == 0);
+ ASSERT_FALSE(name.find("com.android") == 0);
+
+ // Keys must be in reverse domain name format
+ ASSERT_TRUE(std::regex_match(name, reverseDomainName));
+
+ // Keys must be unique within this list
+ const auto& [iter, inserted] = uniqueNames.insert(name);
+ ASSERT_TRUE(inserted);
+ }
+}
+
} // namespace
} // namespace vts
} // namespace V2_4
diff --git a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
index 49891b74cd..352a990af2 100644
--- a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
+++ b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
@@ -315,9 +315,7 @@ TEST_P(HealthHidlTest, getEnergyCounter) {
TEST_P(HealthHidlTest, getChargeStatus) {
SKIP_IF_SKIPPED();
EXPECT_OK(mHealth->getChargeStatus([](auto result, auto value) {
- EXPECT_VALID_OR_UNSUPPORTED_PROP(
- result, toString(value),
- value != BatteryStatus::UNKNOWN && verifyEnum<BatteryStatus>(value));
+ EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyEnum<BatteryStatus>(value));
}));
}
diff --git a/health/2.1/README.md b/health/2.1/README.md
index bfcf13bc95..8390570d60 100644
--- a/health/2.1/README.md
+++ b/health/2.1/README.md
@@ -24,6 +24,9 @@
```mk
# Install default passthrough implementation to vendor.
PRODUCT_PACKAGES += android.hardware.health@2.1-impl
+
+ # For non-A/B devices, install default passthrough implementation to recovery.
+ PRODUCT_PACKAGES += android.hardware.health@2.1-impl.recovery
```
You are done. Otherwise, go to the next step.
@@ -42,6 +45,8 @@
implementation, See
[Upgrading from Health HAL 2.0](#update-from-2-0).
+ 1. [Install the implementation](#install).
+
1. [Update necessary SELinux permissions](#selinux).
1. [Fix `/charger` symlink](#charger-symlink).
@@ -95,15 +100,22 @@ and `update()`, with an additional `energyCounter()` function.
`HealthImpl::getHealthInfo` or `HealthImpl::getHealthInfo_2_1` because they call
`getDiskStats` and `getStorageInfo` to retrieve storage information.
+# Install the implementation {#install}
+
+In `device.mk`:
+
+```mk
+# Install the passthrough implementation to vendor.
+PRODUCT_PACKAGES += android.hardware.health@2.1-impl-<device>
+
+# For non-A/B devices, also install the passthrough implementation to recovery.
+PRODUCT_PACKAGES += android.hardware.health@2.1-impl-<device>.recovery
+```
+
# Update necessary SELinux permissions {#selinux}
For example (replace `<device>` with the device name):
```
-# device/<manufacturer>/<device>/sepolicy/vendor/file_contexts
-# Required for charger to open passthrough implementation. Replace <device> with the proper device
-# name. File name must be consistent with `stem` of the implementation module.
-/vendor/lib(64)?/hw/android\.hardware\.health@2\.0-impl-2\.1-<device>\.so u:object_r:same_process_hal_file:s0
-
# device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
# Add device specific permissions to hal_health_default domain, especially
# if a device-specific libhealthd is used and/or device-specific storage related
diff --git a/health/2.1/default/android.hardware.health@2.1-service.rc b/health/2.1/default/android.hardware.health@2.1-service.rc
index 917f1c2f19..b6d9e3bcf3 100644
--- a/health/2.1/default/android.hardware.health@2.1-service.rc
+++ b/health/2.1/default/android.hardware.health@2.1-service.rc
@@ -1,5 +1,5 @@
service health-hal-2-1 /vendor/bin/hw/android.hardware.health@2.1-service
- class hal
+ class hal charger
user system
group system
capabilities WAKE_ALARM
diff --git a/health/2.1/vts/functional/Android.bp b/health/2.1/vts/functional/Android.bp
index 5aa873ab98..17472fa2fa 100644
--- a/health/2.1/vts/functional/Android.bp
+++ b/health/2.1/vts/functional/Android.bp
@@ -25,5 +25,8 @@ cc_test {
"android.hardware.health@2.0",
"android.hardware.health@2.1",
],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp b/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp
index da9f5bbbbc..e75b299b0b 100644
--- a/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp
+++ b/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp
@@ -233,9 +233,13 @@ TEST_P(HealthHidlTest, getHealthInfo_2_1) {
EXPECT_TRUE(IsEnum(value.batteryCapacityLevel)) << " BatteryCapacityLevel";
EXPECT_GE(value.batteryChargeTimeToFullNowSeconds, 0);
- EXPECT_GE(value.batteryFullCapacityUah, 0) << "batteryFullCapacityUah is unknown";
- EXPECT_GE(value.batteryFullCapacityUah, legacy.batteryFullCharge * 0.50);
- EXPECT_LE(value.batteryFullCapacityUah, legacy.batteryFullCharge * 1.20);
+ EXPECT_GE(value.batteryFullCapacityUah, 0)
+ << "batteryFullCapacityUah should not be negative";
+
+ if (value.batteryFullCapacityUah > 0) {
+ EXPECT_GE(value.batteryFullCapacityUah, legacy.batteryFullCharge * 0.50);
+ EXPECT_LE(value.batteryFullCapacityUah, legacy.batteryFullCharge * 1.20);
+ }
})));
}
diff --git a/health/utils/libhealthloop/utils.cpp b/health/utils/libhealthloop/utils.cpp
index b0d153f583..ebfd8d8c6a 100644
--- a/health/utils/libhealthloop/utils.cpp
+++ b/health/utils/libhealthloop/utils.cpp
@@ -40,6 +40,8 @@ void InitHealthdConfig(struct healthd_config* healthd_config) {
.batteryChargeCounterPath = String8(String8::kEmptyString),
.batteryFullChargePath = String8(String8::kEmptyString),
.batteryCycleCountPath = String8(String8::kEmptyString),
+ .batteryCapacityLevelPath = String8(String8::kEmptyString),
+ .batteryChargeTimeToFullNowPath = String8(String8::kEmptyString),
.energyCounter = NULL,
.boot_min_cap = 0,
.screen_on = NULL,
diff --git a/identity/1.0/Android.bp b/identity/1.0/Android.bp
index a5cea90656..e0a6332f89 100644
--- a/identity/1.0/Android.bp
+++ b/identity/1.0/Android.bp
@@ -13,13 +13,8 @@ hidl_interface {
"IWritableIdentityCredential.hal",
],
interfaces: [
- "android.hidl.base@1.0",
"android.hardware.keymaster@4.0",
- ],
- types: [
- "AuditLogEntry",
- "ResultCode",
- "SecureAccessControlProfile",
+ "android.hidl.base@1.0",
],
gen_java: false,
}
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
index c5ce9505d3..6c186f6429 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
@@ -100,6 +100,7 @@ using V4_0::TAG_VENDOR_PATCHLEVEL;
DECLARE_KM_4_1_TYPED_TAG(EARLY_BOOT_ONLY);
DECLARE_KM_4_1_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION);
+DECLARE_KM_4_1_TYPED_TAG(STORAGE_KEY);
} // namespace android::hardware::keymaster::V4_1
diff --git a/keymaster/4.1/types.hal b/keymaster/4.1/types.hal
index 9e8b30e590..f3bdcc6404 100644
--- a/keymaster/4.1/types.hal
+++ b/keymaster/4.1/types.hal
@@ -50,10 +50,29 @@ enum Tag : @4.0::Tag {
* HAL attests to Credential Keys. IIdentityCredential produces Keymaster-style attestations.
*/
IDENTITY_CREDENTIAL_KEY = TagType:BOOL | 721,
+
+ /**
+ * To prevent keys from being compromised if an attacker acquires read access to system / kernel
+ * memory, some inline encryption hardware supports protecting storage encryption keys in hardware
+ * without software having access to or the ability to set the plaintext keys. Instead, software
+ * only sees wrapped version of these keys.
+ *
+ * STORAGE_KEY is used to denote that a key generated or imported is a key used for storage
+ * encryption. Keys of this type can either be generated or imported or secure imported using
+ * keymaster. exportKey() can be used to re-wrap storage key with a per-boot ephemeral key wrapped
+ * key once the key characteristics are enforced.
+ *
+ * Keys with this tag cannot be used for any operation within keymaster.
+ * ErrorCode::INVALID_OPERATION is returned when a key with Tag::STORAGE_KEY is provided to
+ * begin().
+ */
+ STORAGE_KEY = TagType:BOOL | 722,
};
enum ErrorCode : @4.0::ErrorCode {
EARLY_BOOT_ENDED = -73,
ATTESTATION_KEYS_NOT_PROVISIONED = -74,
ATTESTATION_IDS_NOT_PROVISIONED = -75,
+ INVALID_OPERATION = -76,
+ STORAGE_KEY_UNSUPPORTED = -77,
};
diff --git a/light/aidl/Android.bp b/light/aidl/Android.bp
new file mode 100644
index 0000000000..916a857b58
--- /dev/null
+++ b/light/aidl/Android.bp
@@ -0,0 +1,18 @@
+aidl_interface {
+ name: "android.hardware.light",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/light/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ },
+}
diff --git a/light/aidl/android/hardware/light/BrightnessMode.aidl b/light/aidl/android/hardware/light/BrightnessMode.aidl
new file mode 100644
index 0000000000..bc296990ce
--- /dev/null
+++ b/light/aidl/android/hardware/light/BrightnessMode.aidl
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+package android.hardware.light;
+
+@VintfStability
+enum BrightnessMode {
+ /**
+ * Light brightness is managed by a user setting.
+ */
+ USER = 0,
+
+ /**
+ * Light brightness is managed by a light sensor. This is typically used
+ * to control the display backlight, but not limited to it. HALs and
+ * hardware implementations are free to support sensor for other lights or
+ * none whatsoever.
+ */
+ SENSOR = 1,
+
+ /**
+ * Use a low-persistence mode for display backlights, where the pixel
+ * color transition times are lowered.
+ *
+ * When set, the device driver must switch to a mode optimized for low display
+ * persistence that is intended to be used when the device is being treated as a
+ * head mounted display (HMD). The actual display brightness in this mode is
+ * implementation dependent, and any value set for color in LightState may be
+ * overridden by the HAL implementation.
+ *
+ * For an optimal HMD viewing experience, the display must meet the following
+ * criteria in this mode:
+ * - Gray-to-Gray, White-to-Black, and Black-to-White switching time must be ≤ 3 ms.
+ * - The display must support low-persistence with ≤ 3.5 ms persistence.
+ * Persistence is defined as the amount of time for which a pixel is
+ * emitting light for a single frame.
+ * - Any "smart panel" or other frame buffering options that increase display
+ * latency are disabled.
+ * - Display brightness is set so that the display is still visible to the user
+ * under normal indoor lighting.
+ * - The display must update at 60 Hz at least, but higher refresh rates are
+ * recommended for low latency.
+ *
+ */
+ LOW_PERSISTENCE = 2,
+}
diff --git a/light/aidl/android/hardware/light/FlashMode.aidl b/light/aidl/android/hardware/light/FlashMode.aidl
new file mode 100644
index 0000000000..00c6b6a028
--- /dev/null
+++ b/light/aidl/android/hardware/light/FlashMode.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+package android.hardware.light;
+
+@VintfStability
+enum FlashMode {
+ /**
+ * Keep the light steady on or off.
+ */
+ NONE = 0,
+ /**
+ * Flash the light at specified rate, potentially using a software-based
+ * implementation.
+ */
+ TIMED = 1,
+ /**
+ * Flash the light using hardware flashing support. This may or may not
+ * support a user-defined flashing rate or other features.
+ */
+ HARDWARE = 2,
+}
diff --git a/light/aidl/android/hardware/light/HwLight.aidl b/light/aidl/android/hardware/light/HwLight.aidl
new file mode 100644
index 0000000000..43fdb4bf81
--- /dev/null
+++ b/light/aidl/android/hardware/light/HwLight.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 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 android.hardware.light;
+
+import android.hardware.light.LightType;
+
+/**
+ * A description of a single light. Multiple lights can map to the same physical
+ * LED. Separate physical LEDs are always represented by separate instances.
+ */
+@VintfStability
+parcelable HwLight {
+ /**
+ * Integer ID used for controlling this light
+ */
+ int id;
+
+ /**
+ * For a group of lights of the same logical type, sorting by ordinal should
+ * be give their physical order. No other meaning is carried by it.
+ */
+ int ordinal;
+
+ /**
+ * Logical type use of this light.
+ */
+ LightType type;
+}
diff --git a/light/aidl/android/hardware/light/HwLightState.aidl b/light/aidl/android/hardware/light/HwLightState.aidl
new file mode 100644
index 0000000000..24d3250887
--- /dev/null
+++ b/light/aidl/android/hardware/light/HwLightState.aidl
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+package android.hardware.light;
+
+import android.hardware.light.BrightnessMode;
+import android.hardware.light.FlashMode;
+
+/**
+ * The parameters that can be set for a given light.
+ *
+ * Not all lights must support all parameters. If you
+ * can do something backward-compatible, do it.
+ */
+@VintfStability
+parcelable HwLightState {
+ /**
+ * The color of the LED in ARGB.
+ *
+ * The implementation of this in the HAL and hardware is a best-effort one.
+ * - If a light can only do red or green and blue is requested, green
+ * should be shown.
+ * - If only a brightness ramp is supported, then this formula applies:
+ * unsigned char brightness = ((77*((color>>16)&0x00ff))
+ * + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
+ * - If only on and off are supported, 0 is off, anything else is on.
+ *
+ * The high byte should be ignored. Callers should set it to 0xff (which
+ * would correspond to 255 alpha).
+ */
+ int color;
+
+ /**
+ * To flash the light at a given rate, set flashMode to FLASH_TIMED.
+ */
+ FlashMode flashMode;
+
+ /**
+ * flashOnMs should be set to the number of milliseconds to turn the
+ * light on, before it's turned off.
+ */
+ int flashOnMs;
+
+ /**
+ * flashOfMs should be set to the number of milliseconds to turn the
+ * light off, before it's turned back on.
+ */
+ int flashOffMs;
+
+ BrightnessMode brightnessMode;
+}
diff --git a/light/aidl/android/hardware/light/ILights.aidl b/light/aidl/android/hardware/light/ILights.aidl
new file mode 100644
index 0000000000..2253f73c36
--- /dev/null
+++ b/light/aidl/android/hardware/light/ILights.aidl
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package android.hardware.light;
+
+import android.hardware.light.HwLightState;
+import android.hardware.light.HwLight;
+
+/**
+ * Allows controlling logical lights/indicators, mapped to LEDs in a
+ * hardware-specific manner by the HAL implementation.
+ */
+@VintfStability
+interface ILights {
+ /**
+ * Set light identified by id to the provided state.
+ *
+ * If control over an invalid light is requested, this method exists with
+ * EX_UNSUPPORTED_OPERATION. Control over supported lights is done on a
+ * device-specific best-effort basis and unsupported sub-features will not
+ * be reported.
+ *
+ * @param id ID of logical light to set as returned by getLights()
+ * @param state describes what the light should look like.
+ */
+ void setLightState(in int id, in HwLightState state);
+
+ /**
+ * Discover what lights are supported by the HAL implementation.
+ *
+ * @return List of available lights
+ */
+ HwLight[] getLights();
+}
diff --git a/light/aidl/android/hardware/light/LightType.aidl b/light/aidl/android/hardware/light/LightType.aidl
new file mode 100644
index 0000000000..9a7f65619d
--- /dev/null
+++ b/light/aidl/android/hardware/light/LightType.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+package android.hardware.light;
+
+/**
+ * These light IDs correspond to logical lights, not physical.
+ * So for example, if your INDICATOR light is in line with your
+ * BUTTONS, it might make sense to also light the INDICATOR
+ * light to a reasonable color when the BUTTONS are lit.
+ */
+@VintfStability
+enum LightType {
+ BACKLIGHT = 0,
+ KEYBOARD = 1,
+ BUTTONS = 2,
+ BATTERY = 3,
+ NOTIFICATIONS = 4,
+ ATTENTION = 5,
+ BLUETOOTH = 6,
+ WIFI = 7,
+ MICROPHONE = 8,
+}
diff --git a/light/aidl/default/Android.bp b/light/aidl/default/Android.bp
new file mode 100644
index 0000000000..ae3f4630de
--- /dev/null
+++ b/light/aidl/default/Android.bp
@@ -0,0 +1,16 @@
+cc_binary {
+ name: "android.hardware.lights-service.example",
+ relative_install_path: "hw",
+ init_rc: ["lights-default.rc"],
+ vintf_fragments: ["lights-default.xml"],
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.light-ndk_platform",
+ ],
+ srcs: [
+ "Lights.cpp",
+ "main.cpp",
+ ],
+}
diff --git a/light/aidl/default/Lights.cpp b/light/aidl/default/Lights.cpp
new file mode 100644
index 0000000000..74747d57bd
--- /dev/null
+++ b/light/aidl/default/Lights.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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 "Lights.h"
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace light {
+
+ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) {
+ LOG(INFO) << "Lights setting state for id=" << id << " to color " << std::hex << state.color;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Lights::getLights(std::vector<HwLight>* /*lights*/) {
+ LOG(INFO) << "Lights reporting supported lights";
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace light
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/light/aidl/default/Lights.h b/light/aidl/default/Lights.h
new file mode 100644
index 0000000000..8cba5a1cfd
--- /dev/null
+++ b/light/aidl/default/Lights.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/light/BnLights.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace light {
+
+// Default implementation that reports no supported lights.
+class Lights : public BnLights {
+ ndk::ScopedAStatus setLightState(int id, const HwLightState& state) override;
+ ndk::ScopedAStatus getLights(std::vector<HwLight>* types) override;
+};
+
+} // namespace light
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/light/aidl/default/lights-default.rc b/light/aidl/default/lights-default.rc
new file mode 100644
index 0000000000..687ec97dd1
--- /dev/null
+++ b/light/aidl/default/lights-default.rc
@@ -0,0 +1,5 @@
+service vendor.light-default /vendor/bin/hw/android.hardware.lights-service.example
+ class hal
+ user nobody
+ group nobody
+ shutdown critical
diff --git a/light/aidl/default/lights-default.xml b/light/aidl/default/lights-default.xml
new file mode 100644
index 0000000000..db604d61f0
--- /dev/null
+++ b/light/aidl/default/lights-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.light</name>
+ <fqname>ILights/default</fqname>
+ </hal>
+</manifest>
diff --git a/light/aidl/default/main.cpp b/light/aidl/default/main.cpp
new file mode 100644
index 0000000000..a860bf4a98
--- /dev/null
+++ b/light/aidl/default/main.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#include "Lights.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::aidl::android::hardware::light::Lights;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<Lights> lights = ndk::SharedRefBase::make<Lights>();
+
+ const std::string instance = std::string() + Lights::descriptor + "/default";
+ binder_status_t status = AServiceManager_addService(lights->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reached
+}
diff --git a/light/aidl/vts/functional/Android.bp b/light/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000000..3dd8cf64ce
--- /dev/null
+++ b/light/aidl/vts/functional/Android.bp
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+
+cc_test {
+ name: "VtsHalLightTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "VtsHalLightTargetTest.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ ],
+ static_libs: [
+ "android.hardware.light-cpp",
+ ],
+ test_suites: [
+ "vts-core",
+ ],
+}
diff --git a/light/aidl/vts/functional/VtsHalLightTargetTest.cpp b/light/aidl/vts/functional/VtsHalLightTargetTest.cpp
new file mode 100644
index 0000000000..3c26278a19
--- /dev/null
+++ b/light/aidl/vts/functional/VtsHalLightTargetTest.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "light_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android-base/logging.h>
+#include <android/hardware/light/ILights.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <unistd.h>
+#include <set>
+
+using android::ProcessState;
+using android::sp;
+using android::String16;
+using android::binder::Status;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::light::BrightnessMode;
+using android::hardware::light::FlashMode;
+using android::hardware::light::HwLight;
+using android::hardware::light::HwLightState;
+using android::hardware::light::ILights;
+using android::hardware::light::LightType;
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+const std::set<LightType> kAllTypes{android::enum_range<LightType>().begin(),
+ android::enum_range<LightType>().end()};
+
+class LightsAidl : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ lights = android::waitForDeclaredService<ILights>(String16(GetParam().c_str()));
+ ASSERT_NE(lights, nullptr);
+ ASSERT_TRUE(lights->getLights(&supportedLights).isOk());
+ }
+
+ sp<ILights> lights;
+ std::vector<HwLight> supportedLights;
+
+ virtual void TearDown() override {
+ for (const HwLight& light : supportedLights) {
+ HwLightState off;
+ off.color = 0x00000000;
+ off.flashMode = FlashMode::NONE;
+ off.brightnessMode = BrightnessMode::USER;
+ EXPECT_TRUE(lights->setLightState(light.id, off).isOk());
+ }
+
+ // must leave the device in a useable condition
+ for (const HwLight& light : supportedLights) {
+ if (light.type == LightType::BACKLIGHT) {
+ HwLightState backlightOn;
+ backlightOn.color = 0xFFFFFFFF;
+ backlightOn.flashMode = FlashMode::TIMED;
+ backlightOn.brightnessMode = BrightnessMode::USER;
+ EXPECT_TRUE(lights->setLightState(light.id, backlightOn).isOk());
+ }
+ }
+ }
+};
+
+/**
+ * Ensure all reported lights actually work.
+ */
+TEST_P(LightsAidl, TestSupported) {
+ HwLightState whiteFlashing;
+ whiteFlashing.color = 0xFFFFFFFF;
+ whiteFlashing.flashMode = FlashMode::TIMED;
+ whiteFlashing.flashOnMs = 100;
+ whiteFlashing.flashOffMs = 50;
+ whiteFlashing.brightnessMode = BrightnessMode::USER;
+ for (const HwLight& light : supportedLights) {
+ EXPECT_TRUE(lights->setLightState(light.id, whiteFlashing).isOk());
+ }
+}
+
+/**
+ * Ensure all reported lights have one of the supported types.
+ */
+TEST_P(LightsAidl, TestSupportedLightTypes) {
+ for (const HwLight& light : supportedLights) {
+ EXPECT_TRUE(kAllTypes.find(light.type) != kAllTypes.end());
+ }
+}
+
+/**
+ * Ensure all lights have a unique id.
+ */
+TEST_P(LightsAidl, TestUniqueIds) {
+ std::set<int> ids;
+ for (const HwLight& light : supportedLights) {
+ EXPECT_TRUE(ids.find(light.id) == ids.end());
+ ids.insert(light.id);
+ }
+}
+
+/**
+ * Ensure all lights have a unique ordinal for a given type.
+ */
+TEST_P(LightsAidl, TestUniqueOrdinalsForType) {
+ std::map<int, std::set<int>> ordinalsByType;
+ for (const HwLight& light : supportedLights) {
+ auto& ordinals = ordinalsByType[(int)light.type];
+ EXPECT_TRUE(ordinals.find(light.ordinal) == ordinals.end());
+ ordinals.insert(light.ordinal);
+ }
+}
+
+/**
+ * Ensure EX_UNSUPPORTED_OPERATION is returned if LOW_PERSISTENCE is not supported.
+ */
+TEST_P(LightsAidl, TestLowPersistence) {
+ HwLightState lowPersistence;
+ lowPersistence.color = 0xFF123456;
+ lowPersistence.flashMode = FlashMode::TIMED;
+ lowPersistence.flashOnMs = 100;
+ lowPersistence.flashOffMs = 50;
+ lowPersistence.brightnessMode = BrightnessMode::LOW_PERSISTENCE;
+ for (const HwLight& light : supportedLights) {
+ Status status = lights->setLightState(light.id, lowPersistence);
+ EXPECT_TRUE(status.isOk() || Status::EX_UNSUPPORTED_OPERATION == status.exceptionCode());
+ }
+}
+
+/**
+ * Ensure EX_UNSUPPORTED_OPERATION is returns for an invalid light id.
+ */
+TEST_P(LightsAidl, TestInvalidLightIdUnsupported) {
+ int maxId = INT_MIN;
+ for (const HwLight& light : supportedLights) {
+ maxId = std::max(maxId, light.id);
+ }
+
+ Status status = lights->setLightState(maxId + 1, HwLightState());
+ EXPECT_TRUE(status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION);
+}
+
+INSTANTIATE_TEST_SUITE_P(Lights, LightsAidl,
+ testing::ValuesIn(android::getAidlHalInstanceNames(ILights::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ ProcessState::self()->startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/light/utils/Android.bp b/light/utils/Android.bp
index 4c287e4620..e901129d1f 100644
--- a/light/utils/Android.bp
+++ b/light/utils/Android.bp
@@ -23,7 +23,11 @@ cc_binary {
shared_libs: [
"android.hardware.light@2.0",
"libbase",
+ "libbinder",
"libhidlbase",
"libutils",
],
+ static_libs: [
+ "android.hardware.light-cpp",
+ ],
}
diff --git a/light/utils/main.cpp b/light/utils/main.cpp
index b83413246b..b9b6489eec 100644
--- a/light/utils/main.cpp
+++ b/light/utils/main.cpp
@@ -19,34 +19,23 @@
#include <android-base/logging.h>
#include <android/hardware/light/2.0/ILight.h>
+#include <android/hardware/light/ILights.h>
+#include <binder/IServiceManager.h>
+
+using android::sp;
+using android::waitForVintfService;
+using android::binder::Status;
+using android::hardware::hidl_vec;
+
+namespace V2_0 = android::hardware::light::V2_0;
+namespace aidl = android::hardware::light;
void error(const std::string& msg) {
LOG(ERROR) << msg;
std::cerr << msg << std::endl;
}
-int main(int argc, char* argv[]) {
- using ::android::hardware::hidl_vec;
- using ::android::hardware::light::V2_0::Brightness;
- using ::android::hardware::light::V2_0::Flash;
- using ::android::hardware::light::V2_0::ILight;
- using ::android::hardware::light::V2_0::LightState;
- using ::android::hardware::light::V2_0::Status;
- using ::android::hardware::light::V2_0::Type;
- using ::android::sp;
-
- sp<ILight> service = ILight::getService();
- if (service == nullptr) {
- error("Could not retrieve light service.");
- return -1;
- }
-
- static LightState off = {
- .color = 0u,
- .flashMode = Flash::NONE,
- .brightnessMode = Brightness::USER,
- };
-
+int parseArgs(int argc, char* argv[], unsigned int* color) {
if (argc > 2) {
error("Usage: blank_screen [color]");
return -1;
@@ -54,25 +43,78 @@ int main(int argc, char* argv[]) {
if (argc > 1) {
char* col_ptr;
- unsigned int col_new;
- col_new = strtoul(argv[1], &col_ptr, 0);
+ *color = strtoul(argv[1], &col_ptr, 0);
if (*col_ptr != '\0') {
error("Failed to convert " + std::string(argv[1]) + " to number");
return -1;
}
- off.color = col_new;
+
+ return 0;
+ }
+
+ *color = 0u;
+ return 0;
+}
+
+void setToColorAidl(sp<aidl::ILights> hal, unsigned int color) {
+ static aidl::HwLightState off;
+ off.color = color;
+ off.flashMode = aidl::FlashMode::NONE;
+ off.brightnessMode = aidl::BrightnessMode::USER;
+
+ std::vector<aidl::HwLight> lights;
+ Status status = hal->getLights(&lights);
+ if (!status.isOk()) {
+ error("Failed to list lights");
+ return;
+ }
+
+ for (auto light : lights) {
+ Status setStatus = hal->setLightState(light.id, off);
+ if (!setStatus.isOk()) {
+ error("Failed to shut off light id " + std::to_string(light.id));
+ }
}
+}
- service->getSupportedTypes([&](const hidl_vec<Type>& types) {
- for (Type type : types) {
- Status ret = service->setLight(type, off);
- if (ret != Status::SUCCESS) {
- error("Failed to shut off screen for type " +
+void setToColorHidl(sp<V2_0::ILight> hal, unsigned int color) {
+ static V2_0::LightState off = {
+ .color = color,
+ .flashMode = V2_0::Flash::NONE,
+ .brightnessMode = V2_0::Brightness::USER,
+ };
+
+ hal->getSupportedTypes([&](const hidl_vec<V2_0::Type>& types) {
+ for (auto type : types) {
+ V2_0::Status ret = hal->setLight(type, off);
+ if (ret != V2_0::Status::SUCCESS) {
+ error("Failed to shut off light for type " +
std::to_string(static_cast<int>(type)));
}
}
});
+}
- return 0;
+int main(int argc, char* argv[]) {
+ unsigned int inputColor;
+ int result = parseArgs(argc, argv, &inputColor);
+ if (result != 0) {
+ return result;
+ }
+
+ auto aidlHal = waitForVintfService<aidl::ILights>();
+ if (aidlHal != nullptr) {
+ setToColorAidl(aidlHal, inputColor);
+ return 0;
+ }
+
+ sp<V2_0::ILight> hidlHal = V2_0::ILight::getService();
+ if (hidlHal != nullptr) {
+ setToColorHidl(hidlHal, inputColor);
+ return 0;
+ }
+
+ error("Could not retrieve light service.");
+ return -1;
}
diff --git a/memtrack/1.0/default/Memtrack.cpp b/memtrack/1.0/default/Memtrack.cpp
index 33a6906694..0bbf83d2b3 100644
--- a/memtrack/1.0/default/Memtrack.cpp
+++ b/memtrack/1.0/default/Memtrack.cpp
@@ -34,9 +34,7 @@ Memtrack::Memtrack(const memtrack_module_t *module) : mModule(module) {
mModule->init(mModule);
}
-Memtrack::~Memtrack() {
- delete(mModule);
-}
+Memtrack::~Memtrack() {}
Return<void> Memtrack::getMemory(int32_t pid, MemtrackType type,
getMemory_cb _hidl_cb) {
diff --git a/neuralnetworks/1.3/Android.bp b/neuralnetworks/1.3/Android.bp
index 56011e227d..7b02cc510f 100644
--- a/neuralnetworks/1.3/Android.bp
+++ b/neuralnetworks/1.3/Android.bp
@@ -11,6 +11,7 @@ hidl_interface {
"IBuffer.hal",
"IDevice.hal",
"IExecutionCallback.hal",
+ "IFencedExecutionCallback.hal",
"IPreparedModel.hal",
"IPreparedModelCallback.hal",
],
diff --git a/neuralnetworks/1.3/IFencedExecutionCallback.hal b/neuralnetworks/1.3/IFencedExecutionCallback.hal
new file mode 100644
index 0000000000..6030809406
--- /dev/null
+++ b/neuralnetworks/1.3/IFencedExecutionCallback.hal
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package android.hardware.neuralnetworks@1.3;
+
+import @1.2::Timing;
+import ErrorStatus;
+
+/**
+ * IFencedExecutionCallback can be used to query the error status result
+ * and duration information from an IPreparedModel::executeFenced call.
+ */
+interface IFencedExecutionCallback {
+
+ /**
+ * The getExecutionInfo method is used by the clients to query error status
+ * result and duration information. The method must only be called after the actual
+ * evaluation has finished or resulted in an runtime error, as indicated by the status
+ * of the sync fence returned by the IPreparedModel::executeFenced call, otherwise
+ * GENERAL_FAILURE must be returned.
+ *
+ * @return status Error status returned from the asynchronously dispatched execution
+ * must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if the asynchronous task resulted in an
+ * unspecified error
+ * - MISSED_DEADLINE_* if the deadline for executing a model
+ * cannot be met
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the
+ * driver
+ * @return timingLaunched The duration starts when executeFenced is called and ends when
+ * executeFenced signals the returned syncFence.
+ * Unless MeasureTiming::YES was passed when
+ * launching the execution and status is NONE, all times
+ * must be reported as UINT64_MAX. A driver may choose to
+ * report any time as UINT64_MAX, indicating that particular
+ * measurement is not available.
+ * @return timingFenced The duration starts when all waitFor sync fences have been signaled
+ * and ends when executeFenced signals the returned syncFence.
+ * Unless MeasureTiming::YES was passed when
+ * launching the execution and status is NONE, all times
+ * must be reported as UINT64_MAX. A driver may choose to
+ * report any time as UINT64_MAX, indicating that particular
+ * measurement is not available.
+ */
+ getExecutionInfo() generates (ErrorStatus status, Timing timingLaunched, Timing timingFenced);
+};
diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal
index bce6ee227a..d645de789c 100644
--- a/neuralnetworks/1.3/IPreparedModel.hal
+++ b/neuralnetworks/1.3/IPreparedModel.hal
@@ -21,9 +21,11 @@ import @1.2::MeasureTiming;
import @1.2::OutputShape;
import @1.2::Timing;
import ErrorStatus;
+import OptionalTimeoutDuration;
import OptionalTimePoint;
import Request;
import IExecutionCallback;
+import IFencedExecutionCallback;
/**
* IPreparedModel describes a model that has been prepared for execution and
@@ -67,7 +69,7 @@ interface IPreparedModel extends @1.2::IPreparedModel {
* There must be no failure unless the device itself is in a bad state.
*
* execute_1_3 can be called with an optional deadline. If the execution
- * is not able to completed before the provided deadline, the execution
+ * is not able to be completed before the provided deadline, the execution
* must be aborted, and either {@link
* ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
* ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
@@ -87,11 +89,12 @@ interface IPreparedModel extends @1.2::IPreparedModel {
* The duration runs from the time the driver sees the call
* to the execute_1_3 function to the time the driver invokes
* the callback.
- * @param deadline The time by which execution must complete. If the
+ * @param deadline The time by which the execution must complete. If the
* execution cannot be finished by the deadline, the
* execution must be aborted.
* @param callback A callback object used to return the error status of
- * the execution. The callback object's notify function must
+ * the execution, shape information of model output operands, and
+ * duration of execution. The callback object's notify function must
* be called exactly once, even if the execution was
* unsuccessful.
* @return status Error status of the call, must be:
@@ -137,7 +140,7 @@ interface IPreparedModel extends @1.2::IPreparedModel {
* in a bad state.
*
* executeSynchronously_1_3 can be called with an optional deadline. If the
- * execution is not able to completed before the provided deadline, the
+ * execution is not able to be completed before the provided deadline, the
* execution must be aborted, and either {@link
* ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
* ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
@@ -157,7 +160,7 @@ interface IPreparedModel extends @1.2::IPreparedModel {
* The duration runs from the time the driver sees the call
* to the executeSynchronously_1_3 function to the time the driver
* returns from the function.
- * @param deadline The time by which execution must complete. If the
+ * @param deadline The time by which the execution must complete. If the
* execution cannot be finished by the deadline, the
* execution must be aborted.
* @return status Error status of the execution, must be:
@@ -187,4 +190,80 @@ interface IPreparedModel extends @1.2::IPreparedModel {
OptionalTimePoint deadline)
generates (ErrorStatus status, vec<OutputShape> outputShapes,
Timing timing);
+
+ /**
+ * Launch a fenced asynchronous execution on a prepared model.
+ *
+ * The execution is performed asynchronously with respect to the caller.
+ * executeFenced must verify the inputs to the function are correct, and the usages
+ * of memory pools allocated by IDevice::allocate are valid. If there is an error,
+ * executeFenced must immediately return with the corresponding ErrorStatus, an empty
+ * handle for syncFence, and nullptr for callback. If the inputs to the function
+ * are valid and there is no error, executeFenced must dispatch an asynchronous task
+ * to perform the execution in the background, and immediately return with
+ * ErrorStatus::NONE, a sync fence that will be signaled once the execution is completed,
+ * and a callback that can be used by the client to query the duration and runtime error
+ * status. If the task has finished before the call returns, an empty handle may be returned
+ * for syncFence. The execution must wait for all the sync fences (if any) in waitFor
+ * to be signaled before starting the actual execution.
+ *
+ * When the asynchronous task has finished its execution, it must
+ * immediately signal the syncFence returned from the executeFenced call. After
+ * the syncFence is signaled, the task must not modify the content of
+ * any data object referenced by 'request' (described by the
+ * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}).
+ *
+ * executeFenced can be called with an optional deadline and an optional duration.
+ * If the execution is not able to be completed before the provided deadline or
+ * within the timeout duration (measured from when all sync fences in waitFor are
+ * signaled), whichever comes earlier, the execution must be aborted, and either
+ * {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
+ * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
+ * to an abort must be sent the same way as other errors, described above.
+ * If the service reports that it does not support execution deadlines via
+ * IDevice::supportsDeadlines, and executeFenced is called with a
+ * deadline or duration, then the argument is invalid, and
+ * {@link ErrorStatus::INVALID_ARGUMENT} must be returned.
+ *
+ * If any of the sync fences in waitFor changes to error status after the executeFenced
+ * call succeeds, or the execution is aborted because it cannot finish before the deadline
+ * has been reached or the duration has elapsed, the driver must immediately set the returned
+ * syncFence to error status.
+ *
+ * Any number of calls to the executeFenced, execute* and executeSynchronously*
+ * functions, in any combination, may be made concurrently, even on the same
+ * IPreparedModel object.
+ *
+ * @param request The input and output information on which the prepared
+ * model is to be executed. The outputs in the request must have
+ * fully specified dimensions.
+ * @param waitFor A vector of sync fence file descriptors.
+ * Execution must not start until all sync fences have been signaled.
+ * @param measure Specifies whether or not to measure duration of the execution.
+ * @param deadline The time by which the execution must complete. If the
+ * execution cannot be finished by the deadline, the
+ * execution must be aborted.
+ * @param duration The length of time within which the execution must
+ * complete after all sync fences in waitFor are signaled. If the
+ * execution cannot be finished within the duration, the execution
+ * must be aborted.
+ * @return status Error status of the call, must be:
+ * - NONE if task is successfully launched
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if one of the input arguments is invalid, including
+ * fences in error states.
+ * - MISSED_DEADLINE_* if the deadline for executing a model
+ * cannot be met
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the
+ * driver
+ * @return syncFence The sync fence that will be signaled when the task is completed.
+ * The sync fence will be set to error if a critical error,
+ * e.g. hardware failure or kernel panic, occurs when doing execution.
+ * @return callback The IFencedExecutionCallback can be used to query information like duration
+ * and error status when the execution is completed.
+ */
+ executeFenced(Request request, vec<handle> waitFor, MeasureTiming measure,
+ OptionalTimePoint deadline, OptionalTimeoutDuration duration)
+ generates (ErrorStatus status, handle syncFence, IFencedExecutionCallback callback);
};
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index b330b50084..ed577e4d9d 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -1415,6 +1415,7 @@ enum OperationType : int32_t {
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
* * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+ * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
*
* Supported tensor rank: up to 4
*
@@ -1425,6 +1426,8 @@ enum OperationType : int32_t {
* * 2: An {@link OperandType::INT32} scalar, and has to be one of the
* {@link FusedActivationFunc} values. Specifies the activation to
* invoke on the result.
+ * For a {@link OperandType::TENSOR_INT32} tensor,
+ * the {@link FusedActivationFunc} must be "NONE".
*
* Outputs:
* * 0: The product, a tensor of the same {@link OperandType} as input0.
@@ -1905,6 +1908,11 @@ enum OperationType : int32_t {
* dimensions. The output is the result of dividing the first input tensor
* by the second, optionally modified by an activation function.
*
+ * For inputs of {@link OperandType::TENSOR_INT32}, performs
+ * "floor division" ("//" in Python). For example,
+ * 5 // 2 = 2
+ * -5 // 2 = -3
+ *
* Two dimensions are compatible when:
* 1. they are equal, or
* 2. one of them is 1
@@ -1925,6 +1933,7 @@ enum OperationType : int32_t {
* Supported tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
* * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
*
* Supported tensor rank: up to 4
*
@@ -1935,6 +1944,8 @@ enum OperationType : int32_t {
* * 2: An {@link OperandType::INT32} scalar, and has to be one of the
* {@link FusedActivationFunc} values. Specifies the activation to
* invoke on the result.
+ * For a {@link OperandType::TENSOR_INT32} tensor,
+ * the {@link FusedActivationFunc} must be "NONE".
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
@@ -2186,6 +2197,7 @@ enum OperationType : int32_t {
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
* * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+ * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
*
* Supported tensor rank: up to 4
*
@@ -2196,6 +2208,8 @@ enum OperationType : int32_t {
* * 2: An {@link OperandType::INT32} scalar, and has to be one of the
* {@link FusedActivationFunc} values. Specifies the activation to
* invoke on the result.
+ * For a {@link OperandType::TENSOR_INT32} tensor,
+ * the {@link FusedActivationFunc} must be "NONE".
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
@@ -2242,6 +2256,7 @@ enum OperationType : int32_t {
* Supported tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
*
* Supported tensor rank: from 1.
*
@@ -4972,6 +4987,106 @@ enum OperationType : int32_t {
WHILE = 97,
/**
+ * Computes exponential linear activation on the input tensor element-wise.
+ *
+ * The output is calculated using the following formula:
+ *
+ * ELU(x) = max(0, x) + min(0, alpha * (exp(x) - 1))
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT16}
+ * * {@link OperandType::TENSOR_FLOAT32}
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input. May be zero-sized.
+ * * 1: A scalar, specifying the alpha parameter.
+ * For input tensor of {@link OperandType::TENSOR_FLOAT16},
+ * the alpha value must be of {@link OperandType::FLOAT16}.
+ * For input tensor of {@link OperandType::TENSOR_FLOAT32},
+ * the alpha value must be of {@link OperandType::FLOAT32}.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape and type as input0.
+ */
+ ELU = 98,
+
+ /**
+ * Computes hard-swish activation on the input tensor element-wise.
+ *
+ * Hard swish activation is introduced in
+ * https://arxiv.org/pdf/1905.02244.pdf
+ *
+ * The output is calculated using the following formula:
+ *
+ * h-swish(x) = x * max(0, min(6, (x + 3))) / 6
+
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT16}
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input. May be zero-sized.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape and type as input0.
+ * Scale and zero point of this tensor may be different from the input
+ * tensor's parameters.
+ */
+ HARD_SWISH = 99,
+
+ /**
+ * Creates a tensor filled with a scalar value.
+ *
+ * Supported output tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT16}
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_INT32}
+ *
+ * Inputs:
+ * * 0: A 1-D tensor, specifying the desired output tensor shape.
+ * * 1: A scalar, specifying the value to fill the output tensors with.
+ * For output tensor of {@link OperandType::TENSOR_FLOAT16},
+ * the scalar must be of {@link OperandType::FLOAT16}.
+ * For output tensor of {@link OperandType::TENSOR_FLOAT32},
+ * the scalar must be of {@link OperandType::FLOAT32}.
+ * For output tensor of {@link OperandType::TENSOR_INT32},
+ * the scalar must be of {@link OperandType::INT32}.
+ *
+ * Outputs:
+ * * 0: The output tensor.
+ */
+ FILL = 100,
+
+ /**
+ * Returns the rank of a tensor.
+ *
+ * The rank of a tensor is the number of dimensions in it. Also known as
+ * "order", "degree", "ndims".
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT16}
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_INT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT16_SYMM}
+ * * {@link OperandType::TENSOR_BOOL8}
+ * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+ * * {@link OperandType::TENSOR_QUANT16_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_SYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+ *
+ * Inputs:
+ * * 0: The input tensor.
+ *
+ * Outputs:
+ * * 0: A scalar of {@link OperandType::INT32}, specifying the rank
+ * of the input tensor.
+ */
+ RANK = 101,
+
+ /**
* DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
* OEM operation and data types.
*
@@ -4993,7 +5108,7 @@ enum OperationType : int32_t {
enum OperationTypeRange : uint32_t {
BASE_MIN = 0,
FUNDAMENTAL_MIN = 0,
- FUNDAMENTAL_MAX = 97,
+ FUNDAMENTAL_MAX = 101,
OEM_MIN = 10000,
OEM_MAX = 10000,
BASE_MAX = 0xFFFF,
@@ -5462,6 +5577,19 @@ safe_union OptionalTimePoint {
};
/**
+ * Optional timeout duration measured in nanoseconds.
+ */
+safe_union OptionalTimeoutDuration {
+ /** No time point provided. */
+ Monostate none;
+
+ /**
+ * Timeout duration measured in nanoseconds.
+ */
+ uint64_t nanoseconds;
+};
+
+/**
* Return status of a function.
*/
enum ErrorStatus : @1.0::ErrorStatus {
diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t
index a973923d8d..d4351ec8d7 100644
--- a/neuralnetworks/1.3/types.t
+++ b/neuralnetworks/1.3/types.t
@@ -553,6 +553,19 @@ safe_union OptionalTimePoint {
};
/**
+ * Optional timeout duration measured in nanoseconds.
+ */
+safe_union OptionalTimeoutDuration {
+ /** No time point provided. */
+ Monostate none;
+
+ /**
+ * Timeout duration measured in nanoseconds.
+ */
+ uint64_t nanoseconds;
+};
+
+/**
* Return status of a function.
*/
enum ErrorStatus : @1.0::ErrorStatus {
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index ce2d3a917a..8e7e9b9d62 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -65,6 +65,7 @@ cc_test {
"libhidlmemory",
"libneuralnetworks_generated_test_harness",
"libneuralnetworks_utils",
+ "libsync",
],
whole_static_libs: [
"neuralnetworks_generated_V1_0_example",
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index a2c0c4efa0..8ea0b7eb47 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -29,11 +29,13 @@
#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
#include <android/hardware/neuralnetworks/1.2/types.h>
#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
#include <android/hardware/neuralnetworks/1.3/types.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
+#include <android/sync.h>
#include <gtest/gtest.h>
#include <hidlmemory/mapping.h>
@@ -70,7 +72,7 @@ using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_
namespace {
-enum class Executor { ASYNC, SYNC, BURST };
+enum class Executor { ASYNC, SYNC, BURST, FENCED };
enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
@@ -78,6 +80,13 @@ enum class MemoryType { SHARED, DEVICE };
enum class IOType { INPUT, OUTPUT };
+static void waitForSyncFence(int syncFd) {
+ constexpr int kInfiniteTimeout = -1;
+ ASSERT_GT(syncFd, 0);
+ int r = sync_wait(syncFd, kInfiniteTimeout);
+ ASSERT_GE(r, 0);
+}
+
struct TestConfig {
Executor executor;
MeasureTiming measureTiming;
@@ -562,9 +571,44 @@ void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>&
break;
}
+ case Executor::FENCED: {
+ SCOPED_TRACE("fenced");
+ ErrorStatus result;
+ hidl_handle syncFenceHandle;
+ sp<IFencedExecutionCallback> fencedCallback;
+ Return<void> ret = preparedModel->executeFenced(
+ request, {}, testConfig.measureTiming, {}, {},
+ [&result, &syncFenceHandle, &fencedCallback](
+ ErrorStatus error, const hidl_handle& handle,
+ const sp<IFencedExecutionCallback>& callback) {
+ result = error;
+ syncFenceHandle = handle;
+ fencedCallback = callback;
+ });
+ ASSERT_TRUE(ret.isOk());
+ if (result != ErrorStatus::NONE) {
+ ASSERT_EQ(syncFenceHandle.getNativeHandle(), nullptr);
+ ASSERT_EQ(fencedCallback, nullptr);
+ executionStatus = ErrorStatus::GENERAL_FAILURE;
+ } else if (syncFenceHandle.getNativeHandle()) {
+ waitForSyncFence(syncFenceHandle.getNativeHandle()->data[0]);
+ }
+ if (result == ErrorStatus::NONE) {
+ ASSERT_NE(fencedCallback, nullptr);
+ Return<void> ret = fencedCallback->getExecutionInfo(
+ [&executionStatus, &timing](ErrorStatus error, Timing t, Timing) {
+ executionStatus = error;
+ timing = t;
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ break;
+ }
}
- if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
+ // The driver is allowed to reject executeFenced, and if they do, we should skip.
+ if ((testConfig.outputType != OutputType::FULLY_SPECIFIED ||
+ testConfig.executor == Executor::FENCED) &&
executionStatus == ErrorStatus::GENERAL_FAILURE) {
if (skipped != nullptr) {
*skipped = true;
@@ -648,6 +692,11 @@ void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>&
executorList = {Executor::ASYNC, Executor::SYNC};
memoryType = MemoryType::DEVICE;
} break;
+ case TestKind::FENCED_COMPUTE: {
+ outputTypesList = {OutputType::FULLY_SPECIFIED};
+ measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+ executorList = {Executor::FENCED};
+ } break;
case TestKind::QUANTIZATION_COUPLING: {
LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel";
return;
@@ -671,7 +720,8 @@ void EvaluatePreparedCoupledModels(const sp<IDevice>& device,
const TestModel& coupledModel) {
const std::vector<OutputType> outputTypesList = {OutputType::FULLY_SPECIFIED};
const std::vector<MeasureTiming> measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
- const std::vector<Executor> executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+ const std::vector<Executor> executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST,
+ Executor::FENCED};
for (const OutputType outputType : outputTypesList) {
for (const MeasureTiming measureTiming : measureTimingList) {
@@ -708,7 +758,8 @@ void Execute(const sp<IDevice>& device, const TestModel& testModel, TestKind tes
switch (testKind) {
case TestKind::GENERAL:
case TestKind::DYNAMIC_SHAPE:
- case TestKind::MEMORY_DOMAIN: {
+ case TestKind::MEMORY_DOMAIN:
+ case TestKind::FENCED_COMPUTE: {
createPreparedModel(device, model, &preparedModel);
if (preparedModel == nullptr) return;
EvaluatePreparedModel(device, preparedModel, testModel, testKind);
@@ -771,6 +822,9 @@ class DynamicOutputShapeTest : public GeneratedTest {};
// Tag for the memory domain tests
class MemoryDomainTest : public GeneratedTest {};
+// Tag for the fenced compute tests
+class FencedComputeTest : public GeneratedTest {};
+
// Tag for the dynamic output shape tests
class QuantizationCouplingTest : public GeneratedTest {};
@@ -786,6 +840,10 @@ TEST_P(MemoryDomainTest, Test) {
Execute(kDevice, kTestModel, /*testKind=*/TestKind::MEMORY_DOMAIN);
}
+TEST_P(FencedComputeTest, Test) {
+ Execute(kDevice, kTestModel, /*testKind=*/TestKind::FENCED_COMPUTE);
+}
+
TEST_P(QuantizationCouplingTest, Test) {
Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING);
}
@@ -793,12 +851,16 @@ TEST_P(QuantizationCouplingTest, Test) {
INSTANTIATE_GENERATED_TEST(GeneratedTest,
[](const TestModel& testModel) { return !testModel.expectFailure; });
-INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest,
- [](const TestModel& testModel) { return !testModel.expectFailure; });
+INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) {
+ return !testModel.expectFailure && !testModel.hasScalarOutputs();
+});
INSTANTIATE_GENERATED_TEST(MemoryDomainTest,
[](const TestModel& testModel) { return !testModel.expectFailure; });
+INSTANTIATE_GENERATED_TEST(FencedComputeTest,
+ [](const TestModel& testModel) { return !testModel.expectFailure; });
+
INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) {
return testModel.hasQuant8CoupledOperands() && testModel.operations.size() == 1;
});
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
index fe695b471d..e597fac7cf 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
@@ -65,6 +65,8 @@ enum class TestKind {
DYNAMIC_SHAPE,
// Same as GENERAL but use device memories for inputs and outputs
MEMORY_DOMAIN,
+ // Same as GENERAL but use executeFenced for exeuction
+ FENCED_COMPUTE,
// Tests if quantized model with TENSOR_QUANT8_ASYMM produces the same result
// (OK/SKIPPED/FAILED) as the model with all such tensors converted to
// TENSOR_QUANT8_ASYMM_SIGNED.
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index a21142880e..1245432307 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -337,6 +337,7 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con
// - TRANSPOSE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
// - AXIS_ALIGNED_BBOX_TRANSFORM bounding boxes (arg 1) can be of
// TENSOR_QUANT8_ASYMM or TENSOR_QUANT8_ASYMM_SIGNED.
+ // - RANK's input can have any TENSOR_* type.
switch (operation.type) {
case OperationType::LSH_PROJECTION: {
if (operand == operation.inputs[1]) {
@@ -399,6 +400,20 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con
return true;
}
} break;
+ case OperationType::RANK: {
+ if (operand == operation.inputs[0] &&
+ (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32 ||
+ type == OperandType::TENSOR_INT32 ||
+ type == OperandType::TENSOR_QUANT8_ASYMM ||
+ type == OperandType::TENSOR_QUANT16_SYMM ||
+ type == OperandType::TENSOR_BOOL8 ||
+ type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL ||
+ type == OperandType::TENSOR_QUANT16_ASYMM ||
+ type == OperandType::TENSOR_QUANT8_SYMM ||
+ type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED)) {
+ return true;
+ }
+ } break;
default:
break;
}
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index be4112ac2d..2fd9b647f1 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -16,7 +16,9 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
+#include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
#include <chrono>
+
#include "1.0/Utils.h"
#include "1.3/Callbacks.h"
#include "ExecutionBurstController.h"
@@ -136,6 +138,22 @@ static void validate(const sp<IPreparedModel>& preparedModel, const std::string&
burst->freeMemory(keys.front());
}
}
+
+ // dispatch
+ {
+ SCOPED_TRACE(message + " [executeFenced]");
+ Return<void> ret = preparedModel->executeFenced(
+ request, {}, MeasureTiming::NO, {}, {},
+ [](ErrorStatus error, const hidl_handle& handle,
+ const sp<IFencedExecutionCallback>& callback) {
+ if (error != ErrorStatus::DEVICE_UNAVAILABLE) {
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+ }
+ ASSERT_EQ(handle.getNativeHandle(), nullptr);
+ ASSERT_EQ(callback, nullptr);
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
}
///////////////////////// REMOVE INPUT ////////////////////////////////////
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
index 93c8f13c17..896ace65b9 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
@@ -133,6 +133,23 @@ void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Reque
// Forward declaration from ValidateBurst.cpp
void validateBurst(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
+// Validate sync_fence handles for dispatch with valid input
+void validateExecuteFenced(const sp<IPreparedModel>& preparedModel, const Request& request) {
+ SCOPED_TRACE("Expecting request to fail [executeFenced]");
+ Return<void> ret_null = preparedModel->executeFenced(
+ request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, {}, {},
+ [](ErrorStatus error, const hidl_handle& handle,
+ const sp<IFencedExecutionCallback>& callback) {
+ // TODO: fix this once sample driver impl is merged.
+ if (error != ErrorStatus::DEVICE_UNAVAILABLE) {
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+ }
+ ASSERT_EQ(handle.getNativeHandle(), nullptr);
+ ASSERT_EQ(callback, nullptr);
+ });
+ ASSERT_TRUE(ret_null.isOk());
+}
+
void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request,
std::pair<bool, bool> supportsDeadlines) {
const auto [prepareModelDeadlineSupported, executionDeadlineSupported] = supportsDeadlines;
@@ -144,6 +161,7 @@ void validateEverything(const sp<IDevice>& device, const Model& model, const Req
if (preparedModel == nullptr) return;
validateRequest(preparedModel, request, executionDeadlineSupported);
+ validateExecuteFenced(preparedModel, request);
// TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2.
ASSERT_TRUE(nn::compliantWithV1_0(request));
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_api.cpp b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
index 75abbbf107..02dcbab20d 100644
--- a/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
@@ -24,6 +24,9 @@ TEST_P(RadioHidlTest_v1_1, setSimCardPower_1_1) {
/* Record the sim card state for the testing environment */
CardState cardStateForTest = cardStatus.cardState;
+#if 0
+ /* This test has to be removed for Japan Model.
+ * After "setSimCardPower power down", Japan model can not "setSimCardPower power up" */
/* Test setSimCardPower power down */
serial = GetRandomSerialNumber();
radio_v1_1->setSimCardPower_1_1(serial, CardPowerState::POWER_DOWN);
@@ -46,6 +49,7 @@ TEST_P(RadioHidlTest_v1_1, setSimCardPower_1_1) {
}
EXPECT_EQ(CardState::ABSENT, cardStatus.cardState);
}
+#endif
/* Test setSimCardPower power up */
serial = GetRandomSerialNumber();
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
index ee4438d08d..2ec92e54d1 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -16,15 +16,15 @@
package android.hardware.radio@1.5;
+import @1.0::CdmaSmsMessage;
import @1.2::DataRequestReason;
import @1.4::IRadio;
-import @1.4::DataProfileInfo;
import @1.5::AccessNetwork;
-import @1.5::BarringInfo;
import @1.5::DataProfileInfo;
import @1.5::IndicationFilter;
import @1.5::LinkAddress;
import @1.5::NetworkScanRequest;
+import @1.5::PersoSubstate;
import @1.5::RadioAccessNetworks;
import @1.5::RadioAccessSpecifier;
import @1.5::SignalThresholdInfo;
@@ -116,13 +116,13 @@ interface IRadio extends @1.4::IRadio {
vec<RadioAccessSpecifier> specifiers);
/**
- * Starts a network scan
+ * Starts a network scan.
*
* @param serial Serial number of request.
* @param request Defines the radio networks/bands/channels which need to be scanned.
*
- * Same API as @1.4::IRadio.startNetworkScan_1_4, except using
- * 1.5 version of NetworkScanRequest
+ * Same API as @1.4::IRadio.startNetworkScan_1_4, except using the
+ * 1.5 NetworkScanRequest as the input param.
*/
oneway startNetworkScan_1_5(int32_t serial, NetworkScanRequest request);
@@ -164,14 +164,14 @@ interface IRadio extends @1.4::IRadio {
* Response function is IRadioResponse.setupDataCallResponse_1_5()
*
* Note this API is the same as the 1.4 version except using the
- * 1.5 AccessNetwork, DataProfileInto, and link addresses as the input param.
+ * 1.5 AccessNetwork, DataProfileInto, and LinkAddress as the input param.
*/
oneway setupDataCall_1_5(int32_t serial, AccessNetwork accessNetwork,
DataProfileInfo dataProfileInfo, bool roamingAllowed,
DataRequestReason reason, vec<LinkAddress> addresses, vec<string> dnses);
/**
- * Set an apn to initial attach network
+ * Set an APN to initial attach network.
*
* @param serial Serial number of request.
* @param dataProfileInfo data profile containing APN settings
@@ -187,7 +187,7 @@ interface IRadio extends @1.4::IRadio {
* Send data profiles of the current carrier to the modem.
*
* @param serial Serial number of request.
- * @param profiles Array of DataProfile to set.
+ * @param profiles Array of DataProfileInfo to set.
*
* Response callback is IRadioResponse.setDataProfileResponse_1_5()
*
@@ -228,7 +228,7 @@ interface IRadio extends @1.4::IRadio {
*
* Prevents the reporting of specified unsolicited indications from the radio. This is used
* for power saving in instances when those indications are not needed. If unset, defaults to
- * @1.2::IndicationFilter:ALL.
+ * @1.5::IndicationFilter:ALL.
*
* @param serial Serial number of request.
* @param indicationFilter 32-bit bitmap of IndicationFilter. Bits set to 1 indicate the
@@ -248,7 +248,7 @@ interface IRadio extends @1.4::IRadio {
oneway getBarringInfo(int32_t serial);
/**
- * Request current voice registration state
+ * Request current voice registration state.
*
* @param serial Serial number of request.
*
@@ -257,7 +257,7 @@ interface IRadio extends @1.4::IRadio {
oneway getVoiceRegistrationState_1_5(int32_t serial);
/**
- * Request current data registration state
+ * Request current data registration state.
*
* @param serial Serial number of request.
*
@@ -282,4 +282,26 @@ interface IRadio extends @1.4::IRadio {
*/
oneway setNetworkSelectionModeManual_1_5(int32_t serial, string operatorNumeric,
RadioAccessNetworks ran);
+
+ /**
+ * Send an SMS message. Identical to sendCdmaSms,
+ * except that more messages are expected to be sent soon.
+ *
+ * @param serial Serial number of request.
+ * @param sms Cdma Sms to be sent described by CdmaSmsMessage in types.hal
+ *
+ * Response callback is IRadioResponse.sendCdmaSMSExpectMoreResponse()
+ */
+ oneway sendCdmaSmsExpectMore(int32_t serial, CdmaSmsMessage sms);
+
+ /**
+ * Requests that deactivates one category of the device personalization.
+ *
+ * @param serial Serial number of request.
+ * @param persoType SIM personalization type.
+ * @param controlKey depersonalization code corresponding to persoType
+ *
+ * Response function is IRadioResponse.supplySimDepersonalizationResponse()
+ */
+ oneway supplySimDepersonalization(int32_t serial, PersoSubstate persoType, string controlKey);
};
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index e66e00b1ea..aa8b526ffa 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -17,11 +17,13 @@
package android.hardware.radio@1.5;
import @1.0::RadioResponseInfo;
+import @1.0::SendSmsResult;
import @1.4::IRadioResponse;
import @1.5::BarringInfo;
import @1.5::CellInfo;
-import @1.5::SetupDataCallResult;
+import @1.5::PersoSubstate;
import @1.5::RegStateResult;
+import @1.5::SetupDataCallResult;
/**
* Interface declaring response functions to solicited radio requests.
@@ -213,7 +215,6 @@ interface IRadioResponse extends @1.4::IRadioResponse {
*/
oneway getCellInfoListResponse_1_5(RadioResponseInfo info, vec<CellInfo> cellInfo);
-
/**
* @param info Response info struct containing response type, serial no. and error
*
@@ -236,4 +237,57 @@ interface IRadioResponse extends @1.4::IRadioResponse {
* no retries needed, such as illegal SIM or ME.
*/
oneway setNetworkSelectionModeManualResponse_1_5(RadioResponseInfo info);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param sms Response to sms sent as defined by SendSmsResult in types.hal
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:SMS_SEND_FAIL_RETRY
+ * RadioError:NETWORK_REJECT
+ * RadioError:INVALID_STATE
+ * RadioError:INVALID_ARGUMENTS
+ * RadioError:NO_MEMORY
+ * RadioError:REQUEST_RATE_LIMITED
+ * RadioError:INVALID_SMS_FORMAT
+ * RadioError:SYSTEM_ERR
+ * RadioError:FDN_CHECK_FAILURE
+ * RadioError:ENCODING_ERR
+ * RadioError:INVALID_SMSC_ADDRESS
+ * RadioError:MODEM_ERR
+ * RadioError:NETWORK_ERR
+ * RadioError:INTERNAL_ERR
+ * RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:INVALID_MODEM_STATE
+ * RadioError:NETWORK_NOT_READY
+ * RadioError:OPERATION_NOT_ALLOWED
+ * RadioError:NO_RESOURCES
+ * RadioError:CANCELLED
+ * RadioError:SIM_ABSENT
+ */
+ oneway sendCdmaSmsExpectMoreResponse(RadioResponseInfo info, SendSmsResult sms);
+
+ /**
+ * @param info Response info struct contatining response type, serial no. and error
+ * @param persoType SIM Personalisation type
+ * @param remainingRetries postiive values indicates number of retries remaining,
+ * must be equal to -1 if number of retries is infinite.
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:PASSWORD_INCORRECT (code is invalid)
+ * RadioError:NO_MEMORY
+ * RadioError:INVALID_SIM_STATE
+ * RadioError:INTERNAL_ERR
+ * RadioError:SYSTEM_ERR
+ * RadioError:MODEM_ERR
+ * RadioError:INVALID_ARGUMENTS
+ * RadioError:NO_RESOURCES
+ * RadioError:REQUEST_NOT_SUPPORTED
+ */
+ oneway supplySimDepersonalizationResponse(RadioResponseInfo info,
+ PersoSubstate persoType, int32_t remainingRetries);
};
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index 5482acaf27..a0868337dd 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -19,18 +19,15 @@ package android.hardware.radio@1.5;
import @1.0::ApnAuthType;
import @1.0::DataProfileId;
import @1.0::DataProfileInfoType;
-import @1.0::CdmaSignalStrength;
-import @1.0::EvdoSignalStrength;
import @1.0::GsmSignalStrength;
import @1.0::LteSignalStrength;
-import @1.0::RadioAccessFamily;
+import @1.0::PersoSubstate;
import @1.0::RadioError;
import @1.0::RegState;
import @1.0::TimeStampType;
import @1.1::EutranBands;
import @1.1::GeranBands;
import @1.1::RadioAccessNetworks;
-import @1.1::RadioAccessSpecifier;
import @1.1::ScanStatus;
import @1.1::ScanType;
import @1.1::UtranBands;
@@ -42,7 +39,6 @@ import @1.2::CellIdentityTdscdma;
import @1.2::CellIdentityLte;
import @1.2::CellInfoCdma;
import @1.2::IndicationFilter;
-import @1.2::NetworkScanRequest;
import @1.2::TdscdmaSignalStrength;
import @1.2::WcdmaSignalStrength;
import @1.4::AccessNetwork;
@@ -50,11 +46,11 @@ import @1.4::ApnTypes;
import @1.4::CellIdentityNr;
import @1.4::DataCallFailCause;
import @1.4::DataConnActiveStatus;
-import @1.4::DataProfileInfo;
import @1.4::LteVopsInfo;
import @1.4::NrIndicators;
import @1.4::NrSignalStrength;
import @1.4::PdpProtocolType;
+import @1.4::RadioAccessFamily;
import @1.4::RadioTechnology;
import android.hidl.safe_union@1.0::Monostate;
@@ -130,7 +126,7 @@ struct SignalThresholdInfo {
/** Signal Measurement Type */
SignalMeasurementType signalMeasurement;
- /** A hysteresis time in milliseconds to prevent flapping. A value of 0 disables hysteresis */
+ /** A hysteresis time in milliseconds to prevent flapping. A value of 0 disables hysteresis. */
int32_t hysteresisMs;
/**
@@ -174,7 +170,7 @@ enum RadioAccessNetworks : @1.1::RadioAccessNetworks {
};
/**
- * Overwritten from @1.1::RadioAccessSpecifier to add NGRAN and NgranBands
+ * Overwritten from @1.1::RadioAccessSpecifier to add NGRAN and NgranBands.
*/
struct RadioAccessSpecifier {
/**
@@ -263,8 +259,7 @@ enum UtranBands : @1.1::UtranBands {
};
/**
- * Overwritten from @1.2::NetworkScanRequest to update
- * RadioAccessSpecifier to 1.5 version
+ * Overwritten from @1.2::NetworkScanRequest to update RadioAccessSpecifier to 1.5 version.
*/
struct NetworkScanRequest {
ScanType type;
@@ -327,11 +322,10 @@ enum ApnTypes : @1.4::ApnTypes {
};
/**
- * Extended from @1.4::DataProfileInfo to update ApnTypes to 1.5 version and replace mtu with
+ * Overwritten from @1.4::DataProfileInfo to update ApnTypes to 1.5 version and replace mtu with
* mtuV4 and mtuV6. In the future, this must be extended instead of overwritten.
*/
struct DataProfileInfo {
-
/** ID of the data profile. */
DataProfileId profileId;
@@ -427,21 +421,25 @@ struct LinkAddress {
bitfield<AddressProperty> properties;
/**
- * The UTC time that this link address will be deprecated. 0 indicates this information is not
- * available.
+ * The time, as reported by SystemClock.elapsedRealtime(), when this link address will be or
+ * was deprecated. -1 indicates this information is not available. At the time existing
+ * connections can still use this address until it expires, but new connections should use the
+ * new address. LONG_MAX(0x7FFFFFFFFFFFFFFF) indicates this link address will never be
+ * deprecated.
*/
- uint64_t deprecatedTime;
+ uint64_t deprecationTime;
/**
- * The UTC time that this link address will expire and no longer valid. 0 indicates this
- * information is not available.
+ * The time, as reported by SystemClock.elapsedRealtime(), when this link address will expire
+ * and be removed from the interface. -1 indicates this information is not available.
+ * LONG_MAX(0x7FFFFFFFFFFFFFFF) indicates this link address will never expire.
*/
- uint64_t expiredTime;
+ uint64_t expirationTime;
};
/**
- * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5
- * version. In 1.5 the type of addresses changes to vector of LinkAddress, and mtu is replaced by
+ * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5 version.
+ * In 1.5 the type of addresses changes to vector of LinkAddress, and mtu is replaced by
* mtuV4 and mtuV6.
*/
struct SetupDataCallResult {
@@ -600,6 +598,9 @@ struct CellIdentityLte {
/** Information about any closed subscriber group ID for this cell */
OptionalCsgInfo optionalCsgInfo;
+
+ /** Bands used by the cell. */
+ vec<EutranBands> bands;
};
/**
@@ -615,8 +616,8 @@ struct CellIdentityNr {
/** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */
vec<string> additionalPlmns;
- /** Band used by the cell */
- NgranBands band;
+ /** Bands used by the cell. */
+ vec<NgranBands> bands;
};
struct CellInfoGsm {
@@ -679,7 +680,7 @@ struct CellInfo {
} ratSpecificInfo;
};
-/** A union representing the CellIdentity of a single cell */
+/** A union representing the CellIdentity of a single cell. */
safe_union CellIdentity {
Monostate noinit;
@@ -700,7 +701,7 @@ safe_union CellIdentity {
* -NGRAN - 3gpp 38.331 Sec 6.3.2 UAC-BarringInfo and 22.261 Sec 6.22.2.[2-3]
*/
enum BarringServiceType : int32_t {
- /** Applicabe to UTRAN */
+ /** Applicable to UTRAN */
/** Barring for all CS services, including registration */
CS_SERVICE,
/** Barring for all PS services, including registration */
@@ -955,14 +956,14 @@ struct RegStateResult {
string registeredPlmn;
/**
- * Access-technology-specific registration information, such as for Cdma2000.
+ * Access-technology-specific registration information, such as for CDMA2000.
*/
safe_union AccessTechnologySpecificInfo {
Monostate noinit;
struct Cdma2000RegistrationInfo {
/**
- * concurrent services support indicator. if registered on a CDMA system.
+ * Concurrent services support indicator. if registered on a CDMA system.
* false - Concurrent services not supported,
* true - Concurrent services supported
*/
@@ -991,10 +992,10 @@ struct RegStateResult {
struct EutranRegistrationInfo {
/**
* Network capabilities for voice over PS services. This info is valid only on LTE
- * network and must be present when device is camped on LTE. vopsInfo must be empty when
+ * network and must be present when device is camped on LTE. VopsInfo must be empty when
* device is camped only on 2G/3G.
*/
- LteVopsInfo lteVopsInfo; // LTE network capability
+ LteVopsInfo lteVopsInfo;
/**
* The parameters of NR 5G Non-Standalone. This value is only valid on E-UTRAN,
@@ -1022,3 +1023,22 @@ struct NetworkScanResult {
*/
vec<CellInfo> networkInfos;
};
+
+/**
+ * Additional personalization categories in addition to those specified in 3GPP TS 22.022 and
+ * 3GPP2 C.S0068-0.
+ */
+enum PersoSubstate : @1.0::PersoSubstate {
+ SIM_SPN,
+ SIM_SPN_PUK,
+ /** Equivalent Home PLMN */
+ SIM_SP_EHPLMN,
+ SIM_SP_EHPLMN_PUK,
+ SIM_ICCID,
+ SIM_ICCID_PUK,
+ SIM_IMPI,
+ SIM_IMPI_PUK,
+ /** Network subset service provider */
+ SIM_NS_SP,
+ SIM_NS_SP_PUK,
+};
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index a4095b7a91..621825fa52 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -969,7 +969,10 @@ TEST_F(RadioHidlTest_v1_5, setDataProfile_1_5) {
}
}
-TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancalled) {
+/*
+ * Test IRadio.setRadioPower_1_5() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancelled) {
// Set radio power to off.
serial = GetRandomSerialNumber();
radio_v1_5->setRadioPower_1_5(serial, false, false, false);
@@ -1022,3 +1025,47 @@ TEST_F(RadioHidlTest_v1_5, setNetworkSelectionModeManual_1_5) {
CHECK_GENERAL_ERROR));
}
}
+
+/*
+ * Test IRadio.sendCdmaSmsExpectMore() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_5, sendCdmaSmsExpectMore) {
+ serial = GetRandomSerialNumber();
+
+ // Create a CdmaSmsAddress
+ CdmaSmsAddress cdmaSmsAddress;
+ cdmaSmsAddress.digitMode = CdmaSmsDigitMode::FOUR_BIT;
+ cdmaSmsAddress.numberMode = CdmaSmsNumberMode::NOT_DATA_NETWORK;
+ cdmaSmsAddress.numberType = CdmaSmsNumberType::UNKNOWN;
+ cdmaSmsAddress.numberPlan = CdmaSmsNumberPlan::UNKNOWN;
+ cdmaSmsAddress.digits = (std::vector<uint8_t>){11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
+
+ // Create a CdmaSmsSubAddress
+ CdmaSmsSubaddress cdmaSmsSubaddress;
+ cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddressType::NSAP;
+ cdmaSmsSubaddress.odd = false;
+ cdmaSmsSubaddress.digits = (std::vector<uint8_t>){};
+
+ // Create a CdmaSmsMessage
+ android::hardware::radio::V1_0::CdmaSmsMessage cdmaSmsMessage;
+ cdmaSmsMessage.teleserviceId = 4098;
+ cdmaSmsMessage.isServicePresent = false;
+ cdmaSmsMessage.serviceCategory = 0;
+ cdmaSmsMessage.address = cdmaSmsAddress;
+ cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
+ cdmaSmsMessage.bearerData =
+ (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
+
+ radio_v1_5->sendCdmaSmsExpectMore(serial, cdmaSmsMessage);
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+ if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_5->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
+ CHECK_GENERAL_ERROR));
+ }
+}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index abab452915..ce7b1ab8e7 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -573,6 +573,13 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon
cellInfo);
Return<void> setNetworkSelectionModeManualResponse_1_5(const RadioResponseInfo& info);
+
+ Return<void> sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& info,
+ const SendSmsResult& sms);
+
+ Return<void> supplySimDepersonalizationResponse(
+ const RadioResponseInfo& info,
+ ::android::hardware::radio::V1_5::PersoSubstate persoType, int32_t remainingRetries);
};
/* Callback class for radio indication */
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index d7197d5eb1..26401eb800 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -999,3 +999,15 @@ Return<void> RadioResponse_v1_5::setNetworkSelectionModeManualResponse_1_5(
parent_v1_5.notify(info.serial);
return Void();
}
+
+Return<void> RadioResponse_v1_5::sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& /*info*/,
+ const SendSmsResult& /*sms*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplySimDepersonalizationResponse(
+ const RadioResponseInfo& /*info*/,
+ ::android::hardware::radio::V1_5::PersoSubstate /*persoType*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal
index 3414534138..aef0ff8a21 100644
--- a/radio/config/1.3/types.hal
+++ b/radio/config/1.3/types.hal
@@ -17,10 +17,10 @@
package android.hardware.radio.config@1.3;
import android.hardware.radio@1.1::GeranBands;
-import android.hardware.radio@1.1::UtranBands;
import android.hardware.radio@1.1::EutranBands;
import android.hardware.radio@1.4::RadioAccessFamily;
import android.hardware.radio@1.5::NgranBands;
+import android.hardware.radio@1.5::UtranBands;
/** Type for the SIM slot. */
enum SlotType : int32_t {
@@ -50,17 +50,17 @@ enum ModemFeatures : int32_t {
/** 3GPP capability. */
THREE_GPP_REG = 1 << 1,
/** CDMA 2000 with EHRPD capability. */
- CDMA2000_EHRPD_REG = 1 << 2,
- /** GSM capability. */
- GERAN_REG = 1 << 3,
+ CDMA2000_EHRPD = 1 << 2,
+ /** GSM/EDGE capability. */
+ GERAN = 1 << 3,
/** UMTS capability. */
- UTRAN_REG = 1 << 4,
+ UTRAN = 1 << 4,
/** LTE capability. */
- EUTRAN_REG = 1 << 5,
+ EUTRAN = 1 << 5,
/** 5G capability. */
- NGRAN_REG = 1 << 6,
- /** Dual Connectivity capability. */
- EN_DC_REG = 1 << 7,
+ NGRAN = 1 << 6,
+ /** 5G dual connectivity capability. */
+ EN_DC = 1 << 7,
/** VoLTE capability (IMS registered). */
PS_VOICE_REG = 1 << 8,
/** CS voice call capability. */
@@ -72,7 +72,7 @@ enum ModemFeatures : int32_t {
/** Network scanning capability. */
NETWORK_SCAN = 1 << 12,
/** CDMA capability for SIM associated with modem. */
- CSIM = 1 << 13,
+ CSIM_APP = 1 << 13,
};
struct ConcurrentModemFeatures {
diff --git a/rebootescrow/aidl/default/RebootEscrow.cpp b/rebootescrow/aidl/default/RebootEscrow.cpp
index 94d09010d9..dbc09215b3 100644
--- a/rebootescrow/aidl/default/RebootEscrow.cpp
+++ b/rebootescrow/aidl/default/RebootEscrow.cpp
@@ -29,7 +29,7 @@ namespace rebootescrow {
using ::android::base::unique_fd;
ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector<int8_t>& kek) {
- int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
+ int rawFd = TEMP_FAILURE_RETRY(::open(devicePath_.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
unique_fd fd(rawFd);
if (fd.get() < 0) {
LOG(WARNING) << "Could not open reboot escrow device";
@@ -48,20 +48,19 @@ ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector<int8_t>& kek) {
}
ndk::ScopedAStatus RebootEscrow::retrieveKey(std::vector<int8_t>* _aidl_return) {
- int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
+ int rawFd = TEMP_FAILURE_RETRY(::open(devicePath_.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
unique_fd fd(rawFd);
if (fd.get() < 0) {
LOG(WARNING) << "Could not open reboot escrow device";
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
}
- std::string encodedString;
- if (!::android::base::ReadFdToString(fd, &encodedString)) {
- LOG(WARNING) << "Could not read device to string";
+ std::vector<uint8_t> encodedBytes(hadamard::OUTPUT_SIZE_BYTES);
+ if (!::android::base::ReadFully(fd, &encodedBytes[0], encodedBytes.size())) {
+ LOG(WARNING) << "Could not read device";
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
}
- std::vector<uint8_t> encodedBytes(encodedString.begin(), encodedString.end());
auto keyBytes = hadamard::DecodeKey(encodedBytes);
std::vector<int8_t> signedKeyBytes(keyBytes.begin(), keyBytes.end());
diff --git a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
index 1ed73978d9..00ff16b2ea 100644
--- a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
+++ b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
@@ -23,11 +23,14 @@ namespace android {
namespace hardware {
namespace rebootescrow {
-static const char* REBOOT_ESCROW_DEVICE = "/dev/access-kregistry";
-
class RebootEscrow : public BnRebootEscrow {
+ public:
+ explicit RebootEscrow(const std::string& devicePath) : devicePath_(devicePath) {}
ndk::ScopedAStatus storeKey(const std::vector<int8_t>& kek) override;
ndk::ScopedAStatus retrieveKey(std::vector<int8_t>* _aidl_return) override;
+
+ private:
+ const std::string devicePath_;
};
} // namespace rebootescrow
diff --git a/rebootescrow/aidl/default/rebootescrow-default.rc b/rebootescrow/aidl/default/rebootescrow-default.rc
index e7a9cfcb70..ad90465aa3 100644
--- a/rebootescrow/aidl/default/rebootescrow-default.rc
+++ b/rebootescrow/aidl/default/rebootescrow-default.rc
@@ -3,7 +3,3 @@ service vendor.rebootescrow-default /vendor/bin/hw/android.hardware.rebootescrow
class hal
user system
group system
-
-on boot
- chmod 770 /dev/access-kregistry
- chown system system /dev/access-kregistry
diff --git a/rebootescrow/aidl/default/service.cpp b/rebootescrow/aidl/default/service.cpp
index bd2378e513..8a8086b498 100644
--- a/rebootescrow/aidl/default/service.cpp
+++ b/rebootescrow/aidl/default/service.cpp
@@ -17,15 +17,21 @@
#include "rebootescrow-impl/RebootEscrow.h"
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
using aidl::android::hardware::rebootescrow::RebootEscrow;
+constexpr auto kRebootEscrowDeviceProperty = "ro.rebootescrow.device";
+constexpr auto kRebootEscrowDeviceDefault = "/dev/access-kregistry";
+
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
- auto re = ndk::SharedRefBase::make<RebootEscrow>();
+ auto rebootEscrowDevicePath =
+ android::base::GetProperty(kRebootEscrowDeviceProperty, kRebootEscrowDeviceDefault);
+ auto re = ndk::SharedRefBase::make<RebootEscrow>(rebootEscrowDevicePath);
const std::string instance = std::string() + RebootEscrow::descriptor + "/default";
binder_status_t status = AServiceManager_addService(re->asBinder().get(), instance.c_str());
CHECK(status == STATUS_OK);
diff --git a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
index f69cf877ad..cd8cc3eaa1 100644
--- a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
+++ b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
@@ -26,6 +26,9 @@ using android::sp;
using android::String16;
using android::hardware::rebootescrow::IRebootEscrow;
+#define SKIP_UNSUPPORTED \
+ if (rebootescrow == nullptr) GTEST_SKIP() << "Not supported on this device"
+
/**
* This tests that the key can be written, read, and removed. It does not test
* that the key survives a reboot. That needs a host-based test.
@@ -36,7 +39,6 @@ class RebootEscrowAidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
rebootescrow = android::waitForDeclaredService<IRebootEscrow>(String16(GetParam().c_str()));
- ASSERT_NE(rebootescrow, nullptr);
}
sp<IRebootEscrow> rebootescrow;
@@ -59,6 +61,8 @@ class RebootEscrowAidlTest : public testing::TestWithParam<std::string> {
};
TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_Success) {
+ SKIP_UNSUPPORTED;
+
ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
std::vector<uint8_t> actualKey;
@@ -67,6 +71,8 @@ TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_Success) {
}
TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_SecondRetrieveSucceeds) {
+ SKIP_UNSUPPORTED;
+
ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
std::vector<uint8_t> actualKey;
@@ -78,6 +84,8 @@ TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_SecondRetrieveSucceeds) {
}
TEST_P(RebootEscrowAidlTest, StoreTwiceOverwrites_Success) {
+ SKIP_UNSUPPORTED;
+
ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
ASSERT_TRUE(rebootescrow->storeKey(KEY_2).isOk());
@@ -87,6 +95,8 @@ TEST_P(RebootEscrowAidlTest, StoreTwiceOverwrites_Success) {
}
TEST_P(RebootEscrowAidlTest, StoreEmpty_AfterGetEmptyKey_Success) {
+ SKIP_UNSUPPORTED;
+
rebootescrow->storeKey(KEY_1);
rebootescrow->storeKey(EMPTY_KEY);
diff --git a/secure_element/1.2/Android.bp b/secure_element/1.2/Android.bp
new file mode 100644
index 0000000000..e134771880
--- /dev/null
+++ b/secure_element/1.2/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.secure_element@1.2",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "ISecureElement.hal",
+ ],
+ interfaces: [
+ "android.hardware.secure_element@1.0",
+ "android.hardware.secure_element@1.1",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/secure_element/1.2/ISecureElement.hal b/secure_element/1.2/ISecureElement.hal
new file mode 100644
index 0000000000..16cc5775b5
--- /dev/null
+++ b/secure_element/1.2/ISecureElement.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 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 android.hardware.secure_element@1.2;
+
+import @1.1::ISecureElementHalCallback;
+import @1.1::ISecureElement;
+import @1.0::SecureElementStatus;
+
+interface ISecureElement extends @1.1::ISecureElement {
+ /**
+ * Reset the Secure Element.
+ *
+ * HAL should trigger reset to the secure element. It could hardware power cycle or
+ * a soft reset depends on hardware design.
+ * HAL service must send onStateChange() with connected equal to true
+ * after resetting and all the re-initialization has been successfully completed.
+ *
+ * @return SecureElementStatus::SUCCESS on success and SecureElementStatus::FAILED on error.
+ */
+ reset() generates (SecureElementStatus status);
+};
diff --git a/secure_element/1.2/vts/functional/Android.bp b/secure_element/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000000..a1732108ab
--- /dev/null
+++ b/secure_element/1.2/vts/functional/Android.bp
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 2019 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.
+//
+
+cc_test {
+ name: "VtsHalSecureElementV1_2TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalSecureElementV1_2TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.secure_element@1.0",
+ "android.hardware.secure_element@1.1",
+ "android.hardware.secure_element@1.2",
+ ],
+ test_suites: ["general-tests", "vts-core"],
+}
diff --git a/secure_element/1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp b/secure_element/1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp
new file mode 100644
index 0000000000..98e45021d9
--- /dev/null
+++ b/secure_element/1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 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 <string>
+
+#define LOG_TAG "secure_element_hidl_hal_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/secure_element/1.0/types.h>
+#include <android/hardware/secure_element/1.1/ISecureElementHalCallback.h>
+#include <android/hardware/secure_element/1.2/ISecureElement.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::secure_element::V1_0::SecureElementStatus;
+using ::android::hardware::secure_element::V1_1::ISecureElementHalCallback;
+using ::android::hardware::secure_element::V1_2::ISecureElement;
+
+constexpr char kCallbackNameOnStateChange[] = "onStateChange";
+
+class SecureElementCallbackArgs {
+ public:
+ bool state_;
+ hidl_string reason_;
+};
+
+class SecureElementHalCallback
+ : public ::testing::VtsHalHidlTargetCallbackBase<SecureElementCallbackArgs>,
+ public ISecureElementHalCallback {
+ public:
+ virtual ~SecureElementHalCallback() = default;
+
+ Return<void> onStateChange_1_1(bool state, const hidl_string& reason) override {
+ SecureElementCallbackArgs args;
+ args.state_ = state;
+ args.reason_ = reason;
+ NotifyFromCallback(kCallbackNameOnStateChange, args);
+ return Void();
+ };
+
+ Return<void> onStateChange(__attribute__((unused)) bool state) override { return Void(); }
+};
+
+class SecureElementHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ LOG(INFO) << "get service with name:" << GetParam();
+ se_ = ISecureElement::getService(GetParam());
+ ASSERT_NE(se_, nullptr);
+
+ se_cb_ = new SecureElementHalCallback();
+ ASSERT_NE(se_cb_, nullptr);
+ se_->init_1_1(se_cb_);
+ auto res = se_cb_->WaitForCallback(kCallbackNameOnStateChange);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_TRUE(res.args->state_);
+ EXPECT_NE(res.args->reason_, "");
+ }
+
+ sp<ISecureElement> se_;
+ sp<SecureElementHalCallback> se_cb_;
+};
+
+/*
+ * Reset:
+ * Calls reset()
+ * Checks status
+ * Check onStateChange is received with connected state set to true
+ */
+TEST_P(SecureElementHidlTest, Reset) {
+ EXPECT_EQ(SecureElementStatus::SUCCESS, se_->reset());
+
+ auto res = se_cb_->WaitForCallback(kCallbackNameOnStateChange);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_TRUE(res.args->state_);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, SecureElementHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISecureElement::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
index fd76bda726..7c52661601 100644
--- a/sensors/2.0/multihal/HalProxy.cpp
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -651,12 +651,12 @@ void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelo
if (numWakeupEvents > 0) {
ALOG_ASSERT(wakelock.isLocked(),
"Wakeup events posted while wakelock unlocked for subhal"
- " w/ index %zu.",
+ " w/ index %" PRId32 ".",
mSubHalIndex);
} else {
ALOG_ASSERT(!wakelock.isLocked(),
"No Wakeup events posted but wakelock locked for subhal"
- " w/ index %zu.",
+ " w/ index %" PRId32 ".",
mSubHalIndex);
}
mHalProxy->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock));
diff --git a/soundtrigger/2.3/types.hal b/soundtrigger/2.3/types.hal
index 730f9695af..10fc34e312 100644
--- a/soundtrigger/2.3/types.hal
+++ b/soundtrigger/2.3/types.hal
@@ -66,7 +66,7 @@ struct RecognitionConfig {
* Bit field encoding of the AudioCapabilities
* supported by the firmware.
*/
- uint32_t audioCapabilities;
+ bitfield<AudioCapabilities> audioCapabilities;
};
/**
diff --git a/tv/tuner/1.0/TEST_MAPPING b/tv/tuner/1.0/TEST_MAPPING
new file mode 100644
index 0000000000..1979887eea
--- /dev/null
+++ b/tv/tuner/1.0/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "VtsHalTvTunerV1_0TargetTest"
+ }
+ ]
+} \ No newline at end of file
diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp
index 7d6b990a7b..3637708a6a 100644
--- a/tv/tuner/1.0/vts/functional/Android.bp
+++ b/tv/tuner/1.0/vts/functional/Android.bp
@@ -30,5 +30,10 @@ cc_test {
shared_libs: [
"libbinder",
],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+
+ require_root: true,
}
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 4e7dcc3ae4..820c58c4ce 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -31,8 +31,11 @@
#include <android/hardware/tv/tuner/1.0/types.h>
#include <binder/MemoryDealer.h>
#include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
#include <hidl/Status.h>
#include <hidlmemory/FrameworkUtils.h>
#include <utils/Condition.h>
@@ -633,23 +636,10 @@ void DvrCallback::stopRecordThread() {
android::Mutex::Autolock autoLock(mRecordThreadLock);
}
-// Test environment for Tuner HIDL HAL.
-class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static TunerHidlEnvironment* Instance() {
- static TunerHidlEnvironment* instance = new TunerHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<ITuner>(); }
-};
-
-class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class TunerHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- mService = ::testing::VtsHalHidlTargetTestBase::getService<ITuner>(
- TunerHidlEnvironment::Instance()->getServiceName<ITuner>());
+ mService = ITuner::getService(GetParam());
ASSERT_NE(mService, nullptr);
}
@@ -1242,7 +1232,7 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
/*
* API STATUS TESTS
*/
-TEST_F(TunerHidlTest, CreateFrontend) {
+TEST_P(TunerHidlTest, CreateFrontend) {
Result status;
hidl_vec<FrontendId> feIds;
@@ -1262,7 +1252,7 @@ TEST_F(TunerHidlTest, CreateFrontend) {
}
}
-TEST_F(TunerHidlTest, TuneFrontend) {
+TEST_P(TunerHidlTest, TuneFrontend) {
Result status;
hidl_vec<FrontendId> feIds;
@@ -1282,7 +1272,7 @@ TEST_F(TunerHidlTest, TuneFrontend) {
}
}
-TEST_F(TunerHidlTest, StopTuneFrontend) {
+TEST_P(TunerHidlTest, StopTuneFrontend) {
Result status;
hidl_vec<FrontendId> feIds;
@@ -1302,7 +1292,7 @@ TEST_F(TunerHidlTest, StopTuneFrontend) {
}
}
-TEST_F(TunerHidlTest, CloseFrontend) {
+TEST_P(TunerHidlTest, CloseFrontend) {
Result status;
hidl_vec<FrontendId> feIds;
@@ -1322,7 +1312,7 @@ TEST_F(TunerHidlTest, CloseFrontend) {
}
}
-TEST_F(TunerHidlTest, CreateDemuxWithFrontend) {
+TEST_P(TunerHidlTest, CreateDemuxWithFrontend) {
Result status;
hidl_vec<FrontendId> feIds;
@@ -1349,22 +1339,22 @@ TEST_F(TunerHidlTest, CreateDemuxWithFrontend) {
}
}
-TEST_F(TunerHidlTest, CreateDemux) {
+TEST_P(TunerHidlTest, CreateDemux) {
description("Create Demux");
ASSERT_TRUE(createDemux());
}
-TEST_F(TunerHidlTest, CloseDemux) {
+TEST_P(TunerHidlTest, CloseDemux) {
description("Close Demux");
ASSERT_TRUE(closeDemux());
}
-TEST_F(TunerHidlTest, CreateDescrambler) {
+TEST_P(TunerHidlTest, CreateDescrambler) {
description("Create Descrambler");
ASSERT_TRUE(createDescrambler());
}
-TEST_F(TunerHidlTest, CloseDescrambler) {
+TEST_P(TunerHidlTest, CloseDescrambler) {
description("Close Descrambler");
ASSERT_TRUE(closeDescrambler());
}
@@ -1374,7 +1364,7 @@ TEST_F(TunerHidlTest, CloseDescrambler) {
*
* TODO: re-enable the tests after finalizing the testing stream.
*/
-/*TEST_F(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) {
+/*TEST_P(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) {
description("Feed ts data from playback and configure pes filter to get output");
// todo modulize the filter conf parser
@@ -1417,7 +1407,7 @@ TEST_F(TunerHidlTest, CloseDescrambler) {
ASSERT_TRUE(playbackDataFlowTest(filterConf, playbackConf, goldenOutputFiles));
}
-TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) {
+TEST_P(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) {
description("Feed ts data from frontend and test with PES filter");
// todo modulize the filter conf parser
@@ -1447,7 +1437,7 @@ TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) {
ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles));
}
-TEST_F(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) {
+TEST_P(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) {
description("Feed ts data from frontend to recording and test with ts record filter");
// todo modulize the filter conf parser
@@ -1487,11 +1477,7 @@ TEST_F(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) {
} // namespace
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(TunerHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- TunerHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, TunerHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
index b9a80ec116..0fdfa5d5c2 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
@@ -49,4 +49,9 @@ enum CompositePrimitive {
* A haptic effect that simulates quick downwards movement with gravity.
*/
QUICK_FALL,
+ /**
+ * This very short effect should produce a light crisp sensation intended
+ * to be used repetitively for dynamic feedback.
+ */
+ LIGHT_TICK,
}
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index f553664eeb..06a8bf5c17 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -158,12 +158,31 @@ interface IVibrator {
int getCompositionSizeMax();
/**
+ * List of supported effect primitive.
+ *
+ * Return the effect primitives which are supported by the compose API.
+ * Implementations are expected to support all primitives of the interface
+ * version that they implement.
+ */
+ CompositePrimitive[] getSupportedPrimitives();
+
+ /**
+ * Retrieve effect primitive's duration in milliseconds.
+ *
+ * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS).
+ *
+ * @return Best effort estimation of effect primitive's duration.
+ * @param primitive Effect primitive being queried.
+ */
+ int getPrimitiveDuration(CompositePrimitive primitive);
+
+ /**
* Fire off a string of effect primitives, combined to perform richer effects.
*
* Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS).
*
* Doing this operation while the vibrator is already on is undefined behavior. Clients should
- * explicitly call off.
+ * explicitly call off. IVibratorCallback.onComplete() support is required for this API.
*
* @param composite Array of composition parameters.
*/
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index cedd9cb89c..9236b95ddc 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -113,12 +113,35 @@ ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize) {
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* supported) {
+ *supported = {
+ CompositePrimitive::NOOP, CompositePrimitive::CLICK,
+ CompositePrimitive::THUD, CompositePrimitive::SPIN,
+ CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
+ CompositePrimitive::QUICK_FALL, CompositePrimitive::LIGHT_TICK,
+ };
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
+ int32_t* durationMs) {
+ if (primitive != CompositePrimitive::NOOP) {
+ *durationMs = 100;
+ } else {
+ *durationMs = 0;
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite,
const std::shared_ptr<IVibratorCallback>& callback) {
if (composite.size() > kComposeSizeMax) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
+ std::vector<CompositePrimitive> supported;
+ getSupportedPrimitives(&supported);
+
for (auto& e : composite) {
if (e.delayMs > kComposeDelayMaxMs) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
@@ -126,8 +149,7 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composi
if (e.scale <= 0.0f || e.scale > 1.0f) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- if (e.primitive < CompositePrimitive::NOOP ||
- e.primitive > CompositePrimitive::QUICK_FALL) {
+ if (std::find(supported.begin(), supported.end(), e.primitive) == supported.end()) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
}
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index 0eb957d9fa..c3f3616876 100644
--- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
+++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
@@ -36,6 +36,9 @@ class Vibrator : public BnVibrator {
ndk::ScopedAStatus setExternalControl(bool enabled) override;
ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs);
ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize);
+ ndk::ScopedAStatus getSupportedPrimitives(std::vector<CompositePrimitive>* supported) override;
+ ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive,
+ int32_t* durationMs) override;
ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite,
const std::shared_ptr<IVibratorCallback>& callback) override;
ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) override;
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index f197763be3..411fe7a2fe 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -261,6 +261,29 @@ TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) {
}
}
+TEST_P(VibratorAidl, GetSupportedPrimitives) {
+ if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+ std::vector<CompositePrimitive> supported;
+
+ EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode());
+
+ std::sort(supported.begin(), supported.end());
+
+ EXPECT_EQ(kCompositePrimitives, supported);
+ }
+}
+
+TEST_P(VibratorAidl, GetPrimitiveDuration) {
+ if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+ int32_t duration;
+
+ for (auto primitive : kCompositePrimitives) {
+ EXPECT_EQ(Status::EX_NONE,
+ vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode());
+ }
+ }
+}
+
TEST_P(VibratorAidl, ComposeValidPrimitives) {
if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
int32_t maxDelay, maxSize;
@@ -357,6 +380,30 @@ TEST_P(VibratorAidl, CompseSizeBoundary) {
}
}
+TEST_P(VibratorAidl, ComposeCallback) {
+ if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+ std::promise<void> completionPromise;
+ std::future<void> completionFuture{completionPromise.get_future()};
+ sp<CompletionCallback> callback =
+ new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ CompositePrimitive primitive = CompositePrimitive::CLICK;
+ CompositeEffect effect;
+ std::vector<CompositeEffect> composite;
+ int32_t duration;
+
+ effect.delayMs = 0;
+ effect.primitive = primitive;
+ effect.scale = 1.0f;
+ composite.emplace_back(effect);
+
+ EXPECT_EQ(Status::EX_NONE,
+ vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode());
+ EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode());
+ EXPECT_EQ(completionFuture.wait_for(std::chrono::milliseconds(duration * 2)),
+ std::future_status::ready);
+ }
+}
+
TEST_P(VibratorAidl, AlwaysOn) {
if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) {
std::vector<Effect> supported;
diff --git a/wifi/1.2/IWifiStaIface.hal b/wifi/1.2/IWifiStaIface.hal
index 3a7f7772c8..d65b33bb2b 100644
--- a/wifi/1.2/IWifiStaIface.hal
+++ b/wifi/1.2/IWifiStaIface.hal
@@ -23,7 +23,7 @@ import @1.0::IWifiStaIface;
/**
* Interface used to represent a single STA iface.
*
- * IWifiChip.createStaIface() may return a @1.2::IWifiStaIface when supported.
+ * IWifiChip.createStaIface() must return a @1.2::IWifiStaIface when supported.
*/
interface IWifiStaIface extends @1.0::IWifiStaIface {
/**
diff --git a/wifi/1.3/IWifiStaIface.hal b/wifi/1.3/IWifiStaIface.hal
index 81c0c3869b..3a755090ae 100644
--- a/wifi/1.3/IWifiStaIface.hal
+++ b/wifi/1.3/IWifiStaIface.hal
@@ -23,7 +23,7 @@ import @1.2::IWifiStaIface;
/**
* Interface used to represent a single STA iface.
*
- * IWifiChip.createStaIface() may return a @1.3::IWifiStaIface when supported.
+ * IWifiChip.createStaIface() must return a @1.3::IWifiStaIface when supported.
*/
interface IWifiStaIface extends @1.2::IWifiStaIface {
/**
diff --git a/wifi/1.4/default/wifi.cpp b/wifi/1.4/default/wifi.cpp
index 4f48d7e7a6..9c6b0f0f16 100644
--- a/wifi/1.4/default/wifi.cpp
+++ b/wifi/1.4/default/wifi.cpp
@@ -124,6 +124,8 @@ WifiStatus Wifi::startInternal() {
}
}
LOG(ERROR) << "Wifi HAL start failed";
+ // Clear the event callback objects since the HAL start failed.
+ event_cb_handler_.invalidate();
}
return wifi_status;
}
@@ -158,6 +160,8 @@ WifiStatus Wifi::stopInternal(
}
LOG(ERROR) << "Wifi HAL stop failed";
}
+ // Clear the event callback objects since the HAL is now stopped.
+ event_cb_handler_.invalidate();
return wifi_status;
}
diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp
index 3117473345..4f03fbb489 100644
--- a/wifi/1.4/default/wifi_legacy_hal.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -824,11 +824,10 @@ wifi_error WifiLegacyHal::setLatencyMode(const std::string& iface_name,
mode);
}
-wifi_error WifiLegacyHal::setThermalMitigationMode(
- const std::string& iface_name, wifi_thermal_mode mode,
- uint32_t completion_window) {
+wifi_error WifiLegacyHal::setThermalMitigationMode(wifi_thermal_mode mode,
+ uint32_t completion_window) {
return global_func_table_.wifi_set_thermal_mitigation_mode(
- getIfaceHandle(iface_name), mode, completion_window);
+ global_handle_, mode, completion_window);
}
std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h
index 9df227b34b..67bf6c2d76 100644
--- a/wifi/1.4/default/wifi_legacy_hal.h
+++ b/wifi/1.4/default/wifi_legacy_hal.h
@@ -259,8 +259,7 @@ class WifiLegacyHal {
virtual wifi_error resetTxPowerScenario(const std::string& iface_name);
wifi_error setLatencyMode(const std::string& iface_name,
wifi_latency_mode mode);
- wifi_error setThermalMitigationMode(const std::string& iface_name,
- wifi_thermal_mode mode,
+ wifi_error setThermalMitigationMode(wifi_thermal_mode mode,
uint32_t completion_window);
// Logger/debug functions.
std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(