Merge "Add libaudiofoundation."
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 213c93a..0140275 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -3,3 +3,8 @@
[Builtin Hooks]
clang_format = true
+
+[Hook Scripts]
+aosp_hook_confirmationui = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} confirmationui
+aosp_hook_gatekeeper = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} gatekeeper
+aosp_hook_keymaster = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} keymaster
diff --git a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc b/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
index 6e91bcc..72b4d19 100644
--- a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
+++ b/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
@@ -6,9 +6,4 @@
capabilities BLOCK_SUSPEND
ioprio rt 4
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
- # audioflinger restarts itself when it loses connection with the hal
- # and its .rc file has an "onrestart restart audio-hal" rule, thus
- # an additional auto-restart from the init process isn't needed.
- oneshot
- interface android.hardware.audio@4.0::IDevicesFactory default
- interface android.hardware.audio@2.0::IDevicesFactory default
+ onrestart restart audioserver
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index 8a7b2ea..2a6571b 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -36,6 +36,15 @@
using namespace android::hardware;
using android::OK;
+/** Try to register the provided factories in the provided order.
+ * 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) && ...);
+}
+
int main(int /* argc */, char* /* argv */ []) {
::android::ProcessState::initWithDriver("/dev/vndbinder");
// start a threadpool for vndbinder interactions
@@ -50,30 +59,30 @@
}
configureRpcThreadpool(16, true /*callerWillJoin*/);
- bool fail = registerPassthroughServiceImplementation<audio::V5_0::IDevicesFactory>() != OK &&
- registerPassthroughServiceImplementation<audio::V4_0::IDevicesFactory>() != OK &&
- registerPassthroughServiceImplementation<audio::V2_0::IDevicesFactory>() != OK;
- LOG_ALWAYS_FATAL_IF(fail, "Could not register audio core API 2, 4 nor 5");
+ LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<audio::V5_0::IDevicesFactory,
+ audio::V4_0::IDevicesFactory,
+ audio::V2_0::IDevicesFactory>()),
+ "Could not register audio core API");
- fail = registerPassthroughServiceImplementation<audio::effect::V5_0::IEffectsFactory>() != OK &&
- registerPassthroughServiceImplementation<audio::effect::V4_0::IEffectsFactory>() != OK &&
- registerPassthroughServiceImplementation<audio::effect::V2_0::IEffectsFactory>() != OK,
- LOG_ALWAYS_FATAL_IF(fail, "Could not register audio effect API 2, 4 nor 5");
+ LOG_ALWAYS_FATAL_IF(
+ (registerPassthroughServiceImplementations<audio::effect::V5_0::IEffectsFactory,
+ audio::effect::V4_0::IEffectsFactory,
+ audio::effect::V2_0::IEffectsFactory>()),
+ "Could not register audio effect API");
- fail = registerPassthroughServiceImplementation<soundtrigger::V2_2::ISoundTriggerHw>() != OK &&
- registerPassthroughServiceImplementation<soundtrigger::V2_1::ISoundTriggerHw>() != OK &&
- registerPassthroughServiceImplementation<soundtrigger::V2_0::ISoundTriggerHw>() != OK,
- ALOGW_IF(fail, "Could not register soundtrigger API 2.0, 2.1 nor 2.2");
+ ALOGW_IF((registerPassthroughServiceImplementations<soundtrigger::V2_2::ISoundTriggerHw,
+ soundtrigger::V2_1::ISoundTriggerHw,
+ soundtrigger::V2_0::ISoundTriggerHw>()),
+ "Could not register soundtrigger API");
- fail = registerPassthroughServiceImplementation<
- bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>() != OK;
- ALOGW_IF(fail, "Could not register Bluetooth Audio API 2.0");
+ ALOGW_IF(registerPassthroughServiceImplementations<
+ bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>(),
+ "Could not register Bluetooth audio API");
// remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported
- fail =
- registerPassthroughServiceImplementation<bluetooth::a2dp::V1_0::IBluetoothAudioOffload>() !=
- OK;
- ALOGW_IF(fail, "Could not register Bluetooth audio offload 1.0");
+ ALOGW_IF(registerPassthroughServiceImplementations<
+ bluetooth::a2dp::V1_0::IBluetoothAudioOffload>(),
+ "Could not register Bluetooth audio offload API");
joinRpcThreadpool();
}
diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp
index a1af3c4..97b4553 100644
--- a/audio/core/all-versions/default/Android.bp
+++ b/audio/core/all-versions/default/Android.bp
@@ -26,6 +26,7 @@
"libhidlbase",
"libhidltransport",
"liblog",
+ "libmedia_helper",
"libutils",
"android.hardware.audio.common-util",
],
@@ -37,10 +38,6 @@
"libhardware_headers",
"libmedia_headers",
],
-
- whole_static_libs: [
- "libmedia_helper",
- ],
}
cc_library_shared {
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index bec22df..1a9df21 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -378,7 +378,7 @@
}
Return<Result> Device::setConnectedState(const DeviceAddress& address, bool connected) {
- auto key = connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect;
+ auto key = connected ? AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect;
return setParam(key, address);
}
#endif
diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp
index b995657..e62f6d3 100644
--- a/audio/core/all-versions/default/Stream.cpp
+++ b/audio/core/all-versions/default/Stream.cpp
@@ -243,8 +243,8 @@
Return<Result> Stream::setConnectedState(const DeviceAddress& address, bool connected) {
return setParam(
- connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect,
- address);
+ connected ? AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect,
+ address);
}
#elif MAJOR_VERSION >= 4
Return<void> Stream::getDevices(getDevices_cb _hidl_cb) {
diff --git a/audio/effect/5.0/xml/Android.bp b/audio/effect/5.0/xml/Android.bp
index 967135c..eb2bcee 100644
--- a/audio/effect/5.0/xml/Android.bp
+++ b/audio/effect/5.0/xml/Android.bp
@@ -1,6 +1,6 @@
xsd_config {
- name: "audio_effects_conf",
+ name: "audio_effects_conf_V5_0",
srcs: ["audio_effects_conf.xsd"],
package_name: "audio.effects.V5_0",
}
diff --git a/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc b/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc
index e82da7e..1a95cd0 100644
--- a/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc
+++ b/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.authsecret-1-0 /vendor/bin/hw/android.hardware.authsecret@1.0-service
+ interface android.hardware.authsecret@1.0::IAuthSecret default
class hal
user system
group system
diff --git a/automotive/evs/1.0/IEvsCamera.hal b/automotive/evs/1.0/IEvsCamera.hal
index dbcaf92..464dafb 100644
--- a/automotive/evs/1.0/IEvsCamera.hal
+++ b/automotive/evs/1.0/IEvsCamera.hal
@@ -16,7 +16,6 @@
package android.hardware.automotive.evs@1.0;
-import types;
import IEvsCameraStream;
@@ -28,8 +27,8 @@
/**
* Returns the ID of this camera.
*
- * Returns the description of this camera. This must be the same value as reported
- * by EvsEnumerator::getCamerList().
+ * @return info The description of this camera. This must be the same value as
+ * reported by EvsEnumerator::getCameraList().
*/
getCameraInfo() generates (CameraDesc info);
@@ -43,16 +42,20 @@
* in which case buffers should be added or removed from the chain as appropriate.
* If no call is made to this entry point, the IEvsCamera must support at least one
* frame by default. More is acceptable.
- * BUFFER_NOT_AVAILABLE is returned if the implementation cannot support the
- * requested number of concurrent frames.
+ *
+ * @param bufferCount Number of buffers the client of IEvsCamera may hold concurrently.
+ * @return result EvsResult::OK is returned if this call is successful.
*/
setMaxFramesInFlight(uint32_t bufferCount) generates (EvsResult result);
/**
- * Request delivery of EVS camera frames from this camera.
+ * Request to start EVS camera stream from this camera.
*
- * The IEvsCameraStream must begin receiving periodic calls with new image
- * frames until stopVideoStream() is called.
+ * The IEvsCameraStream must begin receiving calls with various events
+ * including new image frame ready until stopVideoStream() is called.
+ *
+ * @param receiver IEvsCameraStream implementation.
+ * @return result EvsResult::OK is returned if this call is successful.
*/
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
@@ -64,6 +67,8 @@
* A small, finite number of buffers are available (possibly as small
* as one), and if the supply is exhausted, no further frames may be
* delivered until a buffer is returned.
+ *
+ * @param buffer A buffer to be returned.
*/
oneway doneWithFrame(BufferDesc buffer);
@@ -83,6 +88,11 @@
* The values allowed for opaqueIdentifier are driver specific,
* but no value passed in may crash the driver. The driver should
* return 0 for any unrecognized opaqueIdentifier.
+ *
+ * @param opaqueIdentifier An unique identifier of the information to
+ * request.
+ * @return value Requested information. Zero is returned if the
+ * driver does not recognize a given identifier.
*/
getExtendedInfo(uint32_t opaqueIdentifier) generates (int32_t value);
@@ -94,6 +104,11 @@
* in order to function in a default state.
* INVALID_ARG is returned if the opaqueValue is not meaningful to
* the driver implementation.
+ *
+ * @param opaqueIdentifier An unique identifier of the information to
+ * program.
+ * opaqueValue A value to program.
+ * @return result EvsResult::OK is returned if this call is successful.
*/
setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) generates (EvsResult result);
};
diff --git a/automotive/evs/1.0/IEvsCameraStream.hal b/automotive/evs/1.0/IEvsCameraStream.hal
index 4e743b2..ec18f6a 100644
--- a/automotive/evs/1.0/IEvsCameraStream.hal
+++ b/automotive/evs/1.0/IEvsCameraStream.hal
@@ -31,6 +31,8 @@
* When the last frame in the stream has been delivered, a NULL bufferHandle
* must be delivered, signifying the end of the stream. No further frame
* deliveries may happen thereafter.
+ *
+ * @param buffer a buffer descriptor of a delivered image frame.
*/
oneway deliverFrame(BufferDesc buffer);
};
diff --git a/automotive/evs/1.0/IEvsDisplay.hal b/automotive/evs/1.0/IEvsDisplay.hal
index 12541f3..72f767e 100644
--- a/automotive/evs/1.0/IEvsDisplay.hal
+++ b/automotive/evs/1.0/IEvsDisplay.hal
@@ -16,8 +16,6 @@
package android.hardware.automotive.evs@1.0;
-import types;
-
/**
* Represents a single camera and is the primary interface for capturing images.
@@ -28,6 +26,9 @@
* Returns basic information about the EVS display provided by the system.
*
* See the description of the DisplayDesc structure for details.
+ *
+ * @return info The description of this display. Please see the description
+ * of the DisplayDesc structure for details.
*/
getDisplayInfo() generates (DisplayDesc info);
@@ -42,6 +43,9 @@
* video. When the display is no longer required, the client is expected to request
* the NOT_VISIBLE state after passing the last video frame.
* Returns INVALID_ARG if the requested state is not a recognized value.
+ *
+ * @param state Desired new DisplayState.
+ * @return result EvsResult::OK is returned if this call is successful.
*/
setDisplayState(DisplayState state) generates (EvsResult result);
@@ -54,6 +58,8 @@
* the logic responsible for changing display states should generally live above
* the device layer, making it undesirable for the HAL implementation to spontaneously
* change display states.
+ *
+ * @return state Current DisplayState of this Display.
*/
getDisplayState() generates (DisplayState state);
@@ -61,9 +67,11 @@
/**
* This call returns a handle to a frame buffer associated with the display.
*
- * The returned buffer may be locked and written to by software and/or GL. This buffer
- * must be returned via a call to returnTargetBufferForDisplay() even if the
- * display is no longer visible.
+ * @return buffer A handle to a frame buffer. The returned buffer may be
+ * locked and written to by software and/or GL. This buffer
+ * must be returned via a call to
+ * returnTargetBufferForDisplay() even if the display is no
+ * longer visible.
*/
getTargetBuffer() generates (BufferDesc buffer);
@@ -75,6 +83,9 @@
* There is no maximum time the caller may hold onto the buffer before making this
* call. The buffer may be returned at any time and in any DisplayState, but all
* buffers are expected to be returned before the IEvsDisplay interface is destroyed.
+ *
+ * @param buffer A buffer handle to the frame that is ready for display.
+ * @return result EvsResult::OK is returned if this call is successful.
*/
returnTargetBufferForDisplay(BufferDesc buffer) generates (EvsResult result);
};
diff --git a/automotive/evs/1.0/IEvsEnumerator.hal b/automotive/evs/1.0/IEvsEnumerator.hal
index ee51e7e..e5633df 100644
--- a/automotive/evs/1.0/IEvsEnumerator.hal
+++ b/automotive/evs/1.0/IEvsEnumerator.hal
@@ -16,7 +16,6 @@
package android.hardware.automotive.evs@1.0;
-import types;
import IEvsCamera;
import IEvsDisplay;
@@ -28,6 +27,8 @@
/**
* Returns a list of all EVS cameras available to the system
+ *
+ * @return cameras A list of cameras availale for EVS service.
*/
getCameraList() generates (vec<CameraDesc> cameras);
@@ -37,9 +38,9 @@
* Given a camera's unique cameraId from CameraDesc, returns the
* IEvsCamera interface associated with the specified camera. When
* done using the camera, the caller may release it by calling closeCamera().
- * Note: Reliance on the sp<> going out of scope is not recommended
- * because the resources may not be released right away due to asynchronos
- * behavior in the hardware binder (ref b/36122635).
+ *
+ * @param cameraId A unique identifier of the camera.
+ * @return carCamera EvsCamera object associated with a given cameraId.
*/
openCamera(string cameraId) generates (IEvsCamera carCamera);
@@ -48,6 +49,8 @@
*
* When the IEvsCamera object is no longer required, it must be released.
* NOTE: Video streaming must be cleanly stopped before making this call.
+ *
+ * @param carCamera EvsCamera object to be closed.
*/
closeCamera(IEvsCamera carCamera);
@@ -60,8 +63,8 @@
* the old instance shall be closed and give the new caller exclusive
* access.
* When done using the display, the caller may release it by calling closeDisplay().
- * TODO(b/36122635) Reliance on the sp<> going out of scope is not recommended because the
- * resources may not be released right away due to asynchronos behavior in the hardware binder.
+ *
+ * @return display EvsDisplay object to be used.
*/
openDisplay() generates (IEvsDisplay display);
@@ -70,6 +73,8 @@
*
* When the IEvsDisplay object is no longer required, it must be released.
* NOTE: All buffers must have been returned to the display before making this call.
+ *
+ * @param display EvsDisplay object to be closed.
*/
closeDisplay(IEvsDisplay display);
@@ -80,6 +85,8 @@
* the actual state of the active display. This call is replicated on the IEvsEnumerator
* interface in order to allow secondary clients to monitor the state of the EVS display
* without acquiring exclusive ownership of the display.
+ *
+ * @return state Current DisplayState of this Display.
*/
getDisplayState() generates (DisplayState state);
};
diff --git a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
index 117c249..8dcd969 100644
--- a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
+++ b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
@@ -2,3 +2,4 @@
class hal
user automotive_evs
group automotive_evs
+ disabled # do not start automatically
diff --git a/automotive/evs/1.0/types.hal b/automotive/evs/1.0/types.hal
index 7cebf6d..1efd5eb 100644
--- a/automotive/evs/1.0/types.hal
+++ b/automotive/evs/1.0/types.hal
@@ -24,8 +24,15 @@
* EVS camera in the system.
*/
struct CameraDesc {
+ /* Unique identifier for camera devices. This may be a path to detected
+ * camera device; for example, "/dev/video0".
+ */
string cameraId;
- uint32_t vendorFlags; // Opaque value from driver
+
+ /* Opaque value from driver. Vendor may use this field to store additional
+ * information; for example, sensor and bridge chip id.
+ */
+ uint32_t vendorFlags;
};
@@ -38,8 +45,11 @@
* presentation device.
*/
struct DisplayDesc {
+ /* Unique identifier for the display */
string displayId;
- uint32_t vendorFlags; // Opaque value from driver
+
+ /* Opaque value from driver */
+ uint32_t vendorFlags;
};
@@ -56,14 +66,31 @@
* Specifically consider if format and/or usage should become enumerated types.
*/
struct BufferDesc {
- uint32_t width; // Units of pixels
- uint32_t height; // Units of pixels
- uint32_t stride; // Units of pixels to match gralloc
- uint32_t pixelSize; // Units of bytes
- uint32_t format; // May contain values from android_pixel_format_t
- uint32_t usage; // May contain values from from Gralloc.h
- uint32_t bufferId; // Opaque value from driver
- handle memHandle; // gralloc memory buffer handle
+ /* A frame width in the units of pixels */
+ uint32_t width;
+
+ /* A frame height in the units of pixels */
+ uint32_t height;
+
+ /* A frame stride in the units of pixels, to match gralloc */
+ uint32_t stride;
+
+ /* The size of a pixel in the units of bytes */
+ uint32_t pixelSize;
+
+ /* The image format of the frame; may contain values from
+ * android_pixel_format_t
+ */
+ uint32_t format;
+
+ /* May contain values from Gralloc.h */
+ uint32_t usage;
+
+ /* Opaque value from driver */
+ uint32_t bufferId;
+
+ /* Gralloc memory buffer handle */
+ handle memHandle;
};
@@ -77,12 +104,23 @@
* presentation device.
*/
enum DisplayState : uint32_t {
- NOT_OPEN = 0, // Display has not been requested by any application
- NOT_VISIBLE, // Display is inhibited
- VISIBLE_ON_NEXT_FRAME, // Will become visible with next frame
- VISIBLE, // Display is currently active
- DEAD, // Driver is in an undefined state. Interface should be closed.
- NUM_STATES // Must be last
+ /* Display has not been requested by any application yet */
+ NOT_OPEN = 0,
+
+ /* Display is inhibited */
+ NOT_VISIBLE,
+
+ /* Will become visible with next frame */
+ VISIBLE_ON_NEXT_FRAME,
+
+ /* Display is currently active */
+ VISIBLE,
+
+ /* Driver is in an undefined state. Interface should be closed. */
+ DEAD,
+
+ /* Must be the last */
+ NUM_STATES
};
diff --git a/automotive/evs/1.0/vts/functional/Android.bp b/automotive/evs/1.0/vts/functional/Android.bp
index 2ef33fd..8988bfd 100644
--- a/automotive/evs/1.0/vts/functional/Android.bp
+++ b/automotive/evs/1.0/vts/functional/Android.bp
@@ -19,13 +19,15 @@
srcs: [
"VtsHalEvsV1_0TargetTest.cpp",
"FrameHandler.cpp",
- "FormatConvert.cpp"
],
defaults: ["VtsHalTargetTestDefaults"],
shared_libs: [
"libui",
],
- static_libs: ["android.hardware.automotive.evs@1.0"],
+ static_libs: [
+ "android.hardware.automotive.evs@1.0",
+ "android.hardware.automotive.evs@common-default-lib",
+ ],
test_suites: ["general-tests"],
cflags: [
"-O0",
diff --git a/automotive/evs/1.0/vts/functional/FormatConvert.h b/automotive/evs/1.0/vts/functional/FormatConvert.h
deleted file mode 100644
index 4a94f99..0000000
--- a/automotive/evs/1.0/vts/functional/FormatConvert.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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 EVS_VTS_FORMATCONVERT_H
-#define EVS_VTS_FORMATCONVERT_H
-
-#include <queue>
-#include <stdint.h>
-
-
-// Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx/BGRx
-// values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
-// U/V array. It assumes an even width and height for the overall image, and a horizontal
-// stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-void copyNV21toRGB32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels,
- bool bgrxFormat = false);
-
-void copyNV21toBGR32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels);
-
-
-// Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx/BGRx values.
-// The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
-// by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image,
-// and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
-// and V arrays.
-void copyYV12toRGB32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels,
- bool bgrxFormat = false);
-
-void copyYV12toBGR32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels);
-
-// Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx/BGRx
-// values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
-// U/V array. It assumes an even width and height for the overall image, and a horizontal
-// stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-void copyYUYVtoRGB32(unsigned width, unsigned height,
- uint8_t* src, unsigned srcStrideBytes,
- uint32_t* dst, unsigned dstStrideBytes,
- bool bgrxFormat = false);
-
-void copyYUYVtoBGR32(unsigned width, unsigned height,
- uint8_t* src, unsigned srcStrideBytes,
- uint32_t* dst, unsigned dstStrideBytes);
-
-
-// Given an simple rectangular image buffer with an integer number of bytes per pixel,
-// copy the pixel values into a new rectangular buffer (potentially with a different stride).
-// This is typically used to copy RGBx data into an RGBx output buffer.
-void copyMatchedInterleavedFormats(unsigned width, unsigned height,
- void* src, unsigned srcStridePixels,
- void* dst, unsigned dstStridePixels,
- unsigned pixelSize);
-
-#endif // EVS_VTS_FORMATCONVERT_H
diff --git a/automotive/evs/1.0/vts/functional/FrameHandler.cpp b/automotive/evs/1.0/vts/functional/FrameHandler.cpp
index bc3790f..6a01a44 100644
--- a/automotive/evs/1.0/vts/functional/FrameHandler.cpp
+++ b/automotive/evs/1.0/vts/functional/FrameHandler.cpp
@@ -240,46 +240,47 @@
tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
if (srcPixels && tgtPixels) {
+ using namespace ::android::hardware::automotive::evs::common;
if (tgtBuffer.format == HAL_PIXEL_FORMAT_RGBA_8888) {
if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21
- copyNV21toRGB32(width, height,
- srcPixels,
- tgtPixels, tgtBuffer.stride);
+ Utils::copyNV21toRGB32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
} else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
- copyYV12toRGB32(width, height,
- srcPixels,
- tgtPixels, tgtBuffer.stride);
+ Utils::copyYV12toRGB32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
} else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
- copyYUYVtoRGB32(width, height,
- srcPixels, srcBuffer.stride,
- tgtPixels, tgtBuffer.stride);
+ Utils::copyYUYVtoRGB32(width, height,
+ srcPixels, srcBuffer.stride,
+ tgtPixels, tgtBuffer.stride);
} else if (srcBuffer.format == tgtBuffer.format) { // 32bit RGBA
- copyMatchedInterleavedFormats(width, height,
- srcPixels, srcBuffer.stride,
- tgtPixels, tgtBuffer.stride,
- tgtBuffer.pixelSize);
+ Utils::copyMatchedInterleavedFormats(width, height,
+ srcPixels, srcBuffer.stride,
+ tgtPixels, tgtBuffer.stride,
+ tgtBuffer.pixelSize);
} else {
ALOGE("Camera buffer format is not supported");
success = false;
}
} else if (tgtBuffer.format == HAL_PIXEL_FORMAT_BGRA_8888) {
if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21
- copyNV21toBGR32(width, height,
- srcPixels,
- tgtPixels, tgtBuffer.stride);
+ Utils::copyNV21toBGR32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
} else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
- copyYV12toBGR32(width, height,
- srcPixels,
- tgtPixels, tgtBuffer.stride);
+ Utils::copyYV12toBGR32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
} else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
- copyYUYVtoBGR32(width, height,
- srcPixels, srcBuffer.stride,
- tgtPixels, tgtBuffer.stride);
+ Utils::copyYUYVtoBGR32(width, height,
+ srcPixels, srcBuffer.stride,
+ tgtPixels, tgtBuffer.stride);
} else if (srcBuffer.format == tgtBuffer.format) { // 32bit RGBA
- copyMatchedInterleavedFormats(width, height,
- srcPixels, srcBuffer.stride,
- tgtPixels, tgtBuffer.stride,
- tgtBuffer.pixelSize);
+ Utils::copyMatchedInterleavedFormats(width, height,
+ srcPixels, srcBuffer.stride,
+ tgtPixels, tgtBuffer.stride,
+ tgtBuffer.pixelSize);
} else {
ALOGE("Camera buffer format is not supported");
success = false;
diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp
new file mode 100644
index 0000000..d2e85f1
--- /dev/null
+++ b/automotive/evs/1.1/Android.bp
@@ -0,0 +1,22 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.automotive.evs@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IEvsCamera.hal",
+ "IEvsCameraStream.hal",
+ ],
+ interfaces: [
+ "android.hardware.automotive.evs@1.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal
new file mode 100644
index 0000000..e7f6bb7
--- /dev/null
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -0,0 +1,57 @@
+/*
+ * 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.automotive.evs@1.1;
+
+import @1.0::IEvsCamera;
+import @1.0::EvsResult;
+import IEvsCameraStream;
+
+/**
+ * Represents a single camera and is the primary interface for capturing images.
+ */
+interface IEvsCamera extends @1.0::IEvsCamera {
+ /**
+ * Requests to pause EVS camera stream events.
+ *
+ * Like stopVideoStream(), events may continue to arrive for some time
+ * after this call returns. Delivered frame buffers must be returned.
+ *
+ * @return result EvsResult::OK is returned if this call is successful.
+ */
+ pauseVideoStream() generates (EvsResult result);
+
+ /**
+ * Requests to resume EVS camera stream.
+ *
+ * @return result EvsResult::OK is returned if this call is successful.
+ */
+ resumeVideoStream() generates (EvsResult result);
+
+ /**
+ * Returns a frame that was delivered by to the IEvsCameraStream.
+ *
+ * When done consuming a frame delivered to the IEvsCameraStream
+ * interface, it must be returned to the IEvsCamera for reuse.
+ * A small, finite number of buffers are available (possibly as small
+ * as one), and if the supply is exhausted, no further frames may be
+ * delivered until a buffer is returned.
+ *
+ * @param buffer A buffer to be returned.
+ * @return result Return EvsResult::OK if this call is successful.
+ */
+ doneWithFrame_1_1(BufferDesc buffer) generates (EvsResult result);
+};
diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal
new file mode 100644
index 0000000..cd058a5
--- /dev/null
+++ b/automotive/evs/1.1/IEvsCameraStream.hal
@@ -0,0 +1,31 @@
+/*
+ * 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.automotive.evs@1.1;
+
+import @1.0::IEvsCameraStream;
+
+/**
+ * Implemented on client side to receive asynchronous video frame deliveries.
+ */
+interface IEvsCameraStream extends @1.0::IEvsCameraStream {
+ /**
+ * Receives calls from the HAL each time an event happens.
+ *
+ * @param event EVS event with possible event information.
+ */
+ oneway notifyEvent(EvsEvent event);
+};
diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp
new file mode 100644
index 0000000..411f0ff
--- /dev/null
+++ b/automotive/evs/1.1/default/Android.bp
@@ -0,0 +1,32 @@
+cc_binary {
+ name: "android.hardware.automotive.evs@1.1-service",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: [
+ "service.cpp",
+ "EvsCamera.cpp",
+ "EvsEnumerator.cpp",
+ "EvsDisplay.cpp"
+ ],
+ init_rc: ["android.hardware.automotive.evs@1.1-service.rc"],
+
+ shared_libs: [
+ "android.hardware.automotive.evs@1.0",
+ "android.hardware.automotive.evs@1.1",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libui",
+ "libutils",
+ ],
+
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp
new file mode 100644
index 0000000..62d9826
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -0,0 +1,584 @@
+/*
+ * 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 "android.hardware.automotive.evs@1.1-service"
+
+#include "EvsCamera.h"
+#include "EvsEnumerator.h"
+
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+// Special camera names for which we'll initialize alternate test data
+const char EvsCamera::kCameraName_Backup[] = "backup";
+
+
+// Arbitrary limit on number of graphics buffers allowed to be allocated
+// Safeguards against unreasonable resource consumption and provides a testable limit
+const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
+
+
+EvsCamera::EvsCamera(const char *id) :
+ mFramesAllowed(0),
+ mFramesInUse(0),
+ mStreamState(STOPPED) {
+
+ ALOGD("EvsCamera instantiated");
+
+ mDescription.cameraId = id;
+
+ // Set up dummy data for testing
+ if (mDescription.cameraId == kCameraName_Backup) {
+ mWidth = 640; // full NTSC/VGA
+ mHeight = 480; // full NTSC/VGA
+ mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value
+ } else {
+ mWidth = 320; // 1/2 NTSC/VGA
+ mHeight = 240; // 1/2 NTSC/VGA
+ }
+
+ mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
+ GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
+}
+
+
+EvsCamera::~EvsCamera() {
+ ALOGD("EvsCamera being destroyed");
+ forceShutdown();
+}
+
+
+//
+// This gets called if another caller "steals" ownership of the camera
+//
+void EvsCamera::forceShutdown()
+{
+ ALOGD("EvsCamera forceShutdown");
+
+ // Make sure our output stream is cleaned up
+ // (It really should be already)
+ stopVideoStream();
+
+ // Claim the lock while we work on internal state
+ std::lock_guard <std::mutex> lock(mAccessLock);
+
+ // Drop all the graphics buffers we've been using
+ if (mBuffers.size() > 0) {
+ GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ for (auto&& rec : mBuffers) {
+ if (rec.inUse) {
+ ALOGE("Error - releasing buffer despite remote ownership");
+ }
+ alloc.free(rec.handle);
+ rec.handle = nullptr;
+ }
+ mBuffers.clear();
+ }
+
+ // Put this object into an unrecoverable error state since somebody else
+ // is going to own the underlying camera now
+ mStreamState = DEAD;
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+Return<void> EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
+ ALOGD("getCameraInfo");
+
+ // Send back our self description
+ _hidl_cb(mDescription);
+ return Void();
+}
+
+
+Return<EvsResult> EvsCamera::setMaxFramesInFlight(uint32_t bufferCount) {
+ ALOGD("setMaxFramesInFlight");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // If we've been displaced by another owner of the camera, then we can't do anything else
+ if (mStreamState == DEAD) {
+ ALOGE("ignoring setMaxFramesInFlight call when camera has been lost.");
+ return EvsResult::OWNERSHIP_LOST;
+ }
+
+ // We cannot function without at least one video buffer to send data
+ if (bufferCount < 1) {
+ ALOGE("Ignoring setMaxFramesInFlight with less than one buffer requested");
+ return EvsResult::INVALID_ARG;
+ }
+
+ // Update our internal state
+ if (setAvailableFrames_Locked(bufferCount)) {
+ return EvsResult::OK;
+ } else {
+ return EvsResult::BUFFER_NOT_AVAILABLE;
+ }
+}
+
+
+Return<EvsResult> EvsCamera::startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& stream) {
+ ALOGD("startVideoStream");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // If we've been displaced by another owner of the camera, then we can't do anything else
+ if (mStreamState == DEAD) {
+ ALOGE("ignoring startVideoStream call when camera has been lost.");
+ return EvsResult::OWNERSHIP_LOST;
+ }
+ if (mStreamState != STOPPED) {
+ ALOGE("ignoring startVideoStream call when a stream is already running.");
+ return EvsResult::STREAM_ALREADY_RUNNING;
+ }
+
+ // If the client never indicated otherwise, configure ourselves for a single streaming buffer
+ if (mFramesAllowed < 1) {
+ if (!setAvailableFrames_Locked(1)) {
+ ALOGE("Failed to start stream because we couldn't get a graphics buffer");
+ return EvsResult::BUFFER_NOT_AVAILABLE;
+ }
+ }
+
+ // Record the user's callback for use when we have a frame ready
+ mStream = IEvsCameraStream_1_1::castFrom(stream).withDefault(nullptr);
+ if (mStream == nullptr) {
+ ALOGE("Default implementation does not support v1.0 IEvsCameraStream");
+ return EvsResult::INVALID_ARG;
+ }
+
+ // Start the frame generation thread
+ mStreamState = RUNNING;
+ mCaptureThread = std::thread([this](){ generateFrames(); });
+
+ return EvsResult::OK;
+}
+
+
+Return<void> EvsCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
+ std::lock_guard <std::mutex> lock(mAccessLock);
+ returnBuffer(buffer.bufferId, buffer.memHandle);
+
+ return Void();
+}
+
+
+Return<void> EvsCamera::stopVideoStream() {
+ ALOGD("stopVideoStream");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ if (mStreamState == RUNNING) {
+ // Tell the GenerateFrames loop we want it to stop
+ mStreamState = STOPPING;
+
+ // Block outside the mutex until the "stop" flag has been acknowledged
+ // We won't send any more frames, but the client might still get some already in flight
+ ALOGD("Waiting for stream thread to end..");
+ lock.unlock();
+ mCaptureThread.join();
+ lock.lock();
+
+ mStreamState = STOPPED;
+ mStream = nullptr;
+ ALOGD("Stream marked STOPPED.");
+ }
+
+ return Void();
+}
+
+
+Return<int32_t> EvsCamera::getExtendedInfo(uint32_t opaqueIdentifier) {
+ ALOGD("getExtendedInfo");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // For any single digit value, return the index itself as a test value
+ if (opaqueIdentifier <= 9) {
+ return opaqueIdentifier;
+ }
+
+ // Return zero by default as required by the spec
+ return 0;
+}
+
+
+Return<EvsResult> EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int32_t /*opaqueValue*/) {
+ ALOGD("setExtendedInfo");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // If we've been displaced by another owner of the camera, then we can't do anything else
+ if (mStreamState == DEAD) {
+ ALOGE("ignoring setExtendedInfo call when camera has been lost.");
+ return EvsResult::OWNERSHIP_LOST;
+ }
+
+ // We don't store any device specific information in this implementation
+ return EvsResult::INVALID_ARG;
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+Return<EvsResult> EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) {
+ std::lock_guard <std::mutex> lock(mAccessLock);
+ returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle);
+
+ return EvsResult::OK;
+}
+
+
+Return<EvsResult> EvsCamera::pauseVideoStream() {
+ // Default implementation does not support this.
+ return EvsResult::UNDERLYING_SERVICE_ERROR;
+}
+
+
+Return<EvsResult> EvsCamera::resumeVideoStream() {
+ // Default implementation does not support this.
+ return EvsResult::UNDERLYING_SERVICE_ERROR;
+}
+
+
+bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) {
+ if (bufferCount < 1) {
+ ALOGE("Ignoring request to set buffer count to zero");
+ return false;
+ }
+ if (bufferCount > MAX_BUFFERS_IN_FLIGHT) {
+ ALOGE("Rejecting buffer request in excess of internal limit");
+ return false;
+ }
+
+ // Is an increase required?
+ if (mFramesAllowed < bufferCount) {
+ // An increase is required
+ unsigned needed = bufferCount - mFramesAllowed;
+ ALOGI("Allocating %d buffers for camera frames", needed);
+
+ unsigned added = increaseAvailableFrames_Locked(needed);
+ if (added != needed) {
+ // If we didn't add all the frames we needed, then roll back to the previous state
+ ALOGE("Rolling back to previous frame queue size");
+ decreaseAvailableFrames_Locked(added);
+ return false;
+ }
+ } else if (mFramesAllowed > bufferCount) {
+ // A decrease is required
+ unsigned framesToRelease = mFramesAllowed - bufferCount;
+ ALOGI("Returning %d camera frame buffers", framesToRelease);
+
+ unsigned released = decreaseAvailableFrames_Locked(framesToRelease);
+ if (released != framesToRelease) {
+ // This shouldn't happen with a properly behaving client because the client
+ // should only make this call after returning sufficient outstanding buffers
+ // to allow a clean resize.
+ ALOGE("Buffer queue shrink failed -- too many buffers currently in use?");
+ }
+ }
+
+ return true;
+}
+
+
+unsigned EvsCamera::increaseAvailableFrames_Locked(unsigned numToAdd) {
+ // Acquire the graphics buffer allocator
+ GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
+
+ unsigned added = 0;
+
+ while (added < numToAdd) {
+ buffer_handle_t memHandle = nullptr;
+ status_t result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage,
+ &memHandle, &mStride, 0, "EvsCamera");
+ if (result != NO_ERROR) {
+ ALOGE("Error %d allocating %d x %d graphics buffer", result, mWidth, mHeight);
+ break;
+ }
+ if (!memHandle) {
+ ALOGE("We didn't get a buffer handle back from the allocator");
+ break;
+ }
+
+ // Find a place to store the new buffer
+ bool stored = false;
+ for (auto&& rec : mBuffers) {
+ if (rec.handle == nullptr) {
+ // Use this existing entry
+ rec.handle = memHandle;
+ rec.inUse = false;
+ stored = true;
+ break;
+ }
+ }
+ if (!stored) {
+ // Add a BufferRecord wrapping this handle to our set of available buffers
+ mBuffers.emplace_back(memHandle);
+ }
+
+ mFramesAllowed++;
+ added++;
+ }
+
+ return added;
+}
+
+
+unsigned EvsCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) {
+ // Acquire the graphics buffer allocator
+ GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
+
+ unsigned removed = 0;
+
+ for (auto&& rec : mBuffers) {
+ // Is this record not in use, but holding a buffer that we can free?
+ if ((rec.inUse == false) && (rec.handle != nullptr)) {
+ // Release buffer and update the record so we can recognize it as "empty"
+ alloc.free(rec.handle);
+ rec.handle = nullptr;
+
+ mFramesAllowed--;
+ removed++;
+
+ if (removed == numToRemove) {
+ break;
+ }
+ }
+ }
+
+ return removed;
+}
+
+
+// This is the asynchronous frame generation thread that runs in parallel with the
+// main serving thread. There is one for each active camera instance.
+void EvsCamera::generateFrames() {
+ ALOGD("Frame generation loop started");
+
+ unsigned idx;
+
+ while (true) {
+ bool timeForFrame = false;
+ nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // Lock scope for updating shared state
+ {
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mStreamState != RUNNING) {
+ // Break out of our main thread loop
+ break;
+ }
+
+ // Are we allowed to issue another buffer?
+ if (mFramesInUse >= mFramesAllowed) {
+ // Can't do anything right now -- skip this frame
+ ALOGW("Skipped a frame because too many are in flight\n");
+ } else {
+ // Identify an available buffer to fill
+ for (idx = 0; idx < mBuffers.size(); idx++) {
+ if (!mBuffers[idx].inUse) {
+ if (mBuffers[idx].handle != nullptr) {
+ // Found an available record, so stop looking
+ break;
+ }
+ }
+ }
+ if (idx >= mBuffers.size()) {
+ // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
+ ALOGE("Failed to find an available buffer slot\n");
+ } else {
+ // We're going to make the frame busy
+ mBuffers[idx].inUse = true;
+ mFramesInUse++;
+ timeForFrame = true;
+ }
+ }
+ }
+
+ if (timeForFrame) {
+ // Assemble the buffer description we'll transmit below
+ BufferDesc_1_1 newBuffer = {};
+ AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<AHardwareBuffer_Desc *>(&newBuffer.buffer.description);
+ pDesc->width = mWidth;
+ pDesc->height = mHeight;
+ pDesc->layers = 1;
+ pDesc->format = mFormat;
+ pDesc->usage = mUsage;
+ pDesc->stride = mStride;
+ newBuffer.buffer.nativeHandle = mBuffers[idx].handle;
+ newBuffer.pixelSize = sizeof(uint32_t);
+ newBuffer.bufferId = idx;
+
+ // Write test data into the image buffer
+ fillTestFrame(newBuffer);
+
+ // Issue the (asynchronous) callback to the client -- can't be holding the lock
+ EvsEvent event;
+ event.buffer(newBuffer);
+ auto result = mStream->notifyEvent(event);
+ if (result.isOk()) {
+ ALOGD("Delivered %p as id %d",
+ newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId);
+ } else {
+ // This can happen if the client dies and is likely unrecoverable.
+ // To avoid consuming resources generating failing calls, we stop sending
+ // frames. Note, however, that the stream remains in the "STREAMING" state
+ // until cleaned up on the main thread.
+ ALOGE("Frame delivery call failed in the transport layer.");
+
+ // Since we didn't actually deliver it, mark the frame as available
+ std::lock_guard<std::mutex> lock(mAccessLock);
+ mBuffers[idx].inUse = false;
+ mFramesInUse--;
+
+ break;
+ }
+ }
+
+ // We arbitrarily choose to generate frames at 12 fps to ensure we pass the 10fps test requirement
+ static const int kTargetFrameRate = 12;
+ static const nsecs_t kTargetFrameTimeUs = 1000*1000 / kTargetFrameRate;
+ const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ const nsecs_t workTimeUs = (now - startTime) / 1000;
+ const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs;
+ if (sleepDurationUs > 0) {
+ usleep(sleepDurationUs);
+ }
+ }
+
+ // If we've been asked to stop, send an event to signal the actual end of stream
+ EvsEvent event;
+ event.info(EvsEventType::STREAM_STOPPED);
+ auto result = mStream->notifyEvent(event);
+ if (!result.isOk()) {
+ ALOGE("Error delivering end of stream marker");
+ }
+
+ return;
+}
+
+
+void EvsCamera::fillTestFrame(const BufferDesc_1_1& buff) {
+ // Lock our output buffer for writing
+ uint32_t *pixels = nullptr;
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&buff.buffer.description);
+ GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+ mapper.lock(buff.buffer.nativeHandle,
+ GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+ android::Rect(pDesc->width, pDesc->height),
+ (void **) &pixels);
+
+ // If we failed to lock the pixel buffer, we're about to crash, but log it first
+ if (!pixels) {
+ ALOGE("Camera failed to gain access to image buffer for writing");
+ }
+
+ // Fill in the test pixels
+ for (unsigned row = 0; row < pDesc->height; row++) {
+ for (unsigned col = 0; col < pDesc->width; col++) {
+ // Index into the row to check the pixel at this column.
+ // We expect 0xFF in the LSB channel, a vertical gradient in the
+ // second channel, a horitzontal gradient in the third channel, and
+ // 0xFF in the MSB.
+ // The exception is the very first 32 bits which is used for the
+ // time varying frame signature to avoid getting fooled by a static image.
+ uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB
+ ((row & 0xFF) << 8) | // vertical gradient
+ ((col & 0xFF) << 16); // horizontal gradient
+ if ((row | col) == 0) {
+ static uint32_t sFrameTicker = 0;
+ expectedPixel = (sFrameTicker) & 0xFF;
+ sFrameTicker++;
+ }
+ pixels[col] = expectedPixel;
+ }
+ // Point to the next row
+ // NOTE: stride retrieved from gralloc is in units of pixels
+ pixels = pixels + pDesc->stride;
+ }
+
+ // Release our output buffer
+ mapper.unlock(buff.buffer.nativeHandle);
+}
+
+
+void EvsCamera::fillTestFrame(const BufferDesc_1_0& buff) {
+ BufferDesc_1_1 newBufDesc = {};
+ AHardwareBuffer_Desc desc = {
+ buff.width, // width
+ buff.height, // height
+ 1, // layers, always 1 for EVS
+ buff.format, // One of AHardwareBuffer_Format
+ buff.usage, // Combination of AHardwareBuffer_UsageFlags
+ buff.stride, // Row stride in pixels
+ 0, // Reserved
+ 0 // Reserved
+ };
+ memcpy(&desc, &newBufDesc.buffer.description, sizeof(desc));
+ newBufDesc.buffer.nativeHandle = buff.memHandle;
+ newBufDesc.pixelSize = buff.pixelSize;
+ newBufDesc.bufferId = buff.bufferId;
+
+ return fillTestFrame(newBufDesc);
+}
+
+
+void EvsCamera::returnBuffer(const uint32_t bufferId, const buffer_handle_t memHandle) {
+ std::lock_guard <std::mutex> lock(mAccessLock);
+
+ if (memHandle == nullptr) {
+ ALOGE("ignoring doneWithFrame called with null handle");
+ } else if (bufferId >= mBuffers.size()) {
+ ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)",
+ bufferId, mBuffers.size()-1);
+ } else if (!mBuffers[bufferId].inUse) {
+ ALOGE("ignoring doneWithFrame called on frame %d which is already free",
+ bufferId);
+ } else {
+ // Mark the frame as available
+ mBuffers[bufferId].inUse = false;
+ mFramesInUse--;
+
+ // If this frame's index is high in the array, try to move it down
+ // to improve locality after mFramesAllowed has been reduced.
+ if (bufferId >= mFramesAllowed) {
+ // Find an empty slot lower in the array (which should always exist in this case)
+ for (auto&& rec : mBuffers) {
+ if (rec.handle == nullptr) {
+ rec.handle = mBuffers[bufferId].handle;
+ mBuffers[bufferId].handle = nullptr;
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h
new file mode 100644
index 0000000..0982464
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -0,0 +1,128 @@
+/*
+ * 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_EVS_V1_1_EVSCAMERA_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERA_H
+
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <ui/GraphicBuffer.h>
+
+#include <thread>
+
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
+using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_0::CameraDesc;
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+// From EvsEnumerator.h
+class EvsEnumerator;
+
+
+class EvsCamera : public IEvsCamera {
+public:
+ // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+ Return<void> getCameraInfo(getCameraInfo_cb _hidl_cb) override;
+ Return<EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
+ Return<EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& stream) override;
+ Return<void> stopVideoStream() override;
+ Return<void> doneWithFrame(const BufferDesc_1_0& buffer) override;
+
+ Return<int32_t> getExtendedInfo(uint32_t opaqueIdentifier) override;
+ Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
+
+ // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+ Return<EvsResult> pauseVideoStream() override;
+ Return<EvsResult> resumeVideoStream() override;
+ Return<EvsResult> doneWithFrame_1_1(const BufferDesc_1_1& buffer) override;
+
+ // Implementation details
+ EvsCamera(const char *id);
+ virtual ~EvsCamera() override;
+ void forceShutdown(); // This gets called if another caller "steals" ownership of the camera
+
+ const CameraDesc& getDesc() { return mDescription; };
+
+ static const char kCameraName_Backup[];
+
+private:
+ // These three functions are expected to be called while mAccessLock is held
+ bool setAvailableFrames_Locked(unsigned bufferCount);
+ unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
+ unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
+
+ void generateFrames();
+ void fillTestFrame(const BufferDesc_1_0& buff);
+ void fillTestFrame(const BufferDesc_1_1& buff);
+ void returnBuffer(const uint32_t bufferId, const buffer_handle_t memHandle);
+
+ sp<EvsEnumerator> mEnumerator; // The enumerator object that created this camera
+
+ CameraDesc mDescription = {}; // The properties of this camera
+
+ std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+ uint32_t mWidth = 0; // Horizontal pixel count in the buffers
+ uint32_t mHeight = 0; // Vertical pixel count in the buffers
+ uint32_t mFormat = 0; // Values from android_pixel_format_t
+ uint64_t mUsage = 0; // Values from from Gralloc.h
+ uint32_t mStride = 0; // Bytes per line in the buffers
+
+ sp<IEvsCameraStream_1_1> mStream = nullptr; // The callback used to deliver each frame
+
+ struct BufferRecord {
+ buffer_handle_t handle;
+ bool inUse;
+
+ explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false) {};
+ };
+
+ std::vector <BufferRecord> mBuffers; // Graphics buffers to transfer images
+ unsigned mFramesAllowed; // How many buffers are we currently using
+ unsigned mFramesInUse; // How many buffers are currently outstanding
+
+ enum StreamStateValues {
+ STOPPED,
+ RUNNING,
+ STOPPING,
+ DEAD,
+ };
+ StreamStateValues mStreamState;
+
+ // Synchronization necessary to deconflict mCaptureThread from the main service thread
+ std::mutex mAccessLock;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERA_H
diff --git a/automotive/evs/1.1/default/EvsDisplay.cpp b/automotive/evs/1.1/default/EvsDisplay.cpp
new file mode 100644
index 0000000..74c099a
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsDisplay.cpp
@@ -0,0 +1,335 @@
+/*
+ * 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 "android.hardware.automotive.evs@1.1-service"
+
+#include "EvsDisplay.h"
+
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+EvsDisplay::EvsDisplay() {
+ ALOGD("EvsDisplay instantiated");
+
+ // Set up our self description
+ // NOTE: These are arbitrary values chosen for testing
+ mInfo.displayId = "Mock Display";
+ mInfo.vendorFlags = 3870;
+
+ // Assemble the buffer description we'll use for our render target
+ mBuffer.width = 320;
+ mBuffer.height = 240;
+ mBuffer.format = HAL_PIXEL_FORMAT_RGBA_8888;
+ mBuffer.usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
+ mBuffer.bufferId = 0x3870; // Arbitrary magic number for self recognition
+ mBuffer.pixelSize = 4;
+}
+
+
+EvsDisplay::~EvsDisplay() {
+ ALOGD("EvsDisplay being destroyed");
+ forceShutdown();
+}
+
+
+/**
+ * This gets called if another caller "steals" ownership of the display
+ */
+void EvsDisplay::forceShutdown()
+{
+ ALOGD("EvsDisplay forceShutdown");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // If the buffer isn't being held by a remote client, release it now as an
+ // optimization to release the resources more quickly than the destructor might
+ // get called.
+ if (mBuffer.memHandle) {
+ // Report if we're going away while a buffer is outstanding
+ if (mFrameBusy) {
+ ALOGE("EvsDisplay going down while client is holding a buffer");
+ }
+
+ // Drop the graphics buffer we've been using
+ GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ alloc.free(mBuffer.memHandle);
+ mBuffer.memHandle = nullptr;
+ }
+
+ // Put this object into an unrecoverable error state since somebody else
+ // is going to own the display now.
+ mRequestedState = DisplayState::DEAD;
+}
+
+
+/**
+ * Returns basic information about the EVS display provided by the system.
+ * See the description of the DisplayDesc structure for details.
+ */
+Return<void> EvsDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb) {
+ ALOGD("getDisplayInfo");
+
+ // Send back our self description
+ _hidl_cb(mInfo);
+ return Void();
+}
+
+
+/**
+ * Clients may set the display state to express their desired state.
+ * The HAL implementation must gracefully accept a request for any state
+ * while in any other state, although the response may be to ignore the request.
+ * The display is defined to start in the NOT_VISIBLE state upon initialization.
+ * The client is then expected to request the VISIBLE_ON_NEXT_FRAME state, and
+ * then begin providing video. When the display is no longer required, the client
+ * is expected to request the NOT_VISIBLE state after passing the last video frame.
+ */
+Return<EvsResult> EvsDisplay::setDisplayState(DisplayState state) {
+ ALOGD("setDisplayState");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mRequestedState == DisplayState::DEAD) {
+ // This object no longer owns the display -- it's been superceeded!
+ return EvsResult::OWNERSHIP_LOST;
+ }
+
+ // Ensure we recognize the requested state so we don't go off the rails
+ if (state < DisplayState::NUM_STATES) {
+ // Record the requested state
+ mRequestedState = state;
+ return EvsResult::OK;
+ }
+ else {
+ // Turn off the display if asked for an unrecognized state
+ mRequestedState = DisplayState::NOT_VISIBLE;
+ return EvsResult::INVALID_ARG;
+ }
+}
+
+
+/**
+ * The HAL implementation should report the actual current state, which might
+ * transiently differ from the most recently requested state. Note, however, that
+ * the logic responsible for changing display states should generally live above
+ * the device layer, making it undesirable for the HAL implementation to
+ * spontaneously change display states.
+ */
+Return<DisplayState> EvsDisplay::getDisplayState() {
+ ALOGD("getDisplayState");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ return mRequestedState;
+}
+
+
+/**
+ * This call returns a handle to a frame buffer associated with the display.
+ * This buffer may be locked and written to by software and/or GL. This buffer
+ * must be returned via a call to returnTargetBufferForDisplay() even if the
+ * display is no longer visible.
+ */
+// TODO: We need to know if/when our client dies so we can get the buffer back! (blocked b/31632518)
+Return<void> EvsDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb) {
+ ALOGD("getTargetBuffer");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mRequestedState == DisplayState::DEAD) {
+ ALOGE("Rejecting buffer request from object that lost ownership of the display.");
+ BufferDesc_1_0 nullBuff = {};
+ _hidl_cb(nullBuff);
+ return Void();
+ }
+
+ // If we don't already have a buffer, allocate one now
+ if (!mBuffer.memHandle) {
+ // Allocate the buffer that will hold our displayable image
+ buffer_handle_t handle = nullptr;
+ GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ status_t result = alloc.allocate(
+ mBuffer.width, mBuffer.height, mBuffer.format, 1, mBuffer.usage,
+ &handle, &mBuffer.stride, 0, "EvsDisplay");
+ if (result != NO_ERROR) {
+ ALOGE("Error %d allocating %d x %d graphics buffer",
+ result, mBuffer.width, mBuffer.height);
+ BufferDesc_1_0 nullBuff = {};
+ _hidl_cb(nullBuff);
+ return Void();
+ }
+ if (!handle) {
+ ALOGE("We didn't get a buffer handle back from the allocator");
+ BufferDesc_1_0 nullBuff = {};
+ _hidl_cb(nullBuff);
+ return Void();
+ }
+
+ mBuffer.memHandle = handle;
+ mFrameBusy = false;
+ ALOGD("Allocated new buffer %p with stride %u",
+ mBuffer.memHandle.getNativeHandle(), mBuffer.stride);
+ }
+
+ // Do we have a frame available?
+ if (mFrameBusy) {
+ // This means either we have a 2nd client trying to compete for buffers
+ // (an unsupported mode of operation) or else the client hasn't returned
+ // a previously issued buffer yet (they're behaving badly).
+ // NOTE: We have to make the callback even if we have nothing to provide
+ ALOGE("getTargetBuffer called while no buffers available.");
+ BufferDesc_1_0 nullBuff = {};
+ _hidl_cb(nullBuff);
+ return Void();
+ } else {
+ // Mark our buffer as busy
+ mFrameBusy = true;
+
+ // Send the buffer to the client
+ ALOGD("Providing display buffer handle %p as id %d",
+ mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId);
+ _hidl_cb(mBuffer);
+ return Void();
+ }
+}
+
+
+/**
+ * This call tells the display that the buffer is ready for display.
+ * The buffer is no longer valid for use by the client after this call.
+ */
+Return<EvsResult> EvsDisplay::returnTargetBufferForDisplayImpl(const uint32_t bufferId, const buffer_handle_t memHandle) {
+ ALOGD("returnTargetBufferForDisplay %p", memHandle);
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // Nobody should call us with a null handle
+ if (!memHandle) {
+ ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n");
+ return EvsResult::INVALID_ARG;
+ }
+ if (bufferId != mBuffer.bufferId) {
+ ALOGE ("Got an unrecognized frame returned.\n");
+ return EvsResult::INVALID_ARG;
+ }
+ if (!mFrameBusy) {
+ ALOGE ("A frame was returned with no outstanding frames.\n");
+ return EvsResult::BUFFER_NOT_AVAILABLE;
+ }
+
+ mFrameBusy = false;
+
+ // If we've been displaced by another owner of the display, then we can't do anything else
+ if (mRequestedState == DisplayState::DEAD) {
+ return EvsResult::OWNERSHIP_LOST;
+ }
+
+ // If we were waiting for a new frame, this is it!
+ if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) {
+ mRequestedState = DisplayState::VISIBLE;
+ }
+
+ // Validate we're in an expected state
+ if (mRequestedState != DisplayState::VISIBLE) {
+ // We shouldn't get frames back when we're not visible.
+ ALOGE ("Got an unexpected frame returned while not visible - ignoring.\n");
+ } else {
+ // This is where the buffer would be made visible.
+ // For now we simply validate it has the data we expect in it by reading it back
+
+ // Lock our display buffer for reading
+ uint32_t* pixels = nullptr;
+ GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+ mapper.lock(mBuffer.memHandle,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
+ android::Rect(mBuffer.width, mBuffer.height),
+ (void **)&pixels);
+
+ // If we failed to lock the pixel buffer, we're about to crash, but log it first
+ if (!pixels) {
+ ALOGE("Display failed to gain access to image buffer for reading");
+ }
+
+ // Check the test pixels
+ bool frameLooksGood = true;
+ for (unsigned row = 0; row < mBuffer.height; row++) {
+ for (unsigned col = 0; col < mBuffer.width; col++) {
+ // Index into the row to check the pixel at this column.
+ // We expect 0xFF in the LSB channel, a vertical gradient in the
+ // second channel, a horitzontal gradient in the third channel, and
+ // 0xFF in the MSB.
+ // The exception is the very first 32 bits which is used for the
+ // time varying frame signature to avoid getting fooled by a static image.
+ uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB
+ ((row & 0xFF) << 8) | // vertical gradient
+ ((col & 0xFF) << 16); // horizontal gradient
+ if ((row | col) == 0) {
+ // we'll check the "uniqueness" of the frame signature below
+ continue;
+ }
+ // Walk across this row (we'll step rows below)
+ uint32_t receivedPixel = pixels[col];
+ if (receivedPixel != expectedPixel) {
+ ALOGE("Pixel check mismatch in frame buffer");
+ frameLooksGood = false;
+ break;
+ }
+ }
+
+ if (!frameLooksGood) {
+ break;
+ }
+
+ // Point to the next row (NOTE: gralloc reports stride in units of pixels)
+ pixels = pixels + mBuffer.stride;
+ }
+
+ // Ensure we don't see the same buffer twice without it being rewritten
+ static uint32_t prevSignature = ~0;
+ uint32_t signature = pixels[0] & 0xFF;
+ if (prevSignature == signature) {
+ frameLooksGood = false;
+ ALOGE("Duplicate, likely stale frame buffer detected");
+ }
+
+
+ // Release our output buffer
+ mapper.unlock(mBuffer.memHandle);
+
+ if (!frameLooksGood) {
+ return EvsResult::UNDERLYING_SERVICE_ERROR;
+ }
+ }
+
+ return EvsResult::OK;
+}
+
+
+Return<EvsResult> EvsDisplay::returnTargetBufferForDisplay(const BufferDesc_1_0& buffer) {
+ return returnTargetBufferForDisplayImpl(buffer.bufferId, buffer.memHandle);
+}
+
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/evs/1.1/default/EvsDisplay.h b/automotive/evs/1.1/default/EvsDisplay.h
new file mode 100644
index 0000000..2a56535
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsDisplay.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H
+
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <ui/GraphicBuffer.h>
+
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
+using ::android::hardware::automotive::evs::V1_0::DisplayState;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+class EvsDisplay : public IEvsDisplay {
+public:
+ // Methods from ::android::hardware::automotive::evs::V1_0::IEvsDisplay follow.
+ Return<void> getDisplayInfo(getDisplayInfo_cb _hidl_cb) override;
+ Return<EvsResult> setDisplayState(DisplayState state) override;
+ Return<DisplayState> getDisplayState() override;
+ Return<void> getTargetBuffer(getTargetBuffer_cb _hidl_cb) override;
+ Return<EvsResult> returnTargetBufferForDisplay(const BufferDesc_1_0& buffer) override;
+
+
+ // Implementation details
+ EvsDisplay();
+ virtual ~EvsDisplay() override;
+
+ void forceShutdown(); // This gets called if another caller "steals" ownership of the display
+ Return<EvsResult> returnTargetBufferForDisplayImpl(const uint32_t bufferId,
+ const buffer_handle_t memHandle);
+
+private:
+ DisplayDesc mInfo = {};
+ BufferDesc_1_0 mBuffer = {}; // A graphics buffer into which we'll store images
+
+ bool mFrameBusy = false; // A flag telling us our buffer is in use
+ DisplayState mRequestedState = DisplayState::NOT_VISIBLE;
+
+ std::mutex mAccessLock;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
new file mode 100644
index 0000000..b324907
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -0,0 +1,217 @@
+/*
+ * 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 "android.hardware.automotive.evs@1.1-service"
+
+#include "EvsEnumerator.h"
+#include "EvsCamera.h"
+#include "EvsDisplay.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+// NOTE: All members values are static so that all clients operate on the same state
+// That is to say, this is effectively a singleton despite the fact that HIDL
+// constructs a new instance for each client.
+std::list<EvsEnumerator::CameraRecord> EvsEnumerator::sCameraList;
+wp<EvsDisplay> EvsEnumerator::sActiveDisplay;
+
+
+EvsEnumerator::EvsEnumerator() {
+ ALOGD("EvsEnumerator created");
+
+ // Add sample camera data to our list of cameras
+ // In a real driver, this would be expected to can the available hardware
+ sCameraList.emplace_back(EvsCamera::kCameraName_Backup);
+ sCameraList.emplace_back("LaneView");
+ sCameraList.emplace_back("right turn");
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
+Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) {
+ ALOGD("getCameraList");
+
+ const unsigned numCameras = sCameraList.size();
+
+ // Build up a packed array of CameraDesc for return
+ // NOTE: Only has to live until the callback returns
+ std::vector<CameraDesc_1_0> descriptions;
+ descriptions.reserve(numCameras);
+ for (const auto& cam : sCameraList) {
+ descriptions.push_back( cam.desc );
+ }
+
+ // Encapsulate our camera descriptions in the HIDL vec type
+ hidl_vec<CameraDesc_1_0> hidlCameras(descriptions);
+
+ // Send back the results
+ ALOGD("reporting %zu cameras available", hidlCameras.size());
+ _hidl_cb(hidlCameras);
+
+ // HIDL convention says we return Void if we sent our result back via callback
+ return Void();
+}
+
+
+Return<sp<IEvsCamera_1_0>> EvsEnumerator::openCamera(const hidl_string& cameraId) {
+ ALOGD("openCamera");
+
+ // Find the named camera
+ CameraRecord *pRecord = nullptr;
+ for (auto &&cam : sCameraList) {
+ if (cam.desc.cameraId == cameraId) {
+ // Found a match!
+ pRecord = &cam;
+ break;
+ }
+ }
+
+ // Is this a recognized camera id?
+ if (!pRecord) {
+ ALOGE("Requested camera %s not found", cameraId.c_str());
+ return nullptr;
+ }
+
+ // Has this camera already been instantiated by another caller?
+ sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+ if (pActiveCamera != nullptr) {
+ ALOGW("Killing previous camera because of new caller");
+ closeCamera(pActiveCamera);
+ }
+
+ // Construct a camera instance for the caller
+ pActiveCamera = new EvsCamera(cameraId.c_str());
+ pRecord->activeInstance = pActiveCamera;
+ if (pActiveCamera == nullptr) {
+ ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
+ }
+
+ return pActiveCamera;
+}
+
+
+Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera_1_0>& pCamera) {
+ ALOGD("closeCamera");
+
+ auto pCamera_1_1 = IEvsCamera_1_1::castFrom(pCamera).withDefault(nullptr);
+ if (pCamera_1_1 == nullptr) {
+ ALOGE("Ignoring call to closeCamera with null camera ptr");
+ return Void();
+ }
+
+ // Get the camera id so we can find it in our list
+ std::string cameraId;
+ pCamera_1_1->getCameraInfo([&cameraId](CameraDesc desc) {
+ cameraId = desc.cameraId;
+ }
+ );
+
+ // Find the named camera
+ CameraRecord *pRecord = nullptr;
+ for (auto &&cam : sCameraList) {
+ if (cam.desc.cameraId == cameraId) {
+ // Found a match!
+ pRecord = &cam;
+ break;
+ }
+ }
+
+ // Is the display being destroyed actually the one we think is active?
+ if (!pRecord) {
+ ALOGE("Asked to close a camera who's name isn't recognized");
+ } else {
+ sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+
+ if (pActiveCamera == nullptr) {
+ ALOGE("Somehow a camera is being destroyed when the enumerator didn't know one existed");
+ } else if (pActiveCamera != pCamera_1_1) {
+ // This can happen if the camera was aggressively reopened, orphaning this previous instance
+ ALOGW("Ignoring close of previously orphaned camera - why did a client steal?");
+ } else {
+ // Drop the active camera
+ pActiveCamera->forceShutdown();
+ pRecord->activeInstance = nullptr;
+ }
+ }
+
+ return Void();
+}
+
+
+Return<sp<IEvsDisplay>> EvsEnumerator::openDisplay() {
+ ALOGD("openDisplay");
+
+ // If we already have a display active, then we need to shut it down so we can
+ // give exclusive access to the new caller.
+ sp<EvsDisplay> pActiveDisplay = sActiveDisplay.promote();
+ if (pActiveDisplay != nullptr) {
+ ALOGW("Killing previous display because of new caller");
+ closeDisplay(pActiveDisplay);
+ }
+
+ // Create a new display interface and return it
+ pActiveDisplay = new EvsDisplay();
+ sActiveDisplay = pActiveDisplay;
+
+ ALOGD("Returning new EvsDisplay object %p", pActiveDisplay.get());
+ return pActiveDisplay;
+}
+
+
+Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay>& pDisplay) {
+ ALOGD("closeDisplay");
+
+ // Do we still have a display object we think should be active?
+ sp<EvsDisplay> pActiveDisplay = sActiveDisplay.promote();
+ if (pActiveDisplay == nullptr) {
+ ALOGE("Somehow a display is being destroyed when the enumerator didn't know one existed");
+ } else if (sActiveDisplay != pDisplay) {
+ ALOGW("Ignoring close of previously orphaned display - why did a client steal?");
+ } else {
+ // Drop the active display
+ pActiveDisplay->forceShutdown();
+ sActiveDisplay = nullptr;
+ }
+
+ return Void();
+}
+
+
+Return<DisplayState> EvsEnumerator::getDisplayState() {
+ ALOGD("getDisplayState");
+
+ // Do we still have a display object we think should be active?
+ sp<IEvsDisplay> pActiveDisplay = sActiveDisplay.promote();
+ if (pActiveDisplay != nullptr) {
+ return pActiveDisplay->getDisplayState();
+ } else {
+ return DisplayState::NOT_OPEN;
+ }
+}
+
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h
new file mode 100644
index 0000000..11c2170
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsEnumerator.h
@@ -0,0 +1,81 @@
+/*
+ * 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_EVS_V1_1_EVSCAMERAENUMERATOR_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
+
+#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+
+#include <list>
+
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using ::android::hardware::automotive::evs::V1_0::DisplayState;
+using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
+using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+class EvsCamera; // from EvsCamera.h
+class EvsDisplay; // from EvsDisplay.h
+
+
+class EvsEnumerator : public IEvsEnumerator {
+public:
+ // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
+ Return<void> getCameraList(getCameraList_cb _hidl_cb) override;
+ Return<sp<IEvsCamera_1_0>> openCamera(const hidl_string& cameraId) override;
+ Return<void> closeCamera(const ::android::sp<IEvsCamera_1_0>& carCamera) override;
+ Return<sp<IEvsDisplay>> openDisplay() override;
+ Return<void> closeDisplay(const ::android::sp<IEvsDisplay>& display) override;
+ Return<DisplayState> getDisplayState() override;
+
+ // Implementation details
+ EvsEnumerator();
+
+private:
+ // NOTE: All members values are static so that all clients operate on the same state
+ // That is to say, this is effectively a singleton despite the fact that HIDL
+ // constructs a new instance for each client.
+ struct CameraRecord {
+ CameraDesc_1_0 desc;
+ wp<EvsCamera> activeInstance;
+
+ CameraRecord(const char *cameraId) : desc() { desc.cameraId = cameraId; }
+ };
+ static std::list<CameraRecord> sCameraList;
+
+ static wp<EvsDisplay> sActiveDisplay; // Weak pointer. Object destructs if client dies.
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
diff --git a/automotive/evs/1.1/default/ServiceNames.h b/automotive/evs/1.1/default/ServiceNames.h
new file mode 100644
index 0000000..1178da5
--- /dev/null
+++ b/automotive/evs/1.1/default/ServiceNames.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const static char kEnumeratorServiceName[] = "EvsEnumeratorHw";
diff --git a/automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc b/automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc
new file mode 100644
index 0000000..284b3fd
--- /dev/null
+++ b/automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc
@@ -0,0 +1,5 @@
+service vendor.evs-hal-mock /vendor/bin/hw/android.hardware.automotive.evs@1.1-service
+ class hal
+ user automotive_evs
+ group automotive_evs
+ disabled
diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp
new file mode 100644
index 0000000..128a14a
--- /dev/null
+++ b/automotive/evs/1.1/default/service.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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 "android.hardware.automotive.evs@1.1-service"
+
+#include <unistd.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "ServiceNames.h"
+#include "EvsEnumerator.h"
+#include "EvsDisplay.h"
+
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::automotive::evs::V1_0::IEvsEnumerator;
+using android::hardware::automotive::evs::V1_0::IEvsDisplay;
+
+// The namespace in which all our implementation code lives
+using namespace android::hardware::automotive::evs::V1_1::implementation;
+using namespace android;
+
+
+int main() {
+ ALOGI("EVS Hardware Enumerator service is starting");
+ android::sp<IEvsEnumerator> service = new EvsEnumerator();
+
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ // Register our service -- if somebody is already registered by our name,
+ // they will be killed (their thread pool will throw an exception).
+ status_t status = service->registerAsService(kEnumeratorServiceName);
+ if (status == OK) {
+ ALOGD("%s is ready.", kEnumeratorServiceName);
+ joinRpcThreadpool();
+ } else {
+ ALOGE("Could not register service %s (%d).", kEnumeratorServiceName, status);
+ }
+
+ // In normal operation, we don't expect the thread pool to exit
+ ALOGE("EVS Hardware Enumerator is shutting down");
+ return 1;
+}
diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal
new file mode 100644
index 0000000..ff6ab4e
--- /dev/null
+++ b/automotive/evs/1.1/types.hal
@@ -0,0 +1,84 @@
+/*
+ * 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.automotive.evs@1.1;
+
+import @1.0::CameraDesc;
+import @1.0::DisplayDesc;
+import @1.0::DisplayState;
+import @1.0::EvsResult;
+import android.hardware.graphics.common@1.2::HardwareBuffer;
+
+/**
+ * Structure representing an image buffer through our APIs
+ *
+ * In addition to the handle to the graphics memory, we need to retain
+ * the properties of the buffer for easy reference and reconstruction of
+ * an ANativeWindowBuffer object on the remote side of API calls.
+ * (Not least because OpenGL expect an ANativeWindowBuffer* for us as a
+ * texture via eglCreateImageKHR().
+ */
+struct BufferDesc {
+ /**
+ * HIDL counterpart of `AHardwareBuffer_Desc`. Please see
+ * hardware/interfaces/graphics/common/1.2/types.hal for more details.
+ */
+ HardwareBuffer buffer;
+ /**
+ * The size of a pixel in the units of bytes
+ */
+ uint32_t pixelSize;
+ /**
+ * Opaque value from driver
+ */
+ uint32_t bufferId;
+};
+
+/**
+ * EVS event types
+ */
+enum EvsEventType : uint32_t {
+ /**
+ * Video stream is started
+ */
+ STREAM_STARTED = 0,
+ /**
+ * Video stream is stopped
+ */
+ STREAM_STOPPED,
+ /**
+ * Video frame is dropped
+ */
+ FRAME_DROPPED,
+ /**
+ * Timeout happens
+ */
+ TIMEOUT,
+};
+
+/**
+ * EVS event definition
+ */
+safe_union EvsEvent {
+ /**
+ * A buffer descriptor of an image frame
+ */
+ BufferDesc buffer;
+ /**
+ * General streaming events
+ */
+ EvsEventType info;
+};
diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..55c50a4
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/Android.bp
@@ -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.
+//
+
+cc_test {
+ name: "VtsHalEvsV1_1TargetTest",
+ srcs: [
+ "FrameHandler.cpp",
+ "VtsHalEvsV1_1TargetTest.cpp",
+ ],
+ defaults: ["VtsHalTargetTestDefaults"],
+ shared_libs: [
+ "libui",
+ ],
+ 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",
+ ],
+ test_suites: ["general-tests"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
new file mode 100644
index 0000000..b7c7f21
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
@@ -0,0 +1,340 @@
+/*
+ * 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 "VtsHalEvsTest"
+
+#include "FrameHandler.h"
+#include "FormatConvert.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <android/log.h>
+#include <cutils/native_handle.h>
+#include <ui/GraphicBuffer.h>
+
+FrameHandler::FrameHandler(android::sp <IEvsCamera> pCamera, CameraDesc cameraInfo,
+ android::sp <IEvsDisplay> pDisplay,
+ BufferControlFlag mode) :
+ mCamera(pCamera),
+ mCameraInfo(cameraInfo),
+ mDisplay(pDisplay),
+ mReturnMode(mode) {
+ // Nothing but member initialization here...
+}
+
+
+void FrameHandler::shutdown()
+{
+ // Make sure we're not still streaming
+ blockingStopStream();
+
+ // At this point, the receiver thread is no longer running, so we can safely drop
+ // our remote object references so they can be freed
+ mCamera = nullptr;
+ mDisplay = nullptr;
+}
+
+
+bool FrameHandler::startStream() {
+ // Tell the camera to start streaming
+ Return<EvsResult> result = mCamera->startVideoStream(this);
+ if (result != EvsResult::OK) {
+ return false;
+ }
+
+ // Mark ourselves as running
+ mLock.lock();
+ mRunning = true;
+ mLock.unlock();
+
+ return true;
+}
+
+
+void FrameHandler::asyncStopStream() {
+ // Tell the camera to stop streaming.
+ // This will result in a null frame being delivered when the stream actually stops.
+ mCamera->stopVideoStream();
+}
+
+
+void FrameHandler::blockingStopStream() {
+ // Tell the stream to stop
+ asyncStopStream();
+
+ // Wait until the stream has actually stopped
+ std::unique_lock<std::mutex> lock(mLock);
+ if (mRunning) {
+ mSignal.wait(lock, [this]() { return !mRunning; });
+ }
+}
+
+
+bool FrameHandler::returnHeldBuffer() {
+ std::unique_lock<std::mutex> lock(mLock);
+
+ // Return the oldest buffer we're holding
+ if (mHeldBuffers.empty()) {
+ // No buffers are currently held
+ return false;
+ }
+
+ BufferDesc_1_1 buffer = mHeldBuffers.front();
+ mHeldBuffers.pop();
+ mCamera->doneWithFrame_1_1(buffer);
+
+ return true;
+}
+
+
+bool FrameHandler::isRunning() {
+ std::unique_lock<std::mutex> lock(mLock);
+ return mRunning;
+}
+
+
+void FrameHandler::waitForFrameCount(unsigned frameCount) {
+ // Wait until we've seen at least the requested number of frames (could be more)
+ std::unique_lock<std::mutex> lock(mLock);
+ mSignal.wait(lock, [this, frameCount](){ return mFramesReceived >= frameCount; });
+}
+
+
+void FrameHandler::getFramesCounters(unsigned* received, unsigned* displayed) {
+ std::unique_lock<std::mutex> lock(mLock);
+
+ if (received) {
+ *received = mFramesReceived;
+ }
+ if (displayed) {
+ *displayed = mFramesDisplayed;
+ }
+}
+
+
+Return<void> FrameHandler::deliverFrame(const BufferDesc_1_0& bufferArg) {
+ ALOGW("A frame delivered via v1.0 method is rejected.");
+ mCamera->doneWithFrame(bufferArg);
+ return Void();
+}
+
+
+Return<void> FrameHandler::notifyEvent(const EvsEvent& event) {
+ // Local flag we use to keep track of when the stream is stopping
+ bool timeToStop = false;
+
+ auto type = event.getDiscriminator();
+ if (type == EvsEvent::hidl_discriminator::info) {
+ if (event.info() == EvsEventType::STREAM_STOPPED) {
+ // Signal that the last frame has been received and the stream is stopped
+ timeToStop = true;
+ } else {
+ ALOGD("Received an event 0x%X", event.info());
+ }
+ } else {
+ auto bufDesc = event.buffer();
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description);
+ ALOGD("Received a frame from the camera (%p)",
+ bufDesc.buffer.nativeHandle.getNativeHandle());
+
+ // Store a dimension of a received frame.
+ mFrameWidth = pDesc->width;
+ mFrameHeight = pDesc->height;
+
+ // If we were given an opened display at construction time, then send the received
+ // image back down the camera.
+ if (mDisplay.get()) {
+ // Get the output buffer we'll use to display the imagery
+ BufferDesc_1_0 tgtBuffer = {};
+ mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
+ tgtBuffer = buff;
+ }
+ );
+
+ if (tgtBuffer.memHandle == nullptr) {
+ printf("Didn't get target buffer - frame lost\n");
+ ALOGE("Didn't get requested output buffer -- skipping this frame.");
+ } else {
+ // Copy the contents of the of buffer.memHandle into tgtBuffer
+ copyBufferContents(tgtBuffer, bufDesc);
+
+ // Send the target buffer back for display
+ Return<EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
+ if (!result.isOk()) {
+ printf("HIDL error on display buffer (%s)- frame lost\n",
+ result.description().c_str());
+ ALOGE("Error making the remote function call. HIDL said %s",
+ result.description().c_str());
+ } else if (result != EvsResult::OK) {
+ printf("Display reported error - frame lost\n");
+ ALOGE("We encountered error %d when returning a buffer to the display!",
+ (EvsResult) result);
+ } else {
+ // Everything looks good!
+ // Keep track so tests or watch dogs can monitor progress
+ mLock.lock();
+ mFramesDisplayed++;
+ mLock.unlock();
+ }
+ }
+ }
+
+
+ switch (mReturnMode) {
+ case eAutoReturn:
+ // Send the camera buffer back now that the client has seen it
+ ALOGD("Calling doneWithFrame");
+ // TODO: Why is it that we get a HIDL crash if we pass back the cloned buffer?
+ mCamera->doneWithFrame_1_1(bufDesc);
+ break;
+ case eNoAutoReturn:
+ // Hang onto the buffer handle for now -- the client will return it explicitly later
+ mHeldBuffers.push(bufDesc);
+ }
+
+
+ ALOGD("Frame handling complete");
+ }
+
+
+ // Update our received frame count and notify anybody who cares that things have changed
+ mLock.lock();
+ if (timeToStop) {
+ mRunning = false;
+ } else {
+ mFramesReceived++;
+ }
+ mLock.unlock();
+ mSignal.notify_all();
+
+ return Void();
+}
+
+
+bool FrameHandler::copyBufferContents(const BufferDesc_1_0& tgtBuffer,
+ const BufferDesc_1_1& srcBuffer) {
+ bool success = true;
+ const AHardwareBuffer_Desc* pSrcDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&srcBuffer.buffer.description);
+
+ // Make sure we don't run off the end of either buffer
+ const unsigned width = std::min(tgtBuffer.width,
+ pSrcDesc->width);
+ const unsigned height = std::min(tgtBuffer.height,
+ pSrcDesc->height);
+
+ sp<android::GraphicBuffer> tgt = new android::GraphicBuffer(tgtBuffer.memHandle,
+ android::GraphicBuffer::CLONE_HANDLE,
+ tgtBuffer.width,
+ tgtBuffer.height,
+ tgtBuffer.format,
+ 1,
+ tgtBuffer.usage,
+ tgtBuffer.stride);
+ sp<android::GraphicBuffer> src = new android::GraphicBuffer(srcBuffer.buffer.nativeHandle,
+ android::GraphicBuffer::CLONE_HANDLE,
+ pSrcDesc->width,
+ pSrcDesc->height,
+ pSrcDesc->format,
+ pSrcDesc->layers,
+ pSrcDesc->usage,
+ pSrcDesc->stride);
+
+ // Lock our source buffer for reading (current expectation are for this to be NV21 format)
+ uint8_t* srcPixels = nullptr;
+ src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
+
+ // Lock our target buffer for writing (should be either RGBA8888 or BGRA8888 format)
+ uint32_t* tgtPixels = nullptr;
+ tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
+
+ if (srcPixels && tgtPixels) {
+ using namespace ::android::hardware::automotive::evs::common;
+ if (tgtBuffer.format == HAL_PIXEL_FORMAT_RGBA_8888) {
+ if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21
+ Utils::copyNV21toRGB32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
+ } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
+ Utils::copyYV12toRGB32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
+ } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
+ Utils::copyYUYVtoRGB32(width, height,
+ srcPixels, pSrcDesc->stride,
+ tgtPixels, tgtBuffer.stride);
+ } else if (pSrcDesc->format == tgtBuffer.format) { // 32bit RGBA
+ Utils::copyMatchedInterleavedFormats(width, height,
+ srcPixels, pSrcDesc->stride,
+ tgtPixels, tgtBuffer.stride,
+ tgtBuffer.pixelSize);
+ } else {
+ ALOGE("Camera buffer format is not supported");
+ success = false;
+ }
+ } else if (tgtBuffer.format == HAL_PIXEL_FORMAT_BGRA_8888) {
+ if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21
+ Utils::copyNV21toBGR32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
+ } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
+ Utils::copyYV12toBGR32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
+ } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
+ Utils::copyYUYVtoBGR32(width, height,
+ srcPixels, pSrcDesc->stride,
+ tgtPixels, tgtBuffer.stride);
+ } else if (pSrcDesc->format == tgtBuffer.format) { // 32bit RGBA
+ Utils::copyMatchedInterleavedFormats(width, height,
+ srcPixels, pSrcDesc->stride,
+ tgtPixels, tgtBuffer.stride,
+ tgtBuffer.pixelSize);
+ } else {
+ ALOGE("Camera buffer format is not supported");
+ success = false;
+ }
+ } else {
+ // We always expect 32 bit RGB for the display output for now. Is there a need for 565?
+ ALOGE("Diplay buffer is always expected to be 32bit RGBA");
+ success = false;
+ }
+ } else {
+ ALOGE("Failed to lock buffer contents for contents transfer");
+ success = false;
+ }
+
+ if (srcPixels) {
+ src->unlock();
+ }
+ if (tgtPixels) {
+ tgt->unlock();
+ }
+
+ return success;
+}
+
+void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) {
+ if (width) {
+ *width = mFrameWidth;
+ }
+
+ if (height) {
+ *height = mFrameHeight;
+ }
+}
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h
new file mode 100644
index 0000000..49fa736
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.h
@@ -0,0 +1,102 @@
+/*
+ * 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 EVS_VTS_FRAMEHANDLER_H
+#define EVS_VTS_FRAMEHANDLER_H
+
+#include <queue>
+
+#include <FrameHandler.h>
+
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
+using ::android::sp;
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+
+
+/*
+ * FrameHandler:
+ * This class can be used to receive camera imagery from an IEvsCamera implementation. Given an
+ * IEvsDisplay instance at startup, it will forward the received imagery to the display,
+ * providing a trivial implementation of a rear vew camera type application.
+ * Note that the video frames are delivered on a background thread, while the control interface
+ * is actuated from the applications foreground thread.
+ */
+class FrameHandler : public IEvsCameraStream {
+public:
+ enum BufferControlFlag {
+ eAutoReturn,
+ eNoAutoReturn,
+ };
+
+ FrameHandler(android::sp <IEvsCamera> pCamera, CameraDesc cameraInfo,
+ android::sp <IEvsDisplay> pDisplay = nullptr,
+ BufferControlFlag mode = eAutoReturn);
+ void shutdown();
+
+ bool startStream();
+ void asyncStopStream();
+ void blockingStopStream();
+
+ bool returnHeldBuffer();
+
+ bool isRunning();
+
+ void waitForFrameCount(unsigned frameCount);
+ void getFramesCounters(unsigned* received, unsigned* displayed);
+ void getFrameDimension(unsigned* width, unsigned* height);
+
+private:
+ // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
+ Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
+ Return<void> notifyEvent(const EvsEvent& event) override;
+
+ // Local implementation details
+ bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer);
+
+ // Values initialized as startup
+ android::sp <IEvsCamera> mCamera;
+ CameraDesc mCameraInfo;
+ android::sp <IEvsDisplay> mDisplay;
+ BufferControlFlag mReturnMode;
+
+ // Since we get frames delivered to us asynchronously via the IEvsCameraStream interface,
+ // we need to protect all member variables that may be modified while we're streaming
+ // (ie: those below)
+ std::mutex mLock;
+ std::condition_variable mSignal;
+
+ std::queue<BufferDesc_1_1> mHeldBuffers;
+ bool mRunning = false;
+ unsigned mFramesReceived = 0; // Simple counter -- rolls over eventually!
+ unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually!
+ unsigned mFrameWidth = 0;
+ unsigned mFrameHeight = 0;
+};
+
+
+#endif //EVS_VTS_FRAMEHANDLER_H
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
new file mode 100644
index 0000000..4f7082a
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -0,0 +1,526 @@
+/*
+ * 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 "VtsHalEvsTest"
+
+
+// Note: We have't got a great way to indicate which target
+// should be tested, so we'll leave the interface served by the
+// default (mock) EVS driver here for easy reference. All
+// actual EVS drivers should serve on the EvsEnumeratorHw name,
+// however, so the code is checked in that way.
+//const static char kEnumeratorName[] = "EvsEnumeratorHw-Mock";
+const static char kEnumeratorName[] = "EvsEnumeratorHw";
+
+
+// These values are called out in the EVS design doc (as of Mar 8, 2017)
+static const int kMaxStreamStartMilliseconds = 500;
+static const int kMinimumFramesPerSecond = 10;
+
+static const int kSecondsToMilliseconds = 1000;
+static const int kMillisecondsToMicroseconds = 1000;
+static const float kNanoToMilliseconds = 0.000001f;
+static const float kNanoToSeconds = 0.000000001f;
+
+
+#include "FrameHandler.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/log.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
+using ::android::hardware::automotive::evs::V1_0::DisplayState;
+using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
+using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+
+// Test environment for Evs HIDL HAL.
+class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static EvsHidlEnvironment* Instance() {
+ static EvsHidlEnvironment* instance = new EvsHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<IEvsEnumerator>(); }
+
+ private:
+ EvsHidlEnvironment() {}
+};
+
+// The main test class for EVS
+class EvsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+public:
+ virtual void SetUp() override {
+ // Make sure we can connect to the enumerator
+ string service_name =
+ EvsHidlEnvironment::Instance()->getServiceName<IEvsEnumerator>(kEnumeratorName);
+ pEnumerator = getService<IEvsEnumerator>(service_name);
+ ASSERT_NE(pEnumerator.get(), nullptr);
+
+ mIsHwModule = !service_name.compare(kEnumeratorName);
+ }
+
+ virtual void TearDown() override {}
+
+protected:
+ void loadCameraList() {
+ // SetUp() must run first!
+ assert(pEnumerator != nullptr);
+
+ // Get the camera list
+ pEnumerator->getCameraList([this](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.cameraId.c_str());
+ cameraInfo.push_back(cam);
+ }
+ }
+ );
+
+ // We insist on at least one camera for EVS to pass any camera tests
+ ASSERT_GE(cameraInfo.size(), 1u);
+ }
+
+ sp<IEvsEnumerator> pEnumerator; // Every test needs access to the service
+ std::vector <CameraDesc> cameraInfo; // Empty unless/until loadCameraList() is called
+ bool mIsHwModule; // boolean to tell current module under testing
+ // is HW module implementation.
+};
+
+
+// Test cases, their implementations, and corresponding requirements are
+// documented at go/aae-evs-public-api-test.
+
+/*
+ * CameraOpenClean:
+ * Opens each camera reported by the enumerator and then explicitly closes it via a
+ * call to closeCamera. Then repeats the test to ensure all cameras can be reopened.
+ */
+TEST_F(EvsHidlTest, CameraOpenClean) {
+ ALOGI("Starting CameraOpenClean test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Open and close each camera twice
+ for (auto&& cam: cameraInfo) {
+ for (int pass = 0; pass < 2; pass++) {
+ sp<IEvsCamera_1_1> pCam =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam, nullptr);
+
+ // Verify that this camera self-identifies correctly
+ pCam->getCameraInfo([&cam](CameraDesc desc) {
+ ALOGD("Found camera %s", desc.cameraId.c_str());
+ EXPECT_EQ(cam.cameraId, desc.cameraId);
+ }
+ );
+
+ // Explicitly close the camera so resources are released right away
+ pEnumerator->closeCamera(pCam);
+ }
+ }
+}
+
+
+/*
+ * CameraOpenAggressive:
+ * Opens each camera reported by the enumerator twice in a row without an intervening closeCamera
+ * call. This ensures that the intended "aggressive open" behavior works. This is necessary for
+ * the system to be tolerant of shutdown/restart race conditions.
+ */
+TEST_F(EvsHidlTest, CameraOpenAggressive) {
+ ALOGI("Starting CameraOpenAggressive test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Open and close each camera twice
+ for (auto&& cam: cameraInfo) {
+ sp<IEvsCamera_1_1> pCam =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam, nullptr);
+
+ // Verify that this camera self-identifies correctly
+ pCam->getCameraInfo([&cam](CameraDesc desc) {
+ ALOGD("Found camera %s", desc.cameraId.c_str());
+ EXPECT_EQ(cam.cameraId, desc.cameraId);
+ }
+ );
+
+ sp<IEvsCamera_1_1> pCam2 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam, pCam2);
+ ASSERT_NE(pCam2, nullptr);
+
+ Return<EvsResult> result = pCam->setMaxFramesInFlight(2);
+ if (mIsHwModule) {
+ // Verify that the old camera rejects calls via HW module.
+ EXPECT_EQ(EvsResult::OWNERSHIP_LOST, EvsResult(result));
+ } else {
+ // default implementation supports multiple clients.
+ EXPECT_EQ(EvsResult::OK, EvsResult(result));
+ }
+
+ // Close the superceded camera
+ pEnumerator->closeCamera(pCam);
+
+ // Verify that the second camera instance self-identifies correctly
+ pCam2->getCameraInfo([&cam](CameraDesc desc) {
+ ALOGD("Found camera %s", desc.cameraId.c_str());
+ EXPECT_EQ(cam.cameraId, desc.cameraId);
+ }
+ );
+
+ // Close the second camera instance
+ pEnumerator->closeCamera(pCam2);
+ }
+
+ // Sleep here to ensure the destructor cleanup has time to run so we don't break follow on tests
+ sleep(1); // I hate that this is an arbitrary time to wait. :( b/36122635
+}
+
+
+/*
+ * CameraStreamPerformance:
+ * Measure and qualify the stream start up time and streaming frame rate of each reported camera
+ */
+TEST_F(EvsHidlTest, CameraStreamPerformance) {
+ ALOGI("Starting CameraStreamPerformance test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam: cameraInfo) {
+ sp<IEvsCamera_1_1> pCam =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam, nullptr);
+
+ // Set up a frame receiver object which will fire up its own thread
+ sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+
+ // Start the camera's video stream
+ nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC);
+ bool startResult = frameHandler->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Ensure the first frame arrived within the expected time
+ frameHandler->waitForFrameCount(1);
+ nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t timeToFirstFrame = systemTime(SYSTEM_TIME_MONOTONIC) - start;
+ EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame), kMaxStreamStartMilliseconds);
+ printf("Measured time to first frame %0.2f ms\n", timeToFirstFrame * kNanoToMilliseconds);
+ ALOGI("Measured time to first frame %0.2f ms", timeToFirstFrame * kNanoToMilliseconds);
+
+ // Check aspect ratio
+ unsigned width = 0, height = 0;
+ frameHandler->getFrameDimension(&width, &height);
+ EXPECT_GE(width, height);
+
+ // Wait a bit, then ensure we get at least the required minimum number of frames
+ sleep(5);
+ nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+ unsigned framesReceived = 0;
+ frameHandler->getFramesCounters(&framesReceived, nullptr);
+ framesReceived = framesReceived - 1; // Back out the first frame we already waited for
+ nsecs_t runTime = end - firstFrame;
+ float framesPerSecond = framesReceived / (runTime * kNanoToSeconds);
+ printf("Measured camera rate %3.2f fps\n", framesPerSecond);
+ ALOGI("Measured camera rate %3.2f fps", framesPerSecond);
+ EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond);
+
+ // Even when the camera pointer goes out of scope, the FrameHandler object will
+ // keep the stream alive unless we tell it to shutdown.
+ // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+ // we have to break that cycle in order for either of them to get cleaned up.
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam);
+ }
+}
+
+
+/*
+ * CameraStreamBuffering:
+ * Ensure the camera implementation behaves properly when the client holds onto buffers for more
+ * than one frame time. The camera must cleanly skip frames until the client is ready again.
+ */
+TEST_F(EvsHidlTest, CameraStreamBuffering) {
+ ALOGI("Starting CameraStreamBuffering test");
+
+ // Arbitrary constant (should be > 1 and less than crazy)
+ static const unsigned int kBuffersToHold = 6;
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam: cameraInfo) {
+
+ sp<IEvsCamera_1_1> pCam =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam, nullptr);
+
+ // Ask for a crazy number of buffers in flight to ensure it errors correctly
+ Return<EvsResult> badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
+ EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult);
+
+ // Now ask for exactly two buffers in flight as we'll test behavior in that case
+ Return<EvsResult> goodResult = pCam->setMaxFramesInFlight(kBuffersToHold);
+ EXPECT_EQ(EvsResult::OK, goodResult);
+
+
+ // Set up a frame receiver object which will fire up its own thread.
+ sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+ nullptr,
+ FrameHandler::eNoAutoReturn);
+
+ // Start the camera's video stream
+ bool startResult = frameHandler->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Check that the video stream stalls once we've gotten exactly the number of buffers
+ // we requested since we told the frameHandler not to return them.
+ sleep(2); // 1 second should be enough for at least 5 frames to be delivered worst case
+ unsigned framesReceived = 0;
+ frameHandler->getFramesCounters(&framesReceived, nullptr);
+ ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
+
+
+ // Give back one buffer
+ bool didReturnBuffer = frameHandler->returnHeldBuffer();
+ EXPECT_TRUE(didReturnBuffer);
+
+ // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one
+ // filled since we require 10fps minimum -- but give a 10% allowance just in case.
+ usleep(110 * kMillisecondsToMicroseconds);
+ frameHandler->getFramesCounters(&framesReceived, nullptr);
+ EXPECT_EQ(kBuffersToHold+1, framesReceived) << "Stream should've resumed";
+
+ // Even when the camera pointer goes out of scope, the FrameHandler object will
+ // keep the stream alive unless we tell it to shutdown.
+ // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+ // we have to break that cycle in order for either of them to get cleaned up.
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam);
+ }
+}
+
+
+/*
+ * CameraToDisplayRoundTrip:
+ * End to end test of data flowing from the camera to the display. Each delivered frame of camera
+ * imagery is simply copied to the display buffer and presented on screen. This is the one test
+ * which a human could observe to see the operation of the system on the physical display.
+ */
+TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) {
+ ALOGI("Starting CameraToDisplayRoundTrip test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Request exclusive access to the EVS display
+ sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+ ASSERT_NE(pDisplay, nullptr);
+
+ // Test each reported camera
+ for (auto&& cam: cameraInfo) {
+ sp<IEvsCamera_1_1> pCam =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam, nullptr);
+
+ // Set up a frame receiver object which will fire up its own thread.
+ sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+ pDisplay,
+ FrameHandler::eAutoReturn);
+
+
+ // Activate the display
+ pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+
+ // Start the camera's video stream
+ bool startResult = frameHandler->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Wait a while to let the data flow
+ static const int kSecondsToWait = 5;
+ const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds -
+ kMaxStreamStartMilliseconds;
+ const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond /
+ kSecondsToMilliseconds;
+ sleep(kSecondsToWait);
+ unsigned framesReceived = 0;
+ unsigned framesDisplayed = 0;
+ frameHandler->getFramesCounters(&framesReceived, &framesDisplayed);
+ EXPECT_EQ(framesReceived, framesDisplayed);
+ EXPECT_GE(framesDisplayed, minimumFramesExpected);
+
+ // Turn off the display (yes, before the stream stops -- it should be handled)
+ pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
+
+ // Shut down the streamer
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam);
+ }
+
+ // Explicitly release the display
+ pEnumerator->closeDisplay(pDisplay);
+}
+
+
+/*
+ * MultiCameraStream:
+ * Verify that each client can start and stop video streams on the same
+ * underlying camera.
+ */
+TEST_F(EvsHidlTest, MultiCameraStream) {
+ ALOGI("Starting MultiCameraStream test");
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam: cameraInfo) {
+ // Create two camera clients.
+ sp<IEvsCamera_1_1> pCam0 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam0, nullptr);
+
+ sp<IEvsCamera_1_1> pCam1 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam1, nullptr);
+
+ // Set up per-client frame receiver objects which will fire up its own thread
+ sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandler0, nullptr);
+
+ sp<FrameHandler> frameHandler1 = new FrameHandler(pCam1, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandler1, nullptr);
+
+ // Start the camera's video stream via client 0
+ bool startResult = false;
+ startResult = frameHandler0->startStream() &&
+ frameHandler1->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Ensure the stream starts
+ frameHandler0->waitForFrameCount(1);
+ frameHandler1->waitForFrameCount(1);
+
+ nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // Wait a bit, then ensure both clients get at least the required minimum number of frames
+ sleep(5);
+ nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+ unsigned framesReceived0 = 0, framesReceived1 = 0;
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+ framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for
+ framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for
+ nsecs_t runTime = end - firstFrame;
+ float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
+ float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
+ printf("Measured camera rate %3.2f fps and %3.2f fps\n", framesPerSecond0, framesPerSecond1);
+ ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
+ EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
+ EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
+
+ // Shutdown one client
+ frameHandler0->shutdown();
+
+ // Read frame counters again
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+
+ // Wait a bit again
+ sleep(5);
+ unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0;
+ frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr);
+ EXPECT_EQ(framesReceived0, framesReceivedAfterStop0);
+ EXPECT_LT(framesReceived1, framesReceivedAfterStop1);
+
+ // Shutdown another
+ frameHandler1->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam0);
+ pEnumerator->closeCamera(pCam1);
+ }
+}
+
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ EvsHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/automotive/evs/common/utils/default/Android.bp b/automotive/evs/common/utils/default/Android.bp
new file mode 100644
index 0000000..7734f5c
--- /dev/null
+++ b/automotive/evs/common/utils/default/Android.bp
@@ -0,0 +1,31 @@
+//
+// 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_library_static {
+ name: "android.hardware.automotive.evs@common-default-lib",
+ vendor_available: true,
+ relative_install_path: "hw",
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+ srcs: [
+ "FormatConvert.cpp"
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ ],
+}
diff --git a/automotive/evs/1.0/vts/functional/FormatConvert.cpp b/automotive/evs/common/utils/default/FormatConvert.cpp
similarity index 74%
rename from automotive/evs/1.0/vts/functional/FormatConvert.cpp
rename to automotive/evs/common/utils/default/FormatConvert.cpp
index 3d82d32..d4c7da0 100644
--- a/automotive/evs/1.0/vts/functional/FormatConvert.cpp
+++ b/automotive/evs/common/utils/default/FormatConvert.cpp
@@ -18,10 +18,15 @@
#include "FormatConvert.h"
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace common {
// Round up to the nearest multiple of the given alignment value
template<unsigned alignment>
-int align(int value) {
+int Utils::align(int value) {
static_assert((alignment && !(alignment & (alignment - 1))),
"alignment must be a power of 2");
@@ -31,15 +36,17 @@
// Limit the given value to the provided range. :)
-static inline float clamp(float v, float min, float max) {
+inline float Utils::clamp(float v, float min, float max) {
if (v < min) return min;
if (v > max) return max;
return v;
}
-static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin,
- bool bgrxFormat = false) {
+uint32_t Utils::yuvToRgbx(const unsigned char Y,
+ const unsigned char Uin,
+ const unsigned char Vin,
+ bool bgrxFormat) {
// Don't use this if you want to see the best performance. :)
// Better to do this in a pixel shader if we really have to, but on actual
// embedded hardware we expect to be able to texture directly from the YUV data
@@ -67,10 +74,10 @@
}
-void copyNV21toRGB32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels,
- bool bgrxFormat)
+void Utils::copyNV21toRGB32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels,
+ bool bgrxFormat)
{
// The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
// U/V array. It assumes an even width and height for the overall image, and a horizontal
@@ -99,10 +106,10 @@
}
-void copyYV12toRGB32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels,
- bool bgrxFormat)
+void Utils::copyYV12toRGB32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels,
+ bool bgrxFormat)
{
// The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
// by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image,
@@ -134,10 +141,10 @@
}
-void copyYUYVtoRGB32(unsigned width, unsigned height,
- uint8_t* src, unsigned srcStridePixels,
- uint32_t* dst, unsigned dstStridePixels,
- bool bgrxFormat)
+void Utils::copyYUYVtoRGB32(unsigned width, unsigned height,
+ uint8_t* src, unsigned srcStridePixels,
+ uint32_t* dst, unsigned dstStridePixels,
+ bool bgrxFormat)
{
uint32_t* srcWords = (uint32_t*)src;
@@ -167,34 +174,34 @@
}
-void copyNV21toBGR32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels)
+void Utils::copyNV21toBGR32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels)
{
return copyNV21toRGB32(width, height, src, dst, dstStridePixels, true);
}
-void copyYV12toBGR32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels)
+void Utils::copyYV12toBGR32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels)
{
return copyYV12toRGB32(width, height, src, dst, dstStridePixels, true);
}
-void copyYUYVtoBGR32(unsigned width, unsigned height,
- uint8_t* src, unsigned srcStridePixels,
- uint32_t* dst, unsigned dstStridePixels)
+void Utils::copyYUYVtoBGR32(unsigned width, unsigned height,
+ uint8_t* src, unsigned srcStridePixels,
+ uint32_t* dst, unsigned dstStridePixels)
{
return copyYUYVtoRGB32(width, height, src, srcStridePixels, dst, dstStridePixels, true);
}
-void copyMatchedInterleavedFormats(unsigned width, unsigned height,
- void* src, unsigned srcStridePixels,
- void* dst, unsigned dstStridePixels,
- unsigned pixelSize) {
+void Utils::copyMatchedInterleavedFormats(unsigned width, unsigned height,
+ void* src, unsigned srcStridePixels,
+ void* dst, unsigned dstStridePixels,
+ unsigned pixelSize) {
for (unsigned row = 0; row < height; row++) {
// Copy the entire row of pixel data
memcpy(dst, src, width * pixelSize);
@@ -204,3 +211,10 @@
dst = (uint8_t*)dst + dstStridePixels * pixelSize;
}
}
+
+} // namespace common
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
diff --git a/automotive/evs/common/utils/default/include/FormatConvert.h b/automotive/evs/common/utils/default/include/FormatConvert.h
new file mode 100644
index 0000000..2bb8955
--- /dev/null
+++ b/automotive/evs/common/utils/default/include/FormatConvert.h
@@ -0,0 +1,99 @@
+/*
+ * 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 EVS_VTS_FORMATCONVERT_H
+#define EVS_VTS_FORMATCONVERT_H
+
+#include <queue>
+#include <stdint.h>
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace common {
+
+class Utils {
+public:
+ // Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx/BGRx
+ // values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+ // U/V array. It assumes an even width and height for the overall image, and a horizontal
+ // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+ static void copyNV21toRGB32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels,
+ bool bgrxFormat = false);
+
+ static void copyNV21toBGR32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels);
+
+
+ // Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx/BGRx values.
+ // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
+ // by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image,
+ // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
+ // and V arrays.
+ static void copyYV12toRGB32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels,
+ bool bgrxFormat = false);
+
+ static void copyYV12toBGR32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels);
+
+ // Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx/BGRx
+ // values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+ // U/V array. It assumes an even width and height for the overall image, and a horizontal
+ // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+ static void copyYUYVtoRGB32(unsigned width, unsigned height,
+ uint8_t* src, unsigned srcStrideBytes,
+ uint32_t* dst, unsigned dstStrideBytes,
+ bool bgrxFormat = false);
+
+ static void copyYUYVtoBGR32(unsigned width, unsigned height,
+ uint8_t* src, unsigned srcStrideBytes,
+ uint32_t* dst, unsigned dstStrideBytes);
+
+
+ // Given an simple rectangular image buffer with an integer number of bytes per pixel,
+ // copy the pixel values into a new rectangular buffer (potentially with a different stride).
+ // This is typically used to copy RGBx data into an RGBx output buffer.
+ static void copyMatchedInterleavedFormats(unsigned width, unsigned height,
+ void* src, unsigned srcStridePixels,
+ void* dst, unsigned dstStridePixels,
+ unsigned pixelSize);
+
+private:
+ template<unsigned alignment>
+ static int align(int value);
+
+ static inline float clamp(float v, float min, float max);
+ static uint32_t yuvToRgbx(const unsigned char Y,
+ const unsigned char Uin,
+ const unsigned char Vin,
+ bool bgrxFormat = false);
+};
+
+} // namespace common
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // EVS_VTS_FORMATCONVERT_H
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index a46de24..7bafd2c 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -162,672 +162,688 @@
};
const ConfigDeclaration kVehicleProperties[]{
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.floatValues = {15000.0f}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = {.floatValues = {15000.0f}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_FUEL_TYPE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.int32Values = {1}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::INFO_FUEL_TYPE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = {.int32Values = {(int)FuelType::FUEL_TYPE_UNLEADED}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.floatValues = {150000.0f}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = {.floatValues = {150000.0f}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_EV_CONNECTOR_TYPE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.int32Values = {1}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::INFO_EV_CONNECTOR_TYPE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = {.int32Values = {(int)EvConnectorType::IEC_TYPE_1_AC}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {SEAT_1_LEFT}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = {.int32Values = {SEAT_1_LEFT}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_MAKE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.stringValue = "Toy Vehicle"}},
- {.config =
- {
- .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .minSampleRate = 1.0f,
- .maxSampleRate = 10.0f,
- },
- .initialValue = {.floatValues = {0.0f}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::INFO_MAKE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = {.stringValue = "Toy Vehicle"}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 10.0f,
+ },
+ .initialValue = {.floatValues = {0.0f}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {(int)VehicleUnit::METER_PER_SEC,
- (int)VehicleUnit::MILES_PER_HOUR,
- (int)VehicleUnit::KILOMETERS_PER_HOUR},
- },
- .initialValue = {.int32Values = {(int)VehicleUnit::KILOMETERS_PER_HOUR}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {(int)VehicleUnit::METER_PER_SEC,
+ (int)VehicleUnit::MILES_PER_HOUR,
+ (int)VehicleUnit::KILOMETERS_PER_HOUR},
+ },
+ .initialValue = {.int32Values = {(int)VehicleUnit::KILOMETERS_PER_HOUR}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- // this was a zoned property on an old vhal, but it is meant to be global
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {SEAT_1_LEFT}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ // this was a zoned property on an old vhal, but it is meant to be global
+ .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+ },
+ .initialValue = {.int32Values = {SEAT_1_LEFT}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::PERF_ODOMETER),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.floatValues = {0.0f}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::PERF_ODOMETER),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0f,
+ .maxSampleRate = 10.0f,
+ },
+ .initialValue = {.floatValues = {0.0f}}},
- {
- .config =
- {
- .prop = toInt(VehicleProperty::ENGINE_RPM),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 10.0f,
- },
- .initialValue = {.floatValues = {0.0f}},
- },
+ {
+ .config =
+ {
+ .prop = toInt(VehicleProperty::ENGINE_RPM),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 10.0f,
+ },
+ .initialValue = {.floatValues = {0.0f}},
+ },
- {.config =
- {
- .prop = toInt(VehicleProperty::FUEL_LEVEL),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.floatValues = {15000.0f}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::FUEL_LEVEL),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0f,
+ .maxSampleRate = 100.0f,
+ },
+ .initialValue = {.floatValues = {15000.0f}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {0}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {0}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_BATTERY_LEVEL),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.floatValues = {150000.0f}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::EV_BATTERY_LEVEL),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0f,
+ .maxSampleRate = 100.0f,
+ },
+ .initialValue = {.floatValues = {150000.0f}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {0}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {0}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {0}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {0}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.floatValues = {0.0f}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 10.0f,
+ },
+ .initialValue = {.floatValues = {0.0f}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::RANGE_REMAINING),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- .minSampleRate = 1.0f,
- .maxSampleRate = 2.0f,
- },
- .initialValue = {.floatValues = {100.0f}}}, // units in meters
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::RANGE_REMAINING),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 2.0f,
+ },
+ .initialValue = {.floatValues = {100.0f}}}, // units in meters
- {.config =
- {.prop = toInt(VehicleProperty::TIRE_PRESSURE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 2.0f,
- .areaConfigs =
- {VehicleAreaConfig{
- .areaId = WHEEL_FRONT_LEFT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
- },
- VehicleAreaConfig{
- .areaId = WHEEL_FRONT_RIGHT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
- },
- VehicleAreaConfig{
- .areaId = WHEEL_REAR_LEFT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
- },
- VehicleAreaConfig{
- .areaId = WHEEL_REAR_RIGHT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
- }}},
- .initialValue = {.floatValues = {200}}}, // units in kPa
+ {.config = {.prop = toInt(VehicleProperty::TIRE_PRESSURE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 2.0f,
+ .areaConfigs = {VehicleAreaConfig{
+ .areaId = WHEEL_FRONT_LEFT,
+ .minFloatValue = 100.0f,
+ .maxFloatValue = 300.0f,
+ },
+ VehicleAreaConfig{
+ .areaId = WHEEL_FRONT_RIGHT,
+ .minFloatValue = 100.0f,
+ .maxFloatValue = 300.0f,
+ },
+ VehicleAreaConfig{
+ .areaId = WHEEL_REAR_LEFT,
+ .minFloatValue = 100.0f,
+ .maxFloatValue = 300.0f,
+ },
+ VehicleAreaConfig{
+ .areaId = WHEEL_REAR_RIGHT,
+ .minFloatValue = 100.0f,
+ .maxFloatValue = 300.0f,
+ }}},
+ .initialValue = {.floatValues = {200.0f}}}, // units in kPa
- {.config =
- {
- .prop = toInt(VehicleProperty::CURRENT_GEAR),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::CURRENT_GEAR),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::PARKING_BRAKE_ON),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {1}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::PARKING_BRAKE_ON),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {1}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {0}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {0}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::HW_KEY_INPUT),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0, 0, 0}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::HW_KEY_INPUT),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {0, 0, 0}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_POWER_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}},
- // TODO(bryaneyler): Ideally, this is generated dynamically from
- // kHvacPowerProperties.
- .configArray = {toInt(VehicleProperty::HVAC_FAN_SPEED),
- toInt(VehicleProperty::HVAC_FAN_DIRECTION)}},
- .initialValue = {.int32Values = {1}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_POWER_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}},
+ // TODO(bryaneyler): Ideally, this is generated dynamically from
+ // kHvacPowerProperties.
+ .configArray = {toInt(VehicleProperty::HVAC_FAN_SPEED),
+ toInt(VehicleProperty::HVAC_FAN_DIRECTION)}},
+ .initialValue = {.int32Values = {1}}},
- {
- .config = {.prop = toInt(VehicleProperty::HVAC_DEFROSTER),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs =
- {VehicleAreaConfig{.areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)},
- VehicleAreaConfig{.areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
- .initialValue = {.int32Values = {0}} // Will be used for all areas.
- },
+ {
+ .config = {.prop = toInt(VehicleProperty::HVAC_DEFROSTER),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs =
+ {VehicleAreaConfig{
+ .areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)},
+ VehicleAreaConfig{
+ .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
+ .initialValue = {.int32Values = {0}} // Will be used for all areas.
+ },
- {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {0}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+ .initialValue = {.int32Values = {0}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {1}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+ .initialValue = {.int32Values = {1}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_RECIRC_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {0}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_RECIRC_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+ .initialValue = {.int32Values = {0}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_AC_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {1}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_AC_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+ .initialValue = {.int32Values = {1}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_AC_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {0}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_AC_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+ .initialValue = {.int32Values = {0}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {1}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+ .initialValue = {.int32Values = {1}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_DUAL_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {0}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_DUAL_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+ .initialValue = {.int32Values = {0}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = HVAC_ALL, .minInt32Value = 1, .maxInt32Value = 7}}},
- .initialValue = {.int32Values = {3}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{
+ .areaId = HVAC_ALL, .minInt32Value = 1, .maxInt32Value = 7}}},
+ .initialValue = {.int32Values = {3}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {toInt(VehicleHvacFanDirection::FACE)}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+ .initialValue = {.int32Values = {toInt(VehicleHvacFanDirection::FACE)}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION_AVAILABLE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {FAN_DIRECTION_FACE, FAN_DIRECTION_FLOOR,
- FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION_AVAILABLE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+ .initialValue = {.int32Values = {FAN_DIRECTION_FACE, FAN_DIRECTION_FLOOR,
+ FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_VENTILATION),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = SEAT_1_LEFT, .minInt32Value = 0, .maxInt32Value = 3,
- },
- VehicleAreaConfig{
- .areaId = SEAT_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 3,
- }}},
- .initialValue = {.int32Values = {0}}}, // 0 is off and +ve values indicate ventilation level.
+ {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_VENTILATION),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{
+ .areaId = SEAT_1_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 3,
+ },
+ VehicleAreaConfig{
+ .areaId = SEAT_1_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 3,
+ }}},
+ .initialValue =
+ {.int32Values = {0}}}, // 0 is off and +ve values indicate ventilation level.
- {.config = {.prop = toInt(VehicleProperty::HVAC_STEERING_WHEEL_HEAT),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = (0), .minInt32Value = -2, .maxInt32Value = 2}}},
- .initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling
+ {.config = {.prop = toInt(VehicleProperty::HVAC_STEERING_WHEEL_HEAT),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{
+ .areaId = (0), .minInt32Value = -2, .maxInt32Value = 2}}},
+ .initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling
- {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = SEAT_1_LEFT, .minInt32Value = -2, .maxInt32Value = 2,
- },
- VehicleAreaConfig{
- .areaId = SEAT_1_RIGHT, .minInt32Value = -2, .maxInt32Value = 2,
- }}},
- .initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling
+ {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{
+ .areaId = SEAT_1_LEFT,
+ .minInt32Value = -2,
+ .maxInt32Value = 2,
+ },
+ VehicleAreaConfig{
+ .areaId = SEAT_1_RIGHT,
+ .minInt32Value = -2,
+ .maxInt32Value = 2,
+ }}},
+ .initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling
- {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = HVAC_LEFT,
- .minFloatValue = 16,
- .maxFloatValue = 32,
- },
- VehicleAreaConfig{
- .areaId = HVAC_RIGHT,
- .minFloatValue = 16,
- .maxFloatValue = 32,
- }}},
- .initialAreaValues = {{HVAC_LEFT, {.floatValues = {16}}},
- {HVAC_RIGHT, {.floatValues = {20}}}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{
+ .areaId = HVAC_LEFT,
+ .minFloatValue = 16,
+ .maxFloatValue = 32,
+ },
+ VehicleAreaConfig{
+ .areaId = HVAC_RIGHT,
+ .minFloatValue = 16,
+ .maxFloatValue = 32,
+ }}},
+ .initialAreaValues = {{HVAC_LEFT, {.floatValues = {16}}},
+ {HVAC_RIGHT, {.floatValues = {20}}}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
- .access = VehiclePropertyAccess::READ,
- // TODO(bryaneyler): Support ON_CHANGE as well.
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 2.0f,
- },
- .initialValue = {.floatValues = {25.0f}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
+ .access = VehiclePropertyAccess::READ,
+ // TODO(bryaneyler): Support ON_CHANGE as well.
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 2.0f,
+ },
+ .initialValue = {.floatValues = {25.0f}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS},
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}},
- .initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS}},
+ .initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::NIGHT_MODE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::NIGHT_MODE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {0}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::GEAR_SELECTION),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::GEAR_SELECTION),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::IGNITION_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {toInt(VehicleIgnitionState::ON)}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::IGNITION_STATE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {toInt(VehicleIgnitionState::ON)}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {toInt(VehicleOilLevel::NORMAL)}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {toInt(VehicleOilLevel::NORMAL)}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 0.1, // 0.1 Hz, every 10 seconds
- .maxSampleRate = 10, // 10 Hz, every 100 ms
- },
- .initialValue = {.floatValues = {101.0f}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.1, // 0.1 Hz, every 10 seconds
+ .maxSampleRate = 10, // 10 Hz, every 100 ms
+ },
+ .initialValue = {.floatValues = {101.0f}}},
- {
- .config =
- {
- .prop = kGenerateFakeDataControllingProperty,
- .access = VehiclePropertyAccess::WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
+ {
+ .config =
+ {
+ .prop = kGenerateFakeDataControllingProperty,
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ },
- {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
- VehicleAreaConfig{.areaId = DOOR_1_RIGHT},
- VehicleAreaConfig{.areaId = DOOR_2_LEFT},
- VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}},
- .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
- {DOOR_1_RIGHT, {.int32Values = {1}}},
- {DOOR_2_LEFT, {.int32Values = {1}}},
- {DOOR_2_RIGHT, {.int32Values = {1}}}}},
+ {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
+ VehicleAreaConfig{.areaId = DOOR_1_RIGHT},
+ VehicleAreaConfig{.areaId = DOOR_2_LEFT},
+ VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}},
+ .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
+ {DOOR_1_RIGHT, {.int32Values = {1}}},
+ {DOOR_2_LEFT, {.int32Values = {1}}},
+ {DOOR_2_RIGHT, {.int32Values = {1}}}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::DOOR_POS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs =
- {VehicleAreaConfig{.areaId = DOOR_1_LEFT, .minInt32Value = 0, .maxInt32Value = 1},
- VehicleAreaConfig{.areaId = DOOR_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 1},
- VehicleAreaConfig{.areaId = DOOR_2_LEFT, .minInt32Value = 0, .maxInt32Value = 1},
- VehicleAreaConfig{.areaId = DOOR_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 1},
- VehicleAreaConfig{.areaId = DOOR_REAR, .minInt32Value = 0, .maxInt32Value = 1}}},
- .initialValue = {.int32Values = {0}}},
+ {.config = {.prop = toInt(VehicleProperty::DOOR_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs =
+ {VehicleAreaConfig{
+ .areaId = DOOR_1_LEFT, .minInt32Value = 0, .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = DOOR_1_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{
+ .areaId = DOOR_2_LEFT, .minInt32Value = 0, .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = DOOR_2_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{
+ .areaId = DOOR_REAR, .minInt32Value = 0, .maxInt32Value = 1}}},
+ .initialValue = {.int32Values = {0}}},
- {.config = {.prop = toInt(VehicleProperty::WINDOW_LOCK),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_RIGHT | WINDOW_2_LEFT |
- WINDOW_2_RIGHT}}},
- .initialAreaValues = {{WINDOW_1_RIGHT | WINDOW_2_LEFT | WINDOW_2_RIGHT,
- {.int32Values = {0}}}}},
+ {.config = {.prop = toInt(VehicleProperty::WINDOW_LOCK),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_RIGHT | WINDOW_2_LEFT |
+ WINDOW_2_RIGHT}}},
+ .initialAreaValues = {{WINDOW_1_RIGHT | WINDOW_2_LEFT | WINDOW_2_RIGHT,
+ {.int32Values = {0}}}}},
- {.config =
- {.prop = toInt(VehicleProperty::WINDOW_POS),
- .access =
- VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs =
- {VehicleAreaConfig{.areaId = WINDOW_1_LEFT, .minInt32Value = 0, .maxInt32Value = 10},
- VehicleAreaConfig{.areaId = WINDOW_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 10},
- VehicleAreaConfig{.areaId = WINDOW_2_LEFT, .minInt32Value = 0, .maxInt32Value = 10},
- VehicleAreaConfig{.areaId = WINDOW_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 10},
- VehicleAreaConfig{
- .areaId = WINDOW_ROOF_TOP_1, .minInt32Value = -10, .maxInt32Value = 10}}},
- .initialValue = {.int32Values = {0}}},
+ {.config = {.prop = toInt(VehicleProperty::WINDOW_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = WINDOW_1_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = WINDOW_2_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = WINDOW_2_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = WINDOW_ROOF_TOP_1,
+ .minInt32Value = -10,
+ .maxInt32Value = 10}}},
+ .initialValue = {.int32Values = {0}}},
- {.config =
- {
- .prop = WHEEL_TICK,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .configArray = {ALL_WHEELS, 50000, 50000, 50000, 50000},
- .minSampleRate = 1.0f,
- .maxSampleRate = 10.0f,
- },
- .initialValue = {.int64Values = {0, 100000, 200000, 300000, 400000}}},
+ {.config =
+ {
+ .prop = WHEEL_TICK,
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .configArray = {ALL_WHEELS, 50000, 50000, 50000, 50000},
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 10.0f,
+ },
+ .initialValue = {.int64Values = {0, 100000, 200000, 300000, 400000}}},
- {.config = {.prop = ABS_ACTIVE,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- .initialValue = {.int32Values = {0}}},
+ {.config = {.prop = ABS_ACTIVE,
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+ .initialValue = {.int32Values = {0}}},
- {.config = {.prop = TRACTION_CONTROL_ACTIVE,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- .initialValue = {.int32Values = {0}}},
+ {.config = {.prop = TRACTION_CONTROL_ACTIVE,
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+ .initialValue = {.int32Values = {0}}},
- {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {3}},
- .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON), 0}}},
+ {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {3}},
+ .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON), 0}}},
- {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
- .access = VehiclePropertyAccess::WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL), 0}}},
+ {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+ .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL), 0}}},
- {.config = {.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.minInt32Value = 0, .maxInt32Value = 100}}},
- .initialValue = {.int32Values = {100}}},
+ {.config = {.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.minInt32Value = 0, .maxInt32Value = 100}}},
+ .initialValue = {.int32Values = {100}}},
- {
- .config = {.prop = OBD2_LIVE_FRAME,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {0, 0}},
- },
+ {
+ .config = {.prop = OBD2_LIVE_FRAME,
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {0, 0}},
+ },
- {
- .config = {.prop = OBD2_FREEZE_FRAME,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {0, 0}},
- },
+ {
+ .config = {.prop = OBD2_FREEZE_FRAME,
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {0, 0}},
+ },
- {
- .config = {.prop = OBD2_FREEZE_FRAME_INFO,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- },
+ {
+ .config = {.prop = OBD2_FREEZE_FRAME_INFO,
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+ },
- {
- .config = {.prop = OBD2_FREEZE_FRAME_CLEAR,
- .access = VehiclePropertyAccess::WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {1}},
- },
+ {
+ .config = {.prop = OBD2_FREEZE_FRAME_CLEAR,
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {1}},
+ },
- {.config =
- {
- .prop = toInt(VehicleProperty::HEADLIGHTS_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::HEADLIGHTS_STATE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::FOG_LIGHTS_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::FOG_LIGHTS_STATE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
- {.config = {.prop = VEHICLE_MAP_SERVICE,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE}},
+ {.config = {.prop = VEHICLE_MAP_SERVICE,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE}},
- // Example Vendor Extension properties for testing
- {.config = {.prop = VENDOR_EXTENSION_BOOLEAN_PROPERTY,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
- VehicleAreaConfig{.areaId = DOOR_1_RIGHT},
- VehicleAreaConfig{.areaId = DOOR_2_LEFT},
- VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}},
- .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
- {DOOR_1_RIGHT, {.int32Values = {1}}},
- {DOOR_2_LEFT, {.int32Values = {0}}},
- {DOOR_2_RIGHT, {.int32Values = {0}}}}},
+ // Example Vendor Extension properties for testing
+ {.config = {.prop = VENDOR_EXTENSION_BOOLEAN_PROPERTY,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
+ VehicleAreaConfig{.areaId = DOOR_1_RIGHT},
+ VehicleAreaConfig{.areaId = DOOR_2_LEFT},
+ VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}},
+ .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
+ {DOOR_1_RIGHT, {.int32Values = {1}}},
+ {DOOR_2_LEFT, {.int32Values = {0}}},
+ {DOOR_2_RIGHT, {.int32Values = {0}}}}},
- {.config = {.prop = VENDOR_EXTENSION_FLOAT_PROPERTY,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = HVAC_LEFT, .minFloatValue = -10, .maxFloatValue = 10},
- VehicleAreaConfig{.areaId = HVAC_RIGHT,
- .minFloatValue = -10,
- .maxFloatValue = 10}}},
- .initialAreaValues = {{HVAC_LEFT, {.floatValues = {1}}}, {HVAC_RIGHT, {.floatValues = {2}}}}},
+ {.config = {.prop = VENDOR_EXTENSION_FLOAT_PROPERTY,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_LEFT,
+ .minFloatValue = -10,
+ .maxFloatValue = 10},
+ VehicleAreaConfig{.areaId = HVAC_RIGHT,
+ .minFloatValue = -10,
+ .maxFloatValue = 10}}},
+ .initialAreaValues = {{HVAC_LEFT, {.floatValues = {1}}},
+ {HVAC_RIGHT, {.floatValues = {2}}}}},
- {.config = {.prop = VENDOR_EXTENSION_INT_PROPERTY,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = (int)VehicleAreaWindow::FRONT_WINDSHIELD,
- .minInt32Value = -100,
- .maxInt32Value = 100},
- VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::REAR_WINDSHIELD,
- .minInt32Value = -100,
- .maxInt32Value = 100},
- VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::ROOF_TOP_1,
- .minInt32Value = -100,
- .maxInt32Value = 100}}},
- .initialAreaValues = {{(int)VehicleAreaWindow::FRONT_WINDSHIELD, {.int32Values = {1}}},
- {(int)VehicleAreaWindow::REAR_WINDSHIELD, {.int32Values = {0}}},
- {(int)VehicleAreaWindow::ROOF_TOP_1, {.int32Values = {-1}}}}},
+ {.config = {.prop = VENDOR_EXTENSION_INT_PROPERTY,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs =
+ {VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::FRONT_WINDSHIELD,
+ .minInt32Value = -100,
+ .maxInt32Value = 100},
+ VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::REAR_WINDSHIELD,
+ .minInt32Value = -100,
+ .maxInt32Value = 100},
+ VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::ROOF_TOP_1,
+ .minInt32Value = -100,
+ .maxInt32Value = 100}}},
+ .initialAreaValues = {{(int)VehicleAreaWindow::FRONT_WINDSHIELD, {.int32Values = {1}}},
+ {(int)VehicleAreaWindow::REAR_WINDSHIELD, {.int32Values = {0}}},
+ {(int)VehicleAreaWindow::ROOF_TOP_1, {.int32Values = {-1}}}}},
- {.config = {.prop = VENDOR_EXTENSION_STRING_PROPERTY,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- .initialValue = {.stringValue = "Vendor String Property"}},
+ {.config = {.prop = VENDOR_EXTENSION_STRING_PROPERTY,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+ .initialValue = {.stringValue = "Vendor String Property"}},
};
} // impl
diff --git a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
index 40961f7..d3d7387 100644
--- a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
+++ b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
@@ -14,29 +14,24 @@
* limitations under the License.
*/
-#define LOG_TAG "face_hidl_test"
+#define LOG_TAG "biometrics_face_hidl_hal_test"
+#include <android/hardware/biometrics/face/1.0/IBiometricsFace.h>
+#include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android/hardware/biometrics/face/1.0/IBiometricsFace.h>
-#include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/HidlTransportSupport.h>
-#include <utils/Condition.h>
-#include <cinttypes>
+#include <chrono>
#include <cstdint>
-#include <future>
-#include <utility>
+#include <random>
-using android::Condition;
-using android::Mutex;
using android::sp;
-using android::base::GetUintProperty;
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::Feature;
@@ -48,263 +43,203 @@
namespace {
-const uint32_t kTimeout = 3;
-const std::chrono::seconds kTimeoutInSeconds = std::chrono::seconds(kTimeout);
-const uint32_t kUserId = 99;
-const uint32_t kFaceId = 5;
-const char kTmpDir[] = "/data/system/users/0/facedata";
-const int kIterations = 1000;
+// Arbitrary, nonexistent userId
+constexpr uint32_t kUserId = 9;
+// Arbitrary, nonexistent faceId
+constexpr uint32_t kFaceId = 5;
+constexpr uint32_t kTimeoutSec = 3;
+constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
+constexpr int kGenerateChallengeIterations = 10;
+constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata";
+constexpr char kCallbackNameOnEnrollResult[] = "onEnrollResult";
+constexpr char kCallbackNameOnAuthenticated[] = "onAuthenticated";
+constexpr char kCallbackNameOnAcquired[] = "onAcquired";
+constexpr char kCallbackNameOnError[] = "onError";
+constexpr char kCallbackNameOnRemoved[] = "onRemoved";
+constexpr char kCallbackNameOnEnumerate[] = "onEnumerate";
+constexpr char kCallbackNameOnLockoutChanged[] = "onLockoutChanged";
-const auto kAssertCallbackIsSet = [](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);
+// 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 onRemoved() callback.
+ int32_t userId;
};
-// Wait for a callback to occur (signaled by the given future) up to the
-// provided timeout. If the future is invalid or the callback does not come
-// within the given time, returns false.
-template <class ReturnType>
-bool waitForCallback(std::future<ReturnType> future,
- std::chrono::milliseconds timeout = kTimeoutInSeconds) {
- auto expiration = std::chrono::system_clock::now() + timeout;
- EXPECT_TRUE(future.valid());
- if (future.valid()) {
- std::future_status status = future.wait_until(expiration);
- EXPECT_NE(std::future_status::timeout, status) << "Timed out waiting for callback";
- if (status == std::future_status::ready) {
- return true;
- }
- }
- return false;
-}
-
-// Base callback implementation that just logs all callbacks by default
-class FaceCallbackBase : public IBiometricsFaceClientCallback {
+// 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 {
- ALOGD("Enroll callback called.");
- return Return<void>();
+ NotifyFromCallback(kCallbackNameOnEnrollResult);
+ return Void();
}
Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
- ALOGD("Authenticated callback called.");
- return Return<void>();
+ NotifyFromCallback(kCallbackNameOnAuthenticated);
+ return Void();
}
Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
- ALOGD("Acquired callback called.");
- return Return<void>();
+ NotifyFromCallback(kCallbackNameOnAcquired);
+ return Void();
}
- Return<void> onError(uint64_t, int32_t, FaceError, int32_t) override {
- ALOGD("Error callback called.");
- EXPECT_TRUE(false); // fail any test that triggers an error
- return Return<void>();
+ Return<void> onError(uint64_t, int32_t, FaceError error, int32_t) override {
+ FaceCallbackArgs args = {};
+ args.error = error;
+ NotifyFromCallback(kCallbackNameOnError, args);
+ return Void();
}
- Return<void> onRemoved(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
- ALOGD("Removed callback called.");
- return Return<void>();
+ Return<void> onRemoved(uint64_t, const hidl_vec<uint32_t>&, int32_t userId) override {
+ FaceCallbackArgs args = {};
+ args.userId = userId;
+ NotifyFromCallback(kCallbackNameOnRemoved, args);
+ return Void();
}
- Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t /* userId */) override {
- ALOGD("Enumerate callback called.");
- return Return<void>();
+ Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
+ NotifyFromCallback(kCallbackNameOnEnumerate);
+ return Void();
}
Return<void> onLockoutChanged(uint64_t) override {
- ALOGD("LockoutChanged callback called.");
- return Return<void>();
+ NotifyFromCallback(kCallbackNameOnLockoutChanged);
+ return Void();
}
};
-class EnumerateCallback : public FaceCallbackBase {
- public:
- Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
- promise.set_value();
- return Return<void>();
- }
-
- std::promise<void> promise;
-};
-
-class ErrorCallback : public FaceCallbackBase {
- public:
- ErrorCallback(bool filterErrors = false, FaceError errorType = FaceError::HW_UNAVAILABLE)
- : filterErrors(filterErrors), errorType(errorType), hasError(false) {}
-
- Return<void> onError(uint64_t, int32_t, FaceError error, int32_t) override {
- if ((filterErrors && errorType == error) || !filterErrors) {
- hasError = true;
- this->error = error;
- promise.set_value();
- }
- return Return<void>();
- }
-
- bool filterErrors;
- FaceError errorType;
- bool hasError;
- FaceError error;
- std::promise<void> promise;
-};
-
-class RemoveCallback : public FaceCallbackBase {
- public:
- explicit RemoveCallback(int32_t userId) : removeUserId(userId) {}
-
- Return<void> onRemoved(uint64_t, const hidl_vec<uint32_t>&, int32_t userId) override {
- EXPECT_EQ(removeUserId, userId);
- promise.set_value();
- return Return<void>();
- }
-
- int32_t removeUserId;
- std::promise<void> promise;
-};
-
-class LockoutChangedCallback : public FaceCallbackBase {
- public:
- Return<void> onLockoutChanged(uint64_t duration) override {
- this->hasDuration = true;
- this->duration = duration;
- promise.set_value();
- return Return<void>();
- }
- bool hasDuration;
- uint64_t duration;
- std::promise<void> promise;
-};
-
-// Test environment for Face HIDL HAL.
+// Test environment for the BiometricsFace HAL.
class FaceHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
public:
- // get the test environment singleton
+ // Get the test environment singleton.
static FaceHidlEnvironment* Instance() {
static FaceHidlEnvironment* instance = new FaceHidlEnvironment;
return instance;
}
void registerTestServices() override { registerTestService<IBiometricsFace>(); }
+
+ private:
+ FaceHidlEnvironment() = default;
};
+// Test class for the BiometricsFace HAL.
class FaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
void SetUp() override {
mService = ::testing::VtsHalHidlTargetTestBase::getService<IBiometricsFace>(
FaceHidlEnvironment::Instance()->getServiceName<IBiometricsFace>());
- ASSERT_FALSE(mService == nullptr);
- Return<Status> res = mService->setActiveUser(kUserId, kTmpDir);
- ASSERT_EQ(Status::OK, static_cast<Status>(res));
+ 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;
};
-// The service should be reachable.
-TEST_F(FaceHidlTest, ConnectTest) {
- sp<FaceCallbackBase> cb = new FaceCallbackBase();
- mService->setCallback(cb, kAssertCallbackIsSet);
-}
-
-// Starting the service with null callback should succeed.
-TEST_F(FaceHidlTest, ConnectNullTest) {
- mService->setCallback(nullptr, kAssertCallbackIsSet);
-}
-
// generateChallenge should always return a unique, cryptographically secure,
// non-zero number.
TEST_F(FaceHidlTest, GenerateChallengeTest) {
std::map<uint64_t, int> m;
- for (int i = 0; i < kIterations; ++i) {
- mService->generateChallenge(kTimeout, [&m](const OptionalUint64& res) {
- ASSERT_EQ(Status::OK, res.status);
- EXPECT_NE(0UL, res.value);
- m[res.value]++;
- EXPECT_EQ(1UL, m[res.value]);
- });
+ for (int i = 0; i < kGenerateChallengeIterations; ++i) {
+ Return<void> ret =
+ mService->generateChallenge(kTimeoutSec, [&m](const OptionalUint64& res) {
+ ASSERT_EQ(Status::OK, res.status);
+ EXPECT_NE(0UL, res.value);
+ m[res.value]++;
+ EXPECT_EQ(1UL, m[res.value]);
+ });
+ ASSERT_TRUE(ret.isOk());
}
}
// enroll with an invalid (all zeroes) HAT should fail.
TEST_F(FaceHidlTest, EnrollZeroHatTest) {
- sp<ErrorCallback> cb = new ErrorCallback();
- mService->setCallback(cb, kAssertCallbackIsSet);
-
+ // Filling HAT with zeros
hidl_vec<uint8_t> token(69);
for (size_t i = 0; i < 69; i++) {
token[i] = 0;
}
- Return<Status> res = mService->enroll(token, kTimeout, {});
- ASSERT_EQ(Status::OK, static_cast<Status>(res));
+ Return<Status> ret = mService->enroll(token, kTimeoutSec, {});
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
- // At least one call to onError should occur
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
- ASSERT_TRUE(cb->hasError);
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
}
// enroll with an invalid HAT should fail.
TEST_F(FaceHidlTest, EnrollGarbageHatTest) {
- sp<ErrorCallback> cb = new ErrorCallback();
- mService->setCallback(cb, kAssertCallbackIsSet);
-
- // Filling HAT with invalid data
+ // 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] = i;
+ token[i] = dist(gen);
}
- Return<Status> res = mService->enroll(token, kTimeout, {});
- ASSERT_EQ(Status::OK, static_cast<Status>(res));
+ Return<Status> ret = mService->enroll(token, kTimeoutSec, {});
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
- // At least one call to onError should occur
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
- ASSERT_TRUE(cb->hasError);
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
}
// setFeature with an invalid (all zeros) HAT should fail.
TEST_F(FaceHidlTest, SetFeatureZeroHatTest) {
- sp<ErrorCallback> cb = new ErrorCallback();
- mService->setCallback(cb, kAssertCallbackIsSet);
-
hidl_vec<uint8_t> token(69);
for (size_t i = 0; i < 69; i++) {
token[i] = 0;
}
- Return<Status> res = mService->setFeature(Feature::REQUIRE_DIVERSITY, false, token, 0);
- ASSERT_EQ(Status::ILLEGAL_ARGUMENT, static_cast<Status>(res));
+ Return<Status> ret = mService->setFeature(Feature::REQUIRE_DIVERSITY, false, token, 0);
+ ASSERT_EQ(Status::ILLEGAL_ARGUMENT, static_cast<Status>(ret));
}
// setFeature with an invalid HAT should fail.
TEST_F(FaceHidlTest, SetFeatureGarbageHatTest) {
- sp<ErrorCallback> cb = new ErrorCallback();
- mService->setCallback(cb, kAssertCallbackIsSet);
-
- // Filling HAT with invalid data
+ // 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] = i;
+ token[i] = dist(gen);
}
- Return<Status> res = mService->setFeature(Feature::REQUIRE_DIVERSITY, false, token, 0);
- ASSERT_EQ(Status::ILLEGAL_ARGUMENT, static_cast<Status>(res));
+ Return<Status> ret = mService->setFeature(Feature::REQUIRE_DIVERSITY, false, token, 0);
+ ASSERT_EQ(Status::ILLEGAL_ARGUMENT, static_cast<Status>(ret));
}
-void assertGetFeatureFails(sp<IBiometricsFace> service, int faceId, Feature feature) {
- std::promise<void> promise;
-
+void assertGetFeatureFails(const sp<IBiometricsFace>& service, uint32_t faceId, Feature feature) {
// Features cannot be retrieved for invalid faces.
- Return<void> res = service->getFeature(feature, faceId, [&promise](const OptionalBool& result) {
+ Return<void> res = service->getFeature(feature, faceId, [](const OptionalBool& result) {
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, result.status);
- promise.set_value();
});
- ASSERT_TRUE(waitForCallback(promise.get_future()));
+ ASSERT_TRUE(res.isOk());
}
TEST_F(FaceHidlTest, GetFeatureRequireAttentionTest) {
@@ -317,111 +252,95 @@
// revokeChallenge should always return within the timeout
TEST_F(FaceHidlTest, RevokeChallengeTest) {
- sp<FaceCallbackBase> cb = new FaceCallbackBase();
- mService->setCallback(cb, kAssertCallbackIsSet);
-
auto start = std::chrono::system_clock::now();
- mService->revokeChallenge();
+ Return<Status> ret = mService->revokeChallenge();
auto elapsed = std::chrono::system_clock::now() - start;
- ASSERT_GE(kTimeoutInSeconds, elapsed);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+ ASSERT_GE(kTimeout, elapsed);
}
// The call to getAuthenticatorId should succeed.
TEST_F(FaceHidlTest, GetAuthenticatorIdTest) {
- mService->getAuthenticatorId(
+ Return<void> ret = mService->getAuthenticatorId(
[](const OptionalUint64& res) { ASSERT_EQ(Status::OK, res.status); });
+ ASSERT_TRUE(ret.isOk());
}
// The call to enumerate should succeed.
TEST_F(FaceHidlTest, EnumerateTest) {
- sp<EnumerateCallback> cb = new EnumerateCallback();
- mService->setCallback(cb, kAssertCallbackIsSet);
- Return<Status> res = mService->enumerate();
- ASSERT_EQ(Status::OK, static_cast<Status>(res));
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+ Return<Status> ret = mService->enumerate();
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+ auto res = mCallback->WaitForCallback(kCallbackNameOnEnumerate);
+ EXPECT_TRUE(res.no_timeout);
}
// The call to remove should succeed for any faceId
TEST_F(FaceHidlTest, RemoveFaceTest) {
- sp<ErrorCallback> cb = new ErrorCallback();
- mService->setCallback(cb, kAssertCallbackIsSet);
-
// Remove a face
- Return<Status> res = mService->remove(kFaceId);
- ASSERT_EQ(Status::OK, static_cast<Status>(res));
+ Return<Status> ret = mService->remove(kFaceId);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
}
// Remove should accept 0 to delete all faces
TEST_F(FaceHidlTest, RemoveAllFacesTest) {
- sp<ErrorCallback> cb = new ErrorCallback();
- mService->setCallback(cb, kAssertCallbackIsSet);
-
// Remove all faces
- Return<Status> res = mService->remove(0);
- ASSERT_EQ(Status::OK, static_cast<Status>(res));
+ Return<Status> ret = mService->remove(0);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
}
// Active user should successfully set to a writable location.
TEST_F(FaceHidlTest, SetActiveUserTest) {
// Create an active user
- Return<Status> res = mService->setActiveUser(2, kTmpDir);
- ASSERT_EQ(Status::OK, static_cast<Status>(res));
+ Return<Status> ret = mService->setActiveUser(2, kFacedataDir);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
// Reset active user
- res = mService->setActiveUser(kUserId, kTmpDir);
- ASSERT_EQ(Status::OK, static_cast<Status>(res));
+ ret = mService->setActiveUser(kUserId, kFacedataDir);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
}
// Active user should fail to set to an unwritable location.
TEST_F(FaceHidlTest, SetActiveUserUnwritableTest) {
// Create an active user to an unwritable location (device root dir)
- Return<Status> res = mService->setActiveUser(3, "/");
- ASSERT_NE(Status::OK, static_cast<Status>(res));
+ Return<Status> ret = mService->setActiveUser(3, "/");
+ ASSERT_NE(Status::OK, static_cast<Status>(ret));
// Reset active user
- res = mService->setActiveUser(kUserId, kTmpDir);
- ASSERT_EQ(Status::OK, static_cast<Status>(res));
+ ret = mService->setActiveUser(kUserId, kFacedataDir);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
}
// Active user should fail to set to a null location.
TEST_F(FaceHidlTest, SetActiveUserNullTest) {
// Create an active user to a null location.
- Return<Status> res = mService->setActiveUser(4, nullptr);
- ASSERT_NE(Status::OK, static_cast<Status>(res));
+ Return<Status> ret = mService->setActiveUser(4, nullptr);
+ ASSERT_NE(Status::OK, static_cast<Status>(ret));
// Reset active user
- res = mService->setActiveUser(kUserId, kTmpDir);
- ASSERT_EQ(Status::OK, static_cast<Status>(res));
+ ret = mService->setActiveUser(kUserId, kFacedataDir);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
}
// Cancel should always return CANCELED from any starting state including
// the IDLE state.
TEST_F(FaceHidlTest, CancelTest) {
- sp<ErrorCallback> cb = new ErrorCallback(true, FaceError::CANCELED);
- mService->setCallback(cb, kAssertCallbackIsSet);
-
- Return<Status> res = mService->cancel();
+ Return<Status> ret = mService->cancel();
// check that we were able to make an IPC request successfully
- ASSERT_EQ(Status::OK, static_cast<Status>(res));
-
- // make sure callback was invoked within kTimeoutInSeconds
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
- // check error should be CANCELED
- ASSERT_EQ(FaceError::CANCELED, cb->error);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ // make sure callback was invoked within kRevokeChallengeTimeout
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(FaceError::CANCELED, res.args->error);
}
TEST_F(FaceHidlTest, OnLockoutChangedTest) {
- sp<LockoutChangedCallback> cb = new LockoutChangedCallback();
- mService->setCallback(cb, kAssertCallbackIsSet);
-
- // Update active user and ensure lockout duration 0 is received
- mService->setActiveUser(5, kTmpDir);
+ // Update active user and ensure onLockoutChanged was called.
+ Return<Status> ret = mService->setActiveUser(kUserId + 1, kFacedataDir);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
// Make sure callback was invoked
- ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
-
- // Check that duration 0 was received
- ASSERT_EQ(0, cb->duration);
+ auto res = mCallback->WaitForCallback(kCallbackNameOnLockoutChanged);
+ EXPECT_TRUE(res.no_timeout);
}
} // anonymous namespace
diff --git a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
index b615227..9fa128d 100644
--- a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
+++ b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service
+ interface android.hardware.bluetooth@1.0::IBluetoothHci default
class hal
capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
user bluetooth
diff --git a/boot/1.0/default/android.hardware.boot@1.0-service.rc b/boot/1.0/default/android.hardware.boot@1.0-service.rc
index 32f3a45..b8125e1 100644
--- a/boot/1.0/default/android.hardware.boot@1.0-service.rc
+++ b/boot/1.0/default/android.hardware.boot@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.boot-hal-1-0 /vendor/bin/hw/android.hardware.boot@1.0-service
+ interface android.hardware.boot@1.0::IBootControl default
class early_hal
user root
group root
diff --git a/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc b/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc
index 7c57135..6fcbfa6 100644
--- a/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc
+++ b/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc
@@ -1,4 +1,6 @@
service broadcastradio-hal /vendor/bin/hw/android.hardware.broadcastradio@1.1-service
+ interface android.hardware.broadcastradio@1.0::IBroadcastRadioFactory default
+ interface android.hardware.broadcastradio@1.1::IBroadcastRadioFactory default
class hal
user audioserver
group audio
diff --git a/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
index 7d68b6c..dd8c9c6 100644
--- a/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
+++ b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
@@ -1,4 +1,5 @@
service broadcastradio-hal2 /vendor/bin/hw/android.hardware.broadcastradio@2.0-service
+ interface android.hardware.broadcastradio@2.0::IBroadcastRadio default
class hal
user audioserver
group audio
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 86c2c1e..a5369e7 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -607,7 +607,9 @@
struct DeviceCb : public V3_5::ICameraDeviceCallback {
DeviceCb(CameraHidlTest *parent, int deviceVersion, const camera_metadata_t *staticMeta) :
- mParent(parent), mDeviceVersion(deviceVersion), mStaticMetadata(staticMeta) {}
+ mParent(parent), mDeviceVersion(deviceVersion) {
+ mStaticMetadata = staticMeta;
+ }
Return<void> processCaptureResult_3_4(
const hidl_vec<V3_4::CaptureResult>& results) override;
@@ -631,7 +633,7 @@
CameraHidlTest *mParent; // Parent object
int mDeviceVersion;
- const camera_metadata_t *mStaticMetadata;
+ android::hardware::camera::common::V1_0::helper::CameraMetadata mStaticMetadata;
bool hasOutstandingBuffersLocked();
/* members for requestStreamBuffers() and returnStreamBuffers()*/
@@ -1194,18 +1196,20 @@
// Verify final result metadata
bool isAtLeast_3_5 = mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_5;
if (isAtLeast_3_5) {
+ auto staticMetadataBuffer = mStaticMetadata.getAndLock();
bool isMonochrome = Status::OK ==
- CameraHidlTest::isMonochromeCamera(mStaticMetadata);
+ CameraHidlTest::isMonochromeCamera(staticMetadataBuffer);
if (isMonochrome) {
mParent->verifyMonochromeCameraResult(request->collectedResult);
}
// Verify logical camera result metadata
bool isLogicalCamera =
- Status::OK == CameraHidlTest::isLogicalMultiCamera(mStaticMetadata);
+ Status::OK == CameraHidlTest::isLogicalMultiCamera(staticMetadataBuffer);
if (isLogicalCamera) {
- mParent->verifyLogicalCameraResult(mStaticMetadata, request->collectedResult);
+ mParent->verifyLogicalCameraResult(staticMetadataBuffer, request->collectedResult);
}
+ mStaticMetadata.unlock(staticMetadataBuffer);
}
}
@@ -4131,6 +4135,8 @@
&useHalBufManager /*out*/, &cb /*out*/, 0 /*streamConfigCounter*/,
true /*allowUnsupport*/);
if (session3_5 == nullptr) {
+ ret = session3_4->close();
+ ASSERT_TRUE(ret.isOk());
continue;
}
@@ -5402,7 +5408,7 @@
ASSERT_EQ(Status::OK, s);
staticMeta = clone_camera_metadata(
reinterpret_cast<const camera_metadata_t*>(metadata.data()));
- ASSERT_NE(nullptr, staticMeta);
+ ASSERT_NE(nullptr, staticMeta);
});
ASSERT_TRUE(ret.isOk());
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
index 9227b6f..73c505d 100644
--- a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
+++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
@@ -1,4 +1,5 @@
service vendor.cas-hal-1-1 /vendor/bin/hw/android.hardware.cas@1.1-service-lazy
+ interface android.hardware.cas@1.0::IMediaCasService default
interface android.hardware.cas@1.1::IMediaCasService default
oneshot
disabled
diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml
index 21a0847..01ec172 100644
--- a/compatibility_matrices/compatibility_matrix.4.xml
+++ b/compatibility_matrices/compatibility_matrix.4.xml
@@ -365,7 +365,13 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.radio.config</name>
- <version>1.2</version>
+ <!--
+ Note: Devices launching with target-level 4, if implementing the
+ radio config HAL, must provide an implementation of 1.1 IRadioConfig
+ that can handle version 1.2 of IRadioConfigResponse and
+ IRadioConfigIndication.
+ -->
+ <version>1.1</version>
<interface>
<name>IRadioConfig</name>
<instance>default</instance>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 2284723..6e1bc8f 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -365,7 +365,10 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.radio.config</name>
- <version>1.2</version>
+ <!--
+ See compatibility_matrix.4.xml on versioning of radio config HAL.
+ -->
+ <version>1.1</version>
<interface>
<name>IRadioConfig</name>
<instance>default</instance>
diff --git a/configstore/1.1/default/android.hardware.configstore@1.1-service.rc b/configstore/1.1/default/android.hardware.configstore@1.1-service.rc
index 105678a..d62c4a8 100644
--- a/configstore/1.1/default/android.hardware.configstore@1.1-service.rc
+++ b/configstore/1.1/default/android.hardware.configstore@1.1-service.rc
@@ -1,4 +1,6 @@
service vendor.configstore-hal /vendor/bin/hw/android.hardware.configstore@1.1-service
+ interface android.hardware.configstore@1.0::ISurfaceFlingerConfigs default
+ interface android.hardware.configstore@1.1::ISurfaceFlingerConfigs default
class hal animation
user system
group system
diff --git a/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc b/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc
index c04e55e..adc7222 100644
--- a/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc
+++ b/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.confirmationui-1-0 /vendor/bin/hw/android.hardware.confirmationui@1.0-service
+ interface android.hardware.confirmationui@1.0::IConfirmationUI default
class hal
user nobody
group drmrpc
diff --git a/confirmationui/support/include/ConfirmationUITranslations.h b/confirmationui/support/include/ConfirmationUITranslations.h
new file mode 100644
index 0000000..a55dc08
--- /dev/null
+++ b/confirmationui/support/include/ConfirmationUITranslations.h
@@ -0,0 +1,27 @@
+/*
+**
+** Copyright 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.
+*/
+
+/* Generated by generate-translations.py - DO NOT EDIT */
+
+#ifndef ConfirmationUITranslations_H
+#define ConfirmationUITranslations_H
+
+const char* ConfirmationUITranslations_select_lang_id(const char* lang_id);
+
+const char* ConfirmationUITranslations_lookup(const char* translation_id);
+
+#endif // ConfirmationUITranslations_H
diff --git a/confirmationui/support/src/ConfirmationUITranslations.c b/confirmationui/support/src/ConfirmationUITranslations.c
new file mode 100644
index 0000000..4d616ae
--- /dev/null
+++ b/confirmationui/support/src/ConfirmationUITranslations.c
@@ -0,0 +1,1158 @@
+/*
+**
+** Copyright 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.
+*/
+
+/* Generated by generate-translations.py - DO NOT EDIT */
+
+#include "ConfirmationUITranslations.h"
+#include "string.h"
+
+static const char* ConfirmationUITranslations_language_ids[] = {
+ "en", /* untranslated */
+ "af",
+ "am",
+ "ar",
+ "ar-EG",
+ "ar-JO",
+ "ar-MA",
+ "ar-SA",
+ "ar-XB",
+ "as",
+ "az",
+ "be",
+ "bg",
+ "bn",
+ "bs",
+ "ca",
+ "cs",
+ "da",
+ "de",
+ "de-AT",
+ "de-CH",
+ "el",
+ "en-AU",
+ "en-CA",
+ "en-GB",
+ "en-IE",
+ "en-IN",
+ "en-SG",
+ "en-XA",
+ "en-XC",
+ "en-ZA",
+ "es",
+ "es-419",
+ "es-AR",
+ "es-BO",
+ "es-CL",
+ "es-CO",
+ "es-CR",
+ "es-DO",
+ "es-EC",
+ "es-GT",
+ "es-HN",
+ "es-MX",
+ "es-NI",
+ "es-PA",
+ "es-PE",
+ "es-PR",
+ "es-PY",
+ "es-SV",
+ "es-US",
+ "es-UY",
+ "es-VE",
+ "et",
+ "eu",
+ "fa",
+ "fi",
+ "fil",
+ "fr",
+ "fr-CA",
+ "fr-CH",
+ "gl",
+ "gsw",
+ "gu",
+ "he",
+ "hi",
+ "hr",
+ "hu",
+ "hy",
+ "id",
+ "in",
+ "is",
+ "it",
+ "iw",
+ "ja",
+ "ka",
+ "kk",
+ "km",
+ "kn",
+ "ko",
+ "ky",
+ "ln",
+ "lo",
+ "lt",
+ "lv",
+ "mk",
+ "ml",
+ "mn",
+ "mo",
+ "mr",
+ "ms",
+ "my",
+ "nb",
+ "ne",
+ "nl",
+ "no",
+ "or",
+ "pa",
+ "pl",
+ "pt",
+ "pt-BR",
+ "pt-PT",
+ "ro",
+ "ru",
+ "si",
+ "sk",
+ "sl",
+ "sq",
+ "sr",
+ "sr-Latn",
+ "sv",
+ "sw",
+ "ta",
+ "te",
+ "th",
+ "tl",
+ "tr",
+ "uk",
+ "ur",
+ "uz",
+ "vi",
+ "zh",
+ "zh-CN",
+ "zh-HK",
+ "zh-TW",
+ "zu",
+ NULL,
+};
+
+#define ARRAY_ELEMENTS(arr) \
+ (sizeof(arr)/sizeof(arr[0]))
+
+#define ConfirmationUITranslations_NUM_LANGUAGE_IDS \
+ (ARRAY_ELEMENTS(ConfirmationUITranslations_language_ids) - 1)
+
+static const struct {
+ const char* translation_id;
+ const char* translations[ConfirmationUITranslations_NUM_LANGUAGE_IDS];
+} ConfirmationUITranslations_translation_ids[] = {
+ {
+ "1424834532030812203",
+ {
+ "Double-press power to confirm", /* en (untranslated) */
+ "Dubbeldruk aan/af-skakelaar om te bevestig", /* af */
+ "ለማረጋገጥ ኃይልን ሁለቴ ይጫኑ", /* am */
+ "اضغط على زر التشغيل مرتين لتأكيد الإجراء.", /* ar */
+ "اضغط على زر التشغيل مرتين لتأكيد الإجراء.", /* ar-EG */
+ "اضغط على زر التشغيل مرتين لتأكيد الإجراء.", /* ar-JO */
+ "اضغط على زر التشغيل مرتين لتأكيد الإجراء.", /* ar-MA */
+ "اضغط على زر التشغيل مرتين لتأكيد الإجراء.", /* ar-SA */
+ "Double-press power to confirm", /* ar-XB */
+ "নিশ্চিত কৰিবলৈ পাৱাৰ বুটামটো দুবাৰ হেঁচক", /* as */
+ "Təsdiqləmək üçün iki dəfə yandırıb-söndürmək düyməsinə basın", /* az */
+ "Двойчы націсніце кнопку сілкавання, каб пацвердзіць", /* be */
+ "Натиснете два пъти бутона за захранване, за да потвърдите", /* bg */
+ "নিশ্চিত করতে পাওয়ার বোতাম দুবার টিপুন", /* bn */
+ "Dva puta pritisnite dugme za napajanje da potvrdite", /* bs */
+ "Prem dos cops el botó d'engegada per confirmar", /* ca */
+ "Potvrďte dvojitým stisknutím vypínače", /* cs */
+ "Tryk to gange på afbryderknappen for at bekræfte", /* da */
+ "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken", /* de */
+ "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken", /* de-AT */
+ "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken", /* de-CH */
+ "Πατήστε δύο φορές το κουμπί λειτουργίας για επιβεβαίωση", /* el */
+ "Double-press power to confirm", /* en-AU */
+ "Double-press power to confirm", /* en-CA */
+ "Double-press power to confirm", /* en-GB */
+ "Double-press power to confirm", /* en-IE */
+ "Double-press power to confirm", /* en-IN */
+ "Double-press power to confirm", /* en-SG */
+ "[Ðöûбļé-þŕéšš þöŵéŕ ţö çöñƒîŕm one two three four five six seven]", /* en-XA */
+ "Double-press power to confirm", /* en-XC */
+ "Double-press power to confirm", /* en-ZA */
+ "Pulsa dos veces el botón de encendido para confirmar", /* es */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-419 */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-AR */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-BO */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-CL */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-CO */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-CR */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-DO */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-EC */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-GT */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-HN */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-MX */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-NI */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-PA */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-PE */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-PR */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-PY */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-SV */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-US */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-UY */
+ "Presiona dos veces el botón de encendido para confirmar", /* es-VE */
+ "Kinnitamiseks topeltvajutage toitenuppu", /* et */
+ "Berresteko, sakatu birritan pizteko botoia", /* eu */
+ "برای تأیید، دکمه روشن/خاموش را دوبار فشار دهید", /* fa */
+ "Vahvista painamalla virtapainiketta kahdesti", /* fi */
+ "Pindutin nang dalawang beses ang power para kumpirmahin", /* fil */
+ "Appuyez deux fois sur le bouton Marche/Arrêt pour confirmer l'opération", /* fr */
+ "Appuyez deux fois sur l'interrupteur pour confirmer", /* fr-CA */
+ "Appuyez deux fois sur le bouton Marche/Arrêt pour confirmer l'opération", /* fr-CH */
+ "Preme o botón de acendido dúas veces para confirmar", /* gl */
+ "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken", /* gsw */
+ "કન્ફર્મ કરવા માટે પાવર પર બે વાર ટૅપ કરો", /* gu */
+ "יש ללחוץ פעמיים על לחצן ההפעלה כדי לאשר", /* he */
+ "पुष्टि करने के लिए पावर बटन दो बार दबाएं", /* hi */
+ "Dvaput pritisnite tipku za uključivanje/isključivanje da biste potvrdili", /* hr */
+ "A megerősítéshez nyomja meg duplán a bekapcsológombot", /* hu */
+ "Հաստատելու համար կրկնակի սեղմեք սնուցման կոճակը", /* hy */
+ "Tekan dua kali tombol power untuk mengonfirmasi", /* id */
+ "Tekan dua kali tombol power untuk mengonfirmasi", /* in */
+ "Ýttu tvisvar á aflrofann til að staðfesta", /* is */
+ "Premi due volte il tasto di accensione per confermare", /* it */
+ "יש ללחוץ פעמיים על לחצן ההפעלה כדי לאשר", /* iw */
+ "確認するには、電源を 2 回押します", /* ja */
+ "დასადასტურებლად ორმაგად დააჭირეთ ჩართვის ღილაკს", /* ka */
+ "Растау үшін қуат түймесін екі рет басыңыз", /* kk */
+ "ចុចប៊ូតុងថាមពលពីរដងដើម្បីបញ្ជាក់", /* km */
+ "ದೃಢೀಕರಿಸಲು ಪವರ್ ಬಟನ್ ಅನ್ನು ಎರಡು ಬಾರಿ ಒತ್ತಿರಿ", /* kn */
+ "확인하려면 전원 버튼을 두 번 누르세요.", /* ko */
+ "Ырастоо үчүн \"Кубат\" баскычын эки жолу басыңыз", /* ky */
+ "Appuyez deux fois sur le bouton Marche/Arrêt pour confirmer l'opération", /* ln */
+ "ກົດປຸ່ມປິດເປີດເຄື່ອງສອງຄັ້ງເພື່ອຢືນຢັນ", /* lo */
+ "Dukart paspauskite maitinimo mygtuką, kad patvirtintumėte", /* lt */
+ "Lai apstiprinātu, divreiz nospiediet barošanas pogu", /* lv */
+ "Притиснете на копчето за напојување двапати за да потврдите", /* mk */
+ "സ്ഥിരീകരിക്കാൻ പവർ രണ്ടുതവണ അമർത്തുക", /* ml */
+ "Баталгаажуулахын тулд унтраах/асаахыг хоёр удаа дарах", /* mn */
+ "Apăsați de două ori butonul de pornire pentru a confirma", /* mo */
+ "खात्री करण्यासाठी पॉवर बटण दोनदा दाबा", /* mr */
+ "Tekan dua kali butang kuasa untuk mengesahkan", /* ms */
+ "အတည်ပြုရန် ပါဝါခလုတ်ကို နှစ်ချက်နှိပ်ပါ", /* my */
+ "Dobbelttrykk på av/på-knappen for å bekrefte", /* nb */
+ "पुष्टि गर्न पावर बटनमा दुई पटक थिच्नुहोस्", /* ne */
+ "Druk twee keer op de aan/uit-knop om te bevestigen", /* nl */
+ "Dobbelttrykk på av/på-knappen for å bekrefte", /* no */
+ "ସୁନିଶ୍ଚିତ କରିବା ପାଇଁ ପାୱାର୍ ବଟନ୍କୁ ଦୁଇଥର ଦବାନ୍ତୁ", /* or */
+ "ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਪਾਵਰ ਬਟਨ ਨੂੰ ਦੋ ਬਾਰ ਦੱਬੋ", /* pa */
+ "Kliknij dwukrotnie przycisk zasilania, by potwierdzić", /* pl */
+ "Pressione o botão liga/desliga duas vezes para confirmar", /* pt */
+ "Pressione o botão liga/desliga duas vezes para confirmar", /* pt-BR */
+ "Prima duas vezes ligar/desligar para confirmar.", /* pt-PT */
+ "Apăsați de două ori butonul de pornire pentru a confirma", /* ro */
+ "Для подтверждения дважды нажмите кнопку питания.", /* ru */
+ "තහවුරු කිරීමට බල බොත්තම දෙවරක් ඔබන්න", /* si */
+ "Potvrďte dvojitým stlačením vypínača", /* sk */
+ "Dvakrat pritisnite za potrditev", /* sl */
+ "Shtyp dy herë butonin e energjisë për të konfirmuar", /* sq */
+ "Двапут притисните дугме за напајање да бисте потврдили", /* sr */
+ "Dvaput pritisnite dugme za napajanje da biste potvrdili", /* sr-Latn */
+ "Bekräfta genom att trycka två gånger på avstängningsknappen", /* sv */
+ "Bonyeza kitufe cha kuwasha mara mbili ili uthibitishe", /* sw */
+ "உறுதிப்படுத்த, பவர் பட்டனை இருமுறை அழுத்தவும்", /* ta */
+ "నిర్ధారించడానికి పవర్ బటన్ని రెండు సార్లు నొక్కండి", /* te */
+ "กดปุ่มเปิด/ปิด 2 ครั้งเพื่อยืนยัน", /* th */
+ "Pindutin nang dalawang beses ang power para kumpirmahin", /* tl */
+ "Onaylamak için güç düğmesine iki kez basın", /* tr */
+ "Двічі натисніть кнопку живлення, щоб підтвердити", /* uk */
+ "تصدیق کرنے کے لئے پاور بٹن دوبار دبائیں", /* ur */
+ "Tasdiqlash uchun quvvat tugmasini ikki marta bosing", /* uz */
+ "Nhấn hai lần vào nút nguồn để xác nhận", /* vi */
+ "连按两次电源按钮即可确认", /* zh */
+ "连按两次电源按钮即可确认", /* zh-CN */
+ "按兩下電源按鈕即可確認", /* zh-HK */
+ "按兩下電源按鈕即可確認操作", /* zh-TW */
+ "Cindezela kabili ukuze uqinisekise", /* zu */
+ }
+ },
+ {
+ "1796282799666106567",
+ {
+ "Cancel", /* en (untranslated) */
+ "Kanselleer", /* af */
+ "ይቅር", /* am */
+ "إلغاء", /* ar */
+ "إلغاء", /* ar-EG */
+ "إلغاء", /* ar-JO */
+ "إلغاء", /* ar-MA */
+ "إلغاء", /* ar-SA */
+ "Cancel", /* ar-XB */
+ "বাতিল কৰক", /* as */
+ "Ləğv edin", /* az */
+ "Скасаваць", /* be */
+ "Отказ", /* bg */
+ "বাতিল করুন", /* bn */
+ "Otkaži", /* bs */
+ "Cancel·la", /* ca */
+ "Zrušit", /* cs */
+ "Annuller", /* da */
+ "Abbrechen", /* de */
+ "Abbrechen", /* de-AT */
+ "Abbrechen", /* de-CH */
+ "Ακύρωση", /* el */
+ "Cancel", /* en-AU */
+ "Cancel", /* en-CA */
+ "Cancel", /* en-GB */
+ "Cancel", /* en-IE */
+ "Cancel", /* en-IN */
+ "Cancel", /* en-SG */
+ "[Çåñçéļ one]", /* en-XA */
+ "Cancel", /* en-XC */
+ "Cancel", /* en-ZA */
+ "Cancelar", /* es */
+ "Cancelar", /* es-419 */
+ "Cancelar", /* es-AR */
+ "Cancelar", /* es-BO */
+ "Cancelar", /* es-CL */
+ "Cancelar", /* es-CO */
+ "Cancelar", /* es-CR */
+ "Cancelar", /* es-DO */
+ "Cancelar", /* es-EC */
+ "Cancelar", /* es-GT */
+ "Cancelar", /* es-HN */
+ "Cancelar", /* es-MX */
+ "Cancelar", /* es-NI */
+ "Cancelar", /* es-PA */
+ "Cancelar", /* es-PE */
+ "Cancelar", /* es-PR */
+ "Cancelar", /* es-PY */
+ "Cancelar", /* es-SV */
+ "Cancelar", /* es-US */
+ "Cancelar", /* es-UY */
+ "Cancelar", /* es-VE */
+ "Tühista", /* et */
+ "Utzi", /* eu */
+ "لغو", /* fa */
+ "Peruuta", /* fi */
+ "Kanselahin", /* fil */
+ "Annuler", /* fr */
+ "Annuler", /* fr-CA */
+ "Annuler", /* fr-CH */
+ "Cancelar", /* gl */
+ "Abbrechen", /* gsw */
+ "રદ કરો", /* gu */
+ "ביטול", /* he */
+ "रद्द करें", /* hi */
+ "Otkaži", /* hr */
+ "Mégse", /* hu */
+ "Չեղարկել", /* hy */
+ "Batal", /* id */
+ "Batal", /* in */
+ "Hætta við", /* is */
+ "Annulla", /* it */
+ "ביטול", /* iw */
+ "キャンセル", /* ja */
+ "გაუქმება", /* ka */
+ "Бас тарту", /* kk */
+ "បោះបង់", /* km */
+ "ರದ್ದು", /* kn */
+ "취소", /* ko */
+ "Жокко чыгаруу", /* ky */
+ "Annuler", /* ln */
+ "ຍົກເລີກ", /* lo */
+ "Atšaukti", /* lt */
+ "Atcelt", /* lv */
+ "Откажи", /* mk */
+ "റദ്ദാക്കുക", /* ml */
+ "Болих", /* mn */
+ "Anulați", /* mo */
+ "रद्द करा", /* mr */
+ "Batal", /* ms */
+ "မလုပ်တော့", /* my */
+ "Avbryt", /* nb */
+ "रद्द गर्नुहोस्", /* ne */
+ "Annuleren", /* nl */
+ "Avbryt", /* no */
+ "କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ", /* or */
+ "ਰੱਦ ਕਰੋ", /* pa */
+ "Anuluj", /* pl */
+ "Cancelar", /* pt */
+ "Cancelar", /* pt-BR */
+ "Cancelar", /* pt-PT */
+ "Anulați", /* ro */
+ "Отмена", /* ru */
+ "අවලංගු කරන්න", /* si */
+ "Zrušiť", /* sk */
+ "Prekliči", /* sl */
+ "Anulo", /* sq */
+ "Откажи", /* sr */
+ "Otkaži", /* sr-Latn */
+ "Avbryt", /* sv */
+ "Ghairi", /* sw */
+ "ரத்துசெய்", /* ta */
+ "రద్దు చేయండి", /* te */
+ "ยกเลิก", /* th */
+ "Kanselahin", /* tl */
+ "İptal", /* tr */
+ "Скасувати", /* uk */
+ "منسوخ کریں", /* ur */
+ "Bekor qilish", /* uz */
+ "Hủy", /* vi */
+ "取消", /* zh */
+ "取消", /* zh-CN */
+ "取消", /* zh-HK */
+ "取消", /* zh-TW */
+ "Khansela", /* zu */
+ }
+ },
+ {
+ "217688588483778177",
+ {
+ "This confirmation provides an extra layer of security for the action you're about to take.", /* en (untranslated) */
+ "Hierdie bevestiging verskaf 'n ekstra laag sekuriteit vir die handeling wat jy op die punt is om uit te voer.", /* af */
+ "ይህ ማረጋገጫ እርስዎ ለሚወስዱት እርምጃ ተጨማሪ ትርፍ ጥበቃን ይሰጣል።", /* am */
+ "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.", /* ar */
+ "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.", /* ar-EG */
+ "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.", /* ar-JO */
+ "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.", /* ar-MA */
+ "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.", /* ar-SA */
+ "This confirmation provides an extra layer of security for the action you're about to take.", /* ar-XB */
+ "এই প্ৰতিশ্ৰুতিয়ে আপুনি কৰিব বিচৰা কোনো কাৰ্যৰ বাবে অতিৰিক্ত সুৰক্ষা প্ৰদান কৰে।", /* as */
+ "Bu təsdiq etmək üzrə olduğunuz əməliyyat üçün əlavə təhlükəsizlik qatı təmin edir.", /* az */
+ "Гэта пацвярджэнне забяспечвае дадатковы ўзровень бяспекі для дзеянняў, якія вы збіраецеся выконваць.", /* be */
+ "Това потвърждение осигурява допълнителна защита за действието, което сте напът да предприемете.", /* bg */
+ "আপনি যে কাজটি করতে চলেছেন, এই কনফার্মেশনের ফলে সেটির জন্য অতিরিক্ত সুরক্ষার ব্যবস্থা করা হয়।", /* bn */
+ "Ova potvrda pruža dodatni sloj zaštite za radnju koju namjeravate preduzeti.", /* bs */
+ "Aquesta confirmació proporciona una capa de seguretat addicional per a l'acció que estàs a punt de dur a terme.", /* ca */
+ "Toto potvrzení tvoří dodatečnou úroveň zabezpečení akce, kterou se chystáte podniknout.", /* cs */
+ "Denne bekræftelse giver et ekstra beskyttelsesniveau for den handling, du er ved at foretage.", /* da */
+ "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmaßnahme angewandt.", /* de */
+ "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmaßnahme angewandt.", /* de-AT */
+ "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmassnahme angewandt.", /* de-CH */
+ "Αυτή η επιβεβαίωση παρέχει ένα επιπλέον επίπεδο ασφάλειας για την ενέργεια που πρόκειται να εκτελέσετε.", /* el */
+ "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-AU */
+ "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-CA */
+ "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-GB */
+ "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-IE */
+ "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-IN */
+ "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-SG */
+ "[Ţĥîš çöñƒîŕmåţîöñ þŕövîðéš åñ éxţŕå ļåýéŕ öƒ šéçûŕîţý ƒöŕ ţĥé åçţîöñ ýöû'ŕé åбöûţ ţö ţåķé. one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen]", /* en-XA */
+ "This confirmation provides an extra layer of security for the action you're about to take.", /* en-XC */
+ "This confirmation provides an extra layer of security for the action that you're about to take.", /* en-ZA */
+ "Esta confirmación proporciona una capa de seguridad adicional a la acción que vas a realizar.", /* es */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-419 */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-AR */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-BO */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-CL */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-CO */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-CR */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-DO */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-EC */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-GT */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-HN */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-MX */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-NI */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-PA */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-PE */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-PR */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-PY */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-SV */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-US */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-UY */
+ "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.", /* es-VE */
+ "See kinnitus annab veel ühe turvakihi toimingu puhul, mille nüüd teete.", /* et */
+ "Berrespen honek segurtasun handiagoa ematen dizu hurrengo ekintza gauzatzeko.", /* eu */
+ "این تأیید یک لایه امنیتی اضافی برای کنشی که میخواهید انجام دهید فراهم میکند.", /* fa */
+ "Tämä vahvistus tarkoittaa, että seuraava toimintosi on entistä paremmin suojattu.", /* fi */
+ "Ang pagkumpirmang ito ay nagbibigay ng karagdagang layer ng seguridad para sa pagkilos na gagawin mo.", /* fil */
+ "Cette confirmation ajoute un niveau de sécurité supplémentaire à l'action que vous êtes sur le point d'effectuer.", /* fr */
+ "Cette confirmation fournit une couche supplémentaire de sécurité pour l'action que vous êtes sur le point d'effectuer.", /* fr-CA */
+ "Cette confirmation ajoute un niveau de sécurité supplémentaire à l'action que vous êtes sur le point d'effectuer.", /* fr-CH */
+ "Esta confirmación proporciona unha capa adicional de seguranza para a acción que estás a piques de levar a cabo.", /* gl */
+ "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmaßnahme angewandt.", /* gsw */
+ "તમે જે ક્રિયા કરવાના છો તેના માટે આ કન્ફર્મેશન એક અતિરિક્ત સુરક્ષાનું સ્તર પ્રદાન કરે છે.", /* gu */
+ "אישור זה מספק שכבת אבטחה נוספת לפעולה שאתה עומד לבצע.", /* he */
+ "यह पुष्टि मिलने पर आप जो काम करने वाले हैं, उसके लिए सुरक्षा और बढ़ जाती है.", /* hi */
+ "Ta potvrda pruža dodatan sloj zaštite za radnju koju ćete izvršiti.", /* hr */
+ "Ez a megerősítés extra réteg biztonságot nyújt a végrehajtani kívánt művelet számára.", /* hu */
+ "Այս հաստատումն ապահովում է պաշտպանության լրացուցիչ մակարդակ՝ նախքան գործողություն կատարելը", /* hy */
+ "Konfirmasi ini memberikan lapisan keamanan tambahan untuk tindakan yang akan Anda ambil.", /* id */
+ "Konfirmasi ini memberikan lapisan keamanan tambahan untuk tindakan yang akan Anda ambil.", /* in */
+ "Þessi staðfesting veitir aukið öryggi fyrir aðgerðina sem þú ert að fara að framkvæma.", /* is */
+ "Questa conferma garantisce un ulteriore livello di sicurezza per l'azione che stai per compiere.", /* it */
+ "אישור זה מספק שכבת אבטחה נוספת לפעולה שאתה עומד לבצע.", /* iw */
+ "この確認により、これから行う操作のセキュリティが強化されます。", /* ja */
+ "დადასტურება უსაფრთხოების დამატებით შრეს უზრუნველყოფს იმ ქმედების განსახორციელებლად, რომელსაც აპირებთ.", /* ka */
+ "Бұл растау функциясы орындағалы тұрған әрекеттің қауіпсіздігін қосымша күшейтеді.", /* kk */
+ "ការបញ្ជាក់នេះផ្ដល់ស្រទាប់សុវត្ថិភាពបន្ថែមសម្រាប់សកម្មភាពដែលអ្នកហៀបនឹងធ្វើ។", /* km */
+ "ಈ ದೃಢೀಕರಣವು ನೀವು ನಿರ್ವಹಿಸಲು ಬಯಸುವ ಕ್ರಿಯೆಗೆ ಹೆಚ್ಚುವರಿ ಸುರಕ್ಷತೆಯನ್ನು ಒದಗಿಸುತ್ತದೆ.", /* kn */
+ "이 확인 단계를 사용하면 실행하려는 작업의 보안을 한층 강화할 수 있습니다.", /* ko */
+ "Бул ырастоо сиз аткара турган аракеттин коопсуздугун коргоонун дагы бир катмарын камсыздайт.", /* ky */
+ "Cette confirmation ajoute un niveau de sécurité supplémentaire à l'action que vous êtes sur le point d'effectuer.", /* ln */
+ "ການຢືນຢັນນີ້ຈະເພີ່ມຄວາມປອດໄພເພີ່ມເຕີມອີກໜຶ່ງຊັ້ນໃຫ້ກັບຄຳສັ່ງທີ່ທ່ານກຳລັງຈະໃຊ້.", /* lo */
+ "Naudojant šį patvirtinimą, veiksmui, kurį ketinate atlikti, taikomas papildomas saugos lygmuo.", /* lt */
+ "Šis apstiprinājums sniedz papildu aizsardzību darbībai, kuru veiksiet.", /* lv */
+ "Оваа потврда обезбедува дополнителен слој на безбедност за дејството што ќе го преземете.", /* mk */
+ "നിങ്ങൾ സ്വീകരിക്കാൻ പോകുന്ന നടപടിക്കായി, ഈ സ്ഥിരീകരണം ഒരു അധിക സുരക്ഷാ പാളി നൽകുന്നു.", /* ml */
+ "Энэ баталгаажуулалт нь таны авах гэж буй арга хэмжээнд хамгаалалтын нэмэлт давхаргыг олгодог.", /* mn */
+ "Această confirmare oferă un nivel suplimentar de securitate pentru acțiunea pe care urmează să o faceți.", /* mo */
+ "हे निश्चित झाल्यावर, तुम्ही जे काम करणार आहात, त्यासाठी सुरक्षा आणखी वाढते.", /* mr */
+ "Pengesahan ini memberikan lapisan keselamatan tambahan untuk tindakan yang akan anda ambil.", /* ms */
+ "ဤအတည်ပြုချက်က သင်ပြုလုပ်တော့မည့် လုပ်ဆောင်ချက်အတွက် အပိုဆောင်းလုံခြုံရေးကို ပေးထားသည်။", /* my */
+ "Denne bekreftelsen gir et ekstra sikkerhetslag for handlingen du er i ferd med å utføre.", /* nb */
+ "यो पुष्टिले तपाईंले गर्न ऑंट्नुभएको कारबाहीका लागि सुरक्षाको अतिरिक्त तह प्रदान गर्छ।", /* ne */
+ "Deze bevestiging biedt een extra beveiligingslaag voor de actie die je wilt uitvoeren.", /* nl */
+ "Denne bekreftelsen gir et ekstra sikkerhetslag for handlingen du er i ferd med å utføre.", /* no */
+ "ଏହି ସୁନିଶ୍ଚିତତା, ଆପଣ କରିବାକୁ ଯାଉଥିବା କାର୍ଯ୍ୟ ପାଇଁ ଅତିରିକ୍ତ ସୁରକ୍ଷା ପରତ ପ୍ରଦାନ କରିଥାଏ।", /* or */
+ "ਇਹ ਪੁਸ਼ਟੀਕਰਨ ਤੁਹਾਡੇ ਵੱਲੋਂ ਕਾਰਵਾਈ ਨੂੰ ਕੀਤੇ ਜਾਣ ਲਈ ਸੁਰੱਖਿਆ ਦੇ ਇੱਕ ਵਾਧੂ ਪੱਧਰ ਮੁਹੱਈਆ ਕਰਦੀ ਹੈ।", /* pa */
+ "To potwierdzenie stanowi dodatkowe zabezpieczenie czynności, którą zamierzasz wykonać.", /* pl */
+ "Essa confirmação oferece uma camada adicional de segurança para a ação que você está prestes a realizar.", /* pt */
+ "Essa confirmação oferece uma camada adicional de segurança para a ação que você está prestes a realizar.", /* pt-BR */
+ "Esta confirmação oferece um nível extra de segurança para a ação que está prestes a realizar.", /* pt-PT */
+ "Această confirmare oferă un nivel suplimentar de securitate pentru acțiunea pe care urmează să o faceți.", /* ro */
+ "Дополнительный уровень защиты для действия, которое вы собираетесь выполнить.", /* ru */
+ "මෙම තහවුරු කිරිම ඔබ ගැනීමට යන ක්රියාමාර්ගය සඳහා ආරක්ෂාව පිළිබඳ අමතර ස්තරයක් සපයයි.", /* si */
+ "Toto potvrdenie zaistí dodatočnú úroveň zabezpečenia akcie, ktorú sa chystáte vykonať.", /* sk */
+ "Ta potrditev zagotavlja dodatno plast zaščite za dejanje, ki ga boste izvedli.", /* sl */
+ "Konfirmim ofron një shtresë sigurie shtesë për veprimin që je gati për të ndërmarrë.", /* sq */
+ "Ова потврда пружа додатни слој безбедности за радњу коју се спремате да извршите.", /* sr */
+ "Ova potvrda pruža dodatni sloj bezbednosti za radnju koju se spremate da izvršite.", /* sr-Latn */
+ "Bekräftelsen ger extra skydd för åtgärden du ska vidta.", /* sv */
+ "Uthibitishaji huu hutoa ulinzi zaidi wa usalama kwa hatua unayotaka kuchukua.", /* sw */
+ "நீங்கள் மேற்கொள்ளவிருக்கும் செயலுக்கு, கூடுதல் பாதுகாப்பை இந்த உறுதிப்படுத்தல் வழங்கும்.", /* ta */
+ "ఈ నిర్ధారణ మీరు తీసుకోబోయే చర్య కోసం అదనపు భద్రతా లేయర్ను అందిస్తుంది.", /* te */
+ "การยืนยันนี้จะช่วยเพิ่มความปลอดภัยอีกขั้นสำหรับสิ่งที่คุณกำลังจะดำเนินการ", /* th */
+ "Ang pagkumpirmang ito ay nagbibigay ng karagdagang layer ng seguridad para sa pagkilos na gagawin mo.", /* tl */
+ "Bu onay, yapmak üzere olduğunuz işlem için ek güvenlik katmanı sağlar.", /* tr */
+ "Це підтвердження є додатковим рівнем захисту, коли ви збираєтеся виконати дію.", /* uk */
+ "آپ جو کارروائی کرنے والے ہیں اس کے لئے یہ تصدیق ایک اضافی پرت فراہم کرتی ہے۔", /* ur */
+ "Tasdiqlangandan keyin bajarilayotgan amal uchun qo‘shimcha xavfsizlik qatlami taqdim etiladi.", /* uz */
+ "Xác nhận này cung cấp thêm một lớp bảo mật cho hành động bạn sắp thực hiện.", /* vi */
+ "这项确认可为您即将执行的操作增添一层额外的安全保障。", /* zh */
+ "这项确认可为您即将执行的操作增添一层额外的安全保障。", /* zh-CN */
+ "此確認可為你即將執行的操作提供額外安全保障。", /* zh-HK */
+ "這項確認作業可為你即將執行的動作提供多一層安全保障。", /* zh-TW */
+ "Lokhu kuqinisekiswa kunikeza isendlalelo esingeziwe sokuvikelwa sesenzo osuzosithatha.", /* zu */
+ }
+ },
+ {
+ "2181224373757710937",
+ {
+ "Press power to confirm", /* en (untranslated) */
+ "Druk aan/af-skakelaar om te bevestig", /* af */
+ "ለማረጋገጥ ኃይልን ይጫኑ", /* am */
+ "اضغط على زر التشغيل لتأكيد الإجراء.", /* ar */
+ "اضغط على زر التشغيل لتأكيد الإجراء.", /* ar-EG */
+ "اضغط على زر التشغيل لتأكيد الإجراء.", /* ar-JO */
+ "اضغط على زر التشغيل لتأكيد الإجراء.", /* ar-MA */
+ "اضغط على زر التشغيل لتأكيد الإجراء.", /* ar-SA */
+ "Press power to confirm", /* ar-XB */
+ "নিশ্চিত কৰিবলৈ পাৱাৰ বুটাম হেঁচক", /* as */
+ "Təsdiq etmək üçün yandırıb-söndürmə düyməsinə basın", /* az */
+ "Націсніце кнопку сілкавання, каб пацвердзіць", /* be */
+ "Натиснете бутона за захранване, за да потвърдите", /* bg */
+ "নিশ্চিত করতে পাওয়ার বোতাম টিপুন", /* bn */
+ "Pritisnite dugme za napajanje za potvrdu", /* bs */
+ "Prem el botó d'engegada per confirmar", /* ca */
+ "Potvrďte stisknutím vypínače", /* cs */
+ "Tryk på afbryderknappen for at bekræfte", /* da */
+ "Drücke zum Bestätigen die Ein-/Aus-Taste", /* de */
+ "Drücke zum Bestätigen die Ein-/Aus-Taste", /* de-AT */
+ "Drücke zum Bestätigen die Ein-/Aus-Taste", /* de-CH */
+ "Πατήστε το κουμπί λειτουργίας για επιβεβαίωση", /* el */
+ "Press power to confirm", /* en-AU */
+ "Press power to confirm", /* en-CA */
+ "Press power to confirm", /* en-GB */
+ "Press power to confirm", /* en-IE */
+ "Press power to confirm", /* en-IN */
+ "Press power to confirm", /* en-SG */
+ "[Þŕéšš þöŵéŕ ţö çöñƒîŕm one two three four five]", /* en-XA */
+ "Press power to confirm", /* en-XC */
+ "Press power to confirm", /* en-ZA */
+ "Pulsa el botón de encendido para confirmar", /* es */
+ "Presiona el botón de encendido para confirmar", /* es-419 */
+ "Presiona el botón de encendido para confirmar", /* es-AR */
+ "Presiona el botón de encendido para confirmar", /* es-BO */
+ "Presiona el botón de encendido para confirmar", /* es-CL */
+ "Presiona el botón de encendido para confirmar", /* es-CO */
+ "Presiona el botón de encendido para confirmar", /* es-CR */
+ "Presiona el botón de encendido para confirmar", /* es-DO */
+ "Presiona el botón de encendido para confirmar", /* es-EC */
+ "Presiona el botón de encendido para confirmar", /* es-GT */
+ "Presiona el botón de encendido para confirmar", /* es-HN */
+ "Presiona el botón de encendido para confirmar", /* es-MX */
+ "Presiona el botón de encendido para confirmar", /* es-NI */
+ "Presiona el botón de encendido para confirmar", /* es-PA */
+ "Presiona el botón de encendido para confirmar", /* es-PE */
+ "Presiona el botón de encendido para confirmar", /* es-PR */
+ "Presiona el botón de encendido para confirmar", /* es-PY */
+ "Presiona el botón de encendido para confirmar", /* es-SV */
+ "Presiona el botón de encendido para confirmar", /* es-US */
+ "Presiona el botón de encendido para confirmar", /* es-UY */
+ "Presiona el botón de encendido para confirmar", /* es-VE */
+ "Kinnitamiseks vajutage toitenuppu", /* et */
+ "Berresteko, sakatu etengailua", /* eu */
+ "برای تأیید، دکمه روشن/خاموش را فشار دهید", /* fa */
+ "Vahvista painamalla virtapainiketta", /* fi */
+ "Pindutin ang power para kumpirmahin", /* fil */
+ "Appuyez sur le bouton Marche/Arrêt pour confirmer l'opération", /* fr */
+ "Appuyez sur l'interrupteur pour confirmer", /* fr-CA */
+ "Appuyez sur le bouton Marche/Arrêt pour confirmer l'opération", /* fr-CH */
+ "Preme o botón de acendido para confirmar", /* gl */
+ "Drücke zum Bestätigen die Ein-/Aus-Taste", /* gsw */
+ "કન્ફર્મ કરવા માટે પાવર બટન દબાવો", /* gu */
+ "יש ללחוץ על לחצן ההפעלה כדי לאשר", /* he */
+ "पुष्टि करने के लिए पावर बटन दबाएं", /* hi */
+ "Pritisnite tipku za uključivanje/isključivanje da biste potvrdili", /* hr */
+ "Nyomja meg a bekapcsológombot a megerősítéshez", /* hu */
+ "Հաստատելու համար սեղմեք սնուցման կոճակը", /* hy */
+ "Tekan tombol power untuk mengonfirmasi", /* id */
+ "Tekan tombol power untuk mengonfirmasi", /* in */
+ "Ýttu á aflrofann til að staðfesta", /* is */
+ "Premi il tasto di accensione per confermare", /* it */
+ "יש ללחוץ על לחצן ההפעלה כדי לאשר", /* iw */
+ "確認するには、電源を押します", /* ja */
+ "დასადასტურებლად დააჭირეთ ჩართვის ღილაკს", /* ka */
+ "Растау үшін қуат түймесін басыңыз", /* kk */
+ "ចុចប៊ូតុងថាមពលដើម្បីបញ្ជាក់", /* km */
+ "ದೃಢೀಕರಿಸಲು ಪವರ್ ಬಟನ್ ಒತ್ತಿರಿ", /* kn */
+ "확인하려면 전원 버튼을 누르세요.", /* ko */
+ "Ырастоо үчүн \"Кубат\" баскычын басыңыз", /* ky */
+ "Appuyez sur le bouton Marche/Arrêt pour confirmer l'opération", /* ln */
+ "ກົດປຸ່ມເປີດປິດເພື່ອຢືນຢັນ", /* lo */
+ "Paspauskite maitinimo mygtuką, kad patvirtintumėte", /* lt */
+ "Lai apstiprinātu, nospiediet barošanas pogu", /* lv */
+ "Притиснете на копчето за напојување за да потврдите", /* mk */
+ "സ്ഥിരീകരിക്കാൻ പവർ അമർത്തുക", /* ml */
+ "Баталгаажуулахын тулд унтраах/асаахыг дарах", /* mn */
+ "Apăsați butonul de pornire pentru a confirma", /* mo */
+ "निश्चित करण्यासाठी पॉवर दाबा", /* mr */
+ "Tekan kuasa untuk mengesahkan", /* ms */
+ "အတည်ပြုရန် ပါဝါခလုတ်နှိပ်ပါ", /* my */
+ "Trykk på av/på-knappen for å bekrefte", /* nb */
+ "पुष्टि गर्न पावर बटनमा थिच्नुहोस्", /* ne */
+ "Druk op de aan/uit-knop om te bevestigen", /* nl */
+ "Trykk på av/på-knappen for å bekrefte", /* no */
+ "ସୁନିଶ୍ଚିତ କରିବା ପାଇଁ ପାୱର୍ ବଟନ୍କୁ ଦାବନ୍ତୁ", /* or */
+ "ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਪਾਵਰ ਬਟਨ ਦਬਾਓ", /* pa */
+ "Naciśnij przycisk zasilania, aby potwierdzić", /* pl */
+ "Pressione o botão liga/desliga para confirmar", /* pt */
+ "Pressione o botão liga/desliga para confirmar", /* pt-BR */
+ "Prima ligar/desligar para confirmar.", /* pt-PT */
+ "Apăsați butonul de pornire pentru a confirma", /* ro */
+ "Для подтверждения нажмите кнопку питания.", /* ru */
+ "තහවුරු කිරීමට බල බොත්තම ඔබන්න", /* si */
+ "Potvrďte stlačením vypínača", /* sk */
+ "Za potrditev pritisnite gumb za vklop", /* sl */
+ "Shtyp butonin e energjisë për të konfirmuar", /* sq */
+ "Притисните дугме за напајање да бисте потврдили", /* sr */
+ "Pritisnite dugme za napajanje da biste potvrdili", /* sr-Latn */
+ "Bekräfta genom att trycka på strömbrytaren", /* sv */
+ "Bonyeza kitufe cha kuwasha ili uthibitishe", /* sw */
+ "உறுதிப்படுத்த, பவரை அழுத்தவும்", /* ta */
+ "నిర్ధారించడానికి పవర్ను నొక్కండి", /* te */
+ "กดปุ่มเปิด/ปิดเพื่อยืนยัน", /* th */
+ "Pindutin ang power para kumpirmahin", /* tl */
+ "Onaylamak için güç düğmesine basın", /* tr */
+ "Натисніть кнопку живлення, щоб підтвердити", /* uk */
+ "تصدیق کرنے کے لئے پاور بٹن دبائیں", /* ur */
+ "Tasdiqlash uchun quvvat tugmasini bosing", /* uz */
+ "Nhấn vào nút nguồn để xác nhận", /* vi */
+ "按电源按钮即可确认", /* zh */
+ "按电源按钮即可确认", /* zh-CN */
+ "按下電源按鈕即可確認", /* zh-HK */
+ "按下電源按鈕即可確認操作", /* zh-TW */
+ "Cindezela amandla ukuze uqinisekise", /* zu */
+ }
+ },
+ {
+ "2213954494039981979",
+ {
+ "Press any volume button to cancel", /* en (untranslated) */
+ "Druk enige volumeknoppie om te kanselleer", /* af */
+ "ለመሰረዝ ማናቸውንም የድምፅ አዝራር ይጫኑ", /* am */
+ "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.", /* ar */
+ "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.", /* ar-EG */
+ "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.", /* ar-JO */
+ "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.", /* ar-MA */
+ "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.", /* ar-SA */
+ "Press any volume button to cancel", /* ar-XB */
+ "বাতিল কৰিবলৈ যিকোনো ভলিউম বুটাম হেঁচক", /* as */
+ "Ləğv etmək üçün istənilən səs düyməsinə basın", /* az */
+ "Націсніце любую кнопку гучнасці, каб cкасаваць", /* be */
+ "Натиснете някой от бутоните за силата на звука, за да анулирате", /* bg */
+ "বাতিল করতে ভলিউমের যেকোনও বোতাম টিপুন", /* bn */
+ "Pritisnite bilo koje dugme za podešavanje jačine zvuka da otkažete", /* bs */
+ "Prem qualsevol botó de volum per cancel·lar", /* ca */
+ "Zrušte stisknutím tlačítka hlasitosti", /* cs */
+ "Tryk på en af lydstyrkeknapperne for at annullere", /* da */
+ "Zum Abbrechen eine beliebige Lautstärketaste drücken", /* de */
+ "Zum Abbrechen eine beliebige Lautstärketaste drücken", /* de-AT */
+ "Zum Abbrechen eine beliebige Lautstärketaste drücken", /* de-CH */
+ "Πατήστε οποιοδήποτε κουμπί έντασης ήχου για ακύρωση", /* el */
+ "Press any volume button to cancel", /* en-AU */
+ "Press any volume button to cancel", /* en-CA */
+ "Press any volume button to cancel", /* en-GB */
+ "Press any volume button to cancel", /* en-IE */
+ "Press any volume button to cancel", /* en-IN */
+ "Press any volume button to cancel", /* en-SG */
+ "[Þŕéšš åñý vöļûmé бûţţöñ ţö çåñçéļ one two three four five six seven]", /* en-XA */
+ "Press any volume button to cancel", /* en-XC */
+ "Press any volume button to cancel", /* en-ZA */
+ "Pulsa cualquier botón de volumen para cancelar", /* es */
+ "Presiona cualquier botón de volumen para cancelar", /* es-419 */
+ "Presiona cualquier botón de volumen para cancelar", /* es-AR */
+ "Presiona cualquier botón de volumen para cancelar", /* es-BO */
+ "Presiona cualquier botón de volumen para cancelar", /* es-CL */
+ "Presiona cualquier botón de volumen para cancelar", /* es-CO */
+ "Presiona cualquier botón de volumen para cancelar", /* es-CR */
+ "Presiona cualquier botón de volumen para cancelar", /* es-DO */
+ "Presiona cualquier botón de volumen para cancelar", /* es-EC */
+ "Presiona cualquier botón de volumen para cancelar", /* es-GT */
+ "Presiona cualquier botón de volumen para cancelar", /* es-HN */
+ "Presiona cualquier botón de volumen para cancelar", /* es-MX */
+ "Presiona cualquier botón de volumen para cancelar", /* es-NI */
+ "Presiona cualquier botón de volumen para cancelar", /* es-PA */
+ "Presiona cualquier botón de volumen para cancelar", /* es-PE */
+ "Presiona cualquier botón de volumen para cancelar", /* es-PR */
+ "Presiona cualquier botón de volumen para cancelar", /* es-PY */
+ "Presiona cualquier botón de volumen para cancelar", /* es-SV */
+ "Presiona cualquier botón de volumen para cancelar", /* es-US */
+ "Presiona cualquier botón de volumen para cancelar", /* es-UY */
+ "Presiona cualquier botón de volumen para cancelar", /* es-VE */
+ "Tühistamiseks vajutage mis tahes helitugevuse nuppu", /* et */
+ "Bertan behera uzteko, sakatu bolumen-tekla bat", /* eu */
+ "برای لغو، یکی از دکمههای میزان صدا را فشار دهید", /* fa */
+ "Peruuta painamalla äänenvoimakkuuspainiketta", /* fi */
+ "Pindutin ang anumang button ng volume para kanselahin", /* fil */
+ "Appuyez sur l'un des boutons de volume pour annuler l'opération", /* fr */
+ "Appuyez sur un bouton de volume pour annuler l'action", /* fr-CA */
+ "Appuyez sur l'un des boutons de volume pour annuler l'opération", /* fr-CH */
+ "Preme calquera botón de volume para cancelar", /* gl */
+ "Zum Abbrechen eine beliebige Lautstärketaste drücken", /* gsw */
+ "રદ કરવા માટે કોઈપણ વૉલ્યૂમનું બટન દબાવો", /* gu */
+ "יש ללחוץ על לחצן כלשהו של עוצמת הקול כדי לבטל", /* he */
+ "रद्द करने के लिए कोई भी वॉल्यूम बटन दबाएं", /* hi */
+ "Pritisnite bilo koju tipku za glasnoću da biste otkazali", /* hr */
+ "Nyomja meg valamelyik hangerőgombot az elvetéshez", /* hu */
+ "Չեղարկելու համար սեղմեք ձայնի կագավորման որևէ կոճակ", /* hy */
+ "Tekan tombol volume apa saja untuk membatalkan", /* id */
+ "Tekan tombol volume apa saja untuk membatalkan", /* in */
+ "Ýttu á hvaða hljóðstyrkshnapp sem er til að hætta við", /* is */
+ "Premi qualsiasi pulsante del volume per annullare", /* it */
+ "יש ללחוץ על לחצן כלשהו של עוצמת הקול כדי לבטל", /* iw */
+ "キャンセルするには、いずれかの音量ボタンを押します", /* ja */
+ "გასაუქმებლად დააჭირეთ ხმის რეგულირების ნებისმიერ ღილაკს", /* ka */
+ "Бас тарту үшін кез келген дыбыс деңгейі түймесін басыңыз", /* kk */
+ "ចុចប៊ូតុងកម្រិតសំឡេងណាមួយដើម្បីបោះបង់", /* km */
+ "ರದ್ದುಗೊಳಿಸಲು ಯಾವುದೇ ವಾಲ್ಯೂಮ್ ಬಟನ್ ಒತ್ತಿರಿ", /* kn */
+ "취소하려면 볼륨 버튼 중 하나를 누르세요.", /* ko */
+ "Жокко чыгаруу үчүн үн көлөмүнүн баскычтарынын бирин басыңыз", /* ky */
+ "Appuyez sur l'un des boutons de volume pour annuler l'opération", /* ln */
+ "ກົດປຸ່ມສຽງຂຶ້ນ ຫຼື ລົງເພື່ອຍົກເລີກ", /* lo */
+ "Paspauskite bet kurį garsumo mygtuką, kad atšauktumėte", /* lt */
+ "Lai atceltu, nospiediet jebkuru skaļuma pogu", /* lv */
+ "Притиснете на кое било копче за јачина на звук за да откажете", /* mk */
+ "റദ്ദാക്കാൻ എതെങ്കിലും വോളിയം ബട്ടൺ അമർത്തുക", /* ml */
+ "Болихын тулд дууны түвшний товчлуурын аль нэгийг нь дарах", /* mn */
+ "Apăsați orice buton de volum pentru a anula", /* mo */
+ "रद्द करण्यासाठी कोणतेही व्हॉल्यूम बटण दाबा", /* mr */
+ "Tekan sebarang butang kelantangan untuk membatalkan tindakan", /* ms */
+ "ပယ်ဖျက်ရန် အသံအတိုးအကျယ်ခလုတ် တစ်ခုခုကိုနှိပ်ပါ", /* my */
+ "Trykk på en volumknapp for å avbryte", /* nb */
+ "रद्द गर्नका लागि कुनै भोल्युम बटन थिच्नुहोस्", /* ne */
+ "Druk op een volumeknop om te annuleren", /* nl */
+ "Trykk på en volumknapp for å avbryte", /* no */
+ "କ୍ୟାନ୍ସଲ୍ କରିବା ପାଇଁ ଯେକୌଣସି ଭଲ୍ୟୁମ୍ ବଟନ୍କୁ ଦାବନ୍ତୁ", /* or */
+ "ਰੱਦ ਕਰਨ ਲਈ ਕਿਸੇ ਵੀ ਵੌਲਿਊਮ ਬਟਨ ਨੂੰ ਦਬਾਓ", /* pa */
+ "Naciśnij dowolny przycisk głośności, aby anulować", /* pl */
+ "Pressione um dos botões de volume para cancelar", /* pt */
+ "Pressione um dos botões de volume para cancelar", /* pt-BR */
+ "Prima qualquer botão de volume para cancelar.", /* pt-PT */
+ "Apăsați orice buton de volum pentru a anula", /* ro */
+ "Для отмены нажмите на любую кнопку регулировки громкости.", /* ru */
+ "අවලංගු කිරීමට ඕනෑම හඬ පරිමා බොත්තමක් ඔබන්න", /* si */
+ "Zrušte stlačením ľubovoľného tlačidla hlasitosti", /* sk */
+ "Za preklic pritisnite poljuben gumb za glasnost", /* sl */
+ "Shtyp çdo buton volumi për ta anuluar", /* sq */
+ "Притисните било које дугме за јачину звука да бисте отказали", /* sr */
+ "Pritisnite bilo koje dugme za jačinu zvuka da biste otkazali", /* sr-Latn */
+ "Avbryt genom att trycka på valfri volymknapp", /* sv */
+ "Bonyeza kitufe chochote cha sauti ili ughairi", /* sw */
+ "ரத்துசெய்ய, ஏதேனும் ஒலியளவு பட்டனை அழுத்தவும்", /* ta */
+ "రద్దు చేయడానికి ఏదైనా వాల్యూమ్ బటన్ను నొక్కండి", /* te */
+ "กดปุ่มปรับระดับเสียงเพื่อยกเลิก", /* th */
+ "Pindutin ang anumang button ng volume para kanselahin", /* tl */
+ "İptal etmek için herhangi bir ses düğmesine basın", /* tr */
+ "Натисніть будь-яку клавішу гучності, щоб скасувати", /* uk */
+ "منسوخ کرنے کے لئے کوئی بھی والیوم بٹن دبائیں", /* ur */
+ "Bekor qilish uchun istalgan tovush tugmasini bosing", /* uz */
+ "Nhấn vào nút âm lượng bất kỳ để hủy", /* vi */
+ "按任意音量按钮即可取消", /* zh */
+ "按任意音量按钮即可取消", /* zh-CN */
+ "按下任何音量按鈕即可取消", /* zh-HK */
+ "按下任一音量按鈕即可取消操作", /* zh-TW */
+ "Cindezela noma iyiphi inkinobho yevolumu ukuze ukhansele", /* zu */
+ }
+ },
+ {
+ "3999296476990449149",
+ {
+ "Cancel", /* en (untranslated) */
+ "Kanselleer", /* af */
+ "ይቅር", /* am */
+ "إلغاء", /* ar */
+ "إلغاء", /* ar-EG */
+ "إلغاء", /* ar-JO */
+ "إلغاء", /* ar-MA */
+ "إلغاء", /* ar-SA */
+ "Cancel", /* ar-XB */
+ "বাতিল কৰক", /* as */
+ "Ləğv edin", /* az */
+ "Скасаваць", /* be */
+ "Отказ", /* bg */
+ "বাতিল করুন", /* bn */
+ "Otkaži", /* bs */
+ "Cancel·la", /* ca */
+ "Zrušit", /* cs */
+ "Annuller", /* da */
+ "Abbrechen", /* de */
+ "Abbrechen", /* de-AT */
+ "Abbrechen", /* de-CH */
+ "Ακύρωση", /* el */
+ "Cancel", /* en-AU */
+ "Cancel", /* en-CA */
+ "Cancel", /* en-GB */
+ "Cancel", /* en-IE */
+ "Cancel", /* en-IN */
+ "Cancel", /* en-SG */
+ "[Çåñçéļ one]", /* en-XA */
+ "Cancel", /* en-XC */
+ "Cancel", /* en-ZA */
+ "Cancelar", /* es */
+ "Cancelar", /* es-419 */
+ "Cancelar", /* es-AR */
+ "Cancelar", /* es-BO */
+ "Cancelar", /* es-CL */
+ "Cancelar", /* es-CO */
+ "Cancelar", /* es-CR */
+ "Cancelar", /* es-DO */
+ "Cancelar", /* es-EC */
+ "Cancelar", /* es-GT */
+ "Cancelar", /* es-HN */
+ "Cancelar", /* es-MX */
+ "Cancelar", /* es-NI */
+ "Cancelar", /* es-PA */
+ "Cancelar", /* es-PE */
+ "Cancelar", /* es-PR */
+ "Cancelar", /* es-PY */
+ "Cancelar", /* es-SV */
+ "Cancelar", /* es-US */
+ "Cancelar", /* es-UY */
+ "Cancelar", /* es-VE */
+ "Tühista", /* et */
+ "Utzi", /* eu */
+ "لغو", /* fa */
+ "Peruuta", /* fi */
+ "Kanselahin", /* fil */
+ "Annuler", /* fr */
+ "Annuler", /* fr-CA */
+ "Annuler", /* fr-CH */
+ "Cancelar", /* gl */
+ "Abbrechen", /* gsw */
+ "રદ કરો", /* gu */
+ "ביטול", /* he */
+ "रद्द करें", /* hi */
+ "Otkaži", /* hr */
+ "Mégse", /* hu */
+ "Չեղարկել", /* hy */
+ "Batal", /* id */
+ "Batal", /* in */
+ "Hætta við", /* is */
+ "Annulla", /* it */
+ "ביטול", /* iw */
+ "キャンセル", /* ja */
+ "გაუქმება", /* ka */
+ "Бас тарту", /* kk */
+ "បោះបង់", /* km */
+ "ರದ್ದು", /* kn */
+ "취소", /* ko */
+ "Жокко чыгаруу", /* ky */
+ "Annuler", /* ln */
+ "ຍົກເລີກ", /* lo */
+ "Atšaukti", /* lt */
+ "Atcelt", /* lv */
+ "Откажи", /* mk */
+ "റദ്ദാക്കുക", /* ml */
+ "Болих", /* mn */
+ "Anulați", /* mo */
+ "रद्द करा", /* mr */
+ "Batal", /* ms */
+ "မလုပ်တော့", /* my */
+ "Avbryt", /* nb */
+ "रद्द गर्नुहोस्", /* ne */
+ "Annuleren", /* nl */
+ "Avbryt", /* no */
+ "କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ", /* or */
+ "ਰੱਦ ਕਰੋ", /* pa */
+ "Anuluj", /* pl */
+ "Cancelar", /* pt */
+ "Cancelar", /* pt-BR */
+ "Cancelar", /* pt-PT */
+ "Anulați", /* ro */
+ "Отмена", /* ru */
+ "අවලංගු කරන්න", /* si */
+ "Zrušiť", /* sk */
+ "Prekliči", /* sl */
+ "Anulo", /* sq */
+ "Откажи", /* sr */
+ "Otkaži", /* sr-Latn */
+ "Avbryt", /* sv */
+ "Ghairi", /* sw */
+ "ரத்துசெய்", /* ta */
+ "రద్దు చేయండి", /* te */
+ "ยกเลิก", /* th */
+ "Kanselahin", /* tl */
+ "İptal", /* tr */
+ "Скасувати", /* uk */
+ "منسوخ کریں", /* ur */
+ "Bekor qilish", /* uz */
+ "Hủy", /* vi */
+ "取消", /* zh */
+ "取消", /* zh-CN */
+ "取消", /* zh-HK */
+ "取消", /* zh-TW */
+ "Khansela", /* zu */
+ }
+ },
+ {
+ "6973195374358399966",
+ {
+ "Android Protected Confirmation", /* en (untranslated) */
+ "Android se Beskermde Bevestiging", /* af */
+ "በAndroid ጥበቃ የሚደረግለት ማረጋገጫ", /* am */
+ "تأكيد حماية Android", /* ar */
+ "تأكيد حماية Android", /* ar-EG */
+ "تأكيد حماية Android", /* ar-JO */
+ "تأكيد حماية Android", /* ar-MA */
+ "تأكيد حماية Android", /* ar-SA */
+ "Android Protected Confirmation", /* ar-XB */
+ "Androidৰ সুৰক্ষা সম্পৰ্কীয় প্ৰতিশ্ৰুতি", /* as */
+ "Qorunan Android Təsdiqi", /* az */
+ "Пацвярджэнне Android Protected", /* be */
+ "Защитно потвърждение за Android", /* bg */
+ "Android প্রোটেক্টেড কনফার্মেশন", /* bn */
+ "Potvrda zaštite na Androidu", /* bs */
+ "Confirmació de protecció d'Android", /* ca */
+ "Potvrzení ochrany Androidu", /* cs */
+ "Beskyttet bekræftelse i Android", /* da */
+ "Bestätigung für Android Protected", /* de */
+ "Bestätigung für Android Protected", /* de-AT */
+ "Bestätigung für Android Protected", /* de-CH */
+ "Επιβεβαίωση προστασίας Android", /* el */
+ "Android Protected Confirmation", /* en-AU */
+ "Android Protected Confirmation", /* en-CA */
+ "Android Protected Confirmation", /* en-GB */
+ "Android Protected Confirmation", /* en-IE */
+ "Android Protected Confirmation", /* en-IN */
+ "Android Protected Confirmation", /* en-SG */
+ "[Åñðŕöîð Þŕöţéçţéð Çöñƒîŕmåţîöñ one two three four]", /* en-XA */
+ "Android Protected Confirmation", /* en-XC */
+ "Android Protected Confirmation", /* en-ZA */
+ "Confirmación protegida por Android", /* es */
+ "Confirmación de protección de Android", /* es-419 */
+ "Confirmación de protección de Android", /* es-AR */
+ "Confirmación de protección de Android", /* es-BO */
+ "Confirmación de protección de Android", /* es-CL */
+ "Confirmación de protección de Android", /* es-CO */
+ "Confirmación de protección de Android", /* es-CR */
+ "Confirmación de protección de Android", /* es-DO */
+ "Confirmación de protección de Android", /* es-EC */
+ "Confirmación de protección de Android", /* es-GT */
+ "Confirmación de protección de Android", /* es-HN */
+ "Confirmación de protección de Android", /* es-MX */
+ "Confirmación de protección de Android", /* es-NI */
+ "Confirmación de protección de Android", /* es-PA */
+ "Confirmación de protección de Android", /* es-PE */
+ "Confirmación de protección de Android", /* es-PR */
+ "Confirmación de protección de Android", /* es-PY */
+ "Confirmación de protección de Android", /* es-SV */
+ "Confirmación de protección de Android", /* es-US */
+ "Confirmación de protección de Android", /* es-UY */
+ "Confirmación de protección de Android", /* es-VE */
+ "Androidi kaitstud kinnitus", /* et */
+ "Android-en babesa izatearen berrespena", /* eu */
+ "تأیید محافظتشده Android", /* fa */
+ "Vahvistus Android-suojauksesta", /* fi */
+ "Pagkumpirmang Pinoprotektahan ng Android", /* fil */
+ "Confirmation de protection Android", /* fr */
+ "Confirmation protégée Android", /* fr-CA */
+ "Confirmation de protection Android", /* fr-CH */
+ "Android Protected Confirmation", /* gl */
+ "Bestätigung für Android Protected", /* gsw */
+ "Android પ્રોટેક્ટેડ કન્ફર્મેશન", /* gu */
+ "Android Protected Confirmation", /* he */
+ "Android की ओर से सुरक्षा की पुष्टि", /* hi */
+ "Potvrda zaštite na Androidu", /* hr */
+ "Android – védett megerősítés", /* hu */
+ "Android Protected-ի հաստատում", /* hy */
+ "Konfirmasi yang Dilindungi Android", /* id */
+ "Konfirmasi yang Dilindungi Android", /* in */
+ "Varin staðfesting Android", /* is */
+ "Conferma Android Protected", /* it */
+ "Android Protected Confirmation", /* iw */
+ "Android Protected の確認", /* ja */
+ "Android-ის დაცული დადასტურება", /* ka */
+ "Android қорғалған растау", /* kk */
+ "ការបញ្ជាក់ដែលបានការពារ Android", /* km */
+ "Android ಸಂರಕ್ಷಿತ ದೃಢೀಕರಣ", /* kn */
+ "Android 보안 확인", /* ko */
+ "Android Protected ырастоосу", /* ky */
+ "Confirmation de protection Android", /* ln */
+ "ການຢືນຢັນ Android ທີ່ໄດ້ຮັບການປົກປ້ອງ", /* lo */
+ "„Android Protected“ patvirtinimas", /* lt */
+ "Android aizsargātā informācija", /* lv */
+ "Потврда за заштита на Android", /* mk */
+ "Android സംരക്ഷിത സ്ഥിരീകരണം", /* ml */
+ "Андройдоор хамгаалсан баталгаажуулалт", /* mn */
+ "Confirmare protecție pentru Android", /* mo */
+ "Android कडून सुरक्षा निश्चित करणे", /* mr */
+ "Pengesahan Dilindungi Android", /* ms */
+ "Android ကာကွယ်မှု အတည်ပြုချက်", /* my */
+ "Android-beskyttet bekreftelse", /* nb */
+ "Android द्वारा संरक्षण गरिएको पुष्टि", /* ne */
+ "Bevestiging van Android-beveiliging", /* nl */
+ "Android-beskyttet bekreftelse", /* no */
+ "Android ଦ୍ୱାରା ସୁରକ୍ଷିତ ହୋଇଥିବାର ସୁନିଶ୍ଚିତତା", /* or */
+ "Android ਵੱਲੋਂ ਸੁਰੱਖਿਆ ਦੀ ਪੁਸ਼ਟੀ", /* pa */
+ "Zabezpieczone potwierdzenie w Androidzie", /* pl */
+ "Confirmação protegida pelo Android", /* pt */
+ "Confirmação protegida pelo Android", /* pt-BR */
+ "Confirmação protegida do Android", /* pt-PT */
+ "Confirmare protecție pentru Android", /* ro */
+ "Подтверждение Android Protected", /* ru */
+ "Android ආරක්ෂිත තහවුරු කිරීම", /* si */
+ "Chránené potvrdenie Androidu", /* sk */
+ "Zaščitena potrditev v Androidu", /* sl */
+ "Android Protected Confirmation", /* sq */
+ "Потврда заштите на Android-у", /* sr */
+ "Potvrda zaštite na Android-u", /* sr-Latn */
+ "Bekräftelseskydd för Android", /* sv */
+ "Uthibitishaji Unaolindwa wa Android", /* sw */
+ "Android பாதுகாப்பு தொடர்பான உறுதிப்படுத்தல்", /* ta */
+ "Android సురక్షిత నిర్ధారణ", /* te */
+ "ยืนยันการป้องกัน Android", /* th */
+ "Pagkumpirmang Pinoprotektahan ng Android", /* tl */
+ "Android Korumalı Onayı", /* tr */
+ "Підтвердження Android Protected", /* uk */
+ "Android کی تحفظ یافتہ تصدیق", /* ur */
+ "Android Protected nomli tasdiq", /* uz */
+ "Xác nhận bảo vệ Android", /* vi */
+ "Android 保护确认", /* zh */
+ "Android 保护确认", /* zh-CN */
+ "Android 保護確認", /* zh-HK */
+ "Android Protected 確認", /* zh-TW */
+ "Ukuqinisekiswa okuvikelwe i-Android", /* zu */
+ }
+ },
+};
+
+#define ConfirmationUITranslations_NUM_TRANSLATION_IDS \
+ (ARRAY_ELEMENTS(ConfirmationUITranslations_translation_ids))
+
+static int ConfirmationUITranslations_selected_lang_id_index = 0;
+
+static int ConfirmationUITranslations_find_str(const char** haystack, const char* needle) {
+ for (int n = 0; haystack[n] != NULL; n++) {
+ if (strcmp(needle, haystack[n]) == 0) {
+ return n;
+ }
+ }
+ return -1;
+}
+
+#define MAX_LANG_ID_SIZE 256
+
+/* Non-static linkage to allow calling by the test. */
+int ConfirmationUITranslations_lang_id_match(const char** lang_ids, const char* lang_id) {
+ int ret;
+ char lang_id_buf[MAX_LANG_ID_SIZE + 1];
+ size_t n;
+
+ ret = ConfirmationUITranslations_find_str(lang_ids, lang_id);
+ if (ret >= 0) {
+ return ret;
+ }
+
+ /* strncpy.. */
+ for (n = 0; lang_id[n] != '\0' && n < MAX_LANG_ID_SIZE; n++) {
+ lang_id_buf[n] = lang_id[n];
+ }
+ lang_id_buf[n] = '\0';
+
+ while (n >= 1) {
+ /* Remove last component */
+ while (n >= 1 && lang_id_buf[n - 1] != '-') {
+ n--;
+ }
+ if (n < 1) {
+ return -1;
+ }
+ lang_id_buf[n - 1] = '\0';
+ n--;
+ ret = ConfirmationUITranslations_find_str(lang_ids, lang_id_buf);
+ if (ret >= 0) {
+ return ret;
+ }
+ }
+ return -1;
+}
+
+const char* ConfirmationUITranslations_select_lang_id(const char* lang_id) {
+ ConfirmationUITranslations_selected_lang_id_index = 0;
+ if (lang_id == NULL) {
+ return ConfirmationUITranslations_language_ids[0];
+ }
+
+ int ret = ConfirmationUITranslations_lang_id_match(ConfirmationUITranslations_language_ids, lang_id);
+ if (ret < 0) {
+ return ConfirmationUITranslations_language_ids[0];
+ }
+ ConfirmationUITranslations_selected_lang_id_index = ret;
+ return ConfirmationUITranslations_language_ids[ConfirmationUITranslations_selected_lang_id_index];
+}
+
+const char* ConfirmationUITranslations_lookup(const char* translation_id) {
+ for (size_t n = 0; n < ConfirmationUITranslations_NUM_TRANSLATION_IDS; n++) {
+ if (strcmp(translation_id, ConfirmationUITranslations_translation_ids[n].translation_id) == 0) {
+ const char* result;
+ if (ConfirmationUITranslations_selected_lang_id_index < 0 || ConfirmationUITranslations_selected_lang_id_index >= ConfirmationUITranslations_NUM_LANGUAGE_IDS) {
+ return ConfirmationUITranslations_translation_ids[n].translations[0];
+ }
+ result = ConfirmationUITranslations_translation_ids[n].translations[ConfirmationUITranslations_selected_lang_id_index];
+ if (result != NULL) {
+ return result;
+ }
+ return ConfirmationUITranslations_translation_ids[n].translations[0];
+ }
+ }
+ return NULL;
+}
+
+const char* const* ConfirmationUITranslations_get_languages(void) {
+ return (const char* const*) (ConfirmationUITranslations_language_ids);
+}
diff --git a/confirmationui/support/test/ConfirmationUITranslations-test.c b/confirmationui/support/test/ConfirmationUITranslations-test.c
new file mode 100644
index 0000000..a73a8af
--- /dev/null
+++ b/confirmationui/support/test/ConfirmationUITranslations-test.c
@@ -0,0 +1,1338 @@
+/*
+**
+** Copyright 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.
+*/
+
+/* Generated by generate-translations.py - DO NOT EDIT */
+
+#include "ConfirmationUITranslations.h"
+#include "string.h"
+
+#include <stdio.h>
+
+#define ASSERT_STR(str1, str2) \
+ do { \
+ if (strcmp(str1, str2) != 0) { \
+ printf("%s:%d: Assertion failed: '%s' != '%s'\n", \
+ __FILE__, __LINE__, str1, str2); \
+ return 1; \
+ } \
+ } while (0)
+
+extern int ConfirmationUITranslations_lang_id_match(const char** lang_ids,
+ const char* lang_id);
+
+static const char* test_lang_id_match(const char* lang_ids[], const char* lang_id) {
+ int ret = ConfirmationUITranslations_lang_id_match(lang_ids, lang_id);
+ if (ret < 0) {
+ return "";
+ }
+ return lang_ids[ret];
+}
+
+int main(int argc, char* argv[]) {
+ /* Tests for untranslated languages */
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action you're about to take.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for languages without translation */
+ ConfirmationUITranslations_select_lang_id("nosuch-LA");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action you're about to take.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for untranslated language (en) */
+ ConfirmationUITranslations_select_lang_id("en");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action you're about to take.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language af */
+ ConfirmationUITranslations_select_lang_id("af");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dubbeldruk aan/af-skakelaar om te bevestig");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Kanselleer");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Hierdie bevestiging verskaf 'n ekstra laag sekuriteit vir die handeling wat jy op die punt is om uit te voer.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Druk aan/af-skakelaar om te bevestig");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Druk enige volumeknoppie om te kanselleer");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Kanselleer");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android se Beskermde Bevestiging");
+
+ /* Tests for language am */
+ ConfirmationUITranslations_select_lang_id("am");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "ለማረጋገጥ ኃይልን ሁለቴ ይጫኑ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ይቅር");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ይህ ማረጋገጫ እርስዎ ለሚወስዱት እርምጃ ተጨማሪ ትርፍ ጥበቃን ይሰጣል።");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "ለማረጋገጥ ኃይልን ይጫኑ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ለመሰረዝ ማናቸውንም የድምፅ አዝራር ይጫኑ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ይቅር");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "በAndroid ጥበቃ የሚደረግለት ማረጋገጫ");
+
+ /* Tests for language ar */
+ ConfirmationUITranslations_select_lang_id("ar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "اضغط على زر التشغيل مرتين لتأكيد الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "إلغاء");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "اضغط على زر التشغيل لتأكيد الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "إلغاء");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "تأكيد حماية Android");
+
+ /* Tests for language ar-EG */
+ ConfirmationUITranslations_select_lang_id("ar-EG");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "اضغط على زر التشغيل مرتين لتأكيد الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "إلغاء");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "اضغط على زر التشغيل لتأكيد الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "إلغاء");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "تأكيد حماية Android");
+
+ /* Tests for language ar-JO */
+ ConfirmationUITranslations_select_lang_id("ar-JO");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "اضغط على زر التشغيل مرتين لتأكيد الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "إلغاء");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "اضغط على زر التشغيل لتأكيد الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "إلغاء");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "تأكيد حماية Android");
+
+ /* Tests for language ar-MA */
+ ConfirmationUITranslations_select_lang_id("ar-MA");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "اضغط على زر التشغيل مرتين لتأكيد الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "إلغاء");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "اضغط على زر التشغيل لتأكيد الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "إلغاء");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "تأكيد حماية Android");
+
+ /* Tests for language ar-SA */
+ ConfirmationUITranslations_select_lang_id("ar-SA");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "اضغط على زر التشغيل مرتين لتأكيد الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "إلغاء");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "يتيح هذا التأكيد تفعيل طبقة أمان إضافية للإجراء الذي توشك على اتخاذه.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "اضغط على زر التشغيل لتأكيد الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "اضغط على أي زر من أزرار مستوى الصوت لإلغاء الإجراء.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "إلغاء");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "تأكيد حماية Android");
+
+ /* Tests for language ar-XB */
+ ConfirmationUITranslations_select_lang_id("ar-XB");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action you're about to take.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language as */
+ ConfirmationUITranslations_select_lang_id("as");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "নিশ্চিত কৰিবলৈ পাৱাৰ বুটামটো দুবাৰ হেঁচক");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "বাতিল কৰক");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "এই প্ৰতিশ্ৰুতিয়ে আপুনি কৰিব বিচৰা কোনো কাৰ্যৰ বাবে অতিৰিক্ত সুৰক্ষা প্ৰদান কৰে।");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "নিশ্চিত কৰিবলৈ পাৱাৰ বুটাম হেঁচক");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "বাতিল কৰিবলৈ যিকোনো ভলিউম বুটাম হেঁচক");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "বাতিল কৰক");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Androidৰ সুৰক্ষা সম্পৰ্কীয় প্ৰতিশ্ৰুতি");
+
+ /* Tests for language az */
+ ConfirmationUITranslations_select_lang_id("az");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Təsdiqləmək üçün iki dəfə yandırıb-söndürmək düyməsinə basın");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Ləğv edin");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Bu təsdiq etmək üzrə olduğunuz əməliyyat üçün əlavə təhlükəsizlik qatı təmin edir.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Təsdiq etmək üçün yandırıb-söndürmə düyməsinə basın");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Ləğv etmək üçün istənilən səs düyməsinə basın");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Ləğv edin");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Qorunan Android Təsdiqi");
+
+ /* Tests for language be */
+ ConfirmationUITranslations_select_lang_id("be");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Двойчы націсніце кнопку сілкавання, каб пацвердзіць");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Скасаваць");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Гэта пацвярджэнне забяспечвае дадатковы ўзровень бяспекі для дзеянняў, якія вы збіраецеся выконваць.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Націсніце кнопку сілкавання, каб пацвердзіць");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Націсніце любую кнопку гучнасці, каб cкасаваць");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Скасаваць");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Пацвярджэнне Android Protected");
+
+ /* Tests for language bg */
+ ConfirmationUITranslations_select_lang_id("bg");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Натиснете два пъти бутона за захранване, за да потвърдите");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Отказ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Това потвърждение осигурява допълнителна защита за действието, което сте напът да предприемете.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Натиснете бутона за захранване, за да потвърдите");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Натиснете някой от бутоните за силата на звука, за да анулирате");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Отказ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Защитно потвърждение за Android");
+
+ /* Tests for language bn */
+ ConfirmationUITranslations_select_lang_id("bn");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "নিশ্চিত করতে পাওয়ার বোতাম দুবার টিপুন");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "বাতিল করুন");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "আপনি যে কাজটি করতে চলেছেন, এই কনফার্মেশনের ফলে সেটির জন্য অতিরিক্ত সুরক্ষার ব্যবস্থা করা হয়।");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "নিশ্চিত করতে পাওয়ার বোতাম টিপুন");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "বাতিল করতে ভলিউমের যেকোনও বোতাম টিপুন");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "বাতিল করুন");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android প্রোটেক্টেড কনফার্মেশন");
+
+ /* Tests for language bs */
+ ConfirmationUITranslations_select_lang_id("bs");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dva puta pritisnite dugme za napajanje da potvrdite");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Otkaži");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ova potvrda pruža dodatni sloj zaštite za radnju koju namjeravate preduzeti.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pritisnite dugme za napajanje za potvrdu");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pritisnite bilo koje dugme za podešavanje jačine zvuka da otkažete");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Otkaži");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Potvrda zaštite na Androidu");
+
+ /* Tests for language ca */
+ ConfirmationUITranslations_select_lang_id("ca");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Prem dos cops el botó d'engegada per confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel·la");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Aquesta confirmació proporciona una capa de seguretat addicional per a l'acció que estàs a punt de dur a terme.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Prem el botó d'engegada per confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Prem qualsevol botó de volum per cancel·lar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel·la");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmació de protecció d'Android");
+
+ /* Tests for language cs */
+ ConfirmationUITranslations_select_lang_id("cs");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Potvrďte dvojitým stisknutím vypínače");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Zrušit");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Toto potvrzení tvoří dodatečnou úroveň zabezpečení akce, kterou se chystáte podniknout.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Potvrďte stisknutím vypínače");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Zrušte stisknutím tlačítka hlasitosti");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Zrušit");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Potvrzení ochrany Androidu");
+
+ /* Tests for language da */
+ ConfirmationUITranslations_select_lang_id("da");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Tryk to gange på afbryderknappen for at bekræfte");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annuller");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Denne bekræftelse giver et ekstra beskyttelsesniveau for den handling, du er ved at foretage.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Tryk på afbryderknappen for at bekræfte");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Tryk på en af lydstyrkeknapperne for at annullere");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annuller");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Beskyttet bekræftelse i Android");
+
+ /* Tests for language de */
+ ConfirmationUITranslations_select_lang_id("de");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Abbrechen");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmaßnahme angewandt.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Drücke zum Bestätigen die Ein-/Aus-Taste");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Zum Abbrechen eine beliebige Lautstärketaste drücken");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Abbrechen");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Bestätigung für Android Protected");
+
+ /* Tests for language de-AT */
+ ConfirmationUITranslations_select_lang_id("de-AT");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Abbrechen");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmaßnahme angewandt.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Drücke zum Bestätigen die Ein-/Aus-Taste");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Zum Abbrechen eine beliebige Lautstärketaste drücken");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Abbrechen");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Bestätigung für Android Protected");
+
+ /* Tests for language de-CH */
+ ConfirmationUITranslations_select_lang_id("de-CH");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Abbrechen");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmassnahme angewandt.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Drücke zum Bestätigen die Ein-/Aus-Taste");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Zum Abbrechen eine beliebige Lautstärketaste drücken");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Abbrechen");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Bestätigung für Android Protected");
+
+ /* Tests for language el */
+ ConfirmationUITranslations_select_lang_id("el");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Πατήστε δύο φορές το κουμπί λειτουργίας για επιβεβαίωση");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Ακύρωση");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Αυτή η επιβεβαίωση παρέχει ένα επιπλέον επίπεδο ασφάλειας για την ενέργεια που πρόκειται να εκτελέσετε.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Πατήστε το κουμπί λειτουργίας για επιβεβαίωση");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Πατήστε οποιοδήποτε κουμπί έντασης ήχου για ακύρωση");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Ακύρωση");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Επιβεβαίωση προστασίας Android");
+
+ /* Tests for language en-AU */
+ ConfirmationUITranslations_select_lang_id("en-AU");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language en-CA */
+ ConfirmationUITranslations_select_lang_id("en-CA");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language en-GB */
+ ConfirmationUITranslations_select_lang_id("en-GB");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language en-IE */
+ ConfirmationUITranslations_select_lang_id("en-IE");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language en-IN */
+ ConfirmationUITranslations_select_lang_id("en-IN");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language en-SG */
+ ConfirmationUITranslations_select_lang_id("en-SG");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language en-XA */
+ ConfirmationUITranslations_select_lang_id("en-XA");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "[Ðöûбļé-þŕéšš þöŵéŕ ţö çöñƒîŕm one two three four five six seven]");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "[Çåñçéļ one]");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "[Ţĥîš çöñƒîŕmåţîöñ þŕövîðéš åñ éxţŕå ļåýéŕ öƒ šéçûŕîţý ƒöŕ ţĥé åçţîöñ ýöû'ŕé åбöûţ ţö ţåķé. one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen]");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "[Þŕéšš þöŵéŕ ţö çöñƒîŕm one two three four five]");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "[Þŕéšš åñý vöļûmé бûţţöñ ţö çåñçéļ one two three four five six seven]");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "[Çåñçéļ one]");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "[Åñðŕöîð Þŕöţéçţéð Çöñƒîŕmåţîöñ one two three four]");
+
+ /* Tests for language en-XC */
+ ConfirmationUITranslations_select_lang_id("en-XC");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action you're about to take.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language en-ZA */
+ ConfirmationUITranslations_select_lang_id("en-ZA");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Double-press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "This confirmation provides an extra layer of security for the action that you're about to take.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Press power to confirm");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Press any volume button to cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancel");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language es */
+ ConfirmationUITranslations_select_lang_id("es");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Pulsa dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona una capa de seguridad adicional a la acción que vas a realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pulsa el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pulsa cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación protegida por Android");
+
+ /* Tests for language es-419 */
+ ConfirmationUITranslations_select_lang_id("es-419");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-AR */
+ ConfirmationUITranslations_select_lang_id("es-AR");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-BO */
+ ConfirmationUITranslations_select_lang_id("es-BO");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-CL */
+ ConfirmationUITranslations_select_lang_id("es-CL");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-CO */
+ ConfirmationUITranslations_select_lang_id("es-CO");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-CR */
+ ConfirmationUITranslations_select_lang_id("es-CR");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-DO */
+ ConfirmationUITranslations_select_lang_id("es-DO");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-EC */
+ ConfirmationUITranslations_select_lang_id("es-EC");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-GT */
+ ConfirmationUITranslations_select_lang_id("es-GT");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-HN */
+ ConfirmationUITranslations_select_lang_id("es-HN");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-MX */
+ ConfirmationUITranslations_select_lang_id("es-MX");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-NI */
+ ConfirmationUITranslations_select_lang_id("es-NI");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-PA */
+ ConfirmationUITranslations_select_lang_id("es-PA");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-PE */
+ ConfirmationUITranslations_select_lang_id("es-PE");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-PR */
+ ConfirmationUITranslations_select_lang_id("es-PR");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-PY */
+ ConfirmationUITranslations_select_lang_id("es-PY");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-SV */
+ ConfirmationUITranslations_select_lang_id("es-SV");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-US */
+ ConfirmationUITranslations_select_lang_id("es-US");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-UY */
+ ConfirmationUITranslations_select_lang_id("es-UY");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language es-VE */
+ ConfirmationUITranslations_select_lang_id("es-VE");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Presiona dos veces el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona un nivel de seguridad adicional para la acción que estás por realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Presiona el botón de encendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Presiona cualquier botón de volumen para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmación de protección de Android");
+
+ /* Tests for language et */
+ ConfirmationUITranslations_select_lang_id("et");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Kinnitamiseks topeltvajutage toitenuppu");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Tühista");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "See kinnitus annab veel ühe turvakihi toimingu puhul, mille nüüd teete.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Kinnitamiseks vajutage toitenuppu");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Tühistamiseks vajutage mis tahes helitugevuse nuppu");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Tühista");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Androidi kaitstud kinnitus");
+
+ /* Tests for language eu */
+ ConfirmationUITranslations_select_lang_id("eu");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Berresteko, sakatu birritan pizteko botoia");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Utzi");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Berrespen honek segurtasun handiagoa ematen dizu hurrengo ekintza gauzatzeko.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Berresteko, sakatu etengailua");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Bertan behera uzteko, sakatu bolumen-tekla bat");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Utzi");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android-en babesa izatearen berrespena");
+
+ /* Tests for language fa */
+ ConfirmationUITranslations_select_lang_id("fa");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "برای تأیید، دکمه روشن/خاموش را دوبار فشار دهید");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "لغو");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "این تأیید یک لایه امنیتی اضافی برای کنشی که میخواهید انجام دهید فراهم میکند.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "برای تأیید، دکمه روشن/خاموش را فشار دهید");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "برای لغو، یکی از دکمههای میزان صدا را فشار دهید");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "لغو");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "تأیید محافظتشده Android");
+
+ /* Tests for language fi */
+ ConfirmationUITranslations_select_lang_id("fi");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Vahvista painamalla virtapainiketta kahdesti");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Peruuta");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Tämä vahvistus tarkoittaa, että seuraava toimintosi on entistä paremmin suojattu.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Vahvista painamalla virtapainiketta");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Peruuta painamalla äänenvoimakkuuspainiketta");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Peruuta");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Vahvistus Android-suojauksesta");
+
+ /* Tests for language fil */
+ ConfirmationUITranslations_select_lang_id("fil");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Pindutin nang dalawang beses ang power para kumpirmahin");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Kanselahin");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ang pagkumpirmang ito ay nagbibigay ng karagdagang layer ng seguridad para sa pagkilos na gagawin mo.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pindutin ang power para kumpirmahin");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pindutin ang anumang button ng volume para kanselahin");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Kanselahin");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Pagkumpirmang Pinoprotektahan ng Android");
+
+ /* Tests for language fr */
+ ConfirmationUITranslations_select_lang_id("fr");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Appuyez deux fois sur le bouton Marche/Arrêt pour confirmer l'opération");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annuler");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Cette confirmation ajoute un niveau de sécurité supplémentaire à l'action que vous êtes sur le point d'effectuer.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Appuyez sur le bouton Marche/Arrêt pour confirmer l'opération");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Appuyez sur l'un des boutons de volume pour annuler l'opération");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annuler");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmation de protection Android");
+
+ /* Tests for language fr-CA */
+ ConfirmationUITranslations_select_lang_id("fr-CA");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Appuyez deux fois sur l'interrupteur pour confirmer");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annuler");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Cette confirmation fournit une couche supplémentaire de sécurité pour l'action que vous êtes sur le point d'effectuer.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Appuyez sur l'interrupteur pour confirmer");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Appuyez sur un bouton de volume pour annuler l'action");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annuler");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmation protégée Android");
+
+ /* Tests for language fr-CH */
+ ConfirmationUITranslations_select_lang_id("fr-CH");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Appuyez deux fois sur le bouton Marche/Arrêt pour confirmer l'opération");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annuler");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Cette confirmation ajoute un niveau de sécurité supplémentaire à l'action que vous êtes sur le point d'effectuer.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Appuyez sur le bouton Marche/Arrêt pour confirmer l'opération");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Appuyez sur l'un des boutons de volume pour annuler l'opération");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annuler");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmation de protection Android");
+
+ /* Tests for language gl */
+ ConfirmationUITranslations_select_lang_id("gl");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Preme o botón de acendido dúas veces para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmación proporciona unha capa adicional de seguranza para a acción que estás a piques de levar a cabo.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Preme o botón de acendido para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Preme calquera botón de volume para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language gsw */
+ ConfirmationUITranslations_select_lang_id("gsw");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Zum Bestätigen die Ein-/Aus-Taste zweimal drücken");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Abbrechen");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Durch die Bestätigung wird bei der Aktion, die du durchführen möchtest, eine zusätzliche Sicherheitsmaßnahme angewandt.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Drücke zum Bestätigen die Ein-/Aus-Taste");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Zum Abbrechen eine beliebige Lautstärketaste drücken");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Abbrechen");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Bestätigung für Android Protected");
+
+ /* Tests for language gu */
+ ConfirmationUITranslations_select_lang_id("gu");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "કન્ફર્મ કરવા માટે પાવર પર બે વાર ટૅપ કરો");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "રદ કરો");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "તમે જે ક્રિયા કરવાના છો તેના માટે આ કન્ફર્મેશન એક અતિરિક્ત સુરક્ષાનું સ્તર પ્રદાન કરે છે.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "કન્ફર્મ કરવા માટે પાવર બટન દબાવો");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "રદ કરવા માટે કોઈપણ વૉલ્યૂમનું બટન દબાવો");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "રદ કરો");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android પ્રોટેક્ટેડ કન્ફર્મેશન");
+
+ /* Tests for language he */
+ ConfirmationUITranslations_select_lang_id("he");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "יש ללחוץ פעמיים על לחצן ההפעלה כדי לאשר");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ביטול");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "אישור זה מספק שכבת אבטחה נוספת לפעולה שאתה עומד לבצע.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "יש ללחוץ על לחצן ההפעלה כדי לאשר");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "יש ללחוץ על לחצן כלשהו של עוצמת הקול כדי לבטל");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ביטול");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language hi */
+ ConfirmationUITranslations_select_lang_id("hi");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "पुष्टि करने के लिए पावर बटन दो बार दबाएं");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "रद्द करें");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "यह पुष्टि मिलने पर आप जो काम करने वाले हैं, उसके लिए सुरक्षा और बढ़ जाती है.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "पुष्टि करने के लिए पावर बटन दबाएं");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "रद्द करने के लिए कोई भी वॉल्यूम बटन दबाएं");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "रद्द करें");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android की ओर से सुरक्षा की पुष्टि");
+
+ /* Tests for language hr */
+ ConfirmationUITranslations_select_lang_id("hr");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dvaput pritisnite tipku za uključivanje/isključivanje da biste potvrdili");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Otkaži");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ta potvrda pruža dodatan sloj zaštite za radnju koju ćete izvršiti.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pritisnite tipku za uključivanje/isključivanje da biste potvrdili");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pritisnite bilo koju tipku za glasnoću da biste otkazali");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Otkaži");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Potvrda zaštite na Androidu");
+
+ /* Tests for language hu */
+ ConfirmationUITranslations_select_lang_id("hu");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "A megerősítéshez nyomja meg duplán a bekapcsológombot");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Mégse");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ez a megerősítés extra réteg biztonságot nyújt a végrehajtani kívánt művelet számára.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Nyomja meg a bekapcsológombot a megerősítéshez");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Nyomja meg valamelyik hangerőgombot az elvetéshez");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Mégse");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android – védett megerősítés");
+
+ /* Tests for language hy */
+ ConfirmationUITranslations_select_lang_id("hy");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Հաստատելու համար կրկնակի սեղմեք սնուցման կոճակը");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Չեղարկել");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Այս հաստատումն ապահովում է պաշտպանության լրացուցիչ մակարդակ՝ նախքան գործողություն կատարելը");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Հաստատելու համար սեղմեք սնուցման կոճակը");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Չեղարկելու համար սեղմեք ձայնի կագավորման որևէ կոճակ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Չեղարկել");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected-ի հաստատում");
+
+ /* Tests for language id */
+ ConfirmationUITranslations_select_lang_id("id");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Tekan dua kali tombol power untuk mengonfirmasi");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Batal");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Konfirmasi ini memberikan lapisan keamanan tambahan untuk tindakan yang akan Anda ambil.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Tekan tombol power untuk mengonfirmasi");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Tekan tombol volume apa saja untuk membatalkan");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Batal");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Konfirmasi yang Dilindungi Android");
+
+ /* Tests for language in */
+ ConfirmationUITranslations_select_lang_id("in");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Tekan dua kali tombol power untuk mengonfirmasi");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Batal");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Konfirmasi ini memberikan lapisan keamanan tambahan untuk tindakan yang akan Anda ambil.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Tekan tombol power untuk mengonfirmasi");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Tekan tombol volume apa saja untuk membatalkan");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Batal");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Konfirmasi yang Dilindungi Android");
+
+ /* Tests for language is */
+ ConfirmationUITranslations_select_lang_id("is");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Ýttu tvisvar á aflrofann til að staðfesta");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Hætta við");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Þessi staðfesting veitir aukið öryggi fyrir aðgerðina sem þú ert að fara að framkvæma.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Ýttu á aflrofann til að staðfesta");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Ýttu á hvaða hljóðstyrkshnapp sem er til að hætta við");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Hætta við");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Varin staðfesting Android");
+
+ /* Tests for language it */
+ ConfirmationUITranslations_select_lang_id("it");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Premi due volte il tasto di accensione per confermare");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annulla");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Questa conferma garantisce un ulteriore livello di sicurezza per l'azione che stai per compiere.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Premi il tasto di accensione per confermare");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Premi qualsiasi pulsante del volume per annullare");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annulla");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Conferma Android Protected");
+
+ /* Tests for language iw */
+ ConfirmationUITranslations_select_lang_id("iw");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "יש ללחוץ פעמיים על לחצן ההפעלה כדי לאשר");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ביטול");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "אישור זה מספק שכבת אבטחה נוספת לפעולה שאתה עומד לבצע.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "יש ללחוץ על לחצן ההפעלה כדי לאשר");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "יש ללחוץ על לחצן כלשהו של עוצמת הקול כדי לבטל");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ביטול");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language ja */
+ ConfirmationUITranslations_select_lang_id("ja");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "確認するには、電源を 2 回押します");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "キャンセル");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "この確認により、これから行う操作のセキュリティが強化されます。");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "確認するには、電源を押します");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "キャンセルするには、いずれかの音量ボタンを押します");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "キャンセル");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected の確認");
+
+ /* Tests for language ka */
+ ConfirmationUITranslations_select_lang_id("ka");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "დასადასტურებლად ორმაგად დააჭირეთ ჩართვის ღილაკს");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "გაუქმება");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "დადასტურება უსაფრთხოების დამატებით შრეს უზრუნველყოფს იმ ქმედების განსახორციელებლად, რომელსაც აპირებთ.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "დასადასტურებლად დააჭირეთ ჩართვის ღილაკს");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "გასაუქმებლად დააჭირეთ ხმის რეგულირების ნებისმიერ ღილაკს");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "გაუქმება");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android-ის დაცული დადასტურება");
+
+ /* Tests for language kk */
+ ConfirmationUITranslations_select_lang_id("kk");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Растау үшін қуат түймесін екі рет басыңыз");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Бас тарту");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Бұл растау функциясы орындағалы тұрған әрекеттің қауіпсіздігін қосымша күшейтеді.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Растау үшін қуат түймесін басыңыз");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Бас тарту үшін кез келген дыбыс деңгейі түймесін басыңыз");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Бас тарту");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android қорғалған растау");
+
+ /* Tests for language km */
+ ConfirmationUITranslations_select_lang_id("km");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "ចុចប៊ូតុងថាមពលពីរដងដើម្បីបញ្ជាក់");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "បោះបង់");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ការបញ្ជាក់នេះផ្ដល់ស្រទាប់សុវត្ថិភាពបន្ថែមសម្រាប់សកម្មភាពដែលអ្នកហៀបនឹងធ្វើ។");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "ចុចប៊ូតុងថាមពលដើម្បីបញ្ជាក់");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ចុចប៊ូតុងកម្រិតសំឡេងណាមួយដើម្បីបោះបង់");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "បោះបង់");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "ការបញ្ជាក់ដែលបានការពារ Android");
+
+ /* Tests for language kn */
+ ConfirmationUITranslations_select_lang_id("kn");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "ದೃಢೀಕರಿಸಲು ಪವರ್ ಬಟನ್ ಅನ್ನು ಎರಡು ಬಾರಿ ಒತ್ತಿರಿ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ರದ್ದು");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ಈ ದೃಢೀಕರಣವು ನೀವು ನಿರ್ವಹಿಸಲು ಬಯಸುವ ಕ್ರಿಯೆಗೆ ಹೆಚ್ಚುವರಿ ಸುರಕ್ಷತೆಯನ್ನು ಒದಗಿಸುತ್ತದೆ.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "ದೃಢೀಕರಿಸಲು ಪವರ್ ಬಟನ್ ಒತ್ತಿರಿ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ರದ್ದುಗೊಳಿಸಲು ಯಾವುದೇ ವಾಲ್ಯೂಮ್ ಬಟನ್ ಒತ್ತಿರಿ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ರದ್ದು");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android ಸಂರಕ್ಷಿತ ದೃಢೀಕರಣ");
+
+ /* Tests for language ko */
+ ConfirmationUITranslations_select_lang_id("ko");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "확인하려면 전원 버튼을 두 번 누르세요.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "취소");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "이 확인 단계를 사용하면 실행하려는 작업의 보안을 한층 강화할 수 있습니다.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "확인하려면 전원 버튼을 누르세요.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "취소하려면 볼륨 버튼 중 하나를 누르세요.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "취소");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android 보안 확인");
+
+ /* Tests for language ky */
+ ConfirmationUITranslations_select_lang_id("ky");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Ырастоо үчүн \"Кубат\" баскычын эки жолу басыңыз");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Жокко чыгаруу");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Бул ырастоо сиз аткара турган аракеттин коопсуздугун коргоонун дагы бир катмарын камсыздайт.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Ырастоо үчүн \"Кубат\" баскычын басыңыз");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Жокко чыгаруу үчүн үн көлөмүнүн баскычтарынын бирин басыңыз");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Жокко чыгаруу");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected ырастоосу");
+
+ /* Tests for language ln */
+ ConfirmationUITranslations_select_lang_id("ln");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Appuyez deux fois sur le bouton Marche/Arrêt pour confirmer l'opération");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annuler");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Cette confirmation ajoute un niveau de sécurité supplémentaire à l'action que vous êtes sur le point d'effectuer.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Appuyez sur le bouton Marche/Arrêt pour confirmer l'opération");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Appuyez sur l'un des boutons de volume pour annuler l'opération");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annuler");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmation de protection Android");
+
+ /* Tests for language lo */
+ ConfirmationUITranslations_select_lang_id("lo");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "ກົດປຸ່ມປິດເປີດເຄື່ອງສອງຄັ້ງເພື່ອຢືນຢັນ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ຍົກເລີກ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ການຢືນຢັນນີ້ຈະເພີ່ມຄວາມປອດໄພເພີ່ມເຕີມອີກໜຶ່ງຊັ້ນໃຫ້ກັບຄຳສັ່ງທີ່ທ່ານກຳລັງຈະໃຊ້.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "ກົດປຸ່ມເປີດປິດເພື່ອຢືນຢັນ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ກົດປຸ່ມສຽງຂຶ້ນ ຫຼື ລົງເພື່ອຍົກເລີກ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ຍົກເລີກ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "ການຢືນຢັນ Android ທີ່ໄດ້ຮັບການປົກປ້ອງ");
+
+ /* Tests for language lt */
+ ConfirmationUITranslations_select_lang_id("lt");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dukart paspauskite maitinimo mygtuką, kad patvirtintumėte");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Atšaukti");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Naudojant šį patvirtinimą, veiksmui, kurį ketinate atlikti, taikomas papildomas saugos lygmuo.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Paspauskite maitinimo mygtuką, kad patvirtintumėte");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Paspauskite bet kurį garsumo mygtuką, kad atšauktumėte");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Atšaukti");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "„Android Protected“ patvirtinimas");
+
+ /* Tests for language lv */
+ ConfirmationUITranslations_select_lang_id("lv");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Lai apstiprinātu, divreiz nospiediet barošanas pogu");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Atcelt");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Šis apstiprinājums sniedz papildu aizsardzību darbībai, kuru veiksiet.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Lai apstiprinātu, nospiediet barošanas pogu");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Lai atceltu, nospiediet jebkuru skaļuma pogu");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Atcelt");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android aizsargātā informācija");
+
+ /* Tests for language mk */
+ ConfirmationUITranslations_select_lang_id("mk");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Притиснете на копчето за напојување двапати за да потврдите");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Откажи");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Оваа потврда обезбедува дополнителен слој на безбедност за дејството што ќе го преземете.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Притиснете на копчето за напојување за да потврдите");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Притиснете на кое било копче за јачина на звук за да откажете");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Откажи");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Потврда за заштита на Android");
+
+ /* Tests for language ml */
+ ConfirmationUITranslations_select_lang_id("ml");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "സ്ഥിരീകരിക്കാൻ പവർ രണ്ടുതവണ അമർത്തുക");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "റദ്ദാക്കുക");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "നിങ്ങൾ സ്വീകരിക്കാൻ പോകുന്ന നടപടിക്കായി, ഈ സ്ഥിരീകരണം ഒരു അധിക സുരക്ഷാ പാളി നൽകുന്നു.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "സ്ഥിരീകരിക്കാൻ പവർ അമർത്തുക");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "റദ്ദാക്കാൻ എതെങ്കിലും വോളിയം ബട്ടൺ അമർത്തുക");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "റദ്ദാക്കുക");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android സംരക്ഷിത സ്ഥിരീകരണം");
+
+ /* Tests for language mn */
+ ConfirmationUITranslations_select_lang_id("mn");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Баталгаажуулахын тулд унтраах/асаахыг хоёр удаа дарах");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Болих");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Энэ баталгаажуулалт нь таны авах гэж буй арга хэмжээнд хамгаалалтын нэмэлт давхаргыг олгодог.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Баталгаажуулахын тулд унтраах/асаахыг дарах");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Болихын тулд дууны түвшний товчлуурын аль нэгийг нь дарах");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Болих");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Андройдоор хамгаалсан баталгаажуулалт");
+
+ /* Tests for language mo */
+ ConfirmationUITranslations_select_lang_id("mo");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Apăsați de două ori butonul de pornire pentru a confirma");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Anulați");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Această confirmare oferă un nivel suplimentar de securitate pentru acțiunea pe care urmează să o faceți.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Apăsați butonul de pornire pentru a confirma");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Apăsați orice buton de volum pentru a anula");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Anulați");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmare protecție pentru Android");
+
+ /* Tests for language mr */
+ ConfirmationUITranslations_select_lang_id("mr");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "खात्री करण्यासाठी पॉवर बटण दोनदा दाबा");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "रद्द करा");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "हे निश्चित झाल्यावर, तुम्ही जे काम करणार आहात, त्यासाठी सुरक्षा आणखी वाढते.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "निश्चित करण्यासाठी पॉवर दाबा");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "रद्द करण्यासाठी कोणतेही व्हॉल्यूम बटण दाबा");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "रद्द करा");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android कडून सुरक्षा निश्चित करणे");
+
+ /* Tests for language ms */
+ ConfirmationUITranslations_select_lang_id("ms");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Tekan dua kali butang kuasa untuk mengesahkan");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Batal");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Pengesahan ini memberikan lapisan keselamatan tambahan untuk tindakan yang akan anda ambil.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Tekan kuasa untuk mengesahkan");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Tekan sebarang butang kelantangan untuk membatalkan tindakan");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Batal");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Pengesahan Dilindungi Android");
+
+ /* Tests for language my */
+ ConfirmationUITranslations_select_lang_id("my");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "အတည်ပြုရန် ပါဝါခလုတ်ကို နှစ်ချက်နှိပ်ပါ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "မလုပ်တော့");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ဤအတည်ပြုချက်က သင်ပြုလုပ်တော့မည့် လုပ်ဆောင်ချက်အတွက် အပိုဆောင်းလုံခြုံရေးကို ပေးထားသည်။");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "အတည်ပြုရန် ပါဝါခလုတ်နှိပ်ပါ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ပယ်ဖျက်ရန် အသံအတိုးအကျယ်ခလုတ် တစ်ခုခုကိုနှိပ်ပါ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "မလုပ်တော့");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android ကာကွယ်မှု အတည်ပြုချက်");
+
+ /* Tests for language nb */
+ ConfirmationUITranslations_select_lang_id("nb");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dobbelttrykk på av/på-knappen for å bekrefte");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Avbryt");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Denne bekreftelsen gir et ekstra sikkerhetslag for handlingen du er i ferd med å utføre.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Trykk på av/på-knappen for å bekrefte");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Trykk på en volumknapp for å avbryte");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Avbryt");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android-beskyttet bekreftelse");
+
+ /* Tests for language ne */
+ ConfirmationUITranslations_select_lang_id("ne");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "पुष्टि गर्न पावर बटनमा दुई पटक थिच्नुहोस्");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "रद्द गर्नुहोस्");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "यो पुष्टिले तपाईंले गर्न ऑंट्नुभएको कारबाहीका लागि सुरक्षाको अतिरिक्त तह प्रदान गर्छ।");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "पुष्टि गर्न पावर बटनमा थिच्नुहोस्");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "रद्द गर्नका लागि कुनै भोल्युम बटन थिच्नुहोस्");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "रद्द गर्नुहोस्");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android द्वारा संरक्षण गरिएको पुष्टि");
+
+ /* Tests for language nl */
+ ConfirmationUITranslations_select_lang_id("nl");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Druk twee keer op de aan/uit-knop om te bevestigen");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Annuleren");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Deze bevestiging biedt een extra beveiligingslaag voor de actie die je wilt uitvoeren.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Druk op de aan/uit-knop om te bevestigen");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Druk op een volumeknop om te annuleren");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Annuleren");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Bevestiging van Android-beveiliging");
+
+ /* Tests for language no */
+ ConfirmationUITranslations_select_lang_id("no");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dobbelttrykk på av/på-knappen for å bekrefte");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Avbryt");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Denne bekreftelsen gir et ekstra sikkerhetslag for handlingen du er i ferd med å utføre.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Trykk på av/på-knappen for å bekrefte");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Trykk på en volumknapp for å avbryte");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Avbryt");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android-beskyttet bekreftelse");
+
+ /* Tests for language or */
+ ConfirmationUITranslations_select_lang_id("or");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "ସୁନିଶ୍ଚିତ କରିବା ପାଇଁ ପାୱାର୍ ବଟନ୍କୁ ଦୁଇଥର ଦବାନ୍ତୁ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ଏହି ସୁନିଶ୍ଚିତତା, ଆପଣ କରିବାକୁ ଯାଉଥିବା କାର୍ଯ୍ୟ ପାଇଁ ଅତିରିକ୍ତ ସୁରକ୍ଷା ପରତ ପ୍ରଦାନ କରିଥାଏ।");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "ସୁନିଶ୍ଚିତ କରିବା ପାଇଁ ପାୱର୍ ବଟନ୍କୁ ଦାବନ୍ତୁ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "କ୍ୟାନ୍ସଲ୍ କରିବା ପାଇଁ ଯେକୌଣସି ଭଲ୍ୟୁମ୍ ବଟନ୍କୁ ଦାବନ୍ତୁ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android ଦ୍ୱାରା ସୁରକ୍ଷିତ ହୋଇଥିବାର ସୁନିଶ୍ଚିତତା");
+
+ /* Tests for language pa */
+ ConfirmationUITranslations_select_lang_id("pa");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਪਾਵਰ ਬਟਨ ਨੂੰ ਦੋ ਬਾਰ ਦੱਬੋ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ਰੱਦ ਕਰੋ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ਇਹ ਪੁਸ਼ਟੀਕਰਨ ਤੁਹਾਡੇ ਵੱਲੋਂ ਕਾਰਵਾਈ ਨੂੰ ਕੀਤੇ ਜਾਣ ਲਈ ਸੁਰੱਖਿਆ ਦੇ ਇੱਕ ਵਾਧੂ ਪੱਧਰ ਮੁਹੱਈਆ ਕਰਦੀ ਹੈ।");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਪਾਵਰ ਬਟਨ ਦਬਾਓ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ਰੱਦ ਕਰਨ ਲਈ ਕਿਸੇ ਵੀ ਵੌਲਿਊਮ ਬਟਨ ਨੂੰ ਦਬਾਓ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ਰੱਦ ਕਰੋ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android ਵੱਲੋਂ ਸੁਰੱਖਿਆ ਦੀ ਪੁਸ਼ਟੀ");
+
+ /* Tests for language pl */
+ ConfirmationUITranslations_select_lang_id("pl");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Kliknij dwukrotnie przycisk zasilania, by potwierdzić");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Anuluj");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "To potwierdzenie stanowi dodatkowe zabezpieczenie czynności, którą zamierzasz wykonać.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Naciśnij przycisk zasilania, aby potwierdzić");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Naciśnij dowolny przycisk głośności, aby anulować");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Anuluj");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Zabezpieczone potwierdzenie w Androidzie");
+
+ /* Tests for language pt */
+ ConfirmationUITranslations_select_lang_id("pt");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Pressione o botão liga/desliga duas vezes para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Essa confirmação oferece uma camada adicional de segurança para a ação que você está prestes a realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pressione o botão liga/desliga para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pressione um dos botões de volume para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmação protegida pelo Android");
+
+ /* Tests for language pt-BR */
+ ConfirmationUITranslations_select_lang_id("pt-BR");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Pressione o botão liga/desliga duas vezes para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Essa confirmação oferece uma camada adicional de segurança para a ação que você está prestes a realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pressione o botão liga/desliga para confirmar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pressione um dos botões de volume para cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmação protegida pelo Android");
+
+ /* Tests for language pt-PT */
+ ConfirmationUITranslations_select_lang_id("pt-PT");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Prima duas vezes ligar/desligar para confirmar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Esta confirmação oferece um nível extra de segurança para a ação que está prestes a realizar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Prima ligar/desligar para confirmar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Prima qualquer botão de volume para cancelar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Cancelar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmação protegida do Android");
+
+ /* Tests for language ro */
+ ConfirmationUITranslations_select_lang_id("ro");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Apăsați de două ori butonul de pornire pentru a confirma");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Anulați");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Această confirmare oferă un nivel suplimentar de securitate pentru acțiunea pe care urmează să o faceți.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Apăsați butonul de pornire pentru a confirma");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Apăsați orice buton de volum pentru a anula");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Anulați");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Confirmare protecție pentru Android");
+
+ /* Tests for language ru */
+ ConfirmationUITranslations_select_lang_id("ru");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Для подтверждения дважды нажмите кнопку питания.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Отмена");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Дополнительный уровень защиты для действия, которое вы собираетесь выполнить.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Для подтверждения нажмите кнопку питания.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Для отмены нажмите на любую кнопку регулировки громкости.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Отмена");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Подтверждение Android Protected");
+
+ /* Tests for language si */
+ ConfirmationUITranslations_select_lang_id("si");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "තහවුරු කිරීමට බල බොත්තම දෙවරක් ඔබන්න");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "අවලංගු කරන්න");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "මෙම තහවුරු කිරිම ඔබ ගැනීමට යන ක්රියාමාර්ගය සඳහා ආරක්ෂාව පිළිබඳ අමතර ස්තරයක් සපයයි.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "තහවුරු කිරීමට බල බොත්තම ඔබන්න");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "අවලංගු කිරීමට ඕනෑම හඬ පරිමා බොත්තමක් ඔබන්න");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "අවලංගු කරන්න");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android ආරක්ෂිත තහවුරු කිරීම");
+
+ /* Tests for language sk */
+ ConfirmationUITranslations_select_lang_id("sk");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Potvrďte dvojitým stlačením vypínača");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Zrušiť");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Toto potvrdenie zaistí dodatočnú úroveň zabezpečenia akcie, ktorú sa chystáte vykonať.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Potvrďte stlačením vypínača");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Zrušte stlačením ľubovoľného tlačidla hlasitosti");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Zrušiť");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Chránené potvrdenie Androidu");
+
+ /* Tests for language sl */
+ ConfirmationUITranslations_select_lang_id("sl");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dvakrat pritisnite za potrditev");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Prekliči");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ta potrditev zagotavlja dodatno plast zaščite za dejanje, ki ga boste izvedli.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Za potrditev pritisnite gumb za vklop");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Za preklic pritisnite poljuben gumb za glasnost");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Prekliči");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Zaščitena potrditev v Androidu");
+
+ /* Tests for language sq */
+ ConfirmationUITranslations_select_lang_id("sq");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Shtyp dy herë butonin e energjisë për të konfirmuar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Anulo");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Konfirmim ofron një shtresë sigurie shtesë për veprimin që je gati për të ndërmarrë.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Shtyp butonin e energjisë për të konfirmuar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Shtyp çdo buton volumi për ta anuluar");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Anulo");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected Confirmation");
+
+ /* Tests for language sr */
+ ConfirmationUITranslations_select_lang_id("sr");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Двапут притисните дугме за напајање да бисте потврдили");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Откажи");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ова потврда пружа додатни слој безбедности за радњу коју се спремате да извршите.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Притисните дугме за напајање да бисте потврдили");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Притисните било које дугме за јачину звука да бисте отказали");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Откажи");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Потврда заштите на Android-у");
+
+ /* Tests for language sr-Latn */
+ ConfirmationUITranslations_select_lang_id("sr-Latn");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Dvaput pritisnite dugme za napajanje da biste potvrdili");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Otkaži");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ova potvrda pruža dodatni sloj bezbednosti za radnju koju se spremate da izvršite.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pritisnite dugme za napajanje da biste potvrdili");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pritisnite bilo koje dugme za jačinu zvuka da biste otkazali");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Otkaži");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Potvrda zaštite na Android-u");
+
+ /* Tests for language sv */
+ ConfirmationUITranslations_select_lang_id("sv");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Bekräfta genom att trycka två gånger på avstängningsknappen");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Avbryt");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Bekräftelsen ger extra skydd för åtgärden du ska vidta.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Bekräfta genom att trycka på strömbrytaren");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Avbryt genom att trycka på valfri volymknapp");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Avbryt");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Bekräftelseskydd för Android");
+
+ /* Tests for language sw */
+ ConfirmationUITranslations_select_lang_id("sw");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Bonyeza kitufe cha kuwasha mara mbili ili uthibitishe");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Ghairi");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Uthibitishaji huu hutoa ulinzi zaidi wa usalama kwa hatua unayotaka kuchukua.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Bonyeza kitufe cha kuwasha ili uthibitishe");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Bonyeza kitufe chochote cha sauti ili ughairi");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Ghairi");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Uthibitishaji Unaolindwa wa Android");
+
+ /* Tests for language ta */
+ ConfirmationUITranslations_select_lang_id("ta");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "உறுதிப்படுத்த, பவர் பட்டனை இருமுறை அழுத்தவும்");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ரத்துசெய்");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "நீங்கள் மேற்கொள்ளவிருக்கும் செயலுக்கு, கூடுதல் பாதுகாப்பை இந்த உறுதிப்படுத்தல் வழங்கும்.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "உறுதிப்படுத்த, பவரை அழுத்தவும்");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "ரத்துசெய்ய, ஏதேனும் ஒலியளவு பட்டனை அழுத்தவும்");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ரத்துசெய்");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android பாதுகாப்பு தொடர்பான உறுதிப்படுத்தல்");
+
+ /* Tests for language te */
+ ConfirmationUITranslations_select_lang_id("te");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "నిర్ధారించడానికి పవర్ బటన్ని రెండు సార్లు నొక్కండి");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "రద్దు చేయండి");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "ఈ నిర్ధారణ మీరు తీసుకోబోయే చర్య కోసం అదనపు భద్రతా లేయర్ను అందిస్తుంది.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "నిర్ధారించడానికి పవర్ను నొక్కండి");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "రద్దు చేయడానికి ఏదైనా వాల్యూమ్ బటన్ను నొక్కండి");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "రద్దు చేయండి");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android సురక్షిత నిర్ధారణ");
+
+ /* Tests for language th */
+ ConfirmationUITranslations_select_lang_id("th");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "กดปุ่มเปิด/ปิด 2 ครั้งเพื่อยืนยัน");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "ยกเลิก");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "การยืนยันนี้จะช่วยเพิ่มความปลอดภัยอีกขั้นสำหรับสิ่งที่คุณกำลังจะดำเนินการ");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "กดปุ่มเปิด/ปิดเพื่อยืนยัน");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "กดปุ่มปรับระดับเสียงเพื่อยกเลิก");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "ยกเลิก");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "ยืนยันการป้องกัน Android");
+
+ /* Tests for language tl */
+ ConfirmationUITranslations_select_lang_id("tl");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Pindutin nang dalawang beses ang power para kumpirmahin");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Kanselahin");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Ang pagkumpirmang ito ay nagbibigay ng karagdagang layer ng seguridad para sa pagkilos na gagawin mo.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Pindutin ang power para kumpirmahin");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Pindutin ang anumang button ng volume para kanselahin");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Kanselahin");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Pagkumpirmang Pinoprotektahan ng Android");
+
+ /* Tests for language tr */
+ ConfirmationUITranslations_select_lang_id("tr");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Onaylamak için güç düğmesine iki kez basın");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "İptal");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Bu onay, yapmak üzere olduğunuz işlem için ek güvenlik katmanı sağlar.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Onaylamak için güç düğmesine basın");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "İptal etmek için herhangi bir ses düğmesine basın");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "İptal");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Korumalı Onayı");
+
+ /* Tests for language uk */
+ ConfirmationUITranslations_select_lang_id("uk");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Двічі натисніть кнопку живлення, щоб підтвердити");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Скасувати");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Це підтвердження є додатковим рівнем захисту, коли ви збираєтеся виконати дію.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Натисніть кнопку живлення, щоб підтвердити");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Натисніть будь-яку клавішу гучності, щоб скасувати");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Скасувати");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Підтвердження Android Protected");
+
+ /* Tests for language ur */
+ ConfirmationUITranslations_select_lang_id("ur");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "تصدیق کرنے کے لئے پاور بٹن دوبار دبائیں");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "منسوخ کریں");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "آپ جو کارروائی کرنے والے ہیں اس کے لئے یہ تصدیق ایک اضافی پرت فراہم کرتی ہے۔");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "تصدیق کرنے کے لئے پاور بٹن دبائیں");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "منسوخ کرنے کے لئے کوئی بھی والیوم بٹن دبائیں");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "منسوخ کریں");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android کی تحفظ یافتہ تصدیق");
+
+ /* Tests for language uz */
+ ConfirmationUITranslations_select_lang_id("uz");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Tasdiqlash uchun quvvat tugmasini ikki marta bosing");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Bekor qilish");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Tasdiqlangandan keyin bajarilayotgan amal uchun qo‘shimcha xavfsizlik qatlami taqdim etiladi.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Tasdiqlash uchun quvvat tugmasini bosing");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Bekor qilish uchun istalgan tovush tugmasini bosing");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Bekor qilish");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected nomli tasdiq");
+
+ /* Tests for language vi */
+ ConfirmationUITranslations_select_lang_id("vi");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Nhấn hai lần vào nút nguồn để xác nhận");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Hủy");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Xác nhận này cung cấp thêm một lớp bảo mật cho hành động bạn sắp thực hiện.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Nhấn vào nút nguồn để xác nhận");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Nhấn vào nút âm lượng bất kỳ để hủy");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Hủy");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Xác nhận bảo vệ Android");
+
+ /* Tests for language zh */
+ ConfirmationUITranslations_select_lang_id("zh");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "连按两次电源按钮即可确认");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "取消");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "这项确认可为您即将执行的操作增添一层额外的安全保障。");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "按电源按钮即可确认");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "按任意音量按钮即可取消");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "取消");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android 保护确认");
+
+ /* Tests for language zh-CN */
+ ConfirmationUITranslations_select_lang_id("zh-CN");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "连按两次电源按钮即可确认");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "取消");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "这项确认可为您即将执行的操作增添一层额外的安全保障。");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "按电源按钮即可确认");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "按任意音量按钮即可取消");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "取消");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android 保护确认");
+
+ /* Tests for language zh-HK */
+ ConfirmationUITranslations_select_lang_id("zh-HK");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "按兩下電源按鈕即可確認");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "取消");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "此確認可為你即將執行的操作提供額外安全保障。");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "按下電源按鈕即可確認");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "按下任何音量按鈕即可取消");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "取消");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android 保護確認");
+
+ /* Tests for language zh-TW */
+ ConfirmationUITranslations_select_lang_id("zh-TW");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "按兩下電源按鈕即可確認操作");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "取消");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "這項確認作業可為你即將執行的動作提供多一層安全保障。");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "按下電源按鈕即可確認操作");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "按下任一音量按鈕即可取消操作");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "取消");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Android Protected 確認");
+
+ /* Tests for language zu */
+ ConfirmationUITranslations_select_lang_id("zu");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1424834532030812203"), "Cindezela kabili ukuze uqinisekise");
+ ASSERT_STR(ConfirmationUITranslations_lookup("1796282799666106567"), "Khansela");
+ ASSERT_STR(ConfirmationUITranslations_lookup("217688588483778177"), "Lokhu kuqinisekiswa kunikeza isendlalelo esingeziwe sokuvikelwa sesenzo osuzosithatha.");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2181224373757710937"), "Cindezela amandla ukuze uqinisekise");
+ ASSERT_STR(ConfirmationUITranslations_lookup("2213954494039981979"), "Cindezela noma iyiphi inkinobho yevolumu ukuze ukhansele");
+ ASSERT_STR(ConfirmationUITranslations_lookup("3999296476990449149"), "Khansela");
+ ASSERT_STR(ConfirmationUITranslations_lookup("6973195374358399966"), "Ukuqinisekiswa okuvikelwe i-Android");
+
+ /* Check language tag fallback mechanism works
+ (chop off components until a match has been found) */
+ const char* lang_ids[] = {
+ "de",
+ "da",
+ "da-GL",
+ "es-419",
+ "es-AR",
+ NULL
+ };
+ ASSERT_STR(test_lang_id_match(lang_ids, "de"), "de");
+ ASSERT_STR(test_lang_id_match(lang_ids, "de-DE"), "de");
+ ASSERT_STR(test_lang_id_match(lang_ids, "de-CH-1901"), "de");
+ ASSERT_STR(test_lang_id_match(lang_ids, "de-AT"), "de");
+ ASSERT_STR(test_lang_id_match(lang_ids, "da-DK"), "da");
+ ASSERT_STR(test_lang_id_match(lang_ids, "da-GL"), "da-GL");
+ ASSERT_STR(test_lang_id_match(lang_ids, "zh"), "");
+ ASSERT_STR(test_lang_id_match(lang_ids, "es-419"), "es-419");
+ ASSERT_STR(test_lang_id_match(lang_ids, "es-AR"), "es-AR");
+ ASSERT_STR(test_lang_id_match(lang_ids, "es"), "");
+
+ printf("All unit tests passed.\n");
+ return 0;
+}
diff --git a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
index a8c9487..b659be8 100644
--- a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
+++ b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.contexthub-hal-1-0 /vendor/bin/hw/android.hardware.contexthub@1.0-service
+ interface android.hardware.contexthub@1.0::IContexthub default
class hal
user system
group system
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 7dedd7f..6be30d3 100644
--- a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
+++ b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
@@ -24,7 +24,7 @@
#include <android/hardware/drm/1.0/types.h>
#include <android/hardware/drm/1.1/types.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
#include <gtest/gtest.h>
#include <hidl/HidlSupport.h>
#include <hidl/ServiceManagement.h>
@@ -129,9 +129,9 @@
ALOGD("DrmHalClearkeyTest: Running test %s.%s", test_info->test_case_name(),
test_info->name());
- auto manager = android::hardware::defaultServiceManager();
+ auto manager = android::hardware::defaultServiceManager1_2();
ASSERT_NE(nullptr, manager.get());
- manager->listByInterface(IDrmFactory::descriptor,
+ manager->listManifestByInterface(IDrmFactory::descriptor,
[&](const hidl_vec<hidl_string> ®istered) {
for (const auto &instance : registered) {
sp<IDrmFactory> drmFactory =
@@ -144,7 +144,7 @@
}
);
- manager->listByInterface(ICryptoFactory::descriptor,
+ manager->listManifestByInterface(ICryptoFactory::descriptor,
[&](const hidl_vec<hidl_string> ®istered) {
for (const auto &instance : registered) {
sp<ICryptoFactory> cryptoFactory =
diff --git a/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
index da332c7..b13a9ba 100644
--- a/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
+++ b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.gatekeeper-1-0 /vendor/bin/hw/android.hardware.gatekeeper@1.0-service
+ interface android.hardware.gatekeeper@1.0::IGatekeeper default
class hal
user system
group system
diff --git a/gnss/1.0/default/android.hardware.gnss@1.0-service.rc b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
index 1a44d34..1300d81 100644
--- a/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
+++ b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.gnss_service /vendor/bin/hw/android.hardware.gnss@1.0-service
+ interface android.hardware.gnss@1.0::IGnss default
class hal
user gps
group system gps radio
diff --git a/gnss/1.1/default/android.hardware.gnss@1.1-service.rc b/gnss/1.1/default/android.hardware.gnss@1.1-service.rc
index 0cf7c49..73901bf 100644
--- a/gnss/1.1/default/android.hardware.gnss@1.1-service.rc
+++ b/gnss/1.1/default/android.hardware.gnss@1.1-service.rc
@@ -1,4 +1,6 @@
service gnss-1-1 /vendor/bin/hw/android.hardware.gnss@1.1-service
+ interface android.hardware.gnss@1.0::IGnss default
+ interface android.hardware.gnss@1.1::IGnss default
class hal
user system
group system
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index 381ac1d..61a2ce4 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -16,24 +16,21 @@
#define LOG_TAG "GnssHalTest"
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
+
#include <gnss_hal_test.h>
#include <chrono>
#include "Utils.h"
-using ::android::hardware::gnss::common::Utils;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
-// Implementations for the main test class for GNSS HAL
-GnssHalTest::GnssHalTest()
- : info_called_count_(0),
- capabilities_called_count_(0),
- location_called_count_(0),
- name_called_count_(0),
- notify_count_(0) {}
+using ::android::hardware::gnss::common::Utils;
void GnssHalTest::SetUp() {
gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
- list_gnss_sv_status_.clear();
ASSERT_NE(gnss_hal_, nullptr);
SetUpGnssCallback();
@@ -42,14 +39,15 @@
void GnssHalTest::TearDown() {
if (gnss_hal_ != nullptr) {
gnss_hal_->cleanup();
+ gnss_hal_ = nullptr;
}
- if (notify_count_ > 0) {
- ALOGW("%d unprocessed callbacks discarded", notify_count_);
- }
+
+ // Set to nullptr to destruct the callback event queues and warn of any unprocessed events.
+ gnss_cb_ = nullptr;
}
void GnssHalTest::SetUpGnssCallback() {
- gnss_cb_ = new GnssCallback(*this);
+ gnss_cb_ = new GnssCallback();
ASSERT_NE(gnss_cb_, nullptr);
auto result = gnss_hal_->setCallback_1_1(gnss_cb_);
@@ -63,13 +61,13 @@
/*
* All capabilities, name and systemInfo callbacks should trigger
*/
- EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
- EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
- EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+ EXPECT_TRUE(gnss_cb_->capabilities_cbq_.retrieve(gnss_cb_->last_capabilities_, TIMEOUT_SEC));
+ EXPECT_TRUE(gnss_cb_->info_cbq_.retrieve(gnss_cb_->last_info_, TIMEOUT_SEC));
+ EXPECT_TRUE(gnss_cb_->name_cbq_.retrieve(gnss_cb_->last_name_, TIMEOUT_SEC));
- EXPECT_EQ(capabilities_called_count_, 1);
- EXPECT_EQ(info_called_count_, 1);
- EXPECT_EQ(name_called_count_, 1);
+ EXPECT_EQ(gnss_cb_->capabilities_cbq_.calledCount(), 1);
+ EXPECT_EQ(gnss_cb_->info_cbq_.calledCount(), 1);
+ EXPECT_EQ(gnss_cb_->name_cbq_.calledCount(), 1);
}
void GnssHalTest::StopAndClearLocations() {
@@ -83,9 +81,9 @@
* the last reply for final startup messages to arrive (esp. system
* info.)
*/
- while (wait(TIMEOUT_SEC) == std::cv_status::no_timeout) {
+ while (gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, TIMEOUT_SEC)) {
}
- location_called_count_ = 0;
+ gnss_cb_->location_cbq_.reset();
}
void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) {
@@ -112,19 +110,22 @@
*/
const int kFirstGnssLocationTimeoutSeconds = 75;
- wait(kFirstGnssLocationTimeoutSeconds);
- EXPECT_EQ(location_called_count_, 1);
+ EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+ kFirstGnssLocationTimeoutSeconds));
+ int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+ EXPECT_EQ(locationCalledCount, 1);
- if (location_called_count_ > 0) {
+ if (locationCalledCount > 0) {
// don't require speed on first fix
- CheckLocation(last_location_, false);
+ CheckLocation(gnss_cb_->last_location_, false);
return true;
}
return false;
}
void GnssHalTest::CheckLocation(GnssLocation& location, bool check_speed) {
- bool check_more_accuracies = (info_called_count_ > 0 && last_info_.yearOfHw >= 2017);
+ const bool check_more_accuracies =
+ (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017);
Utils::checkLocation(location, check_speed, check_more_accuracies);
}
@@ -139,70 +140,75 @@
EXPECT_TRUE(StartAndCheckFirstLocation());
for (int i = 1; i < count; i++) {
- EXPECT_EQ(std::cv_status::no_timeout, wait(kLocationTimeoutSubsequentSec));
- EXPECT_EQ(location_called_count_, i + 1);
+ EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+ kLocationTimeoutSubsequentSec));
+ int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+ EXPECT_EQ(locationCalledCount, i + 1);
// Don't cause confusion by checking details if no location yet
- if (location_called_count_ > 0) {
+ if (locationCalledCount > 0) {
// Should be more than 1 location by now, but if not, still don't check first fix speed
- CheckLocation(last_location_, location_called_count_ > 1);
+ CheckLocation(gnss_cb_->last_location_, locationCalledCount > 1);
}
}
}
-void GnssHalTest::notify() {
- std::unique_lock<std::mutex> lock(mtx_);
- notify_count_++;
- cv_.notify_one();
+bool GnssHalTest::IsGnssHalVersion_1_1() const {
+ using ::android::hidl::manager::V1_2::IServiceManager;
+ sp<IServiceManager> manager = ::android::hardware::defaultServiceManager1_2();
+
+ bool hasGnssHalVersion_1_1 = false;
+ manager->listManifestByInterface(
+ "android.hardware.gnss@1.1::IGnss",
+ [&hasGnssHalVersion_1_1](const hidl_vec<hidl_string>& registered) {
+ ASSERT_EQ(1, registered.size());
+ hasGnssHalVersion_1_1 = true;
+ });
+
+ bool hasGnssHalVersion_2_0 = false;
+ manager->listManifestByInterface(
+ "android.hardware.gnss@2.0::IGnss",
+ [&hasGnssHalVersion_2_0](const hidl_vec<hidl_string>& registered) {
+ hasGnssHalVersion_2_0 = registered.size() != 0;
+ });
+
+ return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0;
}
-std::cv_status GnssHalTest::wait(int timeout_seconds) {
- std::unique_lock<std::mutex> lock(mtx_);
-
- auto status = std::cv_status::no_timeout;
- while (notify_count_ == 0) {
- status = cv_.wait_for(lock, std::chrono::seconds(timeout_seconds));
- if (status == std::cv_status::timeout) return status;
- }
- notify_count_--;
- return status;
-}
+GnssHalTest::GnssCallback::GnssCallback()
+ : info_cbq_("system_info"),
+ name_cbq_("name"),
+ capabilities_cbq_("capabilities"),
+ location_cbq_("location"),
+ sv_status_cbq_("sv_status") {}
Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
const IGnssCallback::GnssSystemInfo& info) {
ALOGI("Info received, year %d", info.yearOfHw);
- parent_.info_called_count_++;
- parent_.last_info_ = info;
- parent_.notify();
+ info_cbq_.store(info);
return Void();
}
Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
ALOGI("Capabilities received %d", capabilities);
- parent_.capabilities_called_count_++;
- parent_.last_capabilities_ = capabilities;
- parent_.notify();
+ capabilities_cbq_.store(capabilities);
return Void();
}
Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
ALOGI("Name received: %s", name.c_str());
- parent_.name_called_count_++;
- parent_.last_name_ = name;
- parent_.notify();
+ name_cbq_.store(name);
return Void();
}
Return<void> GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation& location) {
ALOGI("Location received");
- parent_.location_called_count_++;
- parent_.last_location_ = location;
- parent_.notify();
+ location_cbq_.store(location);
return Void();
}
Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb(
const IGnssCallback::GnssSvStatus& svStatus) {
ALOGI("GnssSvStatus received");
- parent_.list_gnss_sv_status_.emplace_back(svStatus);
+ sv_status_cbq_.store(svStatus);
return Void();
}
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index 64478b5..e4325bf 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -21,19 +21,17 @@
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
-
-#include <condition_variable>
-#include <list>
-#include <mutex>
+#include "GnssCallbackEventQueue.h"
using android::hardware::Return;
using android::hardware::Void;
using android::hardware::gnss::V1_0::GnssLocation;
+using android::hardware::gnss::common::GnssCallbackEventQueue;
+using android::hardware::gnss::V1_0::GnssLocationFlags;
using android::hardware::gnss::V1_1::IGnss;
using android::hardware::gnss::V1_1::IGnssCallback;
-using android::hardware::gnss::V1_0::GnssLocationFlags;
using android::sp;
@@ -57,8 +55,6 @@
// The main test class for GNSS HAL.
class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
public:
- GnssHalTest();
-
virtual void SetUp() override;
virtual void TearDown() override;
@@ -72,32 +68,40 @@
/* Callback class for data & Event. */
class GnssCallback : public IGnssCallback {
public:
- GnssHalTest& parent_;
+ IGnssCallback::GnssSystemInfo last_info_;
+ android::hardware::hidl_string last_name_;
+ uint32_t last_capabilities_;
+ GnssLocation last_location_;
- GnssCallback(GnssHalTest& parent) : parent_(parent){};
+ GnssCallbackEventQueue<IGnssCallback::GnssSystemInfo> info_cbq_;
+ GnssCallbackEventQueue<android::hardware::hidl_string> name_cbq_;
+ GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+ GnssCallbackEventQueue<GnssLocation> location_cbq_;
+ GnssCallbackEventQueue<IGnssCallback::GnssSvStatus> sv_status_cbq_;
- virtual ~GnssCallback() = default;
+ GnssCallback();
+ virtual ~GnssCallback() = default;
- // Dummy callback handlers
- Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue /* status */) override {
- return Void();
- }
- Return<void> gnssNmeaCb(int64_t /* timestamp */,
- const android::hardware::hidl_string& /* nmea */) override {
- return Void();
- }
- Return<void> gnssAcquireWakelockCb() override { return Void(); }
- Return<void> gnssReleaseWakelockCb() override { return Void(); }
- Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override {
- return Void();
- }
- Return<void> gnssRequestTimeCb() override { return Void(); }
- // Actual (test) callback handlers
- Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
- Return<void> gnssLocationCb(const GnssLocation& location) override;
- Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
- Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
- Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
+ // Dummy callback handlers
+ Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue /* status */) override {
+ return Void();
+ }
+ Return<void> gnssNmeaCb(int64_t /* timestamp */,
+ const android::hardware::hidl_string& /* nmea */) override {
+ return Void();
+ }
+ Return<void> gnssAcquireWakelockCb() override { return Void(); }
+ Return<void> gnssReleaseWakelockCb() override { return Void(); }
+ Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override {
+ return Void();
+ }
+ Return<void> gnssRequestTimeCb() override { return Void(); }
+ // Actual (test) callback handlers
+ Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
+ Return<void> gnssLocationCb(const GnssLocation& location) override;
+ Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
+ Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
+ Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
};
/*
@@ -145,27 +149,14 @@
*/
void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
- sp<IGnss> gnss_hal_; // GNSS HAL to call into
- sp<IGnssCallback> gnss_cb_; // Primary callback interface
-
- /* Count of calls to set the following items, and the latest item (used by
- * test.)
+ /*
+ * IsGnssHalVersion_1_1:
+ * returns true if the GNSS HAL version is exactly 1.1.
*/
- int info_called_count_;
- IGnssCallback::GnssSystemInfo last_info_;
- uint32_t last_capabilities_;
- int capabilities_called_count_;
- int location_called_count_;
- GnssLocation last_location_;
- list<IGnssCallback::GnssSvStatus> list_gnss_sv_status_;
+ bool IsGnssHalVersion_1_1() const;
- int name_called_count_;
- android::hardware::hidl_string last_name_;
-
- private:
- std::mutex mtx_;
- std::condition_variable cv_;
- int notify_count_;
+ sp<IGnss> gnss_hal_; // GNSS HAL to call into
+ sp<GnssCallback> gnss_cb_; // Primary callback interface
};
#endif // GNSS_HAL_TEST_H_
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 2d901f3..3294bcd 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -24,6 +24,9 @@
using android::hardware::hidl_vec;
+using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
+using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
+
using android::hardware::gnss::V1_0::GnssConstellationType;
using android::hardware::gnss::V1_0::GnssLocation;
using android::hardware::gnss::V1_0::IGnssDebug;
@@ -43,11 +46,15 @@
* Gets the GnssMeasurementExtension and verify that it returns an actual extension.
*/
TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
- auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_1_1();
- ASSERT_TRUE(gnssMeasurement.isOk());
- if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
- sp<IGnssMeasurement> iGnssMeas = gnssMeasurement;
- EXPECT_NE(iGnssMeas, nullptr);
+ auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
+ ASSERT_TRUE(gnssMeasurement_1_1.isOk());
+ auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
+ ASSERT_TRUE(gnssMeasurement_1_0.isOk());
+ if (gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
+ sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
+ sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
+ // At least one interface must be non-null.
+ ASSERT_TRUE(iGnssMeas_1_1 != nullptr || iGnssMeas_1_0 != nullptr);
}
}
@@ -59,6 +66,11 @@
* each received location.
*/
TEST_F(GnssHalTest, GetLocationLowPower) {
+ if (!IsGnssHalVersion_1_1()) {
+ ALOGI("Test GetLocationLowPower skipped. GNSS HAL version is greater than 1.1.");
+ return;
+ }
+
const int kMinIntervalMsec = 5000;
const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) * 2;
const int kNoLocationPeriodSec = (kMinIntervalMsec / 1000) / 2;
@@ -66,8 +78,10 @@
const bool kLowPowerMode = true;
// Warmup period - VTS doesn't have AGPS access via GnssLocationProvider
- StartAndCheckLocations(5);
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToCheck);
StopAndClearLocations();
+ gnss_cb_->location_cbq_.reset();
// Start of Low Power Mode test
SetPositionMode(kMinIntervalMsec, kLowPowerMode);
@@ -81,24 +95,27 @@
// Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and
// ensure that no location is received yet
- wait(kNoLocationPeriodSec);
+ gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec);
+ const int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
// Tolerate (ignore) one extra location right after the first one
// to handle startup edge case scheduling limitations in some implementations
- if ((i == 1) && (location_called_count_ == 2)) {
- CheckLocation(last_location_, true);
+ if ((i == 1) && (location_called_count == 2)) {
+ CheckLocation(gnss_cb_->last_location_, true);
continue; // restart the quiet wait period after this too-fast location
}
- EXPECT_LE(location_called_count_, i);
- if (location_called_count_ != i) {
+ EXPECT_LE(location_called_count, i);
+ if (location_called_count != i) {
ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
- location_called_count_, i);
+ location_called_count, i);
}
- if (std::cv_status::no_timeout !=
- wait(kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
+ if (!gnss_cb_->location_cbq_.retrieve(
+ gnss_cb_->last_location_,
+ kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
ALOGW("GetLocationLowPower test - timeout awaiting location %d", i);
} else {
- CheckLocation(last_location_, true);
+ CheckLocation(gnss_cb_->last_location_, true);
}
}
@@ -202,15 +219,23 @@
* formerly strongest satellite
*/
TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+ if (!IsGnssHalVersion_1_1()) {
+ ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 1.1.");
+ return;
+ }
+
const int kLocationsToAwait = 3;
const int kRetriesToUnBlacklist = 10;
+ gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
+ int location_called_count = gnss_cb_->location_cbq_.calledCount();
// Tolerate 1 less sv status to handle edge cases in reporting.
- EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
- (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
+ int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+ EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size,
+ kLocationsToAwait, location_called_count);
/*
* Identify strongest SV seen at least kLocationsToAwait -1 times
@@ -218,8 +243,14 @@
* observability (one epoch RF null)
*/
+ const int kGnssSvStatusTimeout = 2;
+ list<IGnssCallback::GnssSvStatus> sv_status_list;
+ int count = gnss_cb_->sv_status_cbq_.retrieve(sv_status_list, sv_status_cbq_size,
+ kGnssSvStatusTimeout);
+ ASSERT_EQ(count, sv_status_cbq_size);
+
IGnssConfiguration::BlacklistedSource source_to_blacklist =
- FindStrongFrequentNonGpsSource(list_gnss_sv_status_, kLocationsToAwait - 1);
+ FindStrongFrequentNonGpsSource(sv_status_list, kLocationsToAwait - 1);
if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) {
// Cannot find a non-GPS satellite. Let the test pass.
@@ -243,21 +274,26 @@
EXPECT_TRUE(result);
// retry and ensure satellite not used
- list_gnss_sv_status_.clear();
+ gnss_cb_->sv_status_cbq_.reset();
+ gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// early exit if test is being run with insufficient signal
- if (location_called_count_ == 0) {
+ location_called_count = gnss_cb_->location_cbq_.calledCount();
+ if (location_called_count == 0) {
ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
}
- ASSERT_TRUE(location_called_count_ > 0);
+ ASSERT_TRUE(location_called_count > 0);
// Tolerate 1 less sv status to handle edge cases in reporting.
- EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
- (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
- for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+ sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+ EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size,
+ kLocationsToAwait, location_called_count);
+ for (int i = 0; i < sv_status_cbq_size; ++i) {
+ IGnssCallback::GnssSvStatus gnss_sv_status;
+ gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout);
for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
EXPECT_FALSE((gnss_sv.svid == source_to_blacklist.svid) &&
@@ -278,24 +314,28 @@
int unblacklist_loops_remaining = kRetriesToUnBlacklist;
while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) {
StopAndClearLocations();
- list_gnss_sv_status_.clear();
+ gnss_cb_->sv_status_cbq_.reset();
+ gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// early exit loop if test is being run with insufficient signal
- if (location_called_count_ == 0) {
+ location_called_count = gnss_cb_->location_cbq_.calledCount();
+ if (location_called_count == 0) {
ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
}
- ASSERT_TRUE(location_called_count_ > 0);
+ ASSERT_TRUE(location_called_count > 0);
// Tolerate 1 less sv status to handle edge cases in reporting.
- EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD(
- "Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
- ", tries remaining %d",
- (int)list_gnss_sv_status_.size(), kLocationsToAwait, unblacklist_loops_remaining);
+ sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+ EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
+ ", tries remaining %d",
+ sv_status_cbq_size, kLocationsToAwait, unblacklist_loops_remaining);
- for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+ for (int i = 0; i < sv_status_cbq_size; ++i) {
+ IGnssCallback::GnssSvStatus gnss_sv_status;
+ gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout);
for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
if ((gnss_sv.svid == source_to_blacklist.svid) &&
@@ -323,18 +363,29 @@
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
TEST_F(GnssHalTest, BlacklistConstellation) {
+ if (!IsGnssHalVersion_1_1()) {
+ ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
+ return;
+ }
+
const int kLocationsToAwait = 3;
+ gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
+ const int location_called_count = gnss_cb_->location_cbq_.calledCount();
// Tolerate 1 less sv status to handle edge cases in reporting.
- EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
- (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
+ int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+ EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size,
+ kLocationsToAwait, location_called_count);
// Find first non-GPS constellation to blacklist
+ const int kGnssSvStatusTimeout = 2;
GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
- for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+ for (int i = 0; i < sv_status_cbq_size; ++i) {
+ IGnssCallback::GnssSvStatus gnss_sv_status;
+ gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout);
for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
@@ -373,16 +424,19 @@
EXPECT_TRUE(result);
// retry and ensure constellation not used
- list_gnss_sv_status_.clear();
+ gnss_cb_->sv_status_cbq_.reset();
- location_called_count_ = 0;
+ gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// Tolerate 1 less sv status to handle edge cases in reporting.
- EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+ sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+ EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_status_cbq_size,
kLocationsToAwait);
- for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+ for (int i = 0; i < sv_status_cbq_size; ++i) {
+ IGnssCallback::GnssSvStatus gnss_sv_status;
+ gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout);
for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) &&
@@ -405,7 +459,7 @@
*/
TEST_F(GnssHalTest, InjectBestLocation) {
StartAndCheckLocations(1);
- GnssLocation gnssLocation = last_location_;
+ GnssLocation gnssLocation = gnss_cb_->last_location_;
CheckLocation(gnssLocation, true);
auto result = gnss_hal_->injectBestLocation(gnssLocation);
@@ -425,7 +479,7 @@
TEST_F(GnssHalTest, GnssDebugValuesSanityTest) {
auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
ASSERT_TRUE(gnssDebug.isOk());
- if (info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
+ if (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/VtsHalGnssV2_0TargetTest.cpp b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
index a8e40ba..ae36c50 100644
--- a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
+++ b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
@@ -23,7 +23,6 @@
::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
GnssHidlEnvironment::Instance()->init(&argc, argv);
- // TODO (b/122463165): Expand coverage to include 1.1 and 1.0 VTS tests.
int status = RUN_ALL_TESTS();
ALOGI("Test result = %d", status);
return status;
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp
index a9f858c..14ae43c 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -152,7 +152,7 @@
name_cbq_("name"),
capabilities_cbq_("capabilities"),
location_cbq_("location"),
- sv_info_cbq_("sv_info") {}
+ sv_info_list_cbq_("sv_info") {}
Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
const IGnssCallback_1_0::GnssSystemInfo& info) {
@@ -204,7 +204,7 @@
Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb_2_0(
const hidl_vec<IGnssCallback_2_0::GnssSvInfo>& svInfoList) {
ALOGI("gnssSvStatusCb_2_0. Size = %d", (int)svInfoList.size());
- sv_info_cbq_.store(svInfoList);
+ sv_info_list_cbq_.store(svInfoList);
return Void();
}
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h
index 05e37d3..7d07c0f 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.h
+++ b/gnss/2.0/vts/functional/gnss_hal_test.h
@@ -17,18 +17,16 @@
#ifndef GNSS_HAL_TEST_H_
#define GNSS_HAL_TEST_H_
-#include <android/hardware/gnss/2.0/IGnss.h>
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
-
-#include <condition_variable>
-#include <deque>
-#include <mutex>
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include "GnssCallbackEventQueue.h"
using android::hardware::hidl_vec;
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::IGnss;
@@ -69,42 +67,6 @@
virtual void TearDown() override;
- /* Producer/consumer queue for storing/retrieving callback events from GNSS HAL */
- template <class T>
- class CallbackQueue {
- public:
- CallbackQueue(const std::string& name) : name_(name), called_count_(0){};
- ~CallbackQueue() { reset(); }
-
- /* Adds callback event to the end of the queue. */
- void store(const T& event);
-
- /*
- * Removes the callack event at the front of the queue, stores it in event parameter
- * and returns true. Returns false on timeout and event is not populated.
- */
- bool retrieve(T& event, int timeout_seconds);
-
- /* Returns the number of events pending to be retrieved from the callback event queue. */
- int size() const;
-
- /* Returns the number of callback events received since last reset(). */
- int calledCount() const;
-
- /* Clears the callback event queue and resets the calledCount() to 0. */
- void reset();
-
- private:
- CallbackQueue(const CallbackQueue&) = delete;
- CallbackQueue& operator=(const CallbackQueue&) = delete;
-
- std::string name_;
- int called_count_;
- mutable std::recursive_mutex mtx_;
- std::condition_variable_any cv_;
- std::deque<T> events_;
- };
-
/* Callback class for data & Event. */
class GnssCallback : public IGnssCallback_2_0 {
public:
@@ -113,11 +75,11 @@
uint32_t last_capabilities_;
GnssLocation_2_0 last_location_;
- CallbackQueue<IGnssCallback_1_0::GnssSystemInfo> info_cbq_;
- CallbackQueue<android::hardware::hidl_string> name_cbq_;
- CallbackQueue<uint32_t> capabilities_cbq_;
- CallbackQueue<GnssLocation_2_0> location_cbq_;
- CallbackQueue<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_cbq_;
+ GnssCallbackEventQueue<IGnssCallback_1_0::GnssSystemInfo> info_cbq_;
+ GnssCallbackEventQueue<android::hardware::hidl_string> name_cbq_;
+ GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+ GnssCallbackEventQueue<GnssLocation_2_0> location_cbq_;
+ GnssCallbackEventQueue<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_list_cbq_;
GnssCallback();
virtual ~GnssCallback() = default;
@@ -160,7 +122,7 @@
/* Callback class for GnssMeasurement. */
class GnssMeasurementCallback : public IGnssMeasurementCallback_2_0 {
public:
- CallbackQueue<IGnssMeasurementCallback_2_0::GnssData> measurement_cbq_;
+ GnssCallbackEventQueue<IGnssMeasurementCallback_2_0::GnssData> measurement_cbq_;
GnssMeasurementCallback() : measurement_cbq_("measurement"){};
virtual ~GnssMeasurementCallback() = default;
@@ -183,7 +145,7 @@
class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
public:
uint32_t last_capabilities_;
- CallbackQueue<uint32_t> capabilities_cbq_;
+ GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){};
virtual ~GnssMeasurementCorrectionsCallback() = default;
@@ -243,48 +205,4 @@
sp<GnssCallback> gnss_cb_; // Primary callback interface
};
-template <class T>
-void GnssHalTest::CallbackQueue<T>::store(const T& event) {
- std::unique_lock<std::recursive_mutex> lock(mtx_);
- events_.push_back(event);
- ++called_count_;
- lock.unlock();
- cv_.notify_all();
-}
-
-template <class T>
-bool GnssHalTest::CallbackQueue<T>::retrieve(T& event, int timeout_seconds) {
- std::unique_lock<std::recursive_mutex> lock(mtx_);
- cv_.wait_for(lock, std::chrono::seconds(timeout_seconds), [&] { return !events_.empty(); });
- if (events_.empty()) {
- return false;
- }
- event = events_.front();
- events_.pop_front();
- return true;
-}
-
-template <class T>
-int GnssHalTest::CallbackQueue<T>::size() const {
- std::unique_lock<std::recursive_mutex> lock(mtx_);
- return events_.size();
-}
-
-template <class T>
-int GnssHalTest::CallbackQueue<T>::calledCount() const {
- std::unique_lock<std::recursive_mutex> lock(mtx_);
- return called_count_;
-}
-
-template <class T>
-void GnssHalTest::CallbackQueue<T>::reset() {
- std::unique_lock<std::recursive_mutex> lock(mtx_);
- if (!events_.empty()) {
- ALOGW("%u unprocessed events discarded in callback queue %s", (unsigned int)events_.size(),
- name_.c_str());
- }
- events_.clear();
- called_count_ = 0;
-}
-
#endif // GNSS_HAL_TEST_H_
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 155afd6..ca3edc5 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -23,7 +23,10 @@
using android::hardware::hidl_string;
using android::hardware::hidl_vec;
+using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
+using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
+using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
using IAGnssRil_2_0 = android::hardware::gnss::V2_0::IAGnssRil;
using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
@@ -33,15 +36,12 @@
using IAGnss_2_0 = android::hardware::gnss::V2_0::IAGnss;
using IAGnss_1_0 = android::hardware::gnss::V1_0::IAGnss;
using IAGnssCallback_2_0 = android::hardware::gnss::V2_0::IAGnssCallback;
-using IGnssBatching_V1_0 = android::hardware::gnss::V1_0::IGnssBatching;
-using IGnssBatching_V2_0 = android::hardware::gnss::V2_0::IGnssBatching;
using android::hardware::gnss::common::Utils;
using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
using android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
using android::hardware::gnss::V1_0::IGnssNi;
using android::hardware::gnss::V2_0::ElapsedRealtimeFlags;
-using android::hardware::gnss::V2_0::GnssConstellationType;
using android::hardware::gnss::V2_0::IGnssCallback;
using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
@@ -209,9 +209,9 @@
// Verify ConstellationType is valid.
ASSERT_TRUE(static_cast<uint8_t>(measurement.constellation) >=
- static_cast<uint8_t>(GnssConstellationType::UNKNOWN) &&
+ static_cast<uint8_t>(GnssConstellationType_2_0::UNKNOWN) &&
static_cast<uint8_t>(measurement.constellation) <=
- static_cast<uint8_t>(GnssConstellationType::IRNSS));
+ static_cast<uint8_t>(GnssConstellationType_2_0::IRNSS));
// Verify State is valid.
ASSERT_TRUE(
@@ -414,3 +414,423 @@
auto gnssBatching_2_0 = gnss_hal_->getExtensionGnssBatching_2_0();
ASSERT_TRUE(gnssBatching_2_0.isOk());
}
+
+/*
+ * GetLocationLowPower:
+ * Turns on location, waits for at least 5 locations allowing max of LOCATION_TIMEOUT_SUBSEQUENT_SEC
+ * between one location and the next. Also ensure that MIN_INTERVAL_MSEC is respected by waiting
+ * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
+ * each received location.
+ */
+TEST_F(GnssHalTest, GetLocationLowPower) {
+ if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::LOW_POWER_MODE)) {
+ ALOGI("Test GetLocationLowPower skipped. LOW_POWER_MODE capability not supported.");
+ return;
+ }
+
+ const int kMinIntervalMsec = 5000;
+ const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) * 2;
+ const int kNoLocationPeriodSec = (kMinIntervalMsec / 1000) / 2;
+ const int kLocationsToCheck = 5;
+ const bool kLowPowerMode = true;
+
+ // Warmup period - VTS doesn't have AGPS access via GnssLocationProvider
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToCheck);
+ StopAndClearLocations();
+ gnss_cb_->location_cbq_.reset();
+
+ // Start of Low Power Mode test
+ SetPositionMode(kMinIntervalMsec, kLowPowerMode);
+
+ // Don't expect true - as without AGPS access
+ if (!StartAndCheckFirstLocation()) {
+ ALOGW("GetLocationLowPower test - no first low power location received.");
+ }
+
+ for (int i = 1; i < kLocationsToCheck; i++) {
+ // Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and
+ // ensure that no location is received yet
+
+ gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec);
+ const int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+ // Tolerate (ignore) one extra location right after the first one
+ // to handle startup edge case scheduling limitations in some implementations
+ if ((i == 1) && (location_called_count == 2)) {
+ CheckLocation(gnss_cb_->last_location_, true);
+ continue; // restart the quiet wait period after this too-fast location
+ }
+ EXPECT_LE(location_called_count, i);
+ if (location_called_count != i) {
+ ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
+ location_called_count, i);
+ }
+
+ if (!gnss_cb_->location_cbq_.retrieve(
+ gnss_cb_->last_location_,
+ kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
+ ALOGW("GetLocationLowPower test - timeout awaiting location %d", i);
+ } else {
+ CheckLocation(gnss_cb_->last_location_, true);
+ }
+ }
+
+ StopAndClearLocations();
+}
+
+/*
+ * MapConstellationType:
+ * Given a GnssConstellationType_2_0 type constellation, maps to its equivalent
+ * GnssConstellationType_1_0 type constellation. For constellations that do not have
+ * an equivalent value, maps to GnssConstellationType_1_0::UNKNOWN
+ */
+GnssConstellationType_1_0 MapConstellationType(GnssConstellationType_2_0 constellation) {
+ switch (constellation) {
+ case GnssConstellationType_2_0::GPS:
+ return GnssConstellationType_1_0::GPS;
+ case GnssConstellationType_2_0::SBAS:
+ return GnssConstellationType_1_0::SBAS;
+ case GnssConstellationType_2_0::GLONASS:
+ return GnssConstellationType_1_0::GLONASS;
+ case GnssConstellationType_2_0::QZSS:
+ return GnssConstellationType_1_0::QZSS;
+ case GnssConstellationType_2_0::BEIDOU:
+ return GnssConstellationType_1_0::BEIDOU;
+ case GnssConstellationType_2_0::GALILEO:
+ return GnssConstellationType_1_0::GALILEO;
+ default:
+ return GnssConstellationType_1_0::UNKNOWN;
+ }
+}
+
+/*
+ * FindStrongFrequentNonGpsSource:
+ *
+ * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
+ *
+ * returns the strongest source,
+ * or a source with constellation == UNKNOWN if none are found sufficient times
+ */
+IGnssConfiguration_1_1::BlacklistedSource FindStrongFrequentNonGpsSource(
+ const list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>>& sv_info_lists,
+ const int min_observations) {
+ struct ComparableBlacklistedSource {
+ IGnssConfiguration_1_1::BlacklistedSource id;
+
+ ComparableBlacklistedSource() {
+ id.constellation = GnssConstellationType_1_0::UNKNOWN;
+ id.svid = 0;
+ }
+
+ bool operator<(const ComparableBlacklistedSource& compare) const {
+ return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
+ (id.constellation < compare.id.constellation)));
+ }
+ };
+
+ struct SignalCounts {
+ int observations;
+ float max_cn0_dbhz;
+ };
+
+ std::map<ComparableBlacklistedSource, SignalCounts> mapSignals;
+
+ for (const auto& sv_info_list : sv_info_lists) {
+ for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+ if ((sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
+ (sv_info.constellation != GnssConstellationType_2_0::IRNSS) &&
+ (sv_info.constellation != GnssConstellationType_2_0::GPS)) {
+ ComparableBlacklistedSource source;
+ source.id.svid = sv_info.v1_0.svid;
+ source.id.constellation = MapConstellationType(sv_info.constellation);
+
+ const auto& itSignal = mapSignals.find(source);
+ if (itSignal == mapSignals.end()) {
+ SignalCounts counts;
+ counts.observations = 1;
+ counts.max_cn0_dbhz = sv_info.v1_0.cN0Dbhz;
+ mapSignals.insert(
+ std::pair<ComparableBlacklistedSource, SignalCounts>(source, counts));
+ } else {
+ itSignal->second.observations++;
+ if (itSignal->second.max_cn0_dbhz < sv_info.v1_0.cN0Dbhz) {
+ itSignal->second.max_cn0_dbhz = sv_info.v1_0.cN0Dbhz;
+ }
+ }
+ }
+ }
+ }
+
+ float max_cn0_dbhz_with_sufficient_count = 0.;
+ int total_observation_count = 0;
+ int blacklisted_source_count_observation = 0;
+
+ ComparableBlacklistedSource source_to_blacklist; // initializes to zero = UNKNOWN constellation
+ for (auto const& pairSignal : mapSignals) {
+ total_observation_count += pairSignal.second.observations;
+ if ((pairSignal.second.observations >= min_observations) &&
+ (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
+ source_to_blacklist = pairSignal.first;
+ blacklisted_source_count_observation = pairSignal.second.observations;
+ max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
+ }
+ }
+ ALOGD("Among %d observations, chose svid %d, constellation %d, "
+ "with %d observations at %.1f max CNo",
+ total_observation_count, source_to_blacklist.id.svid,
+ (int)source_to_blacklist.id.constellation, blacklisted_source_count_observation,
+ max_cn0_dbhz_with_sufficient_count);
+
+ return source_to_blacklist.id;
+}
+
+/*
+ * BlacklistIndividualSatellites:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for common satellites (strongest and one other.)
+ * 2a & b) Turns off location, and blacklists common satellites.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use those satellites.
+ * 4a & b) Turns off location, and send in empty blacklist.
+ * 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does re-use at least the previously strongest satellite
+ * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
+ * formerly strongest satellite
+ */
+TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+ if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
+ ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability"
+ " not supported.");
+ return;
+ }
+
+ const int kLocationsToAwait = 3;
+ const int kRetriesToUnBlacklist = 10;
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+ int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
+ sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+
+ /*
+ * Identify strongest SV seen at least kLocationsToAwait -1 times
+ * Why -1? To avoid test flakiness in case of (plausible) slight flakiness in strongest signal
+ * observability (one epoch RF null)
+ */
+
+ const int kGnssSvStatusTimeout = 2;
+ list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_lists;
+ int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, sv_info_list_cbq_size,
+ kGnssSvStatusTimeout);
+ ASSERT_EQ(count, sv_info_list_cbq_size);
+
+ IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist =
+ FindStrongFrequentNonGpsSource(sv_info_lists, kLocationsToAwait - 1);
+
+ if (source_to_blacklist.constellation == GnssConstellationType_1_0::UNKNOWN) {
+ // Cannot find a non-GPS satellite. Let the test pass.
+ return;
+ }
+
+ // Stop locations, blacklist the common SV
+ StopAndClearLocations();
+
+ auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
+ ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+ sp<IGnssConfiguration_1_1> gnss_configuration_hal = gnss_configuration_hal_return;
+ ASSERT_NE(gnss_configuration_hal, nullptr);
+
+ hidl_vec<IGnssConfiguration_1_1::BlacklistedSource> sources;
+ sources.resize(1);
+ sources[0] = source_to_blacklist;
+
+ auto result = gnss_configuration_hal->setBlacklist(sources);
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ // retry and ensure satellite not used
+ gnss_cb_->sv_info_list_cbq_.reset();
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+
+ // early exit if test is being run with insufficient signal
+ location_called_count = gnss_cb_->location_cbq_.calledCount();
+ if (location_called_count == 0) {
+ ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
+ }
+ ASSERT_TRUE(location_called_count > 0);
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
+ sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+ for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+ hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
+ for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+ auto constellation = MapConstellationType(sv_info.constellation);
+ EXPECT_FALSE((sv_info.v1_0.svid == source_to_blacklist.svid) &&
+ (constellation == source_to_blacklist.constellation) &&
+ (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
+ }
+ }
+
+ // clear blacklist and restart - this time updating the blacklist while location is still on
+ sources.resize(0);
+
+ result = gnss_configuration_hal->setBlacklist(sources);
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ bool strongest_sv_is_reobserved = false;
+ // do several loops awaiting a few locations, allowing non-immediate reacquisition strategies
+ int unblacklist_loops_remaining = kRetriesToUnBlacklist;
+ while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) {
+ StopAndClearLocations();
+ gnss_cb_->sv_info_list_cbq_.reset();
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+
+ // early exit loop if test is being run with insufficient signal
+ location_called_count = gnss_cb_->location_cbq_.calledCount();
+ if (location_called_count == 0) {
+ ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
+ }
+ ASSERT_TRUE(location_called_count > 0);
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
+ ", tries remaining %d",
+ sv_info_list_cbq_size, kLocationsToAwait, unblacklist_loops_remaining);
+
+ for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+ hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
+ for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+ auto constellation = MapConstellationType(sv_info.constellation);
+ if ((sv_info.v1_0.svid == source_to_blacklist.svid) &&
+ (constellation == source_to_blacklist.constellation) &&
+ (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
+ strongest_sv_is_reobserved = true;
+ break;
+ }
+ }
+ if (strongest_sv_is_reobserved) break;
+ }
+ }
+ EXPECT_TRUE(strongest_sv_is_reobserved);
+ StopAndClearLocations();
+}
+
+/*
+ * BlacklistConstellation:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Turns off location, and blacklist first non-GPS constellations.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use any constellation but GPS.
+ * 4a & b) Clean up by turning off location, and send in empty blacklist.
+ */
+TEST_F(GnssHalTest, BlacklistConstellation) {
+ if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
+ ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
+ return;
+ }
+
+ const int kLocationsToAwait = 3;
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+ const int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
+ sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+
+ // Find first non-GPS constellation to blacklist. Exclude IRNSS in GnssConstellationType_2_0
+ // as blacklisting of this constellation is not supported in gnss@2.0.
+ const int kGnssSvStatusTimeout = 2;
+ GnssConstellationType_1_0 constellation_to_blacklist = GnssConstellationType_1_0::UNKNOWN;
+ for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+ hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
+ for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+ if ((sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
+ (sv_info.constellation != GnssConstellationType_2_0::UNKNOWN) &&
+ (sv_info.constellation != GnssConstellationType_2_0::IRNSS) &&
+ (sv_info.constellation != GnssConstellationType_2_0::GPS)) {
+ // found a non-GPS V1_0 constellation
+ constellation_to_blacklist = MapConstellationType(sv_info.constellation);
+ break;
+ }
+ }
+ if (constellation_to_blacklist != GnssConstellationType_1_0::UNKNOWN) {
+ break;
+ }
+ }
+
+ if (constellation_to_blacklist == GnssConstellationType_1_0::UNKNOWN) {
+ ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
+ // Proceed functionally to blacklist something.
+ constellation_to_blacklist = GnssConstellationType_1_0::GLONASS;
+ }
+ IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist;
+ source_to_blacklist.constellation = constellation_to_blacklist;
+ source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation
+
+ auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
+ ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+ sp<IGnssConfiguration_1_1> gnss_configuration_hal = gnss_configuration_hal_return;
+ ASSERT_NE(gnss_configuration_hal, nullptr);
+
+ hidl_vec<IGnssConfiguration_1_1::BlacklistedSource> sources;
+ sources.resize(1);
+ sources[0] = source_to_blacklist;
+
+ auto result = gnss_configuration_hal->setBlacklist(sources);
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ // retry and ensure constellation not used
+ gnss_cb_->sv_info_list_cbq_.reset();
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_info_list_cbq_size,
+ kLocationsToAwait);
+ for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+ hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
+ for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+ auto constellation = MapConstellationType(sv_info.constellation);
+ EXPECT_FALSE((constellation == source_to_blacklist.constellation) &&
+ (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
+ }
+ }
+
+ // clean up
+ StopAndClearLocations();
+ sources.resize(0);
+ result = gnss_configuration_hal->setBlacklist(sources);
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+}
\ No newline at end of file
diff --git a/gnss/common/utils/vts/include/GnssCallbackEventQueue.h b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h
new file mode 100644
index 0000000..b1d8ed4
--- /dev/null
+++ b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h
@@ -0,0 +1,140 @@
+/*
+ * 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_gnss_common_vts_GnssCallbackEventQueue_H_
+#define android_hardware_gnss_common_vts_GnssCallbackEventQueue_H_
+
+#include <log/log.h>
+
+#include <condition_variable>
+#include <deque>
+#include <list>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+/*
+ * Producer/consumer queue for storing/retrieving callback events from GNSS HAL.
+ */
+template <class T>
+class GnssCallbackEventQueue {
+ public:
+ GnssCallbackEventQueue(const std::string& name) : name_(name), called_count_(0){};
+ ~GnssCallbackEventQueue() { reset(); }
+
+ /* Adds callback event to the end of the queue. */
+ void store(const T& event);
+
+ /*
+ * Removes the callack event at the front of the queue, stores it in event parameter
+ * and returns true. Returns false on timeout and event is not populated.
+ */
+ bool retrieve(T& event, int timeout_seconds);
+
+ /*
+ * Removes parameter count number of callack events at the front of the queue, stores
+ * them in event_list parameter and returns the number of events retrieved. Waits up to
+ * timeout_seconds to retrieve each event. If timeout occurs, it returns the number of
+ * items retrieved which will be less than count.
+ */
+ int retrieve(list<T>& event_list, int count, int timeout_seconds);
+
+ /* Returns the number of events pending to be retrieved from the callback event queue. */
+ int size() const;
+
+ /* Returns the number of callback events received since last reset(). */
+ int calledCount() const;
+
+ /* Clears the callback event queue and resets the calledCount() to 0. */
+ void reset();
+
+ private:
+ GnssCallbackEventQueue(const GnssCallbackEventQueue&) = delete;
+ GnssCallbackEventQueue& operator=(const GnssCallbackEventQueue&) = delete;
+
+ std::string name_;
+ int called_count_;
+ mutable std::recursive_mutex mtx_;
+ std::condition_variable_any cv_;
+ std::deque<T> events_;
+};
+
+template <class T>
+void GnssCallbackEventQueue<T>::store(const T& event) {
+ std::unique_lock<std::recursive_mutex> lock(mtx_);
+ events_.push_back(event);
+ ++called_count_;
+ lock.unlock();
+ cv_.notify_all();
+}
+
+template <class T>
+bool GnssCallbackEventQueue<T>::retrieve(T& event, int timeout_seconds) {
+ std::unique_lock<std::recursive_mutex> lock(mtx_);
+ cv_.wait_for(lock, std::chrono::seconds(timeout_seconds), [&] { return !events_.empty(); });
+ if (events_.empty()) {
+ return false;
+ }
+ event = events_.front();
+ events_.pop_front();
+ return true;
+}
+
+template <class T>
+int GnssCallbackEventQueue<T>::retrieve(list<T>& event_list, int count, int timeout_seconds) {
+ for (int i = 0; i < count; ++i) {
+ T event;
+ if (!retrieve(event, timeout_seconds)) {
+ return i;
+ }
+ event_list.push_back(event);
+ }
+
+ return count;
+}
+
+template <class T>
+int GnssCallbackEventQueue<T>::size() const {
+ std::unique_lock<std::recursive_mutex> lock(mtx_);
+ return events_.size();
+}
+
+template <class T>
+int GnssCallbackEventQueue<T>::calledCount() const {
+ std::unique_lock<std::recursive_mutex> lock(mtx_);
+ return called_count_;
+}
+
+template <class T>
+void GnssCallbackEventQueue<T>::reset() {
+ std::unique_lock<std::recursive_mutex> lock(mtx_);
+ if (!events_.empty()) {
+ ALOGW("%u unprocessed events discarded in callback queue %s", (unsigned int)events_.size(),
+ name_.c_str());
+ }
+ events_.clear();
+ called_count_ = 0;
+}
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_common_vts_GnssCallbackEventQueue_H_
diff --git a/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc
index a2a881a..038e87c 100644
--- a/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc
+++ b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc
@@ -1,4 +1,5 @@
service vendor.gralloc-2-0 /vendor/bin/hw/android.hardware.graphics.allocator@2.0-service
+ interface android.hardware.graphics.allocator@2.0::IAllocator default
class hal animation
interface android.hardware.graphics.allocator@2.0::IAllocator default
user system
diff --git a/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc b/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
index 5a5b51e..cbd589a 100644
--- a/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
+++ b/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
@@ -1,4 +1,5 @@
service vendor.hwcomposer-2-1 /vendor/bin/hw/android.hardware.graphics.composer@2.1-service
+ interface android.hardware.graphics.composer@2.1::IComposer default
class hal animation
user system
group graphics drmrpc
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index fcb327f..88b1a8b 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -28,9 +28,18 @@
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@3.0-vts",
],
+ 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",
+ ],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
cflags: [
"-O0",
"-g",
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 30b9694..fa5ace6 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -790,7 +790,7 @@
TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) {
mWriter->selectDisplay(mPrimaryDisplay);
mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON);
- mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB);
+ mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE);
auto handle = allocate();
ASSERT_NE(nullptr, handle);
diff --git a/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
index efe6dad..0d7e86f 100644
--- a/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
+++ b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
@@ -1,4 +1,6 @@
service vendor.hwcomposer-2-2 /vendor/bin/hw/android.hardware.graphics.composer@2.2-service
+ interface android.hardware.graphics.composer@2.1::IComposer default
+ interface android.hardware.graphics.composer@2.2::IComposer default
class hal animation
user system
group graphics drmrpc
diff --git a/graphics/composer/2.2/utils/OWNERS b/graphics/composer/2.2/utils/OWNERS
index a17a50c..3f1e82c 100644
--- a/graphics/composer/2.2/utils/OWNERS
+++ b/graphics/composer/2.2/utils/OWNERS
@@ -3,7 +3,3 @@
lpy@google.com
stoza@google.com
vhau@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
diff --git a/graphics/composer/2.2/utils/command-buffer/Android.bp b/graphics/composer/2.2/utils/command-buffer/Android.bp
index efaabd4..c4ceaab 100644
--- a/graphics/composer/2.2/utils/command-buffer/Android.bp
+++ b/graphics/composer/2.2/utils/command-buffer/Android.bp
@@ -3,11 +3,16 @@
defaults: ["hidl_defaults"],
vendor_available: true,
shared_libs: [
- "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ ],
+ export_shared_lib_headers: [
"android.hardware.graphics.composer@2.2",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
export_include_dirs: ["include"],
}
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index 56b12f5..1754a43 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -20,26 +20,31 @@
srcs: [
"ComposerVts.cpp",
"ReadbackVts.cpp",
+ "RenderEngineVts.cpp",
+ ],
+ shared_libs: [
+ "libui",
],
static_libs: [
"VtsHalHidlTargetTestBase",
- "android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
- "android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@2.1-vts",
- "android.hardware.graphics.mapper@3.0",
- "android.hardware.graphics.mapper@3.0-vts",
+ "libarect",
+ "libmath",
+ "libnativewindow",
+ "librenderengine",
],
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",
],
header_libs: [
- "android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
],
export_header_lib_headers: [
- "android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
],
cflags: [
diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
index 81a6452..d479aa7 100644
--- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
@@ -34,6 +34,65 @@
writer->setLayerBlendMode(mBlendMode);
}
+const std::vector<ColorMode> ReadbackHelper::colorModes = {ColorMode::SRGB, ColorMode::DISPLAY_P3};
+const std::vector<Dataspace> ReadbackHelper::dataspaces = {Dataspace::V0_SRGB,
+ Dataspace::DISPLAY_P3};
+
+std::string ReadbackHelper::getColorModeString(ColorMode mode) {
+ switch (mode) {
+ case ColorMode::SRGB:
+ return std::string("SRGB");
+ case ColorMode::DISPLAY_P3:
+ return std::string("DISPLAY_P3");
+ default:
+ return std::string("Unsupported color mode for readback");
+ }
+}
+
+std::string ReadbackHelper::getDataspaceString(Dataspace dataspace) {
+ switch (dataspace) {
+ case Dataspace::V0_SRGB:
+ return std::string("V0_SRGB");
+ case Dataspace::DISPLAY_P3:
+ return std::string("DISPLAY_P3");
+ case Dataspace::UNKNOWN:
+ return std::string("UNKNOWN");
+ default:
+ return std::string("Unsupported dataspace for readback");
+ }
+}
+
+Dataspace ReadbackHelper::getDataspaceForColorMode(ColorMode mode) {
+ switch (mode) {
+ case ColorMode::DISPLAY_P3:
+ return Dataspace::DISPLAY_P3;
+ case ColorMode::SRGB:
+ default:
+ return Dataspace::UNKNOWN;
+ }
+}
+
+LayerSettings TestLayer::toRenderEngineLayerSettings() {
+ LayerSettings layerSettings;
+
+ layerSettings.alpha = half(mAlpha);
+ layerSettings.disableBlending = mBlendMode == IComposerClient::BlendMode::NONE;
+ layerSettings.geometry.boundaries = FloatRect(
+ static_cast<float>(mDisplayFrame.left), static_cast<float>(mDisplayFrame.top),
+ static_cast<float>(mDisplayFrame.right), static_cast<float>(mDisplayFrame.bottom));
+
+ const mat4 translation = mat4::translate(vec4(
+ (mTransform & Transform::FLIP_H ? -1.0f : 0.0f) * mDisplayFrame.right,
+ (mTransform & Transform::FLIP_V ? -1.0f : 0.0f) * mDisplayFrame.bottom, 0.0f, 1.0f));
+
+ const mat4 scale = mat4::scale(vec4(mTransform & Transform::FLIP_H ? -1.0f : 1.0f,
+ mTransform & Transform::FLIP_V ? -1.0f : 1.0f, 1.0f, 1.0f));
+
+ layerSettings.geometry.positionTransform = translation * scale;
+
+ return layerSettings;
+}
+
int32_t ReadbackHelper::GetBytesPerPixel(PixelFormat pixelFormat) {
switch (pixelFormat) {
case PixelFormat::RGBA_8888:
@@ -99,12 +158,31 @@
if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
return false;
}
- if (dataspace != Dataspace::V0_SRGB) {
+ if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
return false;
}
return true;
}
+void ReadbackHelper::compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
+ void* bufferData, const uint32_t stride,
+ const uint32_t width, const uint32_t height,
+ const PixelFormat pixelFormat) {
+ const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
+ ASSERT_NE(-1, bytesPerPixel);
+ for (int row = 0; row < height; row++) {
+ for (int col = 0; col < width; col++) {
+ int pixel = row * width + col;
+ int offset = (row * stride + col) * bytesPerPixel;
+ uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+
+ ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
+ ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
+ ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
+ }
+ }
+}
+
ReadbackBuffer::ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
const std::shared_ptr<Gralloc>& gralloc, uint32_t width,
uint32_t height, PixelFormat pixelFormat, Dataspace dataspace) {
@@ -153,19 +231,8 @@
void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, fenceHandle);
ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
- int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(mPixelFormat);
- ASSERT_NE(-1, bytesPerPixel);
- for (int row = 0; row < mHeight; row++) {
- for (int col = 0; col < mWidth; col++) {
- int pixel = row * mWidth + col;
- int offset = (row * mStride + col) * bytesPerPixel;
- uint8_t* pixelColor = (uint8_t*)bufData + offset;
-
- ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
- ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
- ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
- }
- }
+ ReadbackHelper::compareColorBuffers(expectedColors, bufData, mStride, mWidth, mHeight,
+ mPixelFormat);
int32_t unlockFence = mGralloc->unlock(mBufferHandle);
if (unlockFence != -1) {
sync_wait(unlockFence, -1);
@@ -179,6 +246,16 @@
writer->setLayerColor(mColor);
}
+LayerSettings TestColorLayer::toRenderEngineLayerSettings() {
+ LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
+
+ layerSettings.source.solidColor =
+ half3(static_cast<half>(mColor.r) / 255.0, static_cast<half>(mColor.g) / 255.0,
+ static_cast<half>(mColor.b) / 255.0);
+ layerSettings.alpha = mAlpha * (static_cast<half>(mColor.a) / 255.0);
+ return layerSettings;
+}
+
TestBufferLayer::TestBufferLayer(const std::shared_ptr<ComposerClient>& client,
const std::shared_ptr<Gralloc>& gralloc, Display display,
int32_t width, int32_t height, PixelFormat format,
@@ -210,11 +287,31 @@
void TestBufferLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
TestLayer::write(writer);
writer->setLayerCompositionType(mComposition);
- writer->setLayerDataspace(Dataspace::UNKNOWN);
writer->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, mDisplayFrame));
if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence);
}
+LayerSettings TestBufferLayer::toRenderEngineLayerSettings() {
+ LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
+ layerSettings.source.buffer.buffer =
+ new GraphicBuffer(mBufferHandle, GraphicBuffer::CLONE_HANDLE, mWidth, mHeight,
+ static_cast<int32_t>(mFormat), 1, mUsage, mStride);
+ // TODO(b/136483187): Why does this break the premultiply test
+ // layerSettings.source.buffer.usePremultipliedAlpha =
+ // mBlendMode == IComposerClient::BlendMode::PREMULTIPLIED;
+
+ const float scaleX = (mSourceCrop.right - mSourceCrop.left) / (mWidth);
+ const float scaleY = (mSourceCrop.bottom - mSourceCrop.top) / (mHeight);
+ const float translateX = mSourceCrop.left / (mWidth);
+ const float translateY = mSourceCrop.top / (mHeight);
+
+ layerSettings.source.buffer.textureTransform =
+ mat4::translate(vec4(translateX, translateY, 0, 1)) *
+ mat4::scale(vec4(scaleX, scaleY, 1.0, 1.0));
+
+ return layerSettings;
+}
+
void TestBufferLayer::fillBuffer(std::vector<IComposerClient::Color> expectedColors) {
void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, -1);
ASSERT_NO_FATAL_FAILURE(
@@ -225,6 +322,7 @@
close(mFillFence);
}
}
+
void TestBufferLayer::setBuffer(std::vector<IComposerClient::Color> colors) {
if (mBufferHandle != nullptr) {
mGralloc->freeBuffer(mBufferHandle);
@@ -238,6 +336,12 @@
mFormat, mUsage, mStride));
}
+void TestBufferLayer::setDataspace(Dataspace dataspace,
+ const std::shared_ptr<CommandWriterBase>& writer) {
+ writer->selectLayer(mLayer);
+ writer->setLayerDataspace(dataspace);
+}
+
void TestBufferLayer::setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer) {
writer->selectLayer(mLayer);
writer->setLayerCompositionType(IComposerClient::Composition::CLIENT);
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
new file mode 100644
index 0000000..d910169
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 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 <composer-vts/2.2/RenderEngineVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+
+using mapper::V2_1::IMapper;
+using renderengine::DisplaySettings;
+using renderengine::LayerSettings;
+
+TestRenderEngine::TestRenderEngine(common::V1_1::PixelFormat hwcFormat,
+ uint32_t renderEngineFeatures) {
+ mFormat = hwcFormat;
+ mRenderEngine = renderengine::RenderEngine::create(
+ static_cast<int32_t>(mFormat), renderEngineFeatures, mMaxFrameBufferAcquireBuffers);
+}
+
+void TestRenderEngine::setRenderLayers(std::vector<std::shared_ptr<TestLayer>> layers) {
+ sort(layers.begin(), layers.end(),
+ [](const std::shared_ptr<TestLayer>& lhs, const std::shared_ptr<TestLayer>& rhs) -> bool {
+ return lhs->mZOrder < rhs->mZOrder;
+ });
+
+ if (!mCompositionLayers.empty()) {
+ mCompositionLayers.clear();
+ }
+ for (auto& layer : layers) {
+ LayerSettings settings = layer->toRenderEngineLayerSettings();
+ mCompositionLayers.push_back(settings);
+ }
+}
+
+void TestRenderEngine::initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
+ uint64_t usage) {
+ mGraphicBuffer =
+ new GraphicBuffer(width, height, static_cast<int32_t>(mFormat), layerCount, usage);
+}
+
+void TestRenderEngine::drawLayers() {
+ base::unique_fd bufferFence;
+ base::unique_fd readyFence;
+ mRenderEngine->drawLayers(mDisplaySettings, mCompositionLayers,
+ mGraphicBuffer->getNativeBuffer(), true, std::move(bufferFence),
+ &readyFence);
+ int fd = readyFence.release();
+ if (fd != -1) {
+ ASSERT_EQ(0, sync_wait(fd, -1));
+ ASSERT_EQ(0, close(fd));
+ }
+}
+
+void TestRenderEngine::checkColorBuffer(std::vector<V2_2::IComposerClient::Color>& expectedColors) {
+ void* bufferData;
+ ASSERT_EQ(0, mGraphicBuffer->lock(mGraphicBuffer->getUsage(), &bufferData));
+ ReadbackHelper::compareColorBuffers(expectedColors, bufferData, mGraphicBuffer->getStride(),
+ mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
+ mFormat);
+ ASSERT_EQ(0, mGraphicBuffer->unlock());
+}
+
+} // namespace vts
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
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 7e93167..7519a64 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
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#pragma once
+
#include <android-base/unique_fd.h>
#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
@@ -21,6 +23,7 @@
#include <composer-vts/2.1/TestCommandReader.h>
#include <composer-vts/2.2/ComposerVts.h>
#include <mapper-vts/2.1/MapperVts.h>
+#include <renderengine/RenderEngine.h>
namespace android {
namespace hardware {
@@ -35,6 +38,7 @@
using common::V1_1::PixelFormat;
using IMapper2_1 = mapper::V2_1::IMapper;
using Gralloc2_1 = mapper::V2_1::vts::Gralloc;
+using renderengine::LayerSettings;
using V2_1::Display;
using V2_1::Layer;
using V2_1::vts::AccessRegion;
@@ -56,6 +60,7 @@
virtual ~TestLayer(){};
virtual void write(const std::shared_ptr<CommandWriterBase>& writer);
+ virtual LayerSettings toRenderEngineLayerSettings();
void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; }
void setSourceCrop(IComposerClient::FRect crop) { mSourceCrop = crop; }
@@ -93,6 +98,8 @@
void write(const std::shared_ptr<CommandWriterBase>& writer) override;
+ LayerSettings toRenderEngineLayerSettings() override;
+
void setColor(IComposerClient::Color color) { mColor = color; }
private:
@@ -110,10 +117,14 @@
void write(const std::shared_ptr<CommandWriterBase>& writer) override;
+ LayerSettings toRenderEngineLayerSettings() override;
+
void fillBuffer(std::vector<IComposerClient::Color> expectedColors);
void setBuffer(std::vector<IComposerClient::Color> colors);
+ void setDataspace(Dataspace dataspace, const std::shared_ptr<CommandWriterBase>& writer);
+
void setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer);
uint32_t mWidth;
@@ -133,6 +144,12 @@
class ReadbackHelper : public ::testing::VtsHalHidlTargetTestBase {
public:
+ static std::string getColorModeString(ColorMode mode);
+
+ static std::string getDataspaceString(Dataspace dataspace);
+
+ static Dataspace getDataspaceForColorMode(ColorMode mode);
+
static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
@@ -147,6 +164,13 @@
static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
const Error error);
+
+ static const std::vector<ColorMode> colorModes;
+ static const std::vector<Dataspace> dataspaces;
+
+ static void compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
+ void* bufferData, const uint32_t stride, const uint32_t width,
+ const uint32_t height, const PixelFormat pixelFormat);
};
class ReadbackBuffer {
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
new file mode 100644
index 0000000..0ac5a22
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 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 <composer-vts/2.2/ReadbackVts.h>
+#include <math/half.h>
+#include <math/vec3.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+
+using mapper::V2_1::IMapper;
+using renderengine::DisplaySettings;
+using vts::Gralloc;
+
+class TestRenderEngine {
+ public:
+ TestRenderEngine(common::V1_1::PixelFormat hwcFormat, uint32_t renderEngineFeatures);
+ ~TestRenderEngine() = default;
+
+ void setRenderLayers(std::vector<std::shared_ptr<TestLayer>> layers);
+ void initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint64_t usage);
+ void setDisplaySettings(DisplaySettings& displaySettings) {
+ mDisplaySettings = displaySettings;
+ };
+ void drawLayers();
+ void checkColorBuffer(std::vector<V2_2::IComposerClient::Color>& expectedColors);
+
+ private:
+ static constexpr uint32_t mMaxFrameBufferAcquireBuffers = 2;
+ common::V1_1::PixelFormat mFormat;
+ std::vector<renderengine::LayerSettings> mCompositionLayers;
+ std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
+ std::vector<renderengine::LayerSettings> mRenderLayers;
+ sp<GraphicBuffer> mGraphicBuffer;
+ DisplaySettings mDisplaySettings;
+};
+
+} // namespace vts
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index 9f7e1cd..cc24774 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -20,6 +20,7 @@
srcs: [
"VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
"VtsHalGraphicsComposerV2_2TargetTest.cpp",
+ "VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp",
],
// TODO(b/64437680): Assume these libs are always available on the device.
@@ -27,9 +28,19 @@
"libfmq",
"libhidlbase",
"libhidltransport",
+ "libhwbinder",
"libsync",
+ "libui",
+ "libgui",
+ "libEGL",
+ "libGLESv1_CM",
+ "libGLESv2",
],
static_libs: [
+ "librenderengine",
+ "libmath",
+ "libarect",
+ "libnativewindow",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.1",
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp
new file mode 100644
index 0000000..d694a5b
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2CompositionComparisonTest.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright 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 "graphics_composer_hidl_hal_readback_tests@2.2"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.2/ComposerVts.h>
+#include <composer-vts/2.2/ReadbackVts.h>
+#include <composer-vts/2.2/RenderEngineVts.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+namespace {
+
+using android::GraphicBuffer;
+using android::Rect;
+using android::hardware::hidl_handle;
+using common::V1_1::BufferUsage;
+using common::V1_1::Dataspace;
+using common::V1_1::PixelFormat;
+using mapper::V2_1::IMapper;
+using V2_1::Config;
+using V2_1::Display;
+using V2_1::vts::TestCommandReader;
+using vts::Gralloc;
+
+// Test environment for graphics.composer
+class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static GraphicsComposerHidlEnvironment* Instance() {
+ static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
+ return instance;
+ }
+ virtual void registerTestServices() override { registerTestService<IComposer>(); }
+
+ private:
+ GraphicsComposerHidlEnvironment() {}
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
+};
+
+class GraphicsCompositionComparisonTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ using PowerMode = V2_1::IComposerClient::PowerMode;
+ void SetUp() override {
+ VtsHalHidlTargetTestBase::SetUp();
+ ASSERT_NO_FATAL_FAILURE(
+ mComposer = std::make_unique<Composer>(
+ GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+ ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
+ mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
+ mComposerClient->registerCallback(mComposerCallback);
+
+ // assume the first display is primary and is never removed
+ mPrimaryDisplay = waitForFirstDisplay();
+ Config activeConfig;
+ ASSERT_NO_FATAL_FAILURE(activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay));
+ ASSERT_NO_FATAL_FAILURE(
+ mDisplayWidth = mComposerClient->getDisplayAttribute(
+ mPrimaryDisplay, activeConfig, IComposerClient::Attribute::WIDTH));
+ ASSERT_NO_FATAL_FAILURE(
+ mDisplayHeight = mComposerClient->getDisplayAttribute(
+ mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT));
+
+ setTestColorModes();
+
+ // explicitly disable vsync
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false));
+ mComposerCallback->setVsyncAllowed(false);
+
+ // set up command writer/reader and gralloc
+ mWriter = std::make_shared<CommandWriterBase>(1024);
+ mReader = std::make_unique<TestCommandReader>();
+ mGralloc = std::make_shared<Gralloc>();
+
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON));
+
+ ASSERT_NO_FATAL_FAILURE(
+ mTestRenderEngine = std::unique_ptr<TestRenderEngine>(new TestRenderEngine(
+ PixelFormat::RGBA_8888,
+ renderengine::RenderEngine::USE_COLOR_MANAGEMENT |
+ renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT)));
+
+ renderengine::DisplaySettings clientCompositionDisplay;
+ clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight);
+ clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay;
+ clientCompositionDisplay.clearRegion = Region(clientCompositionDisplay.physicalDisplay);
+
+ mTestRenderEngine->initGraphicBuffer(
+ static_cast<uint32_t>(mDisplayWidth), static_cast<uint32_t>(mDisplayHeight), 1,
+ static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN));
+ mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
+ }
+
+ void TearDown() override {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF));
+ EXPECT_EQ(0, mReader->mErrors.size());
+ EXPECT_EQ(0, mReader->mCompositionChanges.size());
+ if (mComposerCallback != nullptr) {
+ EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+ }
+ VtsHalHidlTargetTestBase::TearDown();
+ }
+
+ void clearCommandReaderState() {
+ mReader->mCompositionChanges.clear();
+ mReader->mErrors.clear();
+ }
+
+ void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) {
+ for (auto layer : layers) {
+ layer->write(mWriter);
+ }
+ execute();
+ }
+
+ void execute() {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get()));
+ }
+
+ std::unique_ptr<Composer> mComposer;
+ std::shared_ptr<ComposerClient> mComposerClient;
+
+ sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
+ // the first display and is assumed never to be removed
+ Display mPrimaryDisplay;
+ int32_t mDisplayWidth;
+ int32_t mDisplayHeight;
+ std::vector<ColorMode> mTestColorModes;
+ std::shared_ptr<CommandWriterBase> mWriter;
+ std::unique_ptr<TestCommandReader> mReader;
+ std::shared_ptr<Gralloc> mGralloc;
+ std::unique_ptr<TestRenderEngine> mTestRenderEngine;
+
+ bool mHasReadbackBuffer;
+ PixelFormat mPixelFormat;
+ Dataspace mDataspace;
+
+ private:
+ Display waitForFirstDisplay() {
+ while (true) {
+ std::vector<Display> displays = mComposerCallback->getDisplays();
+ if (displays.empty()) {
+ usleep(5 * 1000);
+ continue;
+ }
+ return displays[0];
+ }
+ }
+
+ void setTestColorModes() {
+ mTestColorModes.clear();
+ mComposerClient->getRaw()->getColorModes_2_2(mPrimaryDisplay, [&](const auto& tmpError,
+ const auto& tmpModes) {
+ ASSERT_EQ(Error::NONE, tmpError);
+ for (ColorMode mode : tmpModes) {
+ if (std::find(ReadbackHelper::colorModes.begin(), ReadbackHelper::colorModes.end(),
+ mode) != ReadbackHelper::colorModes.end()) {
+ mTestColorModes.push_back(mode);
+ }
+ }
+ });
+ }
+};
+
+TEST_F(GraphicsCompositionComparisonTest, SingleSolidColorLayer) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setColor(BLUE);
+ layer->setDisplayFrame(coloredSquare);
+ layer->setZOrder(10);
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ // expected color for each pixel
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ // if hwc cannot handle and asks for composition change,
+ // just succeed the test
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ mTestRenderEngine->setRenderLayers(layers);
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+ }
+}
+
+} // namespace
+} // namespace vts
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index 6ae8446..92c03f0 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 The Android Open Source Project
+ * Copyright 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.
@@ -78,6 +78,8 @@
mDisplayHeight = mComposerClient->getDisplayAttribute(
mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT));
+ setTestColorModes();
+
// explicitly disable vsync
ASSERT_NO_FATAL_FAILURE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false));
mComposerCallback->setVsyncAllowed(false);
@@ -87,17 +89,6 @@
mReader = std::make_unique<TestCommandReader>();
mGralloc = std::make_shared<Gralloc>();
- ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB,
- RenderIntent::COLORIMETRIC));
-
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON));
}
@@ -137,6 +128,7 @@
Display mPrimaryDisplay;
int32_t mDisplayWidth;
int32_t mDisplayHeight;
+ std::vector<ColorMode> mTestColorModes;
std::shared_ptr<CommandWriterBase> mWriter;
std::unique_ptr<TestCommandReader> mReader;
std::shared_ptr<Gralloc> mGralloc;
@@ -158,537 +150,748 @@
return displays[0];
}
}
+
+ void setTestColorModes() {
+ mTestColorModes.clear();
+ mComposerClient->getRaw()->getColorModes_2_2(mPrimaryDisplay, [&](const auto& tmpError,
+ const auto& tmpModes) {
+ ASSERT_EQ(Error::NONE, tmpError);
+ for (ColorMode mode : tmpModes) {
+ if (std::find(ReadbackHelper::colorModes.begin(), ReadbackHelper::colorModes.end(),
+ mode) != ReadbackHelper::colorModes.end()) {
+ mTestColorModes.push_back(mode);
+ }
+ }
+ });
+ }
};
TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setColor(BLUE);
+ layer->setDisplayFrame(coloredSquare);
+ layer->setZOrder(10);
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ // expected color for each pixel
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ // if hwc cannot handle and asks for composition change,
+ // just succeed the test
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
- mWriter->selectDisplay(mPrimaryDisplay);
-
- auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
- IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setColor(BLUE);
- layer->setDisplayFrame(coloredSquare);
- layer->setZOrder(10);
-
- std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
- // expected color for each pixel
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- // if hwc cannot handle and asks for composition change,
- // just succeed the test
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
TEST_F(GraphicsComposerReadbackTest, SetLayerBuffer) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2},
+ GREEN);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
+ BLUE);
+
+ auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+ mDisplayWidth, mDisplayHeight,
+ PixelFormat::RGBA_8888);
+ layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setZOrder(10);
+ layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ mWriter->presentDisplay();
+ execute();
+
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-
- mWriter->selectDisplay(mPrimaryDisplay);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2},
- GREEN);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
-
- auto layer =
- std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
- mDisplayHeight, PixelFormat::RGBA_8888);
- layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setZOrder(10);
- ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
-
- std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
-
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
-
- mWriter->presentDisplay();
- execute();
-
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
TEST_F(GraphicsComposerReadbackTest, SetLayerBufferNoEffect) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setColor(BLUE);
+ layer->setDisplayFrame(coloredSquare);
+ layer->setZOrder(10);
+ layer->write(mWriter);
+
+ // This following buffer call should have no effect
+ uint64_t usage =
+ static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
+ const native_handle_t* bufferHandle =
+ mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage);
+ mWriter->setLayerBuffer(0, bufferHandle, -1);
+
+ // expected color for each pixel
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ mWriter->validateDisplay();
+ execute();
+
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-
- mWriter->selectDisplay(mPrimaryDisplay);
-
- auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
- IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setColor(BLUE);
- layer->setDisplayFrame(coloredSquare);
- layer->setZOrder(10);
- layer->write(mWriter);
-
- // This following buffer call should have no effect
- PixelFormat format = PixelFormat::RGBA_8888;
- uint64_t usage =
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
- const native_handle_t* bufferHandle =
- mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, format, usage);
- mWriter->setLayerBuffer(0, bufferHandle, -1);
-
- // expected color for each pixel
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- mWriter->validateDisplay();
- execute();
-
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
TEST_F(GraphicsComposerReadbackTest, ClientComposition) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
- }
-
- mWriter->selectDisplay(mPrimaryDisplay);
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2},
- GREEN);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
-
- auto layer =
- std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
- mDisplayHeight, PixelFormat::RGBA_FP16);
- layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setZOrder(10);
-
- std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
-
- if (mReader->mCompositionChanges.size() != 0) {
- ASSERT_EQ(1, mReader->mCompositionChanges.size());
- ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
-
- ASSERT_NO_FATAL_FAILURE(
+ ASSERT_NO_FATAL_FAILURE(
mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
- // create client target buffer
- uint32_t clientStride;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2},
+ GREEN);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
+ BLUE);
+
+ auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+ mDisplayWidth, mDisplayHeight,
+ PixelFormat::RGBA_FP16);
+ layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setZOrder(10);
+ layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+
+ if (mReader->mCompositionChanges.size() != 0) {
+ ASSERT_EQ(1, mReader->mCompositionChanges.size());
+ ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
+
+ PixelFormat clientFormat = PixelFormat::RGBA_8888;
+ uint64_t clientUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN |
+ BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_CLIENT_TARGET);
+ Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
+ IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
+
+ bool clientTargetSupported = mComposerClient->getClientTargetSupport_2_2(
+ mPrimaryDisplay, layer->mWidth, layer->mHeight, clientFormat, clientDataspace);
+ // if the client target format is not supported, skip this
+ // configuration
+ if (!clientTargetSupported) {
+ std::cout << "Client target configuration width: " << layer->mWidth
+ << " height: " << layer->mHeight
+ << " pixel format: PixelFormat::RGBA_8888 dataspace: "
+ << ReadbackHelper::getDataspaceString(clientDataspace)
+ << " unsupported for display" << std::endl;
+ continue;
+ }
+
+ // create client target buffer
+ uint32_t clientStride;
+ const native_handle_t* clientBufferHandle =
+ mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount,
+ clientFormat, clientUsage, /*import*/ true, &clientStride);
+ ASSERT_NE(nullptr, clientBufferHandle);
+
+ void* clientBufData =
+ mGralloc->lock(clientBufferHandle, clientUsage, layer->mAccessRegion, -1);
+
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(layer->mWidth, layer->mHeight,
+ clientStride, clientBufData,
+ clientFormat, expectedColors));
+ int clientFence = mGralloc->unlock(clientBufferHandle);
+ if (clientFence != -1) {
+ sync_wait(clientFence, -1);
+ close(clientFence);
+ }
+
+ mWriter->setClientTarget(0, clientBufferHandle, clientFence, clientDataspace,
+ std::vector<IComposerClient::Rect>(1, damage));
+
+ layer->setToClientComposition(mWriter);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mCompositionChanges.size());
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ mWriter->presentDisplay();
+ execute();
+
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ }
+}
+
+TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) {
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
+
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ auto deviceLayer = std::make_shared<TestBufferLayer>(
+ mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2,
+ PixelFormat::RGBA_8888);
+ std::vector<IComposerClient::Color> deviceColors(deviceLayer->mWidth *
+ deviceLayer->mHeight);
+ ReadbackHelper::fillColorsArea(deviceColors, deviceLayer->mWidth,
+ {0, 0, static_cast<int32_t>(deviceLayer->mWidth),
+ static_cast<int32_t>(deviceLayer->mHeight)},
+ GREEN);
+ deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->mWidth),
+ static_cast<int32_t>(deviceLayer->mHeight)});
+ deviceLayer->setZOrder(10);
+ deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
+ deviceLayer->write(mWriter);
+
PixelFormat clientFormat = PixelFormat::RGBA_8888;
uint64_t clientUsage =
static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
BufferUsage::COMPOSER_CLIENT_TARGET);
+ Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
+ int32_t clientWidth = mDisplayWidth;
+ int32_t clientHeight = mDisplayHeight / 2;
+
+ bool clientTargetSupported = mComposerClient->getClientTargetSupport_2_2(
+ mPrimaryDisplay, clientWidth, clientHeight, clientFormat, clientDataspace);
+ // if the client target format is not supported, skip this
+ // configuration
+ if (!clientTargetSupported) {
+ std::cout << "Client target configuration width: " << clientWidth
+ << " height: " << clientHeight
+ << " pixel format: PixelFormat::RGBA_8888 dataspace: "
+ << ReadbackHelper::getDataspaceString(clientDataspace)
+ << " unsupported for display" << std::endl;
+ continue;
+ }
+
+ auto clientLayer = std::make_shared<TestBufferLayer>(
+ mComposerClient, mGralloc, mPrimaryDisplay, clientWidth, clientHeight,
+ PixelFormat::RGBA_FP16, IComposerClient::Composition::DEVICE);
+ IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
+ clientLayer->setDisplayFrame(clientFrame);
+ clientLayer->setZOrder(0);
+ clientLayer->write(mWriter);
+ mWriter->validateDisplay();
+ execute();
+
+ if (mReader->mCompositionChanges.size() != 1) {
+ std::cout << "HWC asked for none or more than 1 composition change, skipping"
+ << std::endl;
+ mReader->mCompositionChanges.clear();
+ continue;
+ }
+ // create client target buffer
+ ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
+ uint32_t clientStride;
const native_handle_t* clientBufferHandle =
- mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount, clientFormat,
- clientUsage, /*import*/ true, &clientStride);
+ mGralloc->allocate(mDisplayWidth, mDisplayHeight, clientLayer->mLayerCount,
+ clientFormat, clientUsage, /*import*/ true, &clientStride);
ASSERT_NE(nullptr, clientBufferHandle);
- void* clientBufData =
- mGralloc->lock(clientBufferHandle, clientUsage, layer->mAccessRegion, -1);
+ void* clientBufData = mGralloc->lock(clientBufferHandle, clientUsage,
+ {0, 0, mDisplayWidth, mDisplayHeight}, -1);
- ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(layer->mWidth, layer->mHeight,
+ std::vector<IComposerClient::Color> clientColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED);
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mDisplayWidth, mDisplayHeight,
clientStride, clientBufData,
- clientFormat, expectedColors));
+ clientFormat, clientColors));
int clientFence = mGralloc->unlock(clientBufferHandle);
if (clientFence != -1) {
sync_wait(clientFence, -1);
close(clientFence);
}
- IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
- mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN,
- std::vector<IComposerClient::Rect>(1, damage));
-
- layer->setToClientComposition(mWriter);
+ mWriter->setClientTarget(0, clientBufferHandle, clientFence, clientDataspace,
+ std::vector<IComposerClient::Rect>(1, clientFrame));
+ clientLayer->setToClientComposition(mWriter);
mWriter->validateDisplay();
execute();
ASSERT_EQ(0, mReader->mCompositionChanges.size());
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
- ASSERT_EQ(0, mReader->mErrors.size());
-
- mWriter->presentDisplay();
- execute();
-
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-}
-
-TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
- }
-
- mWriter->selectDisplay(mPrimaryDisplay);
- ASSERT_NO_FATAL_FAILURE(
- mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- auto deviceLayer =
- std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
- mDisplayHeight / 2, PixelFormat::RGBA_8888);
- std::vector<IComposerClient::Color> deviceColors(deviceLayer->mWidth * deviceLayer->mHeight);
- ReadbackHelper::fillColorsArea(deviceColors, deviceLayer->mWidth,
- {0, 0, static_cast<int32_t>(deviceLayer->mWidth),
- static_cast<int32_t>(deviceLayer->mHeight)},
- GREEN);
- deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->mWidth),
- static_cast<int32_t>(deviceLayer->mHeight)});
- deviceLayer->setZOrder(10);
- ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
- deviceLayer->write(mWriter);
-
- auto clientLayer = std::make_shared<TestBufferLayer>(
- mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2,
- PixelFormat::RGBA_8888, IComposerClient::Composition::CLIENT);
- IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
- clientLayer->setDisplayFrame(clientFrame);
- clientLayer->setZOrder(0);
- clientLayer->write(mWriter);
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- uint64_t clientUsage =
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_CLIENT_TARGET);
- uint32_t clientStride;
- const native_handle_t* clientBufferHandle =
- mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888,
- clientUsage, /*import*/ true, &clientStride);
- ASSERT_NE(nullptr, clientBufferHandle);
-
- AccessRegion clientAccessRegion;
- clientAccessRegion.left = 0;
- clientAccessRegion.top = 0;
- clientAccessRegion.width = mDisplayWidth;
- clientAccessRegion.height = mDisplayHeight;
- void* clientData = mGralloc->lock(clientBufferHandle, clientUsage, clientAccessRegion, -1);
- std::vector<IComposerClient::Color> clientColors(mDisplayWidth * mDisplayHeight);
- ReadbackHelper::fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED);
- ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mDisplayWidth, mDisplayHeight, clientStride,
- clientData, PixelFormat::RGBA_8888,
- clientColors));
- int clientFence = mGralloc->unlock(clientBufferHandle);
- if (clientFence != -1) {
- sync_wait(clientFence, -1);
- close(clientFence);
- }
-
- mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN,
- std::vector<IComposerClient::Rect>(1, clientFrame));
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
TEST_F(GraphicsComposerReadbackTest, SetLayerDamage) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelformat/dataspace";
- return;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ IComposerClient::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4};
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+ auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+ mDisplayWidth, mDisplayHeight,
+ PixelFormat::RGBA_8888);
+ layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setZOrder(10);
+ layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+
+ // update surface damage and recheck
+ redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2};
+ ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+ ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors));
+ layer->setSurfaceDamage(std::vector<IComposerClient::Rect>(
+ 1, {0, 0, mDisplayWidth / 2, mDisplayWidth / 2}));
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_EQ(0, mReader->mCompositionChanges.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-
- mWriter->selectDisplay(mPrimaryDisplay);
-
- IComposerClient::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4};
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
-
- auto layer =
- std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
- mDisplayHeight, PixelFormat::RGBA_8888);
- layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setZOrder(10);
- ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
-
- std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-
- // update surface damage and recheck
- redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2};
- ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
-
- ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors));
- layer->setSurfaceDamage(
- std::vector<IComposerClient::Rect>(1, {0, 0, mDisplayWidth / 2, mDisplayWidth / 2}));
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_EQ(0, mReader->mCompositionChanges.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
TEST_F(GraphicsComposerReadbackTest, SetLayerPlaneAlpha) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ layer->setColor(RED);
+ layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setZOrder(10);
+ layer->setAlpha(0);
+ layer->setBlendMode(IComposerClient::BlendMode::PREMULTIPLIED);
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-
- mWriter->selectDisplay(mPrimaryDisplay);
-
- auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
- layer->setColor(RED);
- layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setZOrder(10);
- layer->setAlpha(0);
- layer->setBlendMode(IComposerClient::BlendMode::PREMULTIPLIED);
-
- std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
-
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
TEST_F(GraphicsComposerReadbackTest, SetLayerSourceCrop) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
+ BLUE);
+
+ auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+ mDisplayWidth, mDisplayHeight,
+ PixelFormat::RGBA_8888);
+ layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setZOrder(10);
+ layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ layer->setSourceCrop({0, static_cast<float>(mDisplayHeight / 2),
+ static_cast<float>(mDisplayWidth),
+ static_cast<float>(mDisplayHeight)});
+ ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ // update expected colors to match crop
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-
- mWriter->selectDisplay(mPrimaryDisplay);
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
-
- auto layer =
- std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
- mDisplayHeight, PixelFormat::RGBA_8888);
- layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setZOrder(10);
- layer->setSourceCrop({0, static_cast<float>(mDisplayHeight / 2),
- static_cast<float>(mDisplayWidth), static_cast<float>(mDisplayHeight)});
- ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
-
- std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
- // update expected colors to match crop
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
TEST_F(GraphicsComposerReadbackTest, SetLayerZOrder) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ IComposerClient::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2};
+ IComposerClient::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight};
+ auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ redLayer->setColor(RED);
+ redLayer->setDisplayFrame(redRect);
+
+ auto blueLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ blueLayer->setColor(BLUE);
+ blueLayer->setDisplayFrame(blueRect);
+ blueLayer->setZOrder(5);
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, blueLayer};
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+ // red in front of blue
+ redLayer->setZOrder(10);
+
+ // fill blue first so that red will overwrite on overlap
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+
+ redLayer->setZOrder(1);
+ ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mCompositionChanges.size());
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-
- mWriter->selectDisplay(mPrimaryDisplay);
-
- IComposerClient::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2};
- IComposerClient::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight};
- auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
- redLayer->setColor(RED);
- redLayer->setDisplayFrame(redRect);
-
- auto blueLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
- blueLayer->setColor(BLUE);
- blueLayer->setDisplayFrame(blueRect);
- blueLayer->setZOrder(5);
-
- std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, blueLayer};
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
- // red in front of blue
- redLayer->setZOrder(10);
-
- // fill blue first so that red will overwrite on overlap
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-
- redLayer->setZOrder(1);
- ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- ASSERT_EQ(0, mReader->mCompositionChanges.size());
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTest,
@@ -696,6 +899,7 @@
public:
void SetUp() override {
GraphicsComposerReadbackTest::SetUp();
+ mTestColorModes = {ColorMode::SRGB}; // TODO: add more color mode support
mBackgroundColor = BLACK;
mTopLayerColor = RED;
}
@@ -722,6 +926,7 @@
PixelFormat::RGBA_8888);
layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
layer->setZOrder(10);
+ layer->setDataspace(Dataspace::UNKNOWN, mWriter);
ASSERT_NO_FATAL_FAILURE(layer->setBuffer(topLayerPixelColors));
layer->setBlendMode(blendMode);
@@ -772,109 +977,162 @@
};
TEST_P(GraphicsComposerBlendModeReadbackTest, None) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+ setBackgroundColor(BLACK);
+ setTopLayerColor(TRANSLUCENT_RED);
+ setUpLayers(IComposerClient::BlendMode::NONE);
+ setExpectedColors(expectedColors);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ writeLayers(mLayers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-
- mWriter->selectDisplay(mPrimaryDisplay);
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
- setBackgroundColor(BLACK);
- setTopLayerColor(TRANSLUCENT_RED);
- setUpLayers(IComposerClient::BlendMode::NONE);
- setExpectedColors(expectedColors);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- writeLayers(mLayers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
// TODO: bug 116865056: Readback returns (245, 0, 0) for layer plane
// alpha of .2, expected 10.2
TEST_P(GraphicsComposerBlendModeReadbackTest, DISABLED_Coverage) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+ setBackgroundColor(BLACK);
+ setTopLayerColor(TRANSLUCENT_RED);
+
+ setUpLayers(IComposerClient::BlendMode::COVERAGE);
+ setExpectedColors(expectedColors);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ writeLayers(mLayers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-
- mWriter->selectDisplay(mPrimaryDisplay);
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
- setBackgroundColor(BLACK);
- setTopLayerColor(TRANSLUCENT_RED);
-
- setUpLayers(IComposerClient::BlendMode::COVERAGE);
- setExpectedColors(expectedColors);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- writeLayers(mLayers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
TEST_P(GraphicsComposerBlendModeReadbackTest, Premultiplied) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+ setBackgroundColor(BLACK);
+ setTopLayerColor(TRANSLUCENT_RED);
+ setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED);
+ setExpectedColors(expectedColors);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ writeLayers(mLayers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-
- mWriter->selectDisplay(mPrimaryDisplay);
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
- setBackgroundColor(BLACK);
- setTopLayerColor(TRANSLUCENT_RED);
- setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED);
- setExpectedColors(expectedColors);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- writeLayers(mLayers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
INSTANTIATE_TEST_CASE_P(BlendModeTest, GraphicsComposerBlendModeReadbackTest,
@@ -919,102 +1177,160 @@
};
TEST_F(GraphicsComposerTransformReadbackTest, FLIP_H) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
- }
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- mLayer->setTransform(Transform::FLIP_H);
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE);
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- writeLayers(mLayers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ mLayer->setTransform(Transform::FLIP_H);
+ mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE);
+
+ writeLayers(mLayers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ }
}
TEST_F(GraphicsComposerTransformReadbackTest, FLIP_V) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ mLayer->setTransform(Transform::FLIP_V);
+ mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE);
+
+ writeLayers(mLayers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- mLayer->setTransform(Transform::FLIP_V);
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE);
-
- writeLayers(mLayers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
TEST_F(GraphicsComposerTransformReadbackTest, ROT_180) {
- if (!mHasReadbackBuffer) {
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ mLayer->setTransform(Transform::ROT_180);
+ mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength},
+ RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mSideLength / 2, mSideLength / 2}, BLUE);
+
+ writeLayers(mLayers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- mLayer->setTransform(Transform::ROT_180);
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength},
- RED);
- ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
- {0, 0, mSideLength / 2, mSideLength / 2}, BLUE);
-
- writeLayers(mLayers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
} // anonymous namespace
diff --git a/graphics/composer/2.3/utils/OWNERS b/graphics/composer/2.3/utils/OWNERS
index b3ea6be..cc6d937 100644
--- a/graphics/composer/2.3/utils/OWNERS
+++ b/graphics/composer/2.3/utils/OWNERS
@@ -2,7 +2,3 @@
lpy@google.com
stoza@google.com
vhau@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
diff --git a/graphics/composer/2.3/utils/command-buffer/Android.bp b/graphics/composer/2.3/utils/command-buffer/Android.bp
index c48fe7a..36ac297 100644
--- a/graphics/composer/2.3/utils/command-buffer/Android.bp
+++ b/graphics/composer/2.3/utils/command-buffer/Android.bp
@@ -3,12 +3,15 @@
defaults: ["hidl_defaults"],
vendor_available: true,
shared_libs: [
- "android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
+ ],
+ export_shared_lib_headers: [
"android.hardware.graphics.composer@2.3",
],
header_libs: [
- "android.hardware.graphics.composer@2.1-command-buffer",
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ ],
+ export_header_lib_headers: [
"android.hardware.graphics.composer@2.2-command-buffer",
],
export_include_dirs: ["include"],
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
index 036ef69..f65a9c4 100644
--- a/graphics/composer/2.3/utils/vts/Android.bp
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -21,22 +21,17 @@
"ComposerVts.cpp",
],
static_libs: [
- "VtsHalHidlTargetTestBase",
- "android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.composer@2.1-vts",
- "android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.2-vts",
"android.hardware.graphics.composer@2.3",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@2.0-vts",
- "android.hardware.graphics.mapper@2.1",
- "android.hardware.graphics.mapper@2.1-vts",
- "android.hardware.graphics.mapper@3.0",
- "android.hardware.graphics.mapper@3.0-vts",
+ ],
+ export_static_lib_headers: [
+ "android.hardware.graphics.composer@2.2-vts",
+ "android.hardware.graphics.composer@2.3",
],
header_libs: [
- "android.hardware.graphics.composer@2.1-command-buffer",
- "android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ export_header_lib_headers: [
"android.hardware.graphics.composer@2.3-command-buffer",
],
cflags: [
diff --git a/graphics/composer/2.4/Android.bp b/graphics/composer/2.4/Android.bp
new file mode 100644
index 0000000..0e1bc09
--- /dev/null
+++ b/graphics/composer/2.4/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.graphics.composer@2.4",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "IComposer.hal",
+ "IComposerClient.hal",
+ ],
+ interfaces: [
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/graphics/composer/2.4/IComposer.hal b/graphics/composer/2.4/IComposer.hal
new file mode 100644
index 0000000..34801da
--- /dev/null
+++ b/graphics/composer/2.4/IComposer.hal
@@ -0,0 +1,34 @@
+/*
+ * Copyright 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.graphics.composer@2.4;
+
+import IComposerClient;
+
+import @2.1::Error;
+import @2.3::IComposer;
+
+interface IComposer extends @2.3::IComposer {
+
+ /**
+ * Creates a v2.4 client of the composer. Supersedes @2.3::createClient.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * NO_RESOURCES when the client could not be created.
+ * @return client is the newly created client.
+ */
+ createClient_2_4() generates (Error error, IComposerClient client);
+};
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
new file mode 100644
index 0000000..8fe0976
--- /dev/null
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -0,0 +1,51 @@
+/*
+ * Copyright 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.graphics.composer@2.4;
+
+import @2.1::Display;
+import @2.1::Error;
+import @2.3::IComposerClient;
+
+interface IComposerClient extends @2.3::IComposerClient {
+
+ /**
+ * Required capabilities which are supported by the display. The
+ * particular set of supported capabilities for a given display may be
+ * retrieved using getDisplayCapabilities.
+ */
+ enum DisplayCapability : uint32_t {
+ /**
+ * Indicates that the display supports protected contents.
+ * When returned, hardware composer must be able to accept client target
+ * with protected buffers.
+ */
+ PROTECTED_CONTENTS = 4,
+ };
+
+ /**
+ * Provides a list of supported capabilities (as described in the
+ * definition of DisplayCapability above). This list must not change after
+ * initialization.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * @return capabilities is a list of supported capabilities.
+ */
+ getDisplayCapabilities_2_4(Display display)
+ generates (Error error,
+ vec<DisplayCapability> capabilities);
+};
diff --git a/graphics/composer/2.4/default/Android.bp b/graphics/composer/2.4/default/Android.bp
new file mode 100644
index 0000000..1bf51e0
--- /dev/null
+++ b/graphics/composer/2.4/default/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright 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_binary {
+ name: "android.hardware.graphics.composer@2.4-service",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: ["service.cpp"],
+ init_rc: ["android.hardware.graphics.composer@2.4-service.rc"],
+ header_libs: [
+ "android.hardware.graphics.composer@2.4-passthrough",
+ ],
+ shared_libs: [
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
+ "android.hardware.graphics.composer@2.4",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwc2on1adapter",
+ "libhwc2onfbadapter",
+ "liblog",
+ "libsync",
+ "libutils",
+ ],
+}
diff --git a/graphics/composer/2.4/default/OWNERS b/graphics/composer/2.4/default/OWNERS
new file mode 100644
index 0000000..cc6d937
--- /dev/null
+++ b/graphics/composer/2.4/default/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+lpy@google.com
+stoza@google.com
+vhau@google.com
diff --git a/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc b/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc
new file mode 100644
index 0000000..a296b0a
--- /dev/null
+++ b/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc
@@ -0,0 +1,7 @@
+service vendor.hwcomposer-2-4 /vendor/bin/hw/android.hardware.graphics.composer@2.4-service
+ class hal animation
+ user system
+ group graphics drmrpc
+ capabilities SYS_NICE
+ onrestart restart surfaceflinger
+ writepid /dev/cpuset/system-background/tasks
diff --git a/graphics/composer/2.4/default/service.cpp b/graphics/composer/2.4/default/service.cpp
new file mode 100644
index 0000000..98dac3e
--- /dev/null
+++ b/graphics/composer/2.4/default/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 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 <sched.h>
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <binder/ProcessState.h>
+#include <composer-passthrough/2.4/HwcLoader.h>
+#include <hidl/HidlTransportSupport.h>
+
+using android::hardware::graphics::composer::V2_4::IComposer;
+using android::hardware::graphics::composer::V2_4::passthrough::HwcLoader;
+
+int main() {
+ // the conventional HAL might start binder services
+ android::ProcessState::initWithDriver("/dev/vndbinder");
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
+ android::ProcessState::self()->startThreadPool();
+
+ // same as SF main thread
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO: %d", errno);
+ }
+
+ android::hardware::configureRpcThreadpool(4, true /* will join */);
+
+ android::sp<IComposer> composer = HwcLoader::load();
+ if (composer == nullptr) {
+ return 1;
+ }
+ if (composer->registerAsService() != android::NO_ERROR) {
+ ALOGE("failed to register service");
+ return 1;
+ }
+
+ android::hardware::joinRpcThreadpool();
+
+ ALOGE("service is terminating");
+ return 1;
+}
diff --git a/graphics/composer/2.4/utils/OWNERS b/graphics/composer/2.4/utils/OWNERS
new file mode 100644
index 0000000..cc6d937
--- /dev/null
+++ b/graphics/composer/2.4/utils/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+lpy@google.com
+stoza@google.com
+vhau@google.com
diff --git a/graphics/composer/2.4/utils/command-buffer/Android.bp b/graphics/composer/2.4/utils/command-buffer/Android.bp
new file mode 100644
index 0000000..8acf0e1
--- /dev/null
+++ b/graphics/composer/2.4/utils/command-buffer/Android.bp
@@ -0,0 +1,18 @@
+cc_library_headers {
+ name: "android.hardware.graphics.composer@2.4-command-buffer",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.4",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.4",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ export_include_dirs: ["include"],
+}
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
new file mode 100644
index 0000000..6b64c16
--- /dev/null
+++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warn "ComposerCommandBuffer.h included without LOG_TAG"
+#endif
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 0
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+
+using android::hardware::MessageQueue;
+using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_4::IComposerClient;
+
+// This class helps build a command queue. Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase : public V2_3::CommandWriterBase {
+ public:
+ CommandWriterBase(uint32_t initialMaxSize) : V2_3::CommandWriterBase(initialMaxSize) {}
+};
+
+// This class helps parse a command queue. Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase : public V2_3::CommandReaderBase {
+ public:
+ CommandReaderBase() : V2_3::CommandReaderBase(){};
+};
+
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/hal/Android.bp b/graphics/composer/2.4/utils/hal/Android.bp
new file mode 100644
index 0000000..3ee4e19
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright 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_library_headers {
+ name: "android.hardware.graphics.composer@2.4-hal",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.4",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.4",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.3-hal",
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.3-hal",
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h
new file mode 100644
index 0000000..129bae6
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "Composer.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <composer-hal/2.3/Composer.h>
+#include <composer-hal/2.4/ComposerClient.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+namespace detail {
+
+// ComposerImpl implements V2_*::IComposer on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerImpl : public V2_3::hal::detail::ComposerImpl<Interface, Hal> {
+ public:
+ static std::unique_ptr<ComposerImpl> create(std::unique_ptr<Hal> hal) {
+ return std::make_unique<ComposerImpl>(std::move(hal));
+ }
+
+ explicit ComposerImpl(std::unique_ptr<Hal> hal) : BaseType2_3(std::move(hal)) {}
+
+ // IComposer 2.4 interface
+
+ Return<void> createClient_2_4(IComposer::createClient_2_4_cb hidl_cb) override {
+ std::unique_lock<std::mutex> lock(mClientMutex);
+ if (!waitForClientDestroyedLocked(lock)) {
+ hidl_cb(Error::NO_RESOURCES, nullptr);
+ return Void();
+ }
+
+ sp<ComposerClient> client = ComposerClient::create(mHal.get()).release();
+ if (!client) {
+ hidl_cb(Error::NO_RESOURCES, nullptr);
+ return Void();
+ }
+
+ auto clientDestroyed = [this]() { onClientDestroyed(); };
+ client->setOnClientDestroyed(clientDestroyed);
+
+ mClient = client;
+ hidl_cb(Error::NONE, client);
+ return Void();
+ }
+
+ private:
+ using BaseType2_3 = V2_3::hal::detail::ComposerImpl<Interface, Hal>;
+ using BaseType2_1 = V2_1::hal::detail::ComposerImpl<Interface, Hal>;
+
+ using BaseType2_1::mClient;
+ using BaseType2_1::mClientMutex;
+ using BaseType2_1::mHal;
+ using BaseType2_1::onClientDestroyed;
+ using BaseType2_1::waitForClientDestroyedLocked;
+};
+
+} // namespace detail
+
+using Composer = detail::ComposerImpl<IComposer, ComposerHal>;
+
+} // namespace hal
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
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
new file mode 100644
index 0000000..7110c80
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerClient.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-hal/2.4/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+namespace detail {
+
+// ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl<Interface, Hal> {
+ public:
+ ComposerClientImpl(Hal* hal) : BaseType2_3(hal) {}
+
+ Return<void> getDisplayCapabilities_2_4(
+ Display display, IComposerClient::getDisplayCapabilities_2_4_cb hidl_cb) override {
+ std::vector<IComposerClient::DisplayCapability> capabilities;
+ Error error = mHal->getDisplayCapabilities_2_4(display, &capabilities);
+ hidl_cb(error, capabilities);
+ return Void();
+ }
+
+ static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
+ auto client = std::make_unique<ComposerClientImpl>(hal);
+ return client->init() ? std::move(client) : nullptr;
+ }
+
+ private:
+ using BaseType2_3 = V2_3::hal::detail::ComposerClientImpl<Interface, Hal>;
+ using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
+ using BaseType2_1::mHal;
+};
+
+} // namespace detail
+
+using ComposerClient = detail::ComposerClientImpl<IComposerClient, ComposerHal>;
+
+} // namespace hal
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
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
new file mode 100644
index 0000000..0074808
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 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 <composer-hal/2.3/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
+using common::V1_2::PixelFormat;
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+
+class ComposerHal : public V2_3::hal::ComposerHal {
+ public:
+ virtual Error getDisplayCapabilities_2_4(
+ Display display, std::vector<IComposerClient::DisplayCapability>* outCapabilities) = 0;
+};
+
+} // namespace hal
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/passthrough/Android.bp b/graphics/composer/2.4/utils/passthrough/Android.bp
new file mode 100644
index 0000000..43d9aaa
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright 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_library_headers {
+ name: "android.hardware.graphics.composer@2.4-passthrough",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ header_libs: [
+ "android.hardware.graphics.composer@2.3-passthrough",
+ "android.hardware.graphics.composer@2.4-hal",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.3-passthrough",
+ "android.hardware.graphics.composer@2.4-hal",
+ ],
+ export_include_dirs: ["include"],
+}
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
new file mode 100644
index 0000000..65d47d7
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcHal.h included without LOG_TAG"
+#endif
+
+#include <type_traits>
+
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-passthrough/2.3/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace passthrough {
+
+namespace detail {
+
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
+using common::V1_2::PixelFormat;
+using V2_1::Display;
+using V2_1::Error;
+
+// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2
+template <typename Hal>
+class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
+ public:
+ Error getDisplayCapabilities_2_4(
+ Display display,
+ std::vector<IComposerClient::DisplayCapability>* outCapabilities) override {
+ std::vector<V2_3::IComposerClient::DisplayCapability> capabilities;
+ Error error = BaseType2_3::getDisplayCapabilities(display, &capabilities);
+ if (error != Error::NONE) {
+ return error;
+ }
+ outCapabilities->clear();
+ outCapabilities->reserve(capabilities.size());
+ for (auto capability : capabilities) {
+ outCapabilities->push_back(static_cast<IComposerClient::DisplayCapability>(capability));
+ }
+ return Error::NONE;
+ }
+
+ protected:
+ bool initDispatch() override {
+ if (!BaseType2_3::initDispatch()) {
+ return false;
+ }
+ return true;
+ }
+
+ private:
+ using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
+ using BaseType2_3 = V2_3::passthrough::detail::HwcHalImpl<Hal>;
+ using BaseType2_1::mDevice;
+};
+
+} // namespace detail
+
+using HwcHal = detail::HwcHalImpl<hal::ComposerHal>;
+
+} // namespace passthrough
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h
new file mode 100644
index 0000000..a7cc588
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcLoader.h included without LOG_TAG"
+#endif
+
+#include <composer-hal/2.4/Composer.h>
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-passthrough/2.3/HwcLoader.h>
+#include <composer-passthrough/2.4/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace passthrough {
+
+class HwcLoader : public V2_3::passthrough::HwcLoader {
+ public:
+ static IComposer* load() {
+ const hw_module_t* module = loadModule();
+ if (!module) {
+ return nullptr;
+ }
+
+ auto hal = createHalWithAdapter(module);
+ if (!hal) {
+ return nullptr;
+ }
+
+ return createComposer(std::move(hal)).release();
+ }
+
+ // create a ComposerHal instance
+ static std::unique_ptr<hal::ComposerHal> createHal(const hw_module_t* module) {
+ auto hal = std::make_unique<HwcHal>();
+ return hal->initWithModule(module) ? std::move(hal) : nullptr;
+ }
+
+ // create a ComposerHal instance, insert an adapter if necessary
+ static std::unique_ptr<hal::ComposerHal> createHalWithAdapter(const hw_module_t* module) {
+ bool adapted;
+ hwc2_device_t* device = openDeviceWithAdapter(module, &adapted);
+ if (!device) {
+ return nullptr;
+ }
+ auto hal = std::make_unique<HwcHal>();
+ return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr;
+ }
+
+ // create an IComposer instance
+ static std::unique_ptr<IComposer> createComposer(std::unique_ptr<hal::ComposerHal> hal) {
+ return hal::Composer::create(std::move(hal));
+ }
+};
+
+} // namespace passthrough
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp
new file mode 100644
index 0000000..b87a116
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright 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_library_static {
+ name: "android.hardware.graphics.composer@2.4-vts",
+ defaults: ["hidl_defaults"],
+ srcs: [
+ "ComposerVts.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",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ cflags: [
+ "-O0",
+ "-g",
+ "-DLOG_TAG=\"ComposerVts\"",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
new file mode 100644
index 0000000..ee4f3a3
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 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 <composer-vts/2.4/ComposerVts.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+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_3::vts::Composer(composer), mComposer(composer) {}
+
+std::unique_ptr<ComposerClient> Composer::createClient() {
+ std::unique_ptr<ComposerClient> client;
+ mComposer->createClient_2_4([&client](const auto& tmpError, const auto& tmpClient) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+ client = std::make_unique<ComposerClient>(tmpClient);
+ });
+
+ return client;
+}
+
+sp<IComposerClient> ComposerClient::getRaw() const {
+ return mClient;
+}
+
+Error ComposerClient::getDisplayCapabilities(
+ Display display, std::vector<IComposerClient::DisplayCapability>* outCapabilities) {
+ std::vector<IComposerClient::DisplayCapability> capabilities;
+ Error error = Error::NONE;
+ mClient->getDisplayCapabilities_2_4(display,
+ [&](const auto& tmpError, const auto& tmpCapabilities) {
+ error = tmpError;
+ *outCapabilities = tmpCapabilities;
+ });
+ return error;
+}
+
+} // namespace vts
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
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
new file mode 100644
index 0000000..0a301c6
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#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>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
+using common::V1_2::PixelFormat;
+using V2_1::Display;
+using V2_1::Error;
+using V2_4::IComposer;
+using V2_4::IComposerClient;
+
+class ComposerClient;
+
+// A wrapper to IComposer.
+class Composer : public V2_3::vts::Composer {
+ public:
+ Composer();
+ explicit Composer(const std::string& name);
+
+ std::unique_ptr<ComposerClient> createClient();
+
+ protected:
+ explicit Composer(const sp<IComposer>& composer);
+
+ private:
+ const sp<IComposer> mComposer;
+};
+
+// A wrapper to IComposerClient.
+class ComposerClient : public V2_3::vts::ComposerClient {
+ public:
+ explicit ComposerClient(const sp<IComposerClient>& client)
+ : V2_3::vts::ComposerClient(client), mClient(client) {}
+
+ sp<IComposerClient> getRaw() const;
+
+ Error getDisplayCapabilities(
+ Display display,
+ std::vector<IComposerClient::DisplayCapability>* outDisplayCapabilities);
+
+ private:
+ const sp<IComposerClient> mClient;
+};
+
+} // namespace vts
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
new file mode 100644
index 0000000..d437f24
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -0,0 +1,48 @@
+//
+// Copyright 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: "VtsHalGraphicsComposerV2_4TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalGraphicsComposerV2_4TargetTest.cpp"],
+
+ // TODO(b/64437680): Assume these libs are always available on the device.
+ shared_libs: [
+ "libfmq",
+ "libhidltransport",
+ "libsync",
+ ],
+ static_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.1-vts",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.2-vts",
+ "android.hardware.graphics.composer@2.3",
+ "android.hardware.graphics.composer@2.3-vts",
+ "android.hardware.graphics.composer@2.4",
+ "android.hardware.graphics.composer@2.4-vts",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@2.0-vts",
+ "android.hardware.graphics.mapper@2.1",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ "android.hardware.graphics.composer@2.4-command-buffer",
+ ],
+}
diff --git a/graphics/composer/2.4/vts/functional/OWNERS b/graphics/composer/2.4/vts/functional/OWNERS
new file mode 100644
index 0000000..b3ea6be
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/OWNERS
@@ -0,0 +1,8 @@
+# Graphics team
+lpy@google.com
+stoza@google.com
+vhau@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
new file mode 100644
index 0000000..0fccc58
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright 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 "graphics_composer_hidl_hal_test@2.4"
+
+#include <algorithm>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.4/ComposerVts.h>
+#include <mapper-vts/2.0/MapperVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+namespace {
+
+using common::V1_0::BufferUsage;
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::PixelFormat;
+using mapper::V2_0::IMapper;
+using mapper::V2_0::vts::Gralloc;
+
+// Test environment for graphics.composer
+class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static GraphicsComposerHidlEnvironment* Instance() {
+ static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<IComposer>(); }
+
+ private:
+ GraphicsComposerHidlEnvironment() {}
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
+};
+
+class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(
+ mComposer = std::make_unique<Composer>(
+ GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+ ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
+
+ mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
+ mComposerClient->registerCallback(mComposerCallback);
+
+ // assume the first display is primary and is never removed
+ mPrimaryDisplay = waitForFirstDisplay();
+
+ mInvalidDisplayId = GetInvalidDisplayId();
+
+ // explicitly disable vsync
+ mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+ mComposerCallback->setVsyncAllowed(false);
+
+ mWriter = std::make_unique<CommandWriterBase>(1024);
+ mReader = std::make_unique<V2_1::vts::TestCommandReader>();
+ }
+
+ void TearDown() override {
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_EQ(0, mReader->mCompositionChanges.size());
+ if (mComposerCallback != nullptr) {
+ EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+ }
+ }
+
+ // returns an invalid display id (one that has not been registered to a
+ // display. Currently assuming that a device will never have close to
+ // std::numeric_limit<uint64_t>::max() displays registered while running tests
+ Display GetInvalidDisplayId() {
+ std::vector<Display> validDisplays = mComposerCallback->getDisplays();
+ uint64_t id = std::numeric_limits<uint64_t>::max();
+ while (id > 0) {
+ if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) {
+ return id;
+ }
+ id--;
+ }
+
+ return 0;
+ }
+
+ void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+ std::unique_ptr<Composer> mComposer;
+ std::unique_ptr<ComposerClient> mComposerClient;
+ sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
+ // the first display and is assumed never to be removed
+ Display mPrimaryDisplay;
+ Display mInvalidDisplayId;
+ std::unique_ptr<CommandWriterBase> mWriter;
+ std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
+
+ private:
+ Display waitForFirstDisplay() {
+ while (true) {
+ std::vector<Display> displays = mComposerCallback->getDisplays();
+ if (displays.empty()) {
+ usleep(5 * 1000);
+ continue;
+ }
+
+ return displays[0];
+ }
+ }
+};
+
+// Tests for IComposerClient::Command.
+class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
+
+ ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
+
+ mWriter = std::make_unique<CommandWriterBase>(1024);
+ mReader = std::make_unique<V2_1::vts::TestCommandReader>();
+ }
+
+ void TearDown() override {
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
+ }
+
+ const native_handle_t* allocate() {
+ IMapper::BufferDescriptorInfo info{};
+ info.width = 64;
+ info.height = 64;
+ info.layerCount = 1;
+ info.format = static_cast<common::V1_0::PixelFormat>(PixelFormat::RGBA_8888);
+ info.usage =
+ static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+ return mGralloc->allocate(info);
+ }
+
+ void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+ std::unique_ptr<CommandWriterBase> mWriter;
+ std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
+
+ private:
+ std::unique_ptr<Gralloc> mGralloc;
+};
+
+TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) {
+ std::vector<IComposerClient::DisplayCapability> capabilities;
+ const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities);
+ EXPECT_EQ(Error::BAD_DISPLAY, error);
+}
+
+} // namespace
+} // namespace vts
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+int main(int argc, char** argv) {
+ using android::hardware::graphics::composer::V2_4::vts::GraphicsComposerHidlEnvironment;
+ ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ return status;
+}
diff --git a/ir/1.0/default/android.hardware.ir@1.0-service.rc b/ir/1.0/default/android.hardware.ir@1.0-service.rc
index 0d06967..b2f1f7d 100644
--- a/ir/1.0/default/android.hardware.ir@1.0-service.rc
+++ b/ir/1.0/default/android.hardware.ir@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.ir-hal-1-0 /vendor/bin/hw/android.hardware.ir@1.0-service
+ interface android.hardware.ir@1.0::IConsumerIr default
class hal
user system
group system
diff --git a/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc b/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc
index ea8d490..dffaca5 100644
--- a/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc
+++ b/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc
@@ -1,4 +1,5 @@
service vendor.keymaster-3-0 /vendor/bin/hw/android.hardware.keymaster@3.0-service
+ interface android.hardware.keymaster@3.0::IKeymasterDevice default
class early_hal
user nobody
group drmrpc
diff --git a/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc b/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc
index 2ce439e..2adfd88 100644
--- a/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc
+++ b/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc
@@ -1,4 +1,5 @@
service vendor.keymaster-4-0 /vendor/bin/hw/android.hardware.keymaster@4.0-service
+ interface android.hardware.keymaster@4.0::IKeymasterDevice default
class early_hal
user system
group system drmrpc
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index c66f574..293c50c 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -309,6 +309,11 @@
return make_string(a, N);
}
+bool avb_verification_enabled() {
+ char value[PROPERTY_VALUE_MAX];
+ return property_get("ro.boot.vbmeta.device_state", value, "") != 0;
+}
+
} // namespace
bool verify_attestation_record(const string& challenge, const string& app_id,
@@ -359,26 +364,32 @@
EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
char property_value[PROPERTY_VALUE_MAX] = {};
- for (int i = 0; i < att_hw_enforced.size(); i++) {
- if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL ||
- att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) {
- std::string date = std::to_string(att_hw_enforced[i].f.integer);
- // strptime seems to require delimiters, but the tag value will be YYYYMMDD
- date.insert(6, "-");
- date.insert(4, "-");
- EXPECT_EQ(date.size(), 10);
- struct tm time;
- strptime(date.c_str(), "%Y-%m-%d", &time);
+ // TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
+ // keymaster implementation will report YYYYMM dates instead of YYYYMMDD
+ // for the BOOT_PATCH_LEVEL.
+ if (avb_verification_enabled()) {
+ for (int i = 0; i < att_hw_enforced.size(); i++) {
+ if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL ||
+ att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) {
+ std::string date = std::to_string(att_hw_enforced[i].f.integer);
+ // strptime seems to require delimiters, but the tag value will
+ // be YYYYMMDD
+ date.insert(6, "-");
+ date.insert(4, "-");
+ EXPECT_EQ(date.size(), 10);
+ struct tm time;
+ strptime(date.c_str(), "%Y-%m-%d", &time);
- // Day of the month (0-31)
- EXPECT_GE(time.tm_mday, 0);
- EXPECT_LT(time.tm_mday, 32);
- // Months since Jan (0-11)
- EXPECT_GE(time.tm_mon, 0);
- EXPECT_LT(time.tm_mon, 12);
- // Years since 1900
- EXPECT_GT(time.tm_year, 110);
- EXPECT_LT(time.tm_year, 200);
+ // Day of the month (0-31)
+ EXPECT_GE(time.tm_mday, 0);
+ EXPECT_LT(time.tm_mday, 32);
+ // Months since Jan (0-11)
+ EXPECT_GE(time.tm_mon, 0);
+ EXPECT_LT(time.tm_mon, 12);
+ // Years since 1900
+ EXPECT_GT(time.tm_year, 110);
+ EXPECT_LT(time.tm_year, 200);
+ }
}
}
@@ -410,18 +421,20 @@
&verified_boot_state, &device_locked, &verified_boot_hash);
EXPECT_EQ(ErrorCode::OK, error);
- property_get("ro.boot.vbmeta.digest", property_value, "nogood");
- EXPECT_NE(strcmp(property_value, "nogood"), 0);
- string prop_string(property_value);
- EXPECT_EQ(prop_string.size(), 64);
- EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
+ if (avb_verification_enabled()) {
+ property_get("ro.boot.vbmeta.digest", property_value, "nogood");
+ EXPECT_NE(strcmp(property_value, "nogood"), 0);
+ string prop_string(property_value);
+ EXPECT_EQ(prop_string.size(), 64);
+ EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
- property_get("ro.boot.vbmeta.device_state", property_value, "nogood");
- EXPECT_NE(property_value, "nogood");
- if (!strcmp(property_value, "unlocked")) {
- EXPECT_FALSE(device_locked);
- } else {
- EXPECT_TRUE(device_locked);
+ property_get("ro.boot.vbmeta.device_state", property_value, "nogood");
+ EXPECT_NE(strcmp(property_value, "nogood"), 0);
+ if (!strcmp(property_value, "unlocked")) {
+ EXPECT_FALSE(device_locked);
+ } else {
+ EXPECT_TRUE(device_locked);
+ }
}
// Verified boot key should be all 0's if the boot state is not verified or self signed
diff --git a/media/omx/1.0/vts/functional/common/Android.bp b/media/omx/1.0/vts/functional/common/Android.bp
index cdc52fb..5a79e55 100644
--- a/media/omx/1.0/vts/functional/common/Android.bp
+++ b/media/omx/1.0/vts/functional/common/Android.bp
@@ -29,6 +29,21 @@
"android.hidl.memory@1.0",
"android.hardware.media.omx@1.0",
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ ],
+ export_static_lib_headers: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
],
}
@@ -40,7 +55,12 @@
static_libs: [
"VtsHalMediaOmxV1_0CommonUtil",
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.bufferqueue@1.0",
"android.hardware.graphics.common@1.0",
"android.hardware.media.omx@1.0",
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
index f299e36..8d4c022 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
@@ -22,8 +22,11 @@
#include <android-base/logging.h>
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/2.0/types.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/types.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <android/hardware/media/omx/1.0/IOmxObserver.h>
@@ -31,7 +34,9 @@
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMapper.h>
#include <android/hidl/memory/1.0/IMemory.h>
-#include <cutils/atomic.h>
+
+#include <atomic>
+#include <variant>
using ::android::hardware::graphics::common::V1_0::BufferUsage;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
@@ -195,67 +200,104 @@
BufferInfo* buffer, uint32_t nFrameWidth,
uint32_t nFrameHeight, int32_t* nStride,
int format) {
- android::hardware::media::omx::V1_0::Status status;
- sp<android::hardware::graphics::allocator::V2_0::IAllocator> allocator =
- android::hardware::graphics::allocator::V2_0::IAllocator::getService();
- ASSERT_NE(nullptr, allocator.get());
+ struct AllocatorV2 : public GrallocV2 {
+ sp<IAllocator> mAllocator;
+ sp<IMapper> mMapper;
+ AllocatorV2(sp<IAllocator>&& allocator, sp<IMapper>&& mapper)
+ : mAllocator{std::move(allocator)}, mMapper{std::move(mapper)} {}
+ AllocatorV2() = default;
+ };
+ struct AllocatorV3 : public GrallocV3 {
+ sp<IAllocator> mAllocator;
+ sp<IMapper> mMapper;
+ AllocatorV3(sp<IAllocator>&& allocator, sp<IMapper>&& mapper)
+ : mAllocator{std::move(allocator)}, mMapper{std::move(mapper)} {}
+ AllocatorV3() = default;
+ };
+ std::variant<AllocatorV2, AllocatorV3> grallocVar;
- sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
- android::hardware::graphics::mapper::V2_0::IMapper::getService();
- ASSERT_NE(mapper.get(), nullptr);
+ sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper2{};
+ sp<android::hardware::graphics::mapper::V3_0::IMapper> mapper3{};
+ sp<android::hardware::graphics::allocator::V2_0::IAllocator> allocator2{};
+ sp<android::hardware::graphics::allocator::V3_0::IAllocator> allocator3 =
+ android::hardware::graphics::allocator::V3_0::IAllocator::getService();
+ if (allocator3) {
+ mapper3 =
+ android::hardware::graphics::mapper::V3_0::IMapper::getService();
+ ASSERT_NE(nullptr, mapper3.get());
+ grallocVar.emplace<AllocatorV3>(std::move(allocator3), std::move(mapper3));
+ } else {
+ allocator2 =
+ android::hardware::graphics::allocator::V2_0::IAllocator::getService();
+ ASSERT_NE(nullptr, allocator2.get());
+ mapper2 =
+ android::hardware::graphics::mapper::V2_0::IMapper::getService();
+ ASSERT_NE(nullptr, allocator2.get());
+ grallocVar.emplace<AllocatorV2>(std::move(allocator2), std::move(mapper2));
+ }
- android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo
- descriptorInfo;
- uint32_t usage;
-
- descriptorInfo.width = nFrameWidth;
- descriptorInfo.height = nFrameHeight;
- descriptorInfo.layerCount = 1;
- descriptorInfo.format = static_cast<PixelFormat>(format);
- descriptorInfo.usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN);
- omxNode->getGraphicBufferUsage(
+ android::hardware::media::omx::V1_0::Status status{};
+ uint64_t usage{};
+ ASSERT_TRUE(omxNode->getGraphicBufferUsage(
portIndex,
[&status, &usage](android::hardware::media::omx::V1_0::Status _s,
uint32_t _n1) {
status = _s;
usage = _n1;
- });
- if (status == android::hardware::media::omx::V1_0::Status::OK) {
- descriptorInfo.usage |= usage;
- }
+ }).isOk());
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
- ::android::hardware::hidl_vec<uint32_t> descriptor;
- android::hardware::graphics::mapper::V2_0::Error error;
- mapper->createDescriptor(
- descriptorInfo, [&error, &descriptor](
- android::hardware::graphics::mapper::V2_0::Error _s,
- ::android::hardware::hidl_vec<uint32_t> _n1) {
- error = _s;
- descriptor = _n1;
- });
- ASSERT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE);
+ static std::atomic_int32_t bufferIdCounter{0};
- static volatile int32_t nextId = 0;
- uint64_t id = static_cast<uint64_t>(getpid()) << 32;
- allocator->allocate(
- descriptor, 1,
- [&](android::hardware::graphics::mapper::V2_0::Error _s, uint32_t _n1,
- const ::android::hardware::hidl_vec<
- ::android::hardware::hidl_handle>& _n2) {
- ASSERT_EQ(android::hardware::graphics::mapper::V2_0::Error::NONE,
- _s);
- *nStride = _n1;
- buffer->omxBuffer.nativeHandle = _n2[0];
- buffer->omxBuffer.attr.anwBuffer.width = nFrameWidth;
- buffer->omxBuffer.attr.anwBuffer.height = nFrameHeight;
- buffer->omxBuffer.attr.anwBuffer.stride = _n1;
- buffer->omxBuffer.attr.anwBuffer.format = descriptorInfo.format;
- buffer->omxBuffer.attr.anwBuffer.usage = descriptorInfo.usage;
- buffer->omxBuffer.attr.anwBuffer.layerCount =
- descriptorInfo.layerCount;
- buffer->omxBuffer.attr.anwBuffer.id =
- id | static_cast<uint32_t>(android_atomic_inc(&nextId));
- });
+ std::visit([buffer, nFrameWidth, nFrameHeight, format, usage, nStride](auto&& gralloc) {
+ using Gralloc = std::remove_reference_t<decltype(gralloc)>;
+ using Descriptor = typename Gralloc::Descriptor;
+ using DescriptorInfo = typename Gralloc::DescriptorInfo;
+ using Error = typename Gralloc::Error;
+ using Format = typename Gralloc::Format;
+ using Usage = typename Gralloc::Usage;
+
+ Error error{};
+ Descriptor descriptor{};
+
+ DescriptorInfo descriptorInfo{};
+ descriptorInfo.width = nFrameWidth;
+ descriptorInfo.height = nFrameHeight;
+ descriptorInfo.layerCount = 1;
+ descriptorInfo.format = static_cast<Format>(format);
+ descriptorInfo.usage = usage | Usage(BufferUsage::CPU_READ_OFTEN);
+
+ gralloc.mMapper->createDescriptor(descriptorInfo,
+ [&error, &descriptor](
+ Error _s,
+ const Descriptor& _n1) {
+ error = _s;
+ descriptor = _n1;
+ });
+ ASSERT_EQ(error, Error::NONE);
+
+ gralloc.mAllocator->allocate(
+ descriptor, 1,
+ [&](Error _s, uint32_t _n1,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::hidl_handle>& _n2) {
+ ASSERT_EQ(Error::NONE, _s);
+ *nStride = _n1;
+ buffer->omxBuffer.nativeHandle = _n2[0];
+ buffer->omxBuffer.attr.anwBuffer.width = nFrameWidth;
+ buffer->omxBuffer.attr.anwBuffer.height = nFrameHeight;
+ buffer->omxBuffer.attr.anwBuffer.stride = _n1;
+ buffer->omxBuffer.attr.anwBuffer.format =
+ static_cast<PixelFormat>(descriptorInfo.format);
+ buffer->omxBuffer.attr.anwBuffer.usage =
+ static_cast<uint32_t>(descriptorInfo.usage);
+ buffer->omxBuffer.attr.anwBuffer.layerCount =
+ descriptorInfo.layerCount;
+ buffer->omxBuffer.attr.anwBuffer.id =
+ (static_cast<uint64_t>(getpid()) << 32) |
+ bufferIdCounter.fetch_add(1, std::memory_order_relaxed);
+ });
+ }, grallocVar);
}
// allocate buffers needed on a component port
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
index 1575ba2..08af26b 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
@@ -22,6 +22,16 @@
#endif
#include <getopt.h>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/graphics/common/1.1/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/2.0/types.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/types.h>
#include <media/stagefright/foundation/ALooper.h>
#include <utils/Condition.h>
#include <utils/List.h>
@@ -288,6 +298,36 @@
/*
* common functions declarations
*/
+struct GrallocV2 {
+ using Format = android::hardware::graphics::common::V1_0::PixelFormat;
+ using Usage = android::hardware::hidl_bitfield<
+ android::hardware::graphics::common::V1_0::BufferUsage>;
+
+ using IAllocator = android::hardware::graphics::allocator::V2_0::IAllocator;
+
+ using IMapper = android::hardware::graphics::mapper::V2_0::IMapper;
+ using Error = android::hardware::graphics::mapper::V2_0::Error;
+ using Descriptor = android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+ using YCbCrLayout = android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+ using DescriptorInfo = IMapper::BufferDescriptorInfo;
+ using Rect = IMapper::Rect;
+};
+
+struct GrallocV3 {
+ using Format = android::hardware::graphics::common::V1_2::PixelFormat;
+ using Usage = android::hardware::hidl_bitfield<
+ android::hardware::graphics::common::V1_2::BufferUsage>;
+
+ using IAllocator = android::hardware::graphics::allocator::V3_0::IAllocator;
+
+ using IMapper = android::hardware::graphics::mapper::V3_0::IMapper;
+ using Error = android::hardware::graphics::mapper::V3_0::Error;
+ using Descriptor = android::hardware::graphics::mapper::V3_0::BufferDescriptor;
+ using YCbCrLayout = android::hardware::graphics::mapper::V3_0::YCbCrLayout;
+ using DescriptorInfo = IMapper::BufferDescriptorInfo;
+ using Rect = IMapper::Rect;
+};
+
Return<android::hardware::media::omx::V1_0::Status> setRole(
sp<IOmxNode> omxNode, const char* role);
diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
index a740a80..2280cee 100644
--- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
+++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
@@ -63,6 +63,7 @@
#include <media_video_hidl_test_common.h>
#include <system/window.h>
#include <fstream>
+#include <variant>
static ComponentTestEnvironment* gEnv = nullptr;
@@ -364,6 +365,61 @@
return Void();
};
+// Variant of mappers
+struct MapperV2 : public GrallocV2 {
+ sp<IMapper> mMapper;
+ MapperV2(sp<IMapper>&& mapper): mMapper{std::move(mapper)} {}
+ MapperV2() = default;
+ android::hardware::Return<void> lock(
+ void* buffer,
+ Usage usage,
+ const Rect& rect,
+ const android::hardware::hidl_handle& handle,
+ Error* error,
+ void** data) {
+ return mMapper->lock(buffer, usage, rect, handle,
+ [error, data](Error e, void* d) {
+ *error = e;
+ *data = d;
+ });
+ }
+};
+struct MapperV3 : public GrallocV3 {
+ sp<IMapper> mMapper;
+ MapperV3(sp<IMapper>&& mapper): mMapper{std::move(mapper)} {}
+ MapperV3() = default;
+ android::hardware::Return<void> lock(
+ void* buffer,
+ Usage usage,
+ const Rect& rect,
+ const android::hardware::hidl_handle& handle,
+ Error* error,
+ void** data) {
+ return mMapper->lock(buffer, usage, rect, handle,
+ [error, data](Error e, void* d, int32_t, int32_t) {
+ *error = e;
+ *data = d;
+ });
+ }
+};
+using MapperVar = std::variant<MapperV2, MapperV3>;
+// Initializes the MapperVar by trying services of different versions.
+bool initialize(MapperVar& mapperVar) {
+ sp<android::hardware::graphics::mapper::V3_0::IMapper> mapper3 =
+ android::hardware::graphics::mapper::V3_0::IMapper::getService();
+ if (mapper3) {
+ mapperVar.emplace<MapperV3>(std::move(mapper3));
+ return true;
+ }
+ sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper2 =
+ android::hardware::graphics::mapper::V2_0::IMapper::getService();
+ if (mapper2) {
+ mapperVar.emplace<MapperV2>(std::move(mapper2));
+ return true;
+ }
+ return false;
+}
+
// request VOP refresh
void requestIDR(sp<IOmxNode> omxNode, OMX_U32 portIndex) {
android::hardware::media::omx::V1_0::Status status;
@@ -574,150 +630,166 @@
int colorFormatConversion(BufferInfo* buffer, void* buff, PixelFormat format,
std::ifstream& eleStream) {
- sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
- android::hardware::graphics::mapper::V2_0::IMapper::getService();
- EXPECT_NE(mapper.get(), nullptr);
- if (mapper.get() == nullptr) return 1;
-
- android::hardware::hidl_handle fence;
- android::hardware::graphics::mapper::V2_0::IMapper::Rect rect;
- android::hardware::graphics::mapper::V2_0::YCbCrLayout ycbcrLayout;
- android::hardware::graphics::mapper::V2_0::Error error;
- rect.left = 0;
- rect.top = 0;
- rect.width = buffer->omxBuffer.attr.anwBuffer.width;
- rect.height = buffer->omxBuffer.attr.anwBuffer.height;
-
- if (format == PixelFormat::YV12 || format == PixelFormat::YCRCB_420_SP ||
- format == PixelFormat::YCBCR_420_888) {
- mapper->lockYCbCr(
- buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, fence,
- [&](android::hardware::graphics::mapper::V2_0::Error _e,
- android::hardware::graphics::mapper::V2_0::YCbCrLayout _n1) {
- error = _e;
- ycbcrLayout = _n1;
- });
- EXPECT_EQ(error,
- android::hardware::graphics::mapper::V2_0::Error::NONE);
- if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
- return 1;
-
- int size = ((rect.width * rect.height * 3) >> 1);
- char* img = new char[size];
- if (img == nullptr) return 1;
- eleStream.read(img, size);
- if (eleStream.gcount() != size) {
- delete[] img;
- return 1;
- }
-
- char* imgTmp = img;
- char* ipBuffer = static_cast<char*>(ycbcrLayout.y);
- for (size_t y = rect.height; y > 0; --y) {
- memcpy(ipBuffer, imgTmp, rect.width);
- ipBuffer += ycbcrLayout.yStride;
- imgTmp += rect.width;
- }
-
- if (format == PixelFormat::YV12)
- EXPECT_EQ(ycbcrLayout.chromaStep, 1U);
- else if (format == PixelFormat::YCRCB_420_SP)
- EXPECT_EQ(ycbcrLayout.chromaStep, 2U);
-
- ipBuffer = static_cast<char*>(ycbcrLayout.cb);
- for (size_t y = rect.height >> 1; y > 0; --y) {
- for (int32_t x = 0; x < (rect.width >> 1); ++x) {
- ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
- }
- ipBuffer += ycbcrLayout.cStride;
- }
- ipBuffer = static_cast<char*>(ycbcrLayout.cr);
- for (size_t y = rect.height >> 1; y > 0; --y) {
- for (int32_t x = 0; x < (rect.width >> 1); ++x) {
- ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
- }
- ipBuffer += ycbcrLayout.cStride;
- }
-
- delete[] img;
-
- mapper->unlock(buff,
- [&](android::hardware::graphics::mapper::V2_0::Error _e,
- android::hardware::hidl_handle _n1) {
- error = _e;
- fence = _n1;
- });
- EXPECT_EQ(error,
- android::hardware::graphics::mapper::V2_0::Error::NONE);
- if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
- return 1;
- } else {
- void* data;
- mapper->lock(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, fence,
- [&](android::hardware::graphics::mapper::V2_0::Error _e,
- void* _n1) {
- error = _e;
- data = _n1;
- });
- EXPECT_EQ(error,
- android::hardware::graphics::mapper::V2_0::Error::NONE);
- if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
- return 1;
-
- if (format == PixelFormat::BGRA_8888) {
- char* ipBuffer = static_cast<char*>(data);
- for (size_t y = rect.height; y > 0; --y) {
- eleStream.read(ipBuffer, rect.width * 4);
- if (eleStream.gcount() != rect.width * 4) return 1;
- ipBuffer += buffer->omxBuffer.attr.anwBuffer.stride * 4;
- }
- } else {
- EXPECT_TRUE(false) << "un expected pixel format";
- return 1;
- }
-
- mapper->unlock(buff,
- [&](android::hardware::graphics::mapper::V2_0::Error _e,
- android::hardware::hidl_handle _n1) {
- error = _e;
- fence = _n1;
- });
- EXPECT_EQ(error,
- android::hardware::graphics::mapper::V2_0::Error::NONE);
- if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
- return 1;
+ MapperVar mapperVar;
+ if (!initialize(mapperVar)) {
+ EXPECT_TRUE(false) << "failed to obtain mapper service";
+ return 1;
}
- return 0;
+ return std::visit([buffer, buff, format, &eleStream](auto&& mapper) -> int {
+ using Gralloc = std::remove_reference_t<decltype(mapper)>;
+ using Error = typename Gralloc::Error;
+ using Rect = typename Gralloc::Rect;
+ using Usage = typename Gralloc::Usage;
+ using YCbCrLayout = typename Gralloc::YCbCrLayout;
+
+ android::hardware::hidl_handle fence;
+ Rect rect;
+ YCbCrLayout ycbcrLayout;
+ Error error;
+ rect.left = 0;
+ rect.top = 0;
+ rect.width = buffer->omxBuffer.attr.anwBuffer.width;
+ rect.height = buffer->omxBuffer.attr.anwBuffer.height;
+
+ if (format == PixelFormat::YV12 || format == PixelFormat::YCRCB_420_SP ||
+ format == PixelFormat::YCBCR_420_888) {
+ mapper.mMapper->lockYCbCr(
+ buff,
+ static_cast<Usage>(
+ buffer->omxBuffer.attr.anwBuffer.usage),
+ rect,
+ fence,
+ [&](Error _e,
+ const YCbCrLayout& _n1) {
+ error = _e;
+ ycbcrLayout = _n1;
+ });
+ EXPECT_EQ(error, Error::NONE);
+ if (error != Error::NONE)
+ return 1;
+
+ int size = ((rect.width * rect.height * 3) >> 1);
+ char* img = new char[size];
+ if (img == nullptr) return 1;
+ eleStream.read(img, size);
+ if (eleStream.gcount() != size) {
+ delete[] img;
+ return 1;
+ }
+
+ char* imgTmp = img;
+ char* ipBuffer = static_cast<char*>(ycbcrLayout.y);
+ for (size_t y = rect.height; y > 0; --y) {
+ memcpy(ipBuffer, imgTmp, rect.width);
+ ipBuffer += ycbcrLayout.yStride;
+ imgTmp += rect.width;
+ }
+
+ if (format == PixelFormat::YV12)
+ EXPECT_EQ(ycbcrLayout.chromaStep, 1U);
+ else if (format == PixelFormat::YCRCB_420_SP)
+ EXPECT_EQ(ycbcrLayout.chromaStep, 2U);
+
+ ipBuffer = static_cast<char*>(ycbcrLayout.cb);
+ for (size_t y = rect.height >> 1; y > 0; --y) {
+ for (int32_t x = 0; x < (rect.width >> 1); ++x) {
+ ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
+ }
+ ipBuffer += ycbcrLayout.cStride;
+ }
+ ipBuffer = static_cast<char*>(ycbcrLayout.cr);
+ for (size_t y = rect.height >> 1; y > 0; --y) {
+ for (int32_t x = 0; x < (rect.width >> 1); ++x) {
+ ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
+ }
+ ipBuffer += ycbcrLayout.cStride;
+ }
+
+ delete[] img;
+
+ mapper.mMapper->unlock(buff,
+ [&](Error _e,
+ const android::hardware::hidl_handle& _n1) {
+ error = _e;
+ fence = _n1;
+ });
+ EXPECT_EQ(error, Error::NONE);
+ if (error != Error::NONE)
+ return 1;
+ } else {
+ void* data;
+ mapper.lock(
+ buff,
+ buffer->omxBuffer.attr.anwBuffer.usage,
+ rect,
+ fence,
+ &error,
+ &data);
+ EXPECT_EQ(error, Error::NONE);
+ if (error != Error::NONE)
+ return 1;
+
+ if (format == PixelFormat::BGRA_8888) {
+ char* ipBuffer = static_cast<char*>(data);
+ for (size_t y = rect.height; y > 0; --y) {
+ eleStream.read(ipBuffer, rect.width * 4);
+ if (eleStream.gcount() != rect.width * 4) return 1;
+ ipBuffer += buffer->omxBuffer.attr.anwBuffer.stride * 4;
+ }
+ } else {
+ EXPECT_TRUE(false) << "un expected pixel format";
+ return 1;
+ }
+
+ mapper.mMapper->unlock(
+ buff,
+ [&](Error _e, const android::hardware::hidl_handle& _n1) {
+ error = _e;
+ fence = _n1;
+ });
+ EXPECT_EQ(error, Error::NONE);
+ if (error != Error::NONE)
+ return 1;
+ }
+
+ return 0;
+ }, mapperVar);
}
int fillGraphicBuffer(BufferInfo* buffer, PixelFormat format,
std::ifstream& eleStream) {
- sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
- android::hardware::graphics::mapper::V2_0::IMapper::getService();
- EXPECT_NE(mapper.get(), nullptr);
- if (mapper.get() == nullptr) return 1;
-
- void* buff = nullptr;
- android::hardware::graphics::mapper::V2_0::Error error;
- mapper->importBuffer(
- buffer->omxBuffer.nativeHandle,
- [&](android::hardware::graphics::mapper::V2_0::Error _e, void* _n1) {
- error = _e;
- buff = _n1;
- });
- EXPECT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE);
- if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
+ MapperVar mapperVar;
+ if (!initialize(mapperVar)) {
+ EXPECT_TRUE(false) << "failed to obtain mapper service";
return 1;
+ }
- if (colorFormatConversion(buffer, buff, format, eleStream)) return 1;
+ return std::visit([buffer, format, &eleStream](auto&& mapper) -> int {
+ using Gralloc = std::remove_reference_t<decltype(mapper)>;
+ using Error = typename Gralloc::Error;
- error = mapper->freeBuffer(buff);
- EXPECT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE);
- if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
- return 1;
+ void* buff = nullptr;
+ Error error;
+ mapper.mMapper->importBuffer(
+ buffer->omxBuffer.nativeHandle,
+ [&](Error _e, void* _n1) {
+ error = _e;
+ buff = _n1;
+ });
+ EXPECT_EQ(error, Error::NONE);
+ if (error != Error::NONE)
+ return 1;
- return 0;
+ if (colorFormatConversion(buffer, buff, format, eleStream)) return 1;
+
+ error = mapper.mMapper->freeBuffer(buff);
+ EXPECT_EQ(error, Error::NONE);
+ if (error != Error::NONE)
+ return 1;
+
+ return 0;
+ }, mapperVar);
}
int dispatchGraphicBuffer(sp<IOmxNode> omxNode,
diff --git a/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc b/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc
index 4327a20..f5eee54 100644
--- a/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc
+++ b/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.memtrack-hal-1-0 /vendor/bin/hw/android.hardware.memtrack@1.0-service
+ interface android.hardware.memtrack@1.0::IMemtrack default
class hal
user system
group system
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 0fb18f1..a8406de 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -15,21 +15,19 @@
//
cc_library_static {
- name: "VtsHalNeuralnetworksTest_utils",
+ name: "VtsHalNeuralNetworksV1_0_utils",
srcs: [
"Callbacks.cpp",
- "GeneratedTestHarness.cpp",
+ "Utils.cpp",
],
defaults: ["VtsHalTargetTestDefaults"],
- export_include_dirs: ["."],
+ export_include_dirs: ["include"],
shared_libs: [
"libfmq",
"libnativewindow",
],
static_libs: [
"android.hardware.neuralnetworks@1.0",
- "android.hardware.neuralnetworks@1.1",
- "android.hardware.neuralnetworks@1.2",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libgmock",
@@ -44,12 +42,13 @@
}
cc_defaults {
- name: "VtsHalNeuralNetworksTargetTestDefaults",
+ name: "VtsHalNeuralNetworksV1_0TargetTestDefaults",
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"ValidateModel.cpp",
"ValidateRequest.cpp",
"VtsHalNeuralnetworks.cpp",
+ "GeneratedTestHarness.cpp",
],
shared_libs: [
"libfmq",
@@ -57,14 +56,12 @@
],
static_libs: [
"android.hardware.neuralnetworks@1.0",
- "android.hardware.neuralnetworks@1.1",
- "android.hardware.neuralnetworks@1.2",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libgmock",
"libhidlmemory",
"libneuralnetworks_utils",
- "VtsHalNeuralnetworksTest_utils",
+ "VtsHalNeuralNetworksV1_0_utils",
],
header_libs: [
"libneuralnetworks_headers",
@@ -76,19 +73,19 @@
cc_test {
name: "VtsHalNeuralnetworksV1_0TargetTest",
- defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"],
srcs: [
"BasicTests.cpp",
- "GeneratedTests.cpp",
+ ":VtsHalNeuralNetworksV1_0_all_generated_V1_0_tests",
],
}
cc_test {
name: "PresubmitHalNeuralnetworksV1_0TargetTest",
- defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"],
srcs: [
"BasicTests.cpp",
- "GeneratedTests.cpp",
+ ":VtsHalNeuralNetworksV1_0_all_generated_V1_0_tests",
],
cflags: [
"-DPRESUBMIT_NOT_VTS",
diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.cpp b/neuralnetworks/1.0/vts/functional/Callbacks.cpp
index c30702c..37afcf0 100644
--- a/neuralnetworks/1.0/vts/functional/Callbacks.cpp
+++ b/neuralnetworks/1.0/vts/functional/Callbacks.cpp
@@ -14,160 +14,78 @@
* limitations under the License.
*/
-#include "Callbacks.h"
+#define LOG_TAG "Callbacks"
+
+#include "1.0/Callbacks.h"
+
#include <android-base/logging.h>
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace implementation {
+namespace android::hardware::neuralnetworks::V1_0::implementation {
-CallbackBase::CallbackBase() : mNotified(false) {}
-
-CallbackBase::~CallbackBase() {
- // Note that we cannot call CallbackBase::join_thread from here:
- // CallbackBase is intended to be reference counted, and it is possible that
- // the reference count drops to zero in the bound thread, causing the
- // bound thread to call this destructor. If a thread tries to join
- // itself, it throws an exception, producing a message like the
- // following:
- //
- // terminating with uncaught exception of type std::__1::system_error:
- // thread::join failed: Resource deadlock would occur
-}
-
-void CallbackBase::wait() {
- std::unique_lock<std::mutex> lock(mMutex);
- mCondition.wait(lock, [this]{return mNotified;});
- join_thread_locked();
-}
-
-bool CallbackBase::on_finish(std::function<bool(void)> post_work) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (mPostWork != nullptr) {
- LOG(ERROR) << "CallbackBase::on_finish -- a post-work function has already been bound to "
- "this callback object";
- return false;
- }
- if (post_work == nullptr) {
- LOG(ERROR) << "CallbackBase::on_finish -- the new post-work function is invalid";
- return false;
- }
- mPostWork = std::move(post_work);
- return true;
-}
-
-bool CallbackBase::bind_thread(std::thread&& asyncThread) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (mThread.joinable()) {
- LOG(ERROR) << "CallbackBase::bind_thread -- a thread has already been bound to this "
- "callback object";
- return false;
- }
- if (!asyncThread.joinable()) {
- LOG(ERROR) << "CallbackBase::bind_thread -- the new thread is not joinable";
- return false;
- }
- mThread = std::move(asyncThread);
- return true;
-}
-
-void CallbackBase::join_thread() {
- std::lock_guard<std::mutex> lock(mMutex);
- join_thread_locked();
-}
-
-void CallbackBase::notify() {
- {
- std::lock_guard<std::mutex> lock(mMutex);
- mNotified = true;
- if (mPostWork != nullptr) {
- bool success = mPostWork();
- if (!success) {
- LOG(ERROR) << "CallbackBase::notify -- post work failed";
- }
- }
- }
- mCondition.notify_all();
-}
-
-void CallbackBase::join_thread_locked() {
- if (mThread.joinable()) {
- mThread.join();
- }
-}
-
-PreparedModelCallback::PreparedModelCallback() :
- mErrorStatus(ErrorStatus::GENERAL_FAILURE), mPreparedModel(nullptr) {}
-
-PreparedModelCallback::~PreparedModelCallback() {}
+// PreparedModelCallback methods begin here
Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus,
- const sp<V1_0::IPreparedModel>& preparedModel) {
- mErrorStatus = errorStatus;
- mPreparedModel = preparedModel;
- CallbackBase::notify();
+ const sp<IPreparedModel>& preparedModel) {
+ {
+ std::lock_guard<std::mutex> hold(mMutex);
+
+ // quick-return if object has already been notified
+ if (mNotified) {
+ return Void();
+ }
+
+ // store results and mark as notified
+ mErrorStatus = errorStatus;
+ mPreparedModel = preparedModel;
+ mNotified = true;
+ }
+
+ mCondition.notify_all();
return Void();
}
-Return<void> PreparedModelCallback::notify_1_2(ErrorStatus errorStatus,
- const sp<V1_2::IPreparedModel>& preparedModel) {
- mErrorStatus = errorStatus;
- mPreparedModel = preparedModel;
- CallbackBase::notify();
- return Void();
+void PreparedModelCallback::wait() const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondition.wait(lock, [this] { return mNotified; });
}
-ErrorStatus PreparedModelCallback::getStatus() {
+ErrorStatus PreparedModelCallback::getStatus() const {
wait();
return mErrorStatus;
}
-sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() {
+sp<IPreparedModel> PreparedModelCallback::getPreparedModel() const {
wait();
return mPreparedModel;
}
-ExecutionCallback::ExecutionCallback() : mErrorStatus(ErrorStatus::GENERAL_FAILURE) {}
-
-ExecutionCallback::~ExecutionCallback() {}
+// ExecutionCallback methods begin here
Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) {
- mErrorStatus = errorStatus;
- mOutputShapes = {};
- mTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
- CallbackBase::notify();
+ {
+ std::lock_guard<std::mutex> hold(mMutex);
+
+ // quick-return if object has already been notified
+ if (mNotified) {
+ return Void();
+ }
+
+ mErrorStatus = errorStatus;
+ mNotified = true;
+ }
+ mCondition.notify_all();
+
return Void();
}
-Return<void> ExecutionCallback::notify_1_2(ErrorStatus errorStatus,
- const hidl_vec<OutputShape>& outputShapes,
- const Timing& timing) {
- mErrorStatus = errorStatus;
- mOutputShapes = outputShapes;
- mTiming = timing;
- CallbackBase::notify();
- return Void();
+void ExecutionCallback::wait() const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondition.wait(lock, [this] { return mNotified; });
}
-ErrorStatus ExecutionCallback::getStatus() {
+ErrorStatus ExecutionCallback::getStatus() const {
wait();
return mErrorStatus;
}
-const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() {
- wait();
- return mOutputShapes;
-}
-
-Timing ExecutionCallback::getTiming() {
- wait();
- return mTiming;
-}
-
-} // namespace implementation
-} // namespace V1_2
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::neuralnetworks::V1_0::implementation
diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.h b/neuralnetworks/1.0/vts/functional/Callbacks.h
deleted file mode 100644
index 4707d0a..0000000
--- a/neuralnetworks/1.0/vts/functional/Callbacks.h
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (C) 2018 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_NEURALNETWORKS_V1_0_CALLBACKS_H
-#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
-
-#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
-#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include <chrono>
-#include <condition_variable>
-#include <functional>
-#include <mutex>
-#include <thread>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace implementation {
-
-using V1_0::ErrorStatus;
-
-/**
- * The CallbackBase class is used internally by the NeuralNetworks runtime to
- * synchronize between different threads. An asynchronous task is launched
- * paired with a callback object. When a client thread requires the output being
- * generated by the asynchronous task, the client thread can wait for the result
- * and be blocked until it has completed or a timeout condition has been
- * reached. Any wait* may safely be called concurrently, even on the same
- * callback object. When the asynchronous task has finished its workload, it
- * must immediately call "notify". If the asynchronous task has failed to launch,
- * the function that tried to launch the asynchronous task must immediately call
- * "notify". This "notify" call awakens any client threads waiting on the
- * callback object.
- *
- * The CallbackBase class implements some of the base synchronization common to
- * both PrepareModelCallback and ExecutionCallback. For consistency, any HIDL
- * callback class must inherit from CallbackBase as well as the HIDL callback
- * interface it implements.
- *
- * This class exists to enable synchronization across HIDL. When synchronization
- * is only required in the same process, consider using std::future, std::mutex,
- * std::condition_variable, or std::experimental::latch instead.
- */
-class CallbackBase {
- public:
- CallbackBase();
- ~CallbackBase();
-
- /**
- * CallbackBase::wait blocks until notify has been called on the callback
- * object.
- */
- void wait();
-
- /**
- * CallbackBase::wait_for blocks until notify has been called on the
- * callback object or the time duration from the time the wait_for function
- * was called has expired, whichever comes first.
- *
- * @return Status std::cv_status::no_timeout if the callback was notified
- * before the time duration expired, std::cv_status::timeout
- * otherwise.
- */
- template<class Rep, class Period>
- std::cv_status wait_for(const std::chrono::duration<Rep,Period>& timeout_duration);
-
- /**
- * CallbackBase::on_finish binds a function to the callback object. This
- * bound function will be executed when CallbackBase::notify is called,
- * before any calls to wait* return. (Note that CallbackBase::wait_for can
- * return std::cv_status::timeout before CallbackBase::notify is called for
- * the first time, and hence before the bound function is executed.)
- *
- * The bound function must not synchronize with or otherwise access the
- * callback object it is bound to, as this could cause a deadlock.
- *
- * CallbackBase::on_finish can be called at most once on a given callback
- * object, and the call to CallbackBase::on_finish must finish before
- * CallbackBase::notify is called.
- *
- * @param post_work Function to be invoked the first time
- * CallbackBase::notify is called. Must have a target --
- * i.e., must not compare equal to nullptr. post_work
- * returns true if it successfully completes, false if it
- * fails.
- * @return bool True if the function was successfully bound, false if
- * unsuccessful.
- *
- * TODO: Why does the return value of the callback matter?
- */
- bool on_finish(std::function<bool(void)> post_work);
-
- /**
- * CallbackBase::bind_thread binds a thread to the event for later use by
- * CallbackBase::join_thread.
- *
- * The thread must be passed using std::move.
- *
- * Once a thread is bound with CallbackBase::bind_thread, the client code
- * should ensure that one of the following occurs before the event is
- * destroyed:
- * - CallbackBase::join_thread has been called.
- * - CallbackBase::wait has been called.
- * - CallbackBase::wait_for has been called and returned other than
- * std::cv_status::no_timeout.
- *
- * The bound thread shall not call any CallbackBase method with the
- * exception of CallbackBase::notify, which it must call when the thread has
- * finished its computation.
- *
- * CallbackBase::bind_thread can be called at most once on a given callback
- * object.
- *
- * @param asyncThread Thread to be bound to the callback object. The thread
- * object must represent a thread of execution -- i.e.,
- * asyncThread.joinable() must be true.
- * @return bool True if successful, false if thread was not properly bound.
- */
- bool bind_thread(std::thread&& asyncThread);
-
- /**
- * CallbackBase::join_thread ensures that the thread (if any) bound to this
- * event with CallbackBase::bind_thread has fully finished and cleaned its
- * resources. It is legal to call this function multiple times, concurrently
- * or sequentially.
- */
- void join_thread();
-
- protected:
- /**
- * CallbackBase::notify enables all prior and future wait* calls on the
- * callback object to proceed. The call to CallbackBase::notify happens
- * before any wait* calls on this callback object return (except in the case
- * of wait_for timing out). The asynchronous call the callback object is
- * paired with must ensure that any update to state that should be visible
- * to the caller of wait* happens before the call to CallbackBase::notify.
- *
- * CallbackBase::notify must be called exactly once on a given callback
- * object.
- */
- void notify();
-
- private:
- // Same as CallbackBase::join_thread but assumes we already hold a lock on
- // mMutex.
- void join_thread_locked();
-
- bool mNotified;
- std::mutex mMutex;
- std::condition_variable mCondition;
- std::function<bool(void)> mPostWork;
- std::thread mThread;
-};
-
-/**
- * The PreparedModelCallback class is used to receive the error status of
- * preparing a model as well as the prepared model from a task executing
- * asynchronously with respect to the runtime. If a calling thread calls wait*
- * or get* on a PreparedModelCallback object and the corresponding asynchronous
- * task has not finished preparing the model, the calling thread will block
- * until the asynchronous task has either called notify or notify_1_2. For more
- * information on the synchronization behavior, refer to the CallbackBase class.
- *
- * This class inherits the basic blocking and signaling calls from
- * CallbackBase, and implements the HIDL notify and notify_1_2 calls from
- * IPreparedModelCallback. This callback object is passed as an argument to
- * IDevice::prepareModel.
- */
-class PreparedModelCallback : public CallbackBase, public IPreparedModelCallback {
- public:
- PreparedModelCallback();
- ~PreparedModelCallback() override;
-
- /**
- * IPreparedModelCallback::notify and IPreparedModelCallback::notify_1_2
- * mark the callback object with the return status of the asynchronous
- * model preparation along with the prepared model, and call
- * CallbackBase::notify, enabling all prior and future wait* calls on the
- * PreparedModelCallback object to proceed. For more information on the
- * synchronization behavior, refer to the CallbackBase class.
- *
- * Either IPreparedModelCallback::notify or IPreparedModelCallback::notify_1_2
- * must be called exactly once on a given PreparedModelCallback object.
- *
- * @param status Error status returned from asynchronously preparing the
- * model; will be:
- * - NONE if the asynchronous preparation was successful
- * - DEVICE_UNAVAILABLE if driver is offline or busy
- * - GENERAL_FAILURE if there is an unspecified error
- * - INVALID_ARGUMENT if the input model is invalid
- * @param preparedModel Returned model that has been prepared for execution,
- * nullptr if the model was unable to be prepared.
- */
- Return<void> notify(ErrorStatus status, const sp<V1_0::IPreparedModel>& preparedModel) override;
- Return<void> notify_1_2(ErrorStatus status,
- const sp<V1_2::IPreparedModel>& preparedModel) override;
-
- /**
- * Retrieves the error status returned from the asynchronous task launched
- * by IDevice::prepareModel. If IDevice::prepareModel has not finished
- * asynchronously preparing the model, this call will block until the
- * asynchronous task notifies the object.
- *
- * @return status Error status returned from asynchronously preparing the
- * model; will be:
- * - NONE if the asynchronous preparation was successful
- * - DEVICE_UNAVAILABLE if driver is offline or busy
- * - GENERAL_FAILURE if there is an unspecified error
- * - INVALID_ARGUMENT if the input model is invalid
- */
- ErrorStatus getStatus();
-
- /**
- * Retrieves the model that has been prepared for execution from the
- * asynchronous task launched by IDevice::prepareModel. If
- * IDevice::prepareModel has not finished asynchronously preparing the
- * model, this call will block until the asynchronous task notifies the
- * object.
- *
- * @return preparedModel Returned model that has been prepared for
- * execution, nullptr if the model was unable to be
- * prepared.
- */
- sp<V1_0::IPreparedModel> getPreparedModel();
-
- private:
- ErrorStatus mErrorStatus;
- sp<V1_0::IPreparedModel> mPreparedModel;
-};
-
-/**
- * The ExecutionCallback class is used to receive the error status of the
- * execution from a task executing asynchronously with respect to the runtime.
- * If a calling thread calls wait* or get* on a PreparedModelCallback object and
- * the corresponding asynchronous task has not finished the execution, the
- * calling thread will block until the asynchronous task has either called notify
- * or notify_1_2. For more information on the synchronization behavior, refer to
- * the CallbackBase class.
- *
- * This class inherits the basic blocking and signaling calls from
- * CallbackBase, and implements the HIDL notify and notify_1_2 calls from
- * IExecutionCallback. This callback object is passed as an argument to
- * IPreparedModel::execute.
- */
-class ExecutionCallback : public CallbackBase, public IExecutionCallback {
- public:
- ExecutionCallback();
- ~ExecutionCallback() override;
-
- /**
- * IExecutionCallback::notify and IExecutionCallback::notify_1_2 mark the
- * callback object with the return status of the asynchronous execution that
- * held this callback and enable all prior and future wait* calls on the
- * ExecutionCallback object to proceed. For more information on the
- * synchronization behavior, refer to the CallbackBase class.
- *
- * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must
- * be called exactly once on a given ExecutionCallback object.
- *
- * @param status Error status returned from launching the asynchronous task
- * (if the launch fails) or from the asynchronous task itself
- * (if the launch succeeds). Must be:
- * - NONE if the asynchronous execution was successful
- * - DEVICE_UNAVAILABLE if driver is offline or busy
- * - GENERAL_FAILURE if there is an unspecified error
- * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is
- * not large enough to store the resultant values
- * - INVALID_ARGUMENT if the input request is invalid
- */
- Return<void> notify(ErrorStatus status) override;
-
- /**
- * Similar to IExecutionCallback::notify, but for V1_2::IPreparedModel to
- * also notify output shapes along with error status.
- *
- * @param status Error status returned from launching the asynchronous task
- * (if the launch fails) or from the asynchronous task itself
- * (if the launch succeeds). 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
- * - OUTPUT_INSUFFICIENT_SIZE if at least one output
- * operand buffer is not large enough to store the
- * corresponding output
- * - INVALID_ARGUMENT if one of the input arguments to
- * prepareModel is invalid
- * @param outputShapes A list of shape information of model output operands.
- * The index into "outputShapes" corresponds to the index
- * of the output operand in the Request outputs vector.
- * outputShapes must be empty unless the status is either
- * NONE or OUTPUT_INSUFFICIENT_SIZE.
- * @return Timing Duration of execution. 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<void> notify_1_2(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
- const Timing& timing) override;
-
- // An overload of the latest notify interface to hide the version from ExecutionBuilder.
- Return<void> notify(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
- const Timing& timing) {
- return notify_1_2(status, outputShapes, timing);
- }
-
- /**
- * Retrieves the error status returned from the asynchronous task launched
- * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If
- * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished
- * asynchronously executing, this call will block until the asynchronous task
- * notifies the object.
- *
- * @return status Error status returned from launching the asynchronous task
- * (if the launch fails) or from the asynchronous task itself
- * (if the launch succeeds). 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
- * - OUTPUT_INSUFFICIENT_SIZE if at least one output
- * operand buffer is not large enough to store the
- * corresponding output
- * - INVALID_ARGUMENT if one of the input arguments to
- * prepareModel is invalid
- */
- ErrorStatus getStatus();
-
- /**
- * Retrieves the output shapes returned from the asynchronous task launched
- * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not finished
- * asynchronously executing, this call will block until the asynchronous task
- * notifies the object.
- *
- * If the asynchronous task was launched by IPreparedModel::execute, an empty vector
- * will be returned.
- *
- * @return outputShapes A list of shape information of model output operands.
- * The index into "outputShapes" corresponds to the index
- * of the output operand in the Request outputs vector.
- * outputShapes must be empty unless the status is either
- * NONE or OUTPUT_INSUFFICIENT_SIZE.
- */
- const std::vector<OutputShape>& getOutputShapes();
-
- /**
- * Retrieves the duration of execution ofthe asynchronous task launched
- * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not finished
- * asynchronously executing, this call will block until the asynchronous task
- * notifies the object.
- *
- * If the asynchronous task was launched by IPreparedModel::execute, every time
- * must be UINT64_MAX.
- *
- * @return timing Duration of the execution. Every time must be UINT64_MAX unless
- * the status is NONE.
- */
- Timing getTiming();
-
- private:
- ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
- std::vector<OutputShape> mOutputShapes = {};
- Timing mTiming = {};
-};
-
-
-// template function implementation(s) below this point
-
-template<class Rep, class Period>
-std::cv_status CallbackBase::wait_for(const std::chrono::duration<Rep,Period>& timeout_duration) {
- std::unique_lock<std::mutex> lock(mMutex);
- std::cv_status status = mCondition.wait_for(lock, timeout_duration, [this]{return mNotified;});
- if (status != std::cv_status::timeout) {
- join_thread_locked();
- }
- return status;
-}
-
-} // namespace implementation
-} // namespace V1_2
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index c819b52..40d2f4c 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -15,129 +15,48 @@
*/
#include "GeneratedTestHarness.h"
-#include "Callbacks.h"
-#include "ExecutionBurstController.h"
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
+#include "MemoryUtils.h"
#include "TestHarness.h"
-#include "Utils.h"
#include <android-base/logging.h>
#include <android/hardware/neuralnetworks/1.0/IDevice.h>
-#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
#include <android/hardware/neuralnetworks/1.0/types.h>
-#include <android/hardware/neuralnetworks/1.1/IDevice.h>
-#include <android/hardware/neuralnetworks/1.2/IDevice.h>
-#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
-#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
+
#include <iostream>
namespace android {
namespace hardware {
namespace neuralnetworks {
-
+namespace V1_0 {
namespace generated_tests {
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::test_helper::bool8;
+
+using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
+using ::android::hardware::neuralnetworks::V1_0::IDevice;
+using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
+using ::android::hardware::neuralnetworks::V1_0::Model;
+using ::android::hardware::neuralnetworks::V1_0::Request;
+using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::hidl::memory::V1_0::IMemory;
using ::test_helper::compare;
-using ::test_helper::expectMultinomialDistributionWithinTolerance;
using ::test_helper::filter;
using ::test_helper::for_all;
-using ::test_helper::for_each;
using ::test_helper::MixedTyped;
using ::test_helper::MixedTypedExample;
using ::test_helper::resize_accordingly;
-using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
-
-template <typename T>
-void copy_back_(std::map<int, std::vector<T>>* dst, const std::vector<RequestArgument>& ra,
- char* src) {
- for_each<T>(*dst, [&ra, src](int index, std::vector<T>& m) {
- ASSERT_EQ(m.size(), ra[index].location.length / sizeof(T));
- char* begin = src + ra[index].location.offset;
- memcpy(m.data(), begin, ra[index].location.length);
- });
-}
-
-void copy_back(MixedTyped* dst, const std::vector<RequestArgument>& ra, char* src) {
- copy_back_(&dst->float32Operands, ra, src);
- copy_back_(&dst->int32Operands, ra, src);
- copy_back_(&dst->quant8AsymmOperands, ra, src);
- copy_back_(&dst->quant16SymmOperands, ra, src);
- copy_back_(&dst->float16Operands, ra, src);
- copy_back_(&dst->bool8Operands, ra, src);
- copy_back_(&dst->quant8ChannelOperands, ra, src);
- copy_back_(&dst->quant16AsymmOperands, ra, src);
- copy_back_(&dst->quant8SymmOperands, ra, src);
- static_assert(9 == MixedTyped::kNumTypes,
- "Number of types in MixedTyped changed, but copy_back function wasn't updated");
-}
-
-static bool isZeroSized(const MixedTyped& example, uint32_t index) {
- for (auto i : example.operandDimensions.at(index)) {
- if (i == 0) return true;
- }
- return false;
-}
// Top level driver for models and examples generated by test_generator.py
// Test driver for those generated from ml/nn/runtime/test/spec
-static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>& preparedModel,
- const Request& request, MeasureTiming,
- sp<ExecutionCallback>& callback) {
- return preparedModel->execute(request, callback);
-}
-static Return<ErrorStatus> ExecutePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
- const Request& request, MeasureTiming measure,
- sp<ExecutionCallback>& callback) {
- return preparedModel->execute_1_2(request, measure, callback);
-}
-static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>&, const Request&,
- MeasureTiming, hidl_vec<OutputShape>*, Timing*) {
- ADD_FAILURE() << "asking for synchronous execution at V1_0";
- return ErrorStatus::GENERAL_FAILURE;
-}
-static Return<ErrorStatus> ExecutePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
- const Request& request, MeasureTiming measure,
- hidl_vec<OutputShape>* outputShapes,
- Timing* timing) {
- ErrorStatus result;
- Return<void> ret = preparedModel->executeSynchronously(
- request, measure,
- [&result, outputShapes, timing](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
- const Timing& time) {
- result = error;
- *outputShapes = shapes;
- *timing = time;
- });
- if (!ret.isOk()) {
- return ErrorStatus::GENERAL_FAILURE;
- }
- return result;
-}
-static std::unique_ptr<::android::nn::ExecutionBurstController> CreateBurst(
- const sp<V1_0::IPreparedModel>&) {
- ADD_FAILURE() << "asking for burst execution at V1_0";
- return nullptr;
-}
-static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst(
- const sp<V1_2::IPreparedModel>& preparedModel) {
- return ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
-}
-enum class Executor { ASYNC, SYNC, BURST };
-enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
-const float kDefaultAtol = 1e-5f;
-const float kDefaultRtol = 1e-5f;
-template <typename T_IPreparedModel>
-void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExample>& examples,
- bool hasRelaxedFloat32Model, float fpAtol, float fpRtol,
- Executor executor, MeasureTiming measure, OutputType outputType) {
+void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
+ const std::vector<MixedTypedExample>& examples, float fpAtol,
+ float fpRtol) {
const uint32_t INPUT = 0;
const uint32_t OUTPUT = 1;
@@ -147,14 +66,7 @@
const MixedTyped& inputs = example.operands.first;
const MixedTyped& golden = example.operands.second;
- const bool hasFloat16Inputs = !inputs.float16Operands.empty();
- if (hasRelaxedFloat32Model || hasFloat16Inputs) {
- // TODO: Adjust the error limit based on testing.
- // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16.
- fpAtol = 5.0f * 0.0009765625f;
- // Set the relative tolerance to be 5ULP of the corresponding FP precision.
- fpRtol = 5.0f * 0.0009765625f;
- }
+ CHECK(inputs.float16Operands.empty()) << "float16 is not supported in 1.0";
std::vector<RequestArgument> inputs_info, outputs_info;
uint32_t inputSize = 0, outputSize = 0;
@@ -163,11 +75,13 @@
for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
RequestArgument arg = {
- .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
- .dimensions = {},
+ .location = {.poolIndex = INPUT,
+ .offset = 0,
+ .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
};
RequestArgument arg_empty = {
- .hasNoValue = true,
+ .hasNoValue = true,
};
inputs_info[index] = s ? arg : arg_empty;
inputSize += s;
@@ -185,31 +99,17 @@
// Go through all outputs, initialize RequestArgument descriptors
resize_accordingly(golden, test);
- bool sizeLargerThanOne = true;
- for_all(golden, [&golden, &outputs_info, &outputSize, &outputType, &sizeLargerThanOne](
- int index, auto, auto s) {
+ for_all(golden, [&outputs_info, &outputSize](int index, auto, auto s) {
if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
- if (index == 0) {
- // On OutputType::INSUFFICIENT, set the output operand with index 0 with
- // buffer size one byte less than needed.
- if (outputType == OutputType::INSUFFICIENT) {
- if (s > 1 && !isZeroSized(golden, index)) {
- s -= 1;
- } else {
- sizeLargerThanOne = false;
- }
- }
- }
RequestArgument arg = {
- .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
- .dimensions = {},
+ .location = {.poolIndex = OUTPUT,
+ .offset = 0,
+ .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
};
outputs_info[index] = arg;
outputSize += s;
});
- // If output0 does not have size larger than one byte,
- // we can not provide an insufficient buffer
- if (!sizeLargerThanOne && outputType == OutputType::INSUFFICIENT) return;
// Compute offset for outputs 1 and so on
{
size_t offset = 0;
@@ -248,107 +148,17 @@
const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools};
- ErrorStatus executionStatus;
- hidl_vec<OutputShape> outputShapes;
- Timing timing;
- switch (executor) {
- case Executor::ASYNC: {
- SCOPED_TRACE("asynchronous");
+ // launch execution
+ sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+ ASSERT_NE(nullptr, executionCallback.get());
+ Return<ErrorStatus> executionLaunchStatus =
+ preparedModel->execute(request, executionCallback);
+ ASSERT_TRUE(executionLaunchStatus.isOk());
+ EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
- // launch execution
- sp<ExecutionCallback> executionCallback = new ExecutionCallback();
- ASSERT_NE(nullptr, executionCallback.get());
- Return<ErrorStatus> executionLaunchStatus =
- ExecutePreparedModel(preparedModel, request, measure, executionCallback);
- ASSERT_TRUE(executionLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
-
- // retrieve execution status
- executionCallback->wait();
- executionStatus = executionCallback->getStatus();
- outputShapes = executionCallback->getOutputShapes();
- timing = executionCallback->getTiming();
-
- break;
- }
- case Executor::SYNC: {
- SCOPED_TRACE("synchronous");
-
- // execute
- Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
- preparedModel, request, measure, &outputShapes, &timing);
- ASSERT_TRUE(executionReturnStatus.isOk());
- executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
-
- break;
- }
- case Executor::BURST: {
- SCOPED_TRACE("burst");
-
- // create burst
- const std::shared_ptr<::android::nn::ExecutionBurstController> controller =
- CreateBurst(preparedModel);
- ASSERT_NE(nullptr, controller.get());
-
- // create memory keys
- std::vector<intptr_t> keys(request.pools.size());
- for (size_t i = 0; i < keys.size(); ++i) {
- keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
- }
-
- // execute burst
- std::tie(executionStatus, outputShapes, timing) =
- controller->compute(request, measure, keys);
-
- break;
- }
- }
-
- if (outputType != OutputType::FULLY_SPECIFIED &&
- executionStatus == ErrorStatus::GENERAL_FAILURE) {
- LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
- "execute model that it does not support.";
- std::cout << "[ ] Early termination of test because vendor service cannot "
- "execute model that it does not support."
- << std::endl;
- GTEST_SKIP();
- }
- if (measure == MeasureTiming::NO) {
- EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
- EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
- } else {
- if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) {
- EXPECT_LE(timing.timeOnDevice, timing.timeInDriver);
- }
- }
-
- switch (outputType) {
- case OutputType::FULLY_SPECIFIED:
- // If the model output operands are fully specified, outputShapes must be either
- // either empty, or have the same number of elements as the number of outputs.
- ASSERT_EQ(ErrorStatus::NONE, executionStatus);
- ASSERT_TRUE(outputShapes.size() == 0 ||
- outputShapes.size() == test.operandDimensions.size());
- break;
- case OutputType::UNSPECIFIED:
- // If the model output operands are not fully specified, outputShapes must have
- // the same number of elements as the number of outputs.
- ASSERT_EQ(ErrorStatus::NONE, executionStatus);
- ASSERT_EQ(outputShapes.size(), test.operandDimensions.size());
- break;
- case OutputType::INSUFFICIENT:
- ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
- ASSERT_EQ(outputShapes.size(), test.operandDimensions.size());
- ASSERT_FALSE(outputShapes[0].isSufficient);
- return;
- }
- // Go through all outputs, overwrite output dimensions with returned output shapes
- if (outputShapes.size() > 0) {
- for_each<uint32_t>(test.operandDimensions,
- [&outputShapes](int idx, std::vector<uint32_t>& dim) {
- dim = outputShapes[idx].dimensions;
- });
- }
+ // retrieve execution status
+ executionCallback->wait();
+ ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
// validate results
outputMemory->read();
@@ -360,89 +170,22 @@
// We want "close-enough" results for float
compare(filtered_golden, filtered_test, fpAtol, fpRtol);
-
- if (example.expectedMultinomialDistributionTolerance > 0) {
- expectMultinomialDistributionWithinTolerance(test, example);
- }
- }
-}
-template <typename T_IPreparedModel>
-void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExample>& examples,
- bool hasRelaxedFloat32Model, Executor executor, MeasureTiming measure,
- OutputType outputType) {
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, kDefaultAtol,
- kDefaultRtol, executor, measure, outputType);
-}
-
-void EvaluatePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
- std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExample>& examples,
- bool hasRelaxedFloat32Model, bool testDynamicOutputShape) {
- if (testDynamicOutputShape) {
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::ASYNC, MeasureTiming::NO, OutputType::UNSPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::SYNC, MeasureTiming::NO, OutputType::UNSPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::BURST, MeasureTiming::NO, OutputType::UNSPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::ASYNC, MeasureTiming::YES, OutputType::UNSPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::SYNC, MeasureTiming::YES, OutputType::UNSPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::BURST, MeasureTiming::YES, OutputType::UNSPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::ASYNC, MeasureTiming::NO, OutputType::INSUFFICIENT);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::SYNC, MeasureTiming::NO, OutputType::INSUFFICIENT);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::BURST, MeasureTiming::NO, OutputType::INSUFFICIENT);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::ASYNC, MeasureTiming::YES, OutputType::INSUFFICIENT);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::SYNC, MeasureTiming::YES, OutputType::INSUFFICIENT);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::BURST, MeasureTiming::YES, OutputType::INSUFFICIENT);
- } else {
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::ASYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::SYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::BURST, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::ASYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::SYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::BURST, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
}
}
-static void getPreparedModel(sp<PreparedModelCallback> callback,
- sp<V1_0::IPreparedModel>* preparedModel) {
- *preparedModel = callback->getPreparedModel();
-}
-static void getPreparedModel(sp<PreparedModelCallback> callback,
- sp<V1_2::IPreparedModel>* preparedModel) {
- sp<V1_0::IPreparedModel> preparedModelV1_0 = callback->getPreparedModel();
- *preparedModel = V1_2::IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr);
-}
-
-void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model,
+void Execute(const sp<IDevice>& device, std::function<Model(void)> create_model,
std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
- V1_0::Model model = create_model();
+ Model model = create_model();
// see if service can handle model
bool fullySupportsModel = false;
Return<void> supportedCall = device->getSupportedOperations(
- model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
- ASSERT_EQ(ErrorStatus::NONE, status);
- ASSERT_NE(0ul, supported.size());
- fullySupportsModel =
- std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
- });
+ model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
+ ASSERT_EQ(ErrorStatus::NONE, status);
+ ASSERT_NE(0ul, supported.size());
+ fullySupportsModel = std::all_of(supported.begin(), supported.end(),
+ [](bool valid) { return valid; });
+ });
ASSERT_TRUE(supportedCall.isOk());
// launch prepare model
@@ -455,8 +198,7 @@
// retrieve prepared model
preparedModelCallback->wait();
ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
- sp<V1_0::IPreparedModel> preparedModel;
- getPreparedModel(preparedModelCallback, &preparedModel);
+ sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
// early termination if vendor service cannot fully prepare model
if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
@@ -472,115 +214,11 @@
ASSERT_NE(nullptr, preparedModel.get());
float fpAtol = 1e-5f, fpRtol = 5.0f * 1.1920928955078125e-7f;
- EvaluatePreparedModel(preparedModel, is_ignored, examples,
- /*hasRelaxedFloat32Model=*/false, fpAtol, fpRtol, Executor::ASYNC,
- MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
-}
-
-void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
- std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
- V1_1::Model model = create_model();
-
- // see if service can handle model
- bool fullySupportsModel = false;
- Return<void> supportedCall = device->getSupportedOperations_1_1(
- model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
- ASSERT_EQ(ErrorStatus::NONE, status);
- ASSERT_NE(0ul, supported.size());
- fullySupportsModel =
- std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
- });
- ASSERT_TRUE(supportedCall.isOk());
-
- // launch prepare model
- sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
- model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
- ASSERT_TRUE(prepareLaunchStatus.isOk());
- ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
-
- // retrieve prepared model
- preparedModelCallback->wait();
- ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
- sp<V1_0::IPreparedModel> preparedModel;
- getPreparedModel(preparedModelCallback, &preparedModel);
-
- // early termination if vendor service cannot fully prepare model
- if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
- ASSERT_EQ(nullptr, preparedModel.get());
- LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
- "prepare model that it does not support.";
- std::cout << "[ ] Early termination of test because vendor service cannot "
- "prepare model that it does not support."
- << std::endl;
- GTEST_SKIP();
- }
- EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
- ASSERT_NE(nullptr, preparedModel.get());
-
- EvaluatePreparedModel(preparedModel, is_ignored, examples,
- model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f, Executor::ASYNC,
- MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
-}
-
-void PrepareModel(const sp<V1_2::IDevice>& device, const V1_2::Model& model,
- sp<V1_2::IPreparedModel>* preparedModel) {
- // see if service can handle model
- bool fullySupportsModel = false;
- Return<void> supportedCall = device->getSupportedOperations_1_2(
- model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
- ASSERT_EQ(ErrorStatus::NONE, status);
- ASSERT_NE(0ul, supported.size());
- fullySupportsModel =
- std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
- });
- ASSERT_TRUE(supportedCall.isOk());
-
- // launch prepare model
- sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_2(
- model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec<hidl_handle>(),
- hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
- ASSERT_TRUE(prepareLaunchStatus.isOk());
- ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
-
- // retrieve prepared model
- preparedModelCallback->wait();
- ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
- getPreparedModel(preparedModelCallback, preparedModel);
-
- // early termination if vendor service cannot fully prepare model
- if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
- ASSERT_EQ(nullptr, preparedModel->get());
- LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
- "prepare model that it does not support.";
- std::cout << "[ ] Early termination of test because vendor service cannot "
- "prepare model that it does not support."
- << std::endl;
- return;
- }
- EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
- ASSERT_NE(nullptr, preparedModel->get());
-}
-
-// TODO: Reduce code duplication.
-void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model,
- std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples,
- bool testDynamicOutputShape) {
- V1_2::Model model = create_model();
- sp<V1_2::IPreparedModel> preparedModel = nullptr;
- PrepareModel(device, model, &preparedModel);
- if (preparedModel == nullptr) {
- GTEST_SKIP();
- }
- EvaluatePreparedModel(preparedModel, is_ignored, examples,
- model.relaxComputationFloat32toFloat16, testDynamicOutputShape);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, fpAtol, fpRtol);
}
} // namespace generated_tests
-
+} // namespace V1_0
} // namespace neuralnetworks
} // namespace hardware
} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
index c7d2399..337eb0f 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
@@ -14,44 +14,27 @@
* limitations under the License.
*/
-#ifndef VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H
-#define VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H
-
-#include "TestHarness.h"
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H
#include <android/hardware/neuralnetworks/1.0/IDevice.h>
-#include <android/hardware/neuralnetworks/1.1/IDevice.h>
-#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include "TestHarness.h"
namespace android {
namespace hardware {
namespace neuralnetworks {
-
+namespace V1_0 {
namespace generated_tests {
+
using ::test_helper::MixedTypedExample;
-void PrepareModel(const sp<V1_2::IDevice>& device, const V1_2::Model& model,
- sp<V1_2::IPreparedModel>* preparedModel);
-
-void EvaluatePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
- std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExample>& examples,
- bool hasRelaxedFloat32Model, bool testDynamicOutputShape);
-
void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model,
std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples);
-void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
- std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples);
-
-void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model,
- std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples,
- bool testDynamicOutputShape = false);
-
} // namespace generated_tests
-
+} // namespace V1_0
} // namespace neuralnetworks
} // namespace hardware
} // namespace android
-#endif // VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H
+#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp
deleted file mode 100644
index d1c7de3..0000000
--- a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "GeneratedTestHarness.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
-
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_0_vts_tests.cpp"
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_0
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.h b/neuralnetworks/1.0/vts/functional/GeneratedTests.h
new file mode 100644
index 0000000..11ee5e8
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTests.h
@@ -0,0 +1,38 @@
+/*
+ * 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/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+#include "GeneratedTestHarness.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_0::vts::functional {
+
+std::vector<Request> createRequests(const std::vector<::test_helper::MixedTypedExample>& examples);
+
+} // namespace android::hardware::neuralnetworks::V1_0::vts::functional
+
+namespace android::hardware::neuralnetworks::V1_0::generated_tests {
+
+using namespace android::hardware::neuralnetworks::V1_0::vts::functional;
+
+using ::android::hardware::neuralnetworks::V1_0::Model;
+using ::android::hardware::neuralnetworks::V1_0::Request;
+
+} // namespace android::hardware::neuralnetworks::V1_0::generated_tests
diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp
new file mode 100644
index 0000000..521e524
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/Utils.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 "GeneratedTestHarness.h"
+#include "TestHarness.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+
+#include <cstring>
+#include <map>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+
+using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
+using ::test_helper::for_each;
+using ::test_helper::MixedTyped;
+
+template <typename T>
+void copy_back_(std::map<int, std::vector<T>>* dst, const std::vector<RequestArgument>& ra,
+ char* src) {
+ for_each<T>(*dst, [&ra, src](int index, std::vector<T>& m) {
+ ASSERT_EQ(m.size(), ra[index].location.length / sizeof(T));
+ char* begin = src + ra[index].location.offset;
+ memcpy(m.data(), begin, ra[index].location.length);
+ });
+}
+
+void copy_back(MixedTyped* dst, const std::vector<RequestArgument>& ra, char* src) {
+ copy_back_(&dst->float32Operands, ra, src);
+ copy_back_(&dst->int32Operands, ra, src);
+ copy_back_(&dst->quant8AsymmOperands, ra, src);
+ copy_back_(&dst->quant16SymmOperands, ra, src);
+ copy_back_(&dst->float16Operands, ra, src);
+ copy_back_(&dst->bool8Operands, ra, src);
+ copy_back_(&dst->quant8ChannelOperands, ra, src);
+ copy_back_(&dst->quant16AsymmOperands, ra, src);
+ copy_back_(&dst->quant8SymmOperands, ra, src);
+ static_assert(9 == MixedTyped::kNumTypes,
+ "Number of types in MixedTyped changed, but copy_back function wasn't updated");
+}
+
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
index 5d24fb5..72c4a2b 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
@@ -18,7 +18,7 @@
#include "VtsHalNeuralnetworks.h"
-#include "Callbacks.h"
+#include "1.0/Callbacks.h"
namespace android {
namespace hardware {
@@ -27,8 +27,8 @@
namespace vts {
namespace functional {
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
///////////////////////// UTILITY FUNCTIONS /////////////////////////
diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
index f0c93b7..058eb25 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
@@ -16,16 +16,15 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
#include <android-base/logging.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
+#include "1.0/Callbacks.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
+
namespace android {
namespace hardware {
namespace neuralnetworks {
@@ -33,7 +32,7 @@
namespace vts {
namespace functional {
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hidl::memory::V1_0::IMemory;
using test_helper::for_all;
using test_helper::MixedTyped;
@@ -121,11 +120,13 @@
for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
RequestArgument arg = {
- .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
- .dimensions = {},
+ .location = {.poolIndex = INPUT,
+ .offset = 0,
+ .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
};
RequestArgument arg_empty = {
- .hasNoValue = true,
+ .hasNoValue = true,
};
inputs_info[index] = s ? arg : arg_empty;
inputSize += s;
@@ -143,8 +144,10 @@
for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
RequestArgument arg = {
- .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
- .dimensions = {},
+ .location = {.poolIndex = OUTPUT,
+ .offset = 0,
+ .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
};
outputs_info[index] = arg;
outputSize += s;
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
index aee2f85..95b7ad3 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
@@ -20,7 +20,7 @@
#include <android-base/logging.h>
-#include "Callbacks.h"
+#include "1.0/Callbacks.h"
namespace android {
namespace hardware {
@@ -29,7 +29,7 @@
namespace vts {
namespace functional {
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
static void createPreparedModel(const sp<IDevice>& device, const V1_0::Model& model,
sp<IPreparedModel>* preparedModel) {
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
index 22285be..c32a91d 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H
-#define VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H
#include <android/hardware/neuralnetworks/1.0/IDevice.h>
#include <android/hardware/neuralnetworks/1.0/types.h>
@@ -89,4 +89,4 @@
} // namespace android::hardware::neuralnetworks::V1_0
-#endif // VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H
+#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H
diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h b/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h
new file mode 100644
index 0000000..820bb10
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2018 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_NEURALNETWORKS_V1_0_CALLBACKS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
+
+#include <android-base/thread_annotations.h>
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <hidl/Status.h>
+#include <condition_variable>
+#include <mutex>
+
+/*
+ * The Callback classes are used internally by the NeuralNetworks runtime to
+ * synchronize between different threads. An asynchronous task is launched
+ * paired with a callback object. When a client thread requires the output being
+ * generated by the asynchronous task, the client thread can wait for the result
+ * and be blocked until it has completed. Any wait may safely be called
+ * concurrently, even on the same callback object. When the asynchronous task
+ * has finished its workload, it must immediately call "notify". If the
+ * asynchronous task has failed to launch, the function that tried to launch the
+ * asynchronous task must immediately call "notify". This "notify" call
+ * awakens any client threads waiting on the callback object.
+ *
+ * These classes exist to enable synchronization across HIDL. When
+ * synchronization is only required in the same process, consider using
+ * std::future, std::mutex, std::condition_variable, or std::experimental::latch
+ * instead.
+ */
+
+namespace android::hardware::neuralnetworks::V1_0::implementation {
+
+/**
+ * The PreparedModelCallback class is used to receive the error status of
+ * preparing a model as well as the prepared model from a task executing
+ * asynchronously with respect to the runtime. If a calling thread calls wait
+ * or get* on a PreparedModelCallback object and the corresponding asynchronous
+ * task has not finished preparing the model, the calling thread will block
+ * until the asynchronous task has called notify.
+ *
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IDevice::prepareModel*.
+ */
+class PreparedModelCallback : public IPreparedModelCallback {
+ public:
+ /**
+ * IPreparedModelCallback::notify marks the callback object with the return
+ * status of the asynchronous model preparation along with the prepared
+ * model, and allows all prior and future wait calls on the
+ * PreparedModelCallback object to proceed.
+ *
+ * IPreparedModelCallback::notify must be called on a given
+ * PreparedModelCallback object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify are used, and the results from subsequent calls
+ * are discarded.
+ *
+ * @param status Error status returned from asynchronously preparing the
+ * model; will be:
+ * - NONE if the asynchronous preparation was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if the input model is invalid
+ * @param preparedModel Returned model that has been prepared for execution,
+ * nullptr if the model was unable to be prepared.
+ */
+ Return<void> notify(ErrorStatus status, const sp<IPreparedModel>& preparedModel) override;
+
+ /**
+ * PreparedModelCallback::wait blocks until notify has been called on the
+ * callback object.
+ */
+ void wait() const;
+
+ /**
+ * Retrieves the error status returned from the asynchronous task launched
+ * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished
+ * asynchronously preparing the model, this call will block until the
+ * asynchronous task notifies the object.
+ *
+ * @return status Error status returned from asynchronously preparing the
+ * model; will be:
+ * - NONE if the asynchronous preparation was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if the input model is invalid
+ */
+ ErrorStatus getStatus() const;
+
+ /**
+ * Retrieves the model that has been prepared for execution from the
+ * asynchronous task launched by IDevice::prepareModel*. If
+ * IDevice::prepareModel* has not finished asynchronously preparing the
+ * model, this call will block until the asynchronous task notifies the
+ * object.
+ *
+ * @return preparedModel Returned model that has been prepared for
+ * execution, nullptr if the model was unable to be prepared.
+ */
+ sp<IPreparedModel> getPreparedModel() const;
+
+ private:
+ mutable std::mutex mMutex;
+ mutable std::condition_variable mCondition;
+ bool mNotified GUARDED_BY(mMutex) = false;
+ ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
+ sp<IPreparedModel> mPreparedModel;
+};
+
+/**
+ * The ExecutionCallback class is used to receive the results of the execution
+ * from a task executing asynchronously with respect to the runtime. If a
+ * calling thread calls wait or get* on a ExecutionCallback object and the
+ * corresponding asynchronous task has not finished the execution, the calling
+ * thread will block until the asynchronous task has called notify.
+ *
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IPreparedModel::execute*.
+ */
+class ExecutionCallback : public IExecutionCallback {
+ public:
+ /**
+ * IExecutionCallback::notify marks the callback object with the return
+ * status of the asynchronous execution that held this callback and enables
+ * all prior and future wait calls on the ExecutionCallback object to
+ * proceed.
+ *
+ * IExecutionCallback::notify must be called on a given ExecutionCallback
+ * object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify are used, and the results from subsequent calls
+ * are discarded.
+ *
+ * @param status Error status returned from launching the asynchronous task
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). Must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large
+ * enough to store the resultant values
+ * - INVALID_ARGUMENT if the input request is invalid
+ */
+ Return<void> notify(ErrorStatus status) override;
+
+ /**
+ * ExecutionCallback::wait blocks until notify has been called on the
+ * callback object.
+ */
+ void wait() const;
+
+ /**
+ * Retrieves the error status returned from the asynchronous task launched
+ * by IPreparedModel::execute. If IPreparedModel::execute has not finished
+ * asynchronously executing, this call will block until the asynchronous
+ * task notifies the object.
+ *
+ * @return status Error status returned from launching the asynchronous task
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). 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
+ * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is
+ * not large enough to store the corresponding output
+ * - INVALID_ARGUMENT if one of the input arguments to prepareModel is
+ * invalid
+ */
+ ErrorStatus getStatus() const;
+
+ private:
+ mutable std::mutex mMutex;
+ mutable std::condition_variable mCondition;
+ bool mNotified GUARDED_BY(mMutex) = false;
+ ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
+};
+
+} // namespace android::hardware::neuralnetworks::V1_0::implementation
+
+#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
new file mode 100644
index 0000000..b270c20
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <algorithm>
+#include <vector>
+#include "TestHarness.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+
+void copy_back(::test_helper::MixedTyped* dst, const std::vector<V1_0::RequestArgument>& ra,
+ char* src);
+
+// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
+// so this is efficiently accomplished by moving the element to the end and
+// resizing the hidl_vec to one less.
+template <typename Type>
+inline void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
+ if (vec) {
+ std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
+ vec->resize(vec->size() - 1);
+ }
+}
+
+template <typename Type>
+inline uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
+ // assume vec is valid
+ const uint32_t index = vec->size();
+ vec->resize(index + 1);
+ (*vec)[index] = value;
+ return index;
+}
+
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index 4fbeac9..1b31008 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -14,31 +14,62 @@
// limitations under the License.
//
+cc_defaults {
+ name: "VtsHalNeuralNetworksV1_1TargetTestDefaults",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "ValidateModel.cpp",
+ "ValidateRequest.cpp",
+ "VtsHalNeuralnetworks.cpp",
+ "GeneratedTestHarness.cpp",
+ ],
+ shared_libs: [
+ "libfmq",
+ "libnativewindow",
+ ],
+ static_libs: [
+ "android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libgmock",
+ "libhidlmemory",
+ "libneuralnetworks_utils",
+ "VtsHalNeuralNetworksV1_0_utils",
+ ],
+ header_libs: [
+ "libneuralnetworks_headers",
+ "libneuralnetworks_generated_test_harness_headers",
+ "libneuralnetworks_generated_tests",
+ ],
+ test_suites: ["general-tests"],
+}
+
// Tests for V1_0 models using the V1_1 HAL.
cc_test {
name: "VtsHalNeuralnetworksV1_1CompatV1_0TargetTest",
- defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"],
srcs: [
- "GeneratedTestsV1_0.cpp",
+ ":VtsHalNeuralNetworksV1_1_all_generated_V1_0_tests",
],
}
// Tests for V1_1 models.
cc_test {
name: "VtsHalNeuralnetworksV1_1TargetTest",
- defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"],
srcs: [
"BasicTests.cpp",
- "GeneratedTests.cpp",
+ ":VtsHalNeuralNetworksV1_1_all_generated_V1_1_tests",
],
}
cc_test {
name: "PresubmitHalNeuralnetworksV1_1TargetTest",
- defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"],
srcs: [
"BasicTests.cpp",
- "GeneratedTests.cpp",
+ ":VtsHalNeuralNetworksV1_1_all_generated_V1_1_tests",
],
cflags: [
"-DPRESUBMIT_NOT_VTS",
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
new file mode 100644
index 0000000..e7d59ec
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
@@ -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.
+ */
+
+#include "GeneratedTestHarness.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+#include <iostream>
+
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+namespace generated_tests {
+
+using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
+using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
+using ::android::hardware::neuralnetworks::V1_0::Request;
+using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference;
+using ::android::hardware::neuralnetworks::V1_1::IDevice;
+using ::android::hardware::neuralnetworks::V1_1::Model;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::test_helper::compare;
+using ::test_helper::filter;
+using ::test_helper::for_all;
+using ::test_helper::MixedTyped;
+using ::test_helper::MixedTypedExample;
+using ::test_helper::resize_accordingly;
+
+// Top level driver for models and examples generated by test_generator.py
+// Test driver for those generated from ml/nn/runtime/test/spec
+void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
+ const std::vector<MixedTypedExample>& examples,
+ bool hasRelaxedFloat32Model, float fpAtol, float fpRtol) {
+ const uint32_t INPUT = 0;
+ const uint32_t OUTPUT = 1;
+
+ int example_no = 1;
+ for (auto& example : examples) {
+ SCOPED_TRACE(example_no++);
+ const MixedTyped& inputs = example.operands.first;
+ const MixedTyped& golden = example.operands.second;
+
+ const bool hasFloat16Inputs = !inputs.float16Operands.empty();
+ if (hasRelaxedFloat32Model || hasFloat16Inputs) {
+ // TODO: Adjust the error limit based on testing.
+ // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16.
+ fpAtol = 5.0f * 0.0009765625f;
+ // Set the relative tolerance to be 5ULP of the corresponding FP precision.
+ fpRtol = 5.0f * 0.0009765625f;
+ }
+
+ std::vector<RequestArgument> inputs_info, outputs_info;
+ uint32_t inputSize = 0, outputSize = 0;
+ // This function only partially specifies the metadata (vector of RequestArguments).
+ // The contents are copied over below.
+ for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
+ if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
+ RequestArgument arg = {
+ .location = {.poolIndex = INPUT,
+ .offset = 0,
+ .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
+ };
+ RequestArgument arg_empty = {
+ .hasNoValue = true,
+ };
+ inputs_info[index] = s ? arg : arg_empty;
+ inputSize += s;
+ });
+ // Compute offset for inputs 1 and so on
+ {
+ size_t offset = 0;
+ for (auto& i : inputs_info) {
+ if (!i.hasNoValue) i.location.offset = offset;
+ offset += i.location.length;
+ }
+ }
+
+ MixedTyped test; // holding test results
+
+ // Go through all outputs, initialize RequestArgument descriptors
+ resize_accordingly(golden, test);
+ for_all(golden, [&outputs_info, &outputSize](int index, auto, auto s) {
+ if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
+ RequestArgument arg = {
+ .location = {.poolIndex = OUTPUT,
+ .offset = 0,
+ .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
+ };
+ outputs_info[index] = arg;
+ outputSize += s;
+ });
+ // Compute offset for outputs 1 and so on
+ {
+ size_t offset = 0;
+ for (auto& i : outputs_info) {
+ i.location.offset = offset;
+ offset += i.location.length;
+ }
+ }
+ std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
+ nn::allocateSharedMemory(outputSize)};
+ ASSERT_NE(0ull, pools[INPUT].size());
+ ASSERT_NE(0ull, pools[OUTPUT].size());
+
+ // load data
+ sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
+ sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
+ ASSERT_NE(nullptr, inputMemory.get());
+ ASSERT_NE(nullptr, outputMemory.get());
+ char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
+ char* outputPtr = reinterpret_cast<char*>(static_cast<void*>(outputMemory->getPointer()));
+ ASSERT_NE(nullptr, inputPtr);
+ ASSERT_NE(nullptr, outputPtr);
+ inputMemory->update();
+ outputMemory->update();
+
+ // Go through all inputs, copy the values
+ for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
+ char* begin = (char*)p;
+ char* end = begin + s;
+ // TODO: handle more than one input
+ std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
+ });
+
+ inputMemory->commit();
+ outputMemory->commit();
+
+ const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools};
+
+ // launch execution
+ sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+ ASSERT_NE(nullptr, executionCallback.get());
+ Return<ErrorStatus> executionLaunchStatus =
+ preparedModel->execute(request, executionCallback);
+ ASSERT_TRUE(executionLaunchStatus.isOk());
+ EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
+
+ // retrieve execution status
+ executionCallback->wait();
+ ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
+
+ // validate results
+ outputMemory->read();
+ copy_back(&test, outputs_info, outputPtr);
+ outputMemory->commit();
+ // Filter out don't cares
+ MixedTyped filtered_golden = filter(golden, is_ignored);
+ MixedTyped filtered_test = filter(test, is_ignored);
+
+ // We want "close-enough" results for float
+ compare(filtered_golden, filtered_test, fpAtol, fpRtol);
+ }
+}
+
+void Execute(const sp<IDevice>& device, std::function<Model(void)> create_model,
+ std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
+ Model model = create_model();
+
+ // see if service can handle model
+ bool fullySupportsModel = false;
+ Return<void> supportedCall = device->getSupportedOperations_1_1(
+ model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
+ ASSERT_EQ(ErrorStatus::NONE, status);
+ ASSERT_NE(0ul, supported.size());
+ fullySupportsModel = std::all_of(supported.begin(), supported.end(),
+ [](bool valid) { return valid; });
+ });
+ ASSERT_TRUE(supportedCall.isOk());
+
+ // launch prepare model
+ sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+ ASSERT_NE(nullptr, preparedModelCallback.get());
+ Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
+ model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
+ ASSERT_TRUE(prepareLaunchStatus.isOk());
+ ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+ // retrieve prepared model
+ preparedModelCallback->wait();
+ ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+ sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
+
+ // early termination if vendor service cannot fully prepare model
+ if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
+ ASSERT_EQ(nullptr, preparedModel.get());
+ LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+ "prepare model that it does not support.";
+ std::cout << "[ ] Early termination of test because vendor service cannot "
+ "prepare model that it does not support."
+ << std::endl;
+ GTEST_SKIP();
+ }
+ EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+ ASSERT_NE(nullptr, preparedModel.get());
+
+ EvaluatePreparedModel(preparedModel, is_ignored, examples,
+ model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f);
+}
+
+} // namespace generated_tests
+} // namespace V1_1
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
new file mode 100644
index 0000000..64b88dd
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H
+
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <functional>
+#include <vector>
+#include "TestHarness.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+namespace generated_tests {
+
+void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
+ std::function<bool(int)> is_ignored,
+ const std::vector<::test_helper::MixedTypedExample>& examples);
+
+} // namespace generated_tests
+} // namespace V1_1
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp
deleted file mode 100644
index 4db1276..0000000
--- a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "GeneratedTestHarness.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
-
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_1_vts_tests.cpp"
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_1
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.h b/neuralnetworks/1.1/vts/functional/GeneratedTests.h
new file mode 100644
index 0000000..2343a4f
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTests.h
@@ -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 <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+#include "GeneratedTestHarness.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_1::vts::functional {
+
+std::vector<Request> createRequests(const std::vector<::test_helper::MixedTypedExample>& examples);
+
+} // namespace android::hardware::neuralnetworks::V1_1::vts::functional
+
+namespace android::hardware::neuralnetworks::V1_1::generated_tests {
+
+using namespace android::hardware::neuralnetworks::V1_1::vts::functional;
+
+using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
+using ::android::hardware::neuralnetworks::V1_0::Request;
+using ::android::hardware::neuralnetworks::V1_1::Model;
+
+} // namespace android::hardware::neuralnetworks::V1_1::generated_tests
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp
deleted file mode 100644
index e67ef8e..0000000
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "GeneratedTestHarness.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
-
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_0_vts_tests.cpp"
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_1
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
index b35a901..fb80d13 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
@@ -16,25 +16,22 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
#include "VtsHalNeuralnetworks.h"
-#include "Callbacks.h"
-
namespace android {
namespace hardware {
namespace neuralnetworks {
namespace V1_1 {
-
-using V1_0::IPreparedModel;
-using V1_0::Operand;
-using V1_0::OperandLifeTime;
-using V1_0::OperandType;
-
namespace vts {
namespace functional {
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
+using ::android::hardware::neuralnetworks::V1_0::Operand;
+using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
+using ::android::hardware::neuralnetworks::V1_0::OperandType;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
///////////////////////// UTILITY FUNCTIONS /////////////////////////
@@ -42,10 +39,10 @@
const V1_1::Model& model) {
SCOPED_TRACE(message + " [getSupportedOperations_1_1]");
- Return<void> ret =
- device->getSupportedOperations_1_1(model, [&](ErrorStatus status, const hidl_vec<bool>&) {
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
- });
+ Return<void> ret = device->getSupportedOperations_1_1(
+ model, [&](ErrorStatus status, const hidl_vec<bool>&) {
+ EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+ });
EXPECT_TRUE(ret.isOk());
}
@@ -56,7 +53,7 @@
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
ASSERT_NE(nullptr, preparedModelCallback.get());
Return<ErrorStatus> prepareLaunchStatus =
- device->prepareModel_1_1(model, preference, preparedModelCallback);
+ device->prepareModel_1_1(model, preference, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
@@ -87,36 +84,16 @@
validatePrepareModel(device, message, model, preference);
}
-// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
-// so this is efficiently accomplished by moving the element to the end and
-// resizing the hidl_vec to one less.
-template <typename Type>
-static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
- if (vec) {
- std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
- vec->resize(vec->size() - 1);
- }
-}
-
-template <typename Type>
-static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
- // assume vec is valid
- const uint32_t index = vec->size();
- vec->resize(index + 1);
- (*vec)[index] = value;
- return index;
-}
-
static uint32_t addOperand(Model* model) {
return hidl_vec_push_back(&model->operands,
{
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 0,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_INPUT,
- .location = {.poolIndex = 0, .offset = 0, .length = 0},
+ .type = OperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 0,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::MODEL_INPUT,
+ .location = {.poolIndex = 0, .offset = 0, .length = 0},
});
}
@@ -130,10 +107,10 @@
///////////////////////// VALIDATE MODEL OPERAND TYPE /////////////////////////
static const int32_t invalidOperandTypes[] = {
- static_cast<int32_t>(OperandType::FLOAT32) - 1, // lower bound fundamental
- static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1, // upper bound fundamental
- static_cast<int32_t>(OperandType::OEM) - 1, // lower bound OEM
- static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM
+ static_cast<int32_t>(OperandType::FLOAT32) - 1, // lower bound fundamental
+ static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1, // upper bound fundamental
+ static_cast<int32_t>(OperandType::OEM) - 1, // lower bound OEM
+ static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM
};
static void mutateOperandTypeTest(const sp<IDevice>& device, const V1_1::Model& model) {
@@ -226,7 +203,7 @@
static void mutateOperandZeroPointTest(const sp<IDevice>& device, const V1_1::Model& model) {
for (size_t operand = 0; operand < model.operands.size(); ++operand) {
const std::vector<int32_t> invalidZeroPoints =
- getInvalidZeroPoints(model.operands[operand].type);
+ getInvalidZeroPoints(model.operands[operand].type);
for (int32_t invalidZeroPoint : invalidZeroPoints) {
const std::string message = "mutateOperandZeroPointTest: operand " +
std::to_string(operand) + " has zero point of " +
@@ -258,18 +235,18 @@
break;
case OperandType::TENSOR_FLOAT32:
newOperand.dimensions =
- operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
newOperand.scale = 0.0f;
newOperand.zeroPoint = 0;
break;
case OperandType::TENSOR_INT32:
newOperand.dimensions =
- operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
newOperand.zeroPoint = 0;
break;
case OperandType::TENSOR_QUANT8_ASYMM:
newOperand.dimensions =
- operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
break;
case OperandType::OEM:
@@ -319,10 +296,10 @@
///////////////////////// VALIDATE MODEL OPERATION TYPE /////////////////////////
static const int32_t invalidOperationTypes[] = {
- static_cast<int32_t>(OperationType::ADD) - 1, // lower bound fundamental
- static_cast<int32_t>(OperationType::TRANSPOSE) + 1, // upper bound fundamental
- static_cast<int32_t>(OperationType::OEM_OPERATION) - 1, // lower bound OEM
- static_cast<int32_t>(OperationType::OEM_OPERATION) + 1, // upper bound OEM
+ static_cast<int32_t>(OperationType::ADD) - 1, // lower bound fundamental
+ static_cast<int32_t>(OperationType::TRANSPOSE) + 1, // upper bound fundamental
+ static_cast<int32_t>(OperationType::OEM_OPERATION) - 1, // lower bound OEM
+ static_cast<int32_t>(OperationType::OEM_OPERATION) + 1, // upper bound OEM
};
static void mutateOperationTypeTest(const sp<IDevice>& device, const V1_1::Model& model) {
@@ -333,7 +310,7 @@
std::to_string(invalidOperationType);
validate(device, message, model, [operation, invalidOperationType](Model* model) {
model->operations[operation].type =
- static_cast<OperationType>(invalidOperationType);
+ static_cast<OperationType>(invalidOperationType);
});
}
}
@@ -486,7 +463,7 @@
static void addOperationOutputTest(const sp<IDevice>& device, const V1_1::Model& model) {
for (size_t operation = 0; operation < model.operations.size(); ++operation) {
const std::string message =
- "addOperationOutputTest: operation " + std::to_string(operation);
+ "addOperationOutputTest: operation " + std::to_string(operation);
validate(device, message, model, [operation](Model* model) {
uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
hidl_vec_push_back(&model->operations[operation].outputs, index);
@@ -498,14 +475,14 @@
///////////////////////// VALIDATE EXECUTION PREFERENCE /////////////////////////
static const int32_t invalidExecutionPreferences[] = {
- static_cast<int32_t>(ExecutionPreference::LOW_POWER) - 1, // lower bound
- static_cast<int32_t>(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound
+ static_cast<int32_t>(ExecutionPreference::LOW_POWER) - 1, // lower bound
+ static_cast<int32_t>(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound
};
static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const V1_1::Model& model) {
for (int32_t preference : invalidExecutionPreferences) {
const std::string message =
- "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
+ "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
validate(device, message, model, [](Model*) {},
static_cast<ExecutionPreference>(preference));
}
diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
index f4adbab..c549728 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
@@ -16,16 +16,16 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
#include <android-base/logging.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
+#include "1.0/Callbacks.h"
+#include "1.0/Utils.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "VtsHalNeuralnetworks.h"
+
namespace android {
namespace hardware {
namespace neuralnetworks {
@@ -33,11 +33,15 @@
namespace vts {
namespace functional {
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
+using ::android::hardware::neuralnetworks::V1_0::Request;
+using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_1::IPreparedModel;
using ::android::hidl::memory::V1_0::IMemory;
-using test_helper::for_all;
-using test_helper::MixedTyped;
-using test_helper::MixedTypedExample;
+using ::test_helper::for_all;
+using ::test_helper::MixedTyped;
+using ::test_helper::MixedTypedExample;
///////////////////////// UTILITY FUNCTIONS /////////////////////////
@@ -61,26 +65,6 @@
ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
}
-// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
-// so this is efficiently accomplished by moving the element to the end and
-// resizing the hidl_vec to one less.
-template <typename Type>
-static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
- if (vec) {
- std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
- vec->resize(vec->size() - 1);
- }
-}
-
-template <typename Type>
-static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
- // assume vec is valid
- const uint32_t index = vec->size();
- vec->resize(index + 1);
- (*vec)[index] = value;
- return index;
-}
-
///////////////////////// REMOVE INPUT ////////////////////////////////////
static void removeInputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
@@ -121,11 +105,13 @@
for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
RequestArgument arg = {
- .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
- .dimensions = {},
+ .location = {.poolIndex = INPUT,
+ .offset = 0,
+ .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
};
RequestArgument arg_empty = {
- .hasNoValue = true,
+ .hasNoValue = true,
};
inputs_info[index] = s ? arg : arg_empty;
inputSize += s;
@@ -143,8 +129,10 @@
for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
RequestArgument arg = {
- .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
- .dimensions = {},
+ .location = {.poolIndex = OUTPUT,
+ .offset = 0,
+ .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
};
outputs_info[index] = arg;
outputSize += s;
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
index 08069f2..12bdd3f 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
@@ -20,7 +20,7 @@
#include <android-base/logging.h>
-#include "Callbacks.h"
+#include "1.0/Callbacks.h"
namespace android {
namespace hardware {
@@ -29,7 +29,7 @@
namespace vts {
namespace functional {
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
static void createPreparedModel(const sp<IDevice>& device, const V1_1::Model& model,
sp<IPreparedModel>* preparedModel) {
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
index f3f587b..3156784 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef VTS_HAL_NEURALNETWORKS_V1_1_H
-#define VTS_HAL_NEURALNETWORKS_V1_1_H
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H
#include <android/hardware/neuralnetworks/1.0/types.h>
#include <android/hardware/neuralnetworks/1.1/IDevice.h>
@@ -98,4 +98,4 @@
} // namespace android::hardware::neuralnetworks::V1_0
-#endif // VTS_HAL_NEURALNETWORKS_V1_1_H
+#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 6c26820..301ca5d 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -14,57 +14,82 @@
// limitations under the License.
//
+cc_defaults {
+ name: "VtsHalNeuralNetworksV1_2TargetTestDefaults",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "ValidateModel.cpp",
+ "ValidateRequest.cpp",
+ "VtsHalNeuralnetworks.cpp",
+ "Callbacks.cpp",
+ "GeneratedTestHarness.cpp",
+ ],
+ local_include_dirs: ["include"],
+ shared_libs: [
+ "libfmq",
+ "libnativewindow",
+ ],
+ static_libs: [
+ "android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
+ "android.hardware.neuralnetworks@1.2",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libgmock",
+ "libhidlmemory",
+ "libneuralnetworks_utils",
+ "VtsHalNeuralNetworksV1_0_utils",
+ ],
+ header_libs: [
+ "libneuralnetworks_headers",
+ "libneuralnetworks_generated_test_harness_headers",
+ "libneuralnetworks_generated_tests",
+ ],
+ test_suites: ["general-tests"],
+}
+
// Tests for V1_0 models using the V1_2 HAL.
cc_test {
name: "VtsHalNeuralnetworksV1_2CompatV1_0TargetTest",
- defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"],
srcs: [
- "GeneratedTestsV1_0.cpp",
+ ":VtsHalNeuralNetworksV1_2_all_generated_V1_0_tests",
"ValidateBurst.cpp",
],
- cflags: [
- "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE"
- ],
}
// Tests for V1_1 models using the V1_2 HAL.
cc_test {
name: "VtsHalNeuralnetworksV1_2CompatV1_1TargetTest",
- defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"],
srcs: [
- "GeneratedTestsV1_1.cpp",
+ ":VtsHalNeuralNetworksV1_2_all_generated_V1_1_tests",
"ValidateBurst.cpp",
],
- cflags: [
- "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE"
- ],
}
// Tests for V1_2 models.
cc_test {
name: "VtsHalNeuralnetworksV1_2TargetTest",
- defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"],
srcs: [
"BasicTests.cpp",
+ ":VtsHalNeuralNetworksV1_2_all_generated_V1_2_tests",
"CompilationCachingTests.cpp",
- "GeneratedTests.cpp",
+ ":VtsHalNeuralNetworksV1_2_mobilenets", // CompilationCachingTests depend on MobileNets.
"ValidateBurst.cpp",
],
- cflags: [
- "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE"
- ],
}
cc_test {
name: "PresubmitHalNeuralnetworksV1_2TargetTest",
- defaults: ["VtsHalNeuralNetworksTargetTestDefaults"],
+ defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"],
srcs: [
"BasicTests.cpp",
- "GeneratedTests.cpp",
+ ":VtsHalNeuralNetworksV1_2_all_generated_V1_2_tests",
"ValidateBurst.cpp",
],
cflags: [
- "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE",
"-DPRESUBMIT_NOT_VTS",
],
}
diff --git a/neuralnetworks/1.2/vts/functional/Callbacks.cpp b/neuralnetworks/1.2/vts/functional/Callbacks.cpp
new file mode 100644
index 0000000..a607a08
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/Callbacks.cpp
@@ -0,0 +1,141 @@
+/*
+ * 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 "Callbacks"
+
+#include "1.2/Callbacks.h"
+
+#include <android-base/logging.h>
+
+#include <limits>
+
+namespace android::hardware::neuralnetworks::V1_2::implementation {
+
+constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits<uint64_t>::max(),
+ .timeInDriver = std::numeric_limits<uint64_t>::max()};
+
+// PreparedModelCallback methods begin here
+
+Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus,
+ const sp<V1_0::IPreparedModel>& preparedModel) {
+ {
+ std::lock_guard<std::mutex> hold(mMutex);
+
+ // quick-return if object has already been notified
+ if (mNotified) {
+ return Void();
+ }
+
+ // store results and mark as notified
+ mErrorStatus = errorStatus;
+ mPreparedModel = preparedModel;
+ mNotified = true;
+ }
+
+ mCondition.notify_all();
+ return Void();
+}
+
+Return<void> PreparedModelCallback::notify_1_2(ErrorStatus errorStatus,
+ const sp<V1_2::IPreparedModel>& preparedModel) {
+ return notify(errorStatus, preparedModel);
+}
+
+void PreparedModelCallback::wait() const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondition.wait(lock, [this] { return mNotified; });
+}
+
+ErrorStatus PreparedModelCallback::getStatus() const {
+ wait();
+ return mErrorStatus;
+}
+
+sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() const {
+ wait();
+ return mPreparedModel;
+}
+
+// ExecutionCallback methods begin here
+
+Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) {
+ notifyInternal(errorStatus, {}, kNoTiming);
+ return Void();
+}
+
+Return<void> ExecutionCallback::notify_1_2(ErrorStatus errorStatus,
+ const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing) {
+ if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
+ // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE.
+ if (outputShapes.size() == 0) {
+ LOG(ERROR) << "Notified with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE";
+ notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming);
+ return Void();
+ }
+ } else if (errorStatus != ErrorStatus::NONE) {
+ // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE.
+ if (outputShapes.size() != 0) {
+ LOG(ERROR) << "Notified with non-empty output shape vector when error status is "
+ "neither NONE nor OUTPUT_INSUFFICIENT_SIZE";
+ notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming);
+ return Void();
+ }
+ }
+ notifyInternal(errorStatus, outputShapes, timing);
+ return Void();
+}
+
+void ExecutionCallback::wait() const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondition.wait(lock, [this] { return mNotified; });
+}
+
+ErrorStatus ExecutionCallback::getStatus() const {
+ wait();
+ return mErrorStatus;
+}
+
+const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() const {
+ wait();
+ return mOutputShapes;
+}
+
+Timing ExecutionCallback::getTiming() const {
+ wait();
+ return mTiming;
+}
+
+void ExecutionCallback::notifyInternal(ErrorStatus errorStatus,
+ const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing) {
+ {
+ std::lock_guard<std::mutex> hold(mMutex);
+
+ // quick-return if object has already been notified
+ if (mNotified) {
+ return;
+ }
+
+ mErrorStatus = errorStatus;
+ mOutputShapes = outputShapes;
+ mTiming = timing;
+ mNotified = true;
+ }
+ mCondition.notify_all();
+}
+
+} // namespace android::hardware::neuralnetworks::V1_2::implementation
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 4411b90..082d758 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -26,13 +26,32 @@
#include <cstdio>
#include <cstdlib>
#include <random>
+#include <thread>
-#include "Callbacks.h"
+#include "1.2/Callbacks.h"
#include "GeneratedTestHarness.h"
+#include "MemoryUtils.h"
#include "TestHarness.h"
#include "Utils.h"
#include "VtsHalNeuralnetworks.h"
+namespace android::hardware::neuralnetworks::V1_2::generated_tests::
+ mobilenet_224_gender_basic_fixed {
+Model createTestModel();
+} // namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_224_gender_basic_fixed
+
+namespace generated_tests::mobilenet_224_gender_basic_fixed {
+std::vector<test_helper::MixedTypedExample>& get_examples();
+} // namespace generated_tests::mobilenet_224_gender_basic_fixed
+
+namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_quantized {
+Model createTestModel();
+} // namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_quantized
+
+namespace generated_tests::mobilenet_quantized {
+std::vector<test_helper::MixedTypedExample>& get_examples();
+} // namespace generated_tests::mobilenet_quantized
+
namespace android {
namespace hardware {
namespace neuralnetworks {
@@ -40,20 +59,19 @@
namespace vts {
namespace functional {
+using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
+using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference;
using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+using ::android::hidl::memory::V1_0::IMemory;
using ::android::nn::allocateSharedMemory;
using ::test_helper::MixedTypedExample;
namespace float32_model {
-// In frameworks/ml/nn/runtime/test/generated/, creates a hidl model of float32 mobilenet.
-#include "examples/mobilenet_224_gender_basic_fixed.example.cpp"
-#include "vts_models/mobilenet_224_gender_basic_fixed.model.cpp"
-
-// Prevent the compiler from complaining about an otherwise unused function.
-[[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape;
-[[maybe_unused]] auto dummy_get_examples = get_examples_dynamic_output_shape;
+constexpr auto createTestModel = ::android::hardware::neuralnetworks::V1_2::generated_tests::
+ mobilenet_224_gender_basic_fixed::createTestModel;
+constexpr auto get_examples = ::generated_tests::mobilenet_224_gender_basic_fixed::get_examples;
// MixedTypedExample is defined in frameworks/ml/nn/tools/test_generator/include/TestHarness.h.
// This function assumes the operation is always ADD.
@@ -70,13 +88,9 @@
namespace quant8_model {
-// In frameworks/ml/nn/runtime/test/generated/, creates a hidl model of quant8 mobilenet.
-#include "examples/mobilenet_quantized.example.cpp"
-#include "vts_models/mobilenet_quantized.model.cpp"
-
-// Prevent the compiler from complaining about an otherwise unused function.
-[[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape;
-[[maybe_unused]] auto dummy_get_examples = get_examples_dynamic_output_shape;
+constexpr auto createTestModel = ::android::hardware::neuralnetworks::V1_2::generated_tests::
+ mobilenet_quantized::createTestModel;
+constexpr auto get_examples = ::generated_tests::mobilenet_quantized::get_examples;
// MixedTypedExample is defined in frameworks/ml/nn/tools/test_generator/include/TestHarness.h.
// This function assumes the operation is always ADD.
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
new file mode 100644
index 0000000..82cc73d
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -0,0 +1,458 @@
+/*
+ * 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 "GeneratedTestHarness.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/IDevice.h>
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+#include <iostream>
+
+#include "1.0/Utils.h"
+#include "1.2/Callbacks.h"
+#include "ExecutionBurstController.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_2 {
+namespace generated_tests {
+
+using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
+using ::android::hardware::neuralnetworks::V1_0::Request;
+using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
+using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference;
+using ::android::hardware::neuralnetworks::V1_2::Constant;
+using ::android::hardware::neuralnetworks::V1_2::IDevice;
+using ::android::hardware::neuralnetworks::V1_2::IPreparedModel;
+using ::android::hardware::neuralnetworks::V1_2::MeasureTiming;
+using ::android::hardware::neuralnetworks::V1_2::Model;
+using ::android::hardware::neuralnetworks::V1_2::OutputShape;
+using ::android::hardware::neuralnetworks::V1_2::Timing;
+using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::test_helper::compare;
+using ::test_helper::expectMultinomialDistributionWithinTolerance;
+using ::test_helper::filter;
+using ::test_helper::for_all;
+using ::test_helper::for_each;
+using ::test_helper::MixedTyped;
+using ::test_helper::MixedTypedExample;
+using ::test_helper::resize_accordingly;
+using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
+
+static bool isZeroSized(const MixedTyped& example, uint32_t index) {
+ for (auto i : example.operandDimensions.at(index)) {
+ if (i == 0) return true;
+ }
+ return false;
+}
+
+static Return<ErrorStatus> ExecutePreparedModel(sp<IPreparedModel>& preparedModel,
+ const Request& request, MeasureTiming measure,
+ sp<ExecutionCallback>& callback) {
+ return preparedModel->execute_1_2(request, measure, callback);
+}
+static Return<ErrorStatus> ExecutePreparedModel(sp<IPreparedModel>& preparedModel,
+ const Request& request, MeasureTiming measure,
+ hidl_vec<OutputShape>* outputShapes,
+ Timing* timing) {
+ ErrorStatus result;
+ Return<void> ret = preparedModel->executeSynchronously(
+ request, measure,
+ [&result, outputShapes, timing](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
+ const Timing& time) {
+ result = error;
+ *outputShapes = shapes;
+ *timing = time;
+ });
+ if (!ret.isOk()) {
+ return ErrorStatus::GENERAL_FAILURE;
+ }
+ return result;
+}
+static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst(
+ const sp<IPreparedModel>& preparedModel) {
+ return ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
+}
+enum class Executor { ASYNC, SYNC, BURST };
+enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
+const float kDefaultAtol = 1e-5f;
+const float kDefaultRtol = 1e-5f;
+void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
+ const std::vector<MixedTypedExample>& examples,
+ bool hasRelaxedFloat32Model, float fpAtol, float fpRtol,
+ Executor executor, MeasureTiming measure, OutputType outputType) {
+ const uint32_t INPUT = 0;
+ const uint32_t OUTPUT = 1;
+
+ int example_no = 1;
+ for (auto& example : examples) {
+ SCOPED_TRACE(example_no++);
+ const MixedTyped& inputs = example.operands.first;
+ const MixedTyped& golden = example.operands.second;
+
+ const bool hasFloat16Inputs = !inputs.float16Operands.empty();
+ if (hasRelaxedFloat32Model || hasFloat16Inputs) {
+ // TODO: Adjust the error limit based on testing.
+ // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16.
+ fpAtol = 5.0f * 0.0009765625f;
+ // Set the relative tolerance to be 5ULP of the corresponding FP precision.
+ fpRtol = 5.0f * 0.0009765625f;
+ }
+
+ std::vector<RequestArgument> inputs_info, outputs_info;
+ uint32_t inputSize = 0, outputSize = 0;
+ // This function only partially specifies the metadata (vector of RequestArguments).
+ // The contents are copied over below.
+ for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
+ if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
+ RequestArgument arg = {
+ .location = {.poolIndex = INPUT,
+ .offset = 0,
+ .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
+ };
+ RequestArgument arg_empty = {
+ .hasNoValue = true,
+ };
+ inputs_info[index] = s ? arg : arg_empty;
+ inputSize += s;
+ });
+ // Compute offset for inputs 1 and so on
+ {
+ size_t offset = 0;
+ for (auto& i : inputs_info) {
+ if (!i.hasNoValue) i.location.offset = offset;
+ offset += i.location.length;
+ }
+ }
+
+ MixedTyped test; // holding test results
+
+ // Go through all outputs, initialize RequestArgument descriptors
+ resize_accordingly(golden, test);
+ bool sizeLargerThanOne = true;
+ for_all(golden, [&golden, &outputs_info, &outputSize, &outputType, &sizeLargerThanOne](
+ int index, auto, auto s) {
+ if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
+ if (index == 0) {
+ // On OutputType::INSUFFICIENT, set the output operand with index 0 with
+ // buffer size one byte less than needed.
+ if (outputType == OutputType::INSUFFICIENT) {
+ if (s > 1 && !isZeroSized(golden, index)) {
+ s -= 1;
+ } else {
+ sizeLargerThanOne = false;
+ }
+ }
+ }
+ RequestArgument arg = {
+ .location = {.poolIndex = OUTPUT,
+ .offset = 0,
+ .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
+ };
+ outputs_info[index] = arg;
+ outputSize += s;
+ });
+ // If output0 does not have size larger than one byte,
+ // we can not provide an insufficient buffer
+ if (!sizeLargerThanOne && outputType == OutputType::INSUFFICIENT) return;
+ // Compute offset for outputs 1 and so on
+ {
+ size_t offset = 0;
+ for (auto& i : outputs_info) {
+ i.location.offset = offset;
+ offset += i.location.length;
+ }
+ }
+ std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
+ nn::allocateSharedMemory(outputSize)};
+ ASSERT_NE(0ull, pools[INPUT].size());
+ ASSERT_NE(0ull, pools[OUTPUT].size());
+
+ // load data
+ sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
+ sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
+ ASSERT_NE(nullptr, inputMemory.get());
+ ASSERT_NE(nullptr, outputMemory.get());
+ char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
+ char* outputPtr = reinterpret_cast<char*>(static_cast<void*>(outputMemory->getPointer()));
+ ASSERT_NE(nullptr, inputPtr);
+ ASSERT_NE(nullptr, outputPtr);
+ inputMemory->update();
+ outputMemory->update();
+
+ // Go through all inputs, copy the values
+ for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
+ char* begin = (char*)p;
+ char* end = begin + s;
+ // TODO: handle more than one input
+ std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
+ });
+
+ inputMemory->commit();
+ outputMemory->commit();
+
+ const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools};
+
+ ErrorStatus executionStatus;
+ hidl_vec<OutputShape> outputShapes;
+ Timing timing;
+ switch (executor) {
+ case Executor::ASYNC: {
+ SCOPED_TRACE("asynchronous");
+
+ // launch execution
+ sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+ ASSERT_NE(nullptr, executionCallback.get());
+ Return<ErrorStatus> executionLaunchStatus =
+ ExecutePreparedModel(preparedModel, request, measure, executionCallback);
+ ASSERT_TRUE(executionLaunchStatus.isOk());
+ EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
+
+ // retrieve execution status
+ executionCallback->wait();
+ executionStatus = executionCallback->getStatus();
+ outputShapes = executionCallback->getOutputShapes();
+ timing = executionCallback->getTiming();
+
+ break;
+ }
+ case Executor::SYNC: {
+ SCOPED_TRACE("synchronous");
+
+ // execute
+ Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
+ preparedModel, request, measure, &outputShapes, &timing);
+ ASSERT_TRUE(executionReturnStatus.isOk());
+ executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
+
+ break;
+ }
+ case Executor::BURST: {
+ SCOPED_TRACE("burst");
+
+ // create burst
+ const std::shared_ptr<::android::nn::ExecutionBurstController> controller =
+ CreateBurst(preparedModel);
+ ASSERT_NE(nullptr, controller.get());
+
+ // create memory keys
+ std::vector<intptr_t> keys(request.pools.size());
+ for (size_t i = 0; i < keys.size(); ++i) {
+ keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
+ }
+
+ // execute burst
+ std::tie(executionStatus, outputShapes, timing) =
+ controller->compute(request, measure, keys);
+
+ break;
+ }
+ }
+
+ if (outputType != OutputType::FULLY_SPECIFIED &&
+ executionStatus == ErrorStatus::GENERAL_FAILURE) {
+ LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+ "execute model that it does not support.";
+ std::cout << "[ ] Early termination of test because vendor service cannot "
+ "execute model that it does not support."
+ << std::endl;
+ GTEST_SKIP();
+ }
+ if (measure == MeasureTiming::NO) {
+ EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
+ EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
+ } else {
+ if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) {
+ EXPECT_LE(timing.timeOnDevice, timing.timeInDriver);
+ }
+ }
+
+ switch (outputType) {
+ case OutputType::FULLY_SPECIFIED:
+ // If the model output operands are fully specified, outputShapes must be either
+ // either empty, or have the same number of elements as the number of outputs.
+ ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+ ASSERT_TRUE(outputShapes.size() == 0 ||
+ outputShapes.size() == test.operandDimensions.size());
+ break;
+ case OutputType::UNSPECIFIED:
+ // If the model output operands are not fully specified, outputShapes must have
+ // the same number of elements as the number of outputs.
+ ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+ ASSERT_EQ(outputShapes.size(), test.operandDimensions.size());
+ break;
+ case OutputType::INSUFFICIENT:
+ ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
+ ASSERT_EQ(outputShapes.size(), test.operandDimensions.size());
+ ASSERT_FALSE(outputShapes[0].isSufficient);
+ return;
+ }
+ // Go through all outputs, overwrite output dimensions with returned output shapes
+ if (outputShapes.size() > 0) {
+ for_each<uint32_t>(test.operandDimensions,
+ [&outputShapes](int idx, std::vector<uint32_t>& dim) {
+ dim = outputShapes[idx].dimensions;
+ });
+ }
+
+ // validate results
+ outputMemory->read();
+ copy_back(&test, outputs_info, outputPtr);
+ outputMemory->commit();
+ // Filter out don't cares
+ MixedTyped filtered_golden = filter(golden, is_ignored);
+ MixedTyped filtered_test = filter(test, is_ignored);
+
+ // We want "close-enough" results for float
+ compare(filtered_golden, filtered_test, fpAtol, fpRtol);
+
+ if (example.expectedMultinomialDistributionTolerance > 0) {
+ expectMultinomialDistributionWithinTolerance(test, example);
+ }
+ }
+}
+void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
+ const std::vector<MixedTypedExample>& examples,
+ bool hasRelaxedFloat32Model, Executor executor, MeasureTiming measure,
+ OutputType outputType) {
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, kDefaultAtol,
+ kDefaultRtol, executor, measure, outputType);
+}
+
+void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
+ const std::vector<MixedTypedExample>& examples,
+ bool hasRelaxedFloat32Model, bool testDynamicOutputShape) {
+ if (testDynamicOutputShape) {
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::ASYNC, MeasureTiming::NO, OutputType::UNSPECIFIED);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::SYNC, MeasureTiming::NO, OutputType::UNSPECIFIED);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::BURST, MeasureTiming::NO, OutputType::UNSPECIFIED);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::ASYNC, MeasureTiming::YES, OutputType::UNSPECIFIED);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::SYNC, MeasureTiming::YES, OutputType::UNSPECIFIED);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::BURST, MeasureTiming::YES, OutputType::UNSPECIFIED);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::ASYNC, MeasureTiming::NO, OutputType::INSUFFICIENT);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::SYNC, MeasureTiming::NO, OutputType::INSUFFICIENT);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::BURST, MeasureTiming::NO, OutputType::INSUFFICIENT);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::ASYNC, MeasureTiming::YES, OutputType::INSUFFICIENT);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::SYNC, MeasureTiming::YES, OutputType::INSUFFICIENT);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::BURST, MeasureTiming::YES, OutputType::INSUFFICIENT);
+ } else {
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::ASYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::SYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::BURST, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::ASYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::SYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
+ Executor::BURST, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
+ }
+}
+
+void PrepareModel(const sp<IDevice>& device, const Model& model,
+ sp<IPreparedModel>* preparedModel) {
+ // see if service can handle model
+ bool fullySupportsModel = false;
+ Return<void> supportedCall = device->getSupportedOperations_1_2(
+ model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
+ ASSERT_EQ(ErrorStatus::NONE, status);
+ ASSERT_NE(0ul, supported.size());
+ fullySupportsModel = std::all_of(supported.begin(), supported.end(),
+ [](bool valid) { return valid; });
+ });
+ ASSERT_TRUE(supportedCall.isOk());
+
+ // launch prepare model
+ sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+ ASSERT_NE(nullptr, preparedModelCallback.get());
+ Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_2(
+ model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec<hidl_handle>(),
+ hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
+ ASSERT_TRUE(prepareLaunchStatus.isOk());
+ ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+ // retrieve prepared model
+ preparedModelCallback->wait();
+ ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+ sp<V1_0::IPreparedModel> preparedModelV1_0 = preparedModelCallback->getPreparedModel();
+ *preparedModel = IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr);
+
+ // early termination if vendor service cannot fully prepare model
+ if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
+ ASSERT_EQ(nullptr, preparedModel->get());
+ LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+ "prepare model that it does not support.";
+ std::cout << "[ ] Early termination of test because vendor service cannot "
+ "prepare model that it does not support."
+ << std::endl;
+ return;
+ }
+ EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+ ASSERT_NE(nullptr, preparedModel->get());
+}
+
+void Execute(const sp<IDevice>& device, std::function<Model(void)> create_model,
+ std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples,
+ bool testDynamicOutputShape) {
+ Model model = create_model();
+ sp<IPreparedModel> preparedModel = nullptr;
+ PrepareModel(device, model, &preparedModel);
+ if (preparedModel == nullptr) {
+ GTEST_SKIP();
+ }
+ EvaluatePreparedModel(preparedModel, is_ignored, examples,
+ model.relaxComputationFloat32toFloat16, testDynamicOutputShape);
+}
+
+} // namespace generated_tests
+} // namespace V1_2
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
new file mode 100644
index 0000000..0ecbe7e
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
@@ -0,0 +1,53 @@
+/*
+ * 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_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H
+
+#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <functional>
+#include <vector>
+#include "TestHarness.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_2 {
+namespace generated_tests {
+
+using ::test_helper::MixedTypedExample;
+
+void PrepareModel(const sp<V1_2::IDevice>& device, const V1_2::Model& model,
+ sp<V1_2::IPreparedModel>* preparedModel);
+
+void EvaluatePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
+ std::function<bool(int)> is_ignored,
+ const std::vector<MixedTypedExample>& examples,
+ bool hasRelaxedFloat32Model, bool testDynamicOutputShape);
+
+void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model,
+ std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples,
+ bool testDynamicOutputShape = false);
+
+} // namespace generated_tests
+} // namespace V1_2
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp
deleted file mode 100644
index 5af3255..0000000
--- a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "GeneratedTestHarness.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
-
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_2_vts_tests.cpp"
-
-// Generated from spec/strided_slice_invalid_output_dims.mod.py.
-// TODO(b/132155416): Make this part of all_generated_V1_2_vts_tests.cpp.
-namespace strided_slice_invalid_output_dims {
-#include "generated/strided_slice_invalid_output_dims.example.cpp"
-#include "generated/strided_slice_invalid_output_dims.model.cpp"
-} // namespace strided_slice_invalid_output_dims
-
-// TODO(b/132155416): Make this part of all_generated_V1_2_vts_tests.cpp.
-TEST_F(ValidationTest, strided_slice_invalid_output_dims) {
- const Model model = strided_slice_invalid_output_dims::createTestModel();
- const std::vector<Request> requests =
- createRequests(strided_slice_invalid_output_dims::get_examples());
- validateFailure(model, requests);
-}
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_2
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.h b/neuralnetworks/1.2/vts/functional/GeneratedTests.h
new file mode 100644
index 0000000..f393eb2
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTests.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.
+ */
+
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+#include "GeneratedTestHarness.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "Utils.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_2::vts::functional {
+
+std::vector<Request> createRequests(const std::vector<::test_helper::MixedTypedExample>& examples);
+
+} // namespace android::hardware::neuralnetworks::V1_2::vts::functional
+
+namespace android::hardware::neuralnetworks::V1_2::generated_tests {
+
+using namespace ::android::hardware::neuralnetworks::V1_2::vts::functional;
+
+using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
+using ::android::hardware::neuralnetworks::V1_0::Request;
+using ::android::hardware::neuralnetworks::V1_2::Model;
+
+} // namespace android::hardware::neuralnetworks::V1_2::generated_tests
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp
deleted file mode 100644
index 990cab9..0000000
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "GeneratedTestHarness.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
-
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_0_vts_tests.cpp"
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_2
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp
deleted file mode 100644
index fa6d54d..0000000
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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 "neuralnetworks_hidl_hal_test"
-
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "GeneratedTestHarness.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace vts {
-namespace functional {
-
-using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
-using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
-
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_1_vts_tests.cpp"
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_2
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
index 8c6391e..4d6bdbb 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
@@ -18,7 +18,7 @@
#include "VtsHalNeuralnetworks.h"
-#include "Callbacks.h"
+#include "1.2/Callbacks.h"
#include "ExecutionBurstController.h"
#include "ExecutionBurstServer.h"
#include "TestHarness.h"
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index a0b6d9a..78bb194 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -16,10 +16,10 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
+#include "1.0/Utils.h"
+#include "1.2/Callbacks.h"
#include "VtsHalNeuralnetworks.h"
-#include "Callbacks.h"
-
namespace android {
namespace hardware {
namespace neuralnetworks {
@@ -41,10 +41,10 @@
const Model& model) {
SCOPED_TRACE(message + " [getSupportedOperations_1_2]");
- Return<void> ret =
- device->getSupportedOperations_1_2(model, [&](ErrorStatus status, const hidl_vec<bool>&) {
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
- });
+ Return<void> ret = device->getSupportedOperations_1_2(
+ model, [&](ErrorStatus status, const hidl_vec<bool>&) {
+ EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+ });
EXPECT_TRUE(ret.isOk());
}
@@ -87,36 +87,16 @@
validatePrepareModel(device, message, model, preference);
}
-// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
-// so this is efficiently accomplished by moving the element to the end and
-// resizing the hidl_vec to one less.
-template <typename Type>
-static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
- if (vec) {
- std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
- vec->resize(vec->size() - 1);
- }
-}
-
-template <typename Type>
-static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
- // assume vec is valid
- const uint32_t index = vec->size();
- vec->resize(index + 1);
- (*vec)[index] = value;
- return index;
-}
-
static uint32_t addOperand(Model* model) {
return hidl_vec_push_back(&model->operands,
{
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 0,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_INPUT,
- .location = {.poolIndex = 0, .offset = 0, .length = 0},
+ .type = OperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 0,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::MODEL_INPUT,
+ .location = {.poolIndex = 0, .offset = 0, .length = 0},
});
}
@@ -243,7 +223,7 @@
case OperandType::TENSOR_QUANT8_ASYMM:
return {-1, 256};
case OperandType::TENSOR_QUANT8_SYMM:
- return {-129, -1, 1, 128};
+ return {-129, -1, 1, 128};
case OperandType::TENSOR_QUANT16_ASYMM:
return {-1, 65536};
case OperandType::TENSOR_QUANT16_SYMM:
@@ -256,7 +236,7 @@
static void mutateOperandZeroPointTest(const sp<IDevice>& device, const Model& model) {
for (size_t operand = 0; operand < model.operands.size(); ++operand) {
const std::vector<int32_t> invalidZeroPoints =
- getInvalidZeroPoints(model.operands[operand].type);
+ getInvalidZeroPoints(model.operands[operand].type);
for (int32_t invalidZeroPoint : invalidZeroPoints) {
const std::string message = "mutateOperandZeroPointTest: operand " +
std::to_string(operand) + " has zero point of " +
@@ -292,13 +272,13 @@
case OperandType::TENSOR_FLOAT16:
case OperandType::TENSOR_FLOAT32:
newOperand.dimensions =
- operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
newOperand.scale = 0.0f;
newOperand.zeroPoint = 0;
break;
case OperandType::TENSOR_INT32:
newOperand.dimensions =
- operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
newOperand.zeroPoint = 0;
break;
case OperandType::TENSOR_QUANT8_ASYMM:
@@ -306,19 +286,20 @@
case OperandType::TENSOR_QUANT16_ASYMM:
case OperandType::TENSOR_QUANT16_SYMM:
newOperand.dimensions =
- operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
break;
case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: {
newOperand.dimensions =
- operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
newOperand.scale = 0.0f;
newOperand.zeroPoint = 0;
SymmPerChannelQuantParams channelQuant;
channelQuant.channelDim = 0;
channelQuant.scales = hidl_vec<float>(
- operand->dimensions.size() > 0 ? static_cast<size_t>(operand->dimensions[0]) : 0);
+ operand->dimensions.size() > 0 ? static_cast<size_t>(operand->dimensions[0])
+ : 0);
for (size_t i = 0; i < channelQuant.scales.size(); ++i) {
channelQuant.scales[i] = 1.0f;
}
@@ -435,7 +416,7 @@
std::to_string(invalidOperationType);
validate(device, message, model, [operation, invalidOperationType](Model* model) {
model->operations[operation].type =
- static_cast<OperationType>(invalidOperationType);
+ static_cast<OperationType>(invalidOperationType);
});
}
}
@@ -690,7 +671,7 @@
static void addOperationOutputTest(const sp<IDevice>& device, const Model& model) {
for (size_t operation = 0; operation < model.operations.size(); ++operation) {
const std::string message =
- "addOperationOutputTest: operation " + std::to_string(operation);
+ "addOperationOutputTest: operation " + std::to_string(operation);
validate(device, message, model, [operation](Model* model) {
uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
hidl_vec_push_back(&model->operations[operation].outputs, index);
@@ -702,14 +683,14 @@
///////////////////////// VALIDATE EXECUTION PREFERENCE /////////////////////////
static const int32_t invalidExecutionPreferences[] = {
- static_cast<int32_t>(ExecutionPreference::LOW_POWER) - 1, // lower bound
- static_cast<int32_t>(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound
+ static_cast<int32_t>(ExecutionPreference::LOW_POWER) - 1, // lower bound
+ static_cast<int32_t>(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound
};
static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const Model& model) {
for (int32_t preference : invalidExecutionPreferences) {
const std::string message =
- "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
+ "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
validate(device, message, model, [](Model*) {},
static_cast<ExecutionPreference>(preference));
}
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index e935aaa..cf5905f 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -16,17 +16,18 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include "VtsHalNeuralnetworks.h"
-
-#include "Callbacks.h"
-#include "ExecutionBurstController.h"
-#include "TestHarness.h"
-#include "Utils.h"
-
#include <android-base/logging.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
+#include "1.0/Utils.h"
+#include "1.2/Callbacks.h"
+#include "ExecutionBurstController.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "Utils.h"
+#include "VtsHalNeuralnetworks.h"
+
namespace android {
namespace hardware {
namespace neuralnetworks {
@@ -34,6 +35,7 @@
namespace vts {
namespace functional {
+using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
using ::android::hidl::memory::V1_0::IMemory;
using test_helper::for_all;
@@ -137,26 +139,6 @@
}
}
-// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
-// so this is efficiently accomplished by moving the element to the end and
-// resizing the hidl_vec to one less.
-template <typename Type>
-static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
- if (vec) {
- std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
- vec->resize(vec->size() - 1);
- }
-}
-
-template <typename Type>
-static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
- // assume vec is valid
- const uint32_t index = vec->size();
- vec->resize(index + 1);
- (*vec)[index] = value;
- return index;
-}
-
///////////////////////// REMOVE INPUT ////////////////////////////////////
static void removeInputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
@@ -197,11 +179,13 @@
for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
RequestArgument arg = {
- .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
- .dimensions = {},
+ .location = {.poolIndex = INPUT,
+ .offset = 0,
+ .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
};
RequestArgument arg_empty = {
- .hasNoValue = true,
+ .hasNoValue = true,
};
inputs_info[index] = s ? arg : arg_empty;
inputSize += s;
@@ -219,8 +203,10 @@
for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
RequestArgument arg = {
- .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
- .dimensions = {},
+ .location = {.poolIndex = OUTPUT,
+ .offset = 0,
+ .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
};
outputs_info[index] = arg;
outputSize += s;
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
index 666f9b5..bd24edc 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
@@ -20,7 +20,7 @@
#include <android-base/logging.h>
-#include "Callbacks.h"
+#include "1.2/Callbacks.h"
namespace android {
namespace hardware {
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
index 80e810a..90dfe25 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
@@ -14,24 +14,23 @@
* limitations under the License.
*/
-#ifndef VTS_HAL_NEURALNETWORKS_V1_2_H
-#define VTS_HAL_NEURALNETWORKS_V1_2_H
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H
-#include "Callbacks.h"
-
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/macros.h>
#include <android/hardware/neuralnetworks/1.0/types.h>
#include <android/hardware/neuralnetworks/1.1/types.h>
#include <android/hardware/neuralnetworks/1.2/IDevice.h>
#include <android/hardware/neuralnetworks/1.2/types.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
-#include <android-base/macros.h>
#include <gtest/gtest.h>
+
#include <iostream>
#include <vector>
+#include "1.2/Callbacks.h"
+
namespace android {
namespace hardware {
namespace neuralnetworks {
@@ -50,7 +49,7 @@
NeuralnetworksHidlEnvironment();
~NeuralnetworksHidlEnvironment() override;
- public:
+ public:
static NeuralnetworksHidlEnvironment* getInstance();
void registerTestServices() override;
};
@@ -59,30 +58,30 @@
class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase {
DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
- public:
+ public:
NeuralnetworksHidlTest();
~NeuralnetworksHidlTest() override;
void SetUp() override;
void TearDown() override;
- protected:
+ protected:
sp<IDevice> device;
};
// Tag for the validation tests
class ValidationTest : public NeuralnetworksHidlTest {
- protected:
- void validateEverything(const Model& model, const std::vector<Request>& requests);
- void validateFailure(const Model& model, const std::vector<Request>& requests);
+ protected:
+ void validateEverything(const Model& model, const std::vector<Request>& requests);
+ void validateFailure(const Model& model, const std::vector<Request>& requests);
- private:
- void validateModel(const Model& model);
- void validateRequests(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests);
- void validateRequestFailure(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests);
- void validateBurst(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests);
+ private:
+ void validateModel(const Model& model);
+ void validateRequests(const sp<IPreparedModel>& preparedModel,
+ const std::vector<Request>& requests);
+ void validateRequestFailure(const sp<IPreparedModel>& preparedModel,
+ const std::vector<Request>& requests);
+ void validateBurst(const sp<IPreparedModel>& preparedModel,
+ const std::vector<Request>& requests);
};
// Tag for the generated tests
@@ -93,7 +92,7 @@
// Utility function to get PreparedModel from callback and downcast to V1_2.
sp<IPreparedModel> getPreparedModel_1_2(
- const sp<V1_2::implementation::PreparedModelCallback>& callback);
+ const sp<V1_2::implementation::PreparedModelCallback>& callback);
} // namespace functional
} // namespace vts
@@ -110,4 +109,4 @@
} // namespace android::hardware::neuralnetworks::V1_0
-#endif // VTS_HAL_NEURALNETWORKS_V1_2_H
+#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H
diff --git a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp
deleted file mode 100644
index 0640833..0000000
--- a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-// clang-format off
-// Generated file (from: strided_slice_invalid_output_dims.mod.py). Do not edit
-std::vector<MixedTypedExample>& get_examples() {
-static std::vector<MixedTypedExample> examples = {
-// Begin of an example
-{
-.operands = {
-//Input(s)
-{ // See tools/test_generator/include/TestHarness.h:MixedTyped
- // int -> Dimensions map
- .operandDimensions = {{0, {2, 3}}},
- // int -> FLOAT32 map
- .float32Operands = {{0, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}}},
- // int -> INT32 map
- .int32Operands = {},
- // int -> QUANT8_ASYMM map
- .quant8AsymmOperands = {},
- // int -> QUANT16_SYMM map
- .quant16SymmOperands = {},
- // int -> FLOAT16 map
- .float16Operands = {},
- // int -> BOOL8 map
- .bool8Operands = {},
- // int -> QUANT8_SYMM_PER_CHANNEL map
- .quant8ChannelOperands = {},
- // int -> QUANT16_ASYMM map
- .quant16AsymmOperands = {},
- // int -> QUANT8_SYMM map
- .quant8SymmOperands = {},
-},
-//Output(s)
-{ // See tools/test_generator/include/TestHarness.h:MixedTyped
- // int -> Dimensions map
- .operandDimensions = {{0, {3}}},
- // int -> FLOAT32 map
- .float32Operands = {{0, {1.0f, 2.0f, 3.0f}}},
- // int -> INT32 map
- .int32Operands = {},
- // int -> QUANT8_ASYMM map
- .quant8AsymmOperands = {},
- // int -> QUANT16_SYMM map
- .quant16SymmOperands = {},
- // int -> FLOAT16 map
- .float16Operands = {},
- // int -> BOOL8 map
- .bool8Operands = {},
- // int -> QUANT8_SYMM_PER_CHANNEL map
- .quant8ChannelOperands = {},
- // int -> QUANT16_ASYMM map
- .quant16AsymmOperands = {},
- // int -> QUANT8_SYMM map
- .quant8SymmOperands = {},
-}
-},
-}, // End of an example
-};
-return examples;
-};
-
-std::vector<MixedTypedExample>& get_examples_dynamic_output_shape() {
-static std::vector<MixedTypedExample> examples_dynamic_output_shape = {
-// Begin of an example
-{
-.operands = {
-//Input(s)
-{ // See tools/test_generator/include/TestHarness.h:MixedTyped
- // int -> Dimensions map
- .operandDimensions = {{0, {2, 3}}},
- // int -> FLOAT32 map
- .float32Operands = {{0, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}}},
- // int -> INT32 map
- .int32Operands = {},
- // int -> QUANT8_ASYMM map
- .quant8AsymmOperands = {},
- // int -> QUANT16_SYMM map
- .quant16SymmOperands = {},
- // int -> FLOAT16 map
- .float16Operands = {},
- // int -> BOOL8 map
- .bool8Operands = {},
- // int -> QUANT8_SYMM_PER_CHANNEL map
- .quant8ChannelOperands = {},
- // int -> QUANT16_ASYMM map
- .quant16AsymmOperands = {},
- // int -> QUANT8_SYMM map
- .quant8SymmOperands = {},
-},
-//Output(s)
-{ // See tools/test_generator/include/TestHarness.h:MixedTyped
- // int -> Dimensions map
- .operandDimensions = {{0, {3}}},
- // int -> FLOAT32 map
- .float32Operands = {{0, {1.0f, 2.0f, 3.0f}}},
- // int -> INT32 map
- .int32Operands = {},
- // int -> QUANT8_ASYMM map
- .quant8AsymmOperands = {},
- // int -> QUANT16_SYMM map
- .quant16SymmOperands = {},
- // int -> FLOAT16 map
- .float16Operands = {},
- // int -> BOOL8 map
- .bool8Operands = {},
- // int -> QUANT8_SYMM_PER_CHANNEL map
- .quant8ChannelOperands = {},
- // int -> QUANT16_ASYMM map
- .quant16AsymmOperands = {},
- // int -> QUANT8_SYMM map
- .quant8SymmOperands = {},
-}
-},
-}, // End of an example
-};
-return examples_dynamic_output_shape;
-};
-
diff --git a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp
deleted file mode 100644
index 106655a..0000000
--- a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-// clang-format off
-// Generated file (from: strided_slice_invalid_output_dims.mod.py). Do not edit
-// Create the model
-Model createTestModel() {
- const std::vector<Operand> operands = {
- {
- .type = OperandType::TENSOR_FLOAT32,
- .dimensions = {2, 3},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_INPUT,
- .location = {.poolIndex = 0, .offset = 0, .length = 0},
- },
- {
- .type = OperandType::TENSOR_INT32,
- .dimensions = {2},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 0, .length = 8},
- },
- {
- .type = OperandType::TENSOR_INT32,
- .dimensions = {2},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 8, .length = 8},
- },
- {
- .type = OperandType::TENSOR_INT32,
- .dimensions = {2},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 16, .length = 8},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 24, .length = 4},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 28, .length = 4},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 32, .length = 4},
- },
- {
- .type = OperandType::TENSOR_FLOAT32,
- .dimensions = {3},
- .numberOfConsumers = 0,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_OUTPUT,
- .location = {.poolIndex = 0, .offset = 0, .length = 0},
- }
- };
-
- const std::vector<Operation> operations = {
- {
- .type = OperationType::STRIDED_SLICE,
- .inputs = {0, 1, 2, 3, 4, 5, 6},
- .outputs = {7},
- }
- };
-
- const std::vector<uint32_t> inputIndexes = {0};
- const std::vector<uint32_t> outputIndexes = {7};
- std::vector<uint8_t> operandValues = {
- 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0
- };
- const std::vector<hidl_memory> pools = {};
-
- return {
- .operands = operands,
- .operations = operations,
- .inputIndexes = inputIndexes,
- .outputIndexes = outputIndexes,
- .operandValues = operandValues,
- .pools = pools,
- };
-}
-
-inline bool is_ignored(int i) {
- static std::set<int> ignore = {};
- return ignore.find(i) != ignore.end();
-}
-
-// Create the model
-Model createTestModel_dynamic_output_shape() {
- const std::vector<Operand> operands = {
- {
- .type = OperandType::TENSOR_FLOAT32,
- .dimensions = {2, 3},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_INPUT,
- .location = {.poolIndex = 0, .offset = 0, .length = 0},
- },
- {
- .type = OperandType::TENSOR_INT32,
- .dimensions = {2},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 0, .length = 8},
- },
- {
- .type = OperandType::TENSOR_INT32,
- .dimensions = {2},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 8, .length = 8},
- },
- {
- .type = OperandType::TENSOR_INT32,
- .dimensions = {2},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 16, .length = 8},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 24, .length = 4},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 28, .length = 4},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 32, .length = 4},
- },
- {
- .type = OperandType::TENSOR_FLOAT32,
- .dimensions = {0},
- .numberOfConsumers = 0,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_OUTPUT,
- .location = {.poolIndex = 0, .offset = 0, .length = 0},
- }
- };
-
- const std::vector<Operation> operations = {
- {
- .type = OperationType::STRIDED_SLICE,
- .inputs = {0, 1, 2, 3, 4, 5, 6},
- .outputs = {7},
- }
- };
-
- const std::vector<uint32_t> inputIndexes = {0};
- const std::vector<uint32_t> outputIndexes = {7};
- std::vector<uint8_t> operandValues = {
- 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0
- };
- const std::vector<hidl_memory> pools = {};
-
- return {
- .operands = operands,
- .operations = operations,
- .inputIndexes = inputIndexes,
- .outputIndexes = outputIndexes,
- .operandValues = operandValues,
- .pools = pools,
- };
-}
-
-inline bool is_ignored_dynamic_output_shape(int i) {
- static std::set<int> ignore = {};
- return ignore.find(i) != ignore.end();
-}
-
diff --git a/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h
new file mode 100644
index 0000000..2992c0c
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2018 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_NEURALNETWORKS_V1_2_CALLBACKS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H
+
+#include <android-base/thread_annotations.h>
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <hidl/Status.h>
+#include <condition_variable>
+#include <mutex>
+
+/*
+ * The Callback classes are used internally by the NeuralNetworks runtime to
+ * synchronize between different threads. An asynchronous task is launched
+ * paired with a callback object. When a client thread requires the output being
+ * generated by the asynchronous task, the client thread can wait for the result
+ * and be blocked until it has completed. Any wait may safely be called
+ * concurrently, even on the same callback object. When the asynchronous task
+ * has finished its workload, it must immediately call "notify*". If the
+ * asynchronous task has failed to launch, the function that tried to launch the
+ * asynchronous task must immediately call "notify*". This "notify*" call
+ * awakens any client threads waiting on the callback object.
+ *
+ * These classes exist to enable synchronization across HIDL. When
+ * synchronization is only required in the same process, consider using
+ * std::future, std::mutex, std::condition_variable, or std::experimental::latch
+ * instead.
+ */
+
+namespace android::hardware::neuralnetworks::V1_2::implementation {
+
+using V1_0::ErrorStatus;
+
+/**
+ * The PreparedModelCallback class is used to receive the error status of
+ * preparing a model as well as the prepared model from a task executing
+ * asynchronously with respect to the runtime. If a calling thread calls wait
+ * or get* on a PreparedModelCallback object and the corresponding asynchronous
+ * task has not finished preparing the model, the calling thread will block
+ * until the asynchronous task has either called notify or notify_1_2.
+ *
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify* are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IDevice::prepareModel*.
+ */
+class PreparedModelCallback : public IPreparedModelCallback {
+ public:
+ /**
+ * IPreparedModelCallback::notify marks the callback object with the return
+ * status of the asynchronous model preparation along with the prepared
+ * model, and allows all prior and future wait calls on the
+ * PreparedModelCallback object to proceed.
+ *
+ * Either IPreparedModelCallback::notify or
+ * IPreparedModelCallback::notify_1_2 must be called on a given
+ * PreparedModelCallback object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify* are used, and the results from subsequent calls
+ * are discarded.
+ *
+ * @param status Error status returned from asynchronously preparing the
+ * model; will be:
+ * - NONE if the asynchronous preparation was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if the input model is invalid
+ * @param preparedModel Returned model that has been prepared for execution,
+ * nullptr if the model was unable to be prepared.
+ */
+ Return<void> notify(ErrorStatus status, const sp<V1_0::IPreparedModel>& preparedModel) override;
+
+ /**
+ * IPreparedModelCallback::notify_1_2 marks the callback object with the
+ * return status of the asynchronous model preparation along with the
+ * prepared model, and allows all prior and future wait calls on the
+ * PreparedModelCallback object to proceed.
+ *
+ * Either IPreparedModelCallback::notify or
+ * IPreparedModelCallback::notify_1_2 must be called on a given
+ * PreparedModelCallback object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify* are used, and the results from subsequent calls
+ * are discarded.
+ *
+ * @param status Error status returned from asynchronously preparing the
+ * model; will be:
+ * - NONE if the asynchronous preparation was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if the input model is invalid
+ * @param preparedModel Returned model that has been prepared for execution,
+ * nullptr if the model was unable to be prepared.
+ */
+ Return<void> notify_1_2(ErrorStatus status,
+ const sp<V1_2::IPreparedModel>& preparedModel) override;
+
+ /**
+ * PreparedModelCallback::wait blocks until notify* has been called on the
+ * callback object.
+ */
+ void wait() const;
+
+ /**
+ * Retrieves the error status returned from the asynchronous task launched
+ * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished
+ * asynchronously preparing the model, this call will block until the
+ * asynchronous task notifies the object.
+ *
+ * @return status Error status returned from asynchronously preparing the
+ * model; will be:
+ * - NONE if the asynchronous preparation was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if the input model is invalid
+ */
+ ErrorStatus getStatus() const;
+
+ /**
+ * Retrieves the model that has been prepared for execution from the
+ * asynchronous task launched by IDevice::prepareModel*. If
+ * IDevice::prepareModel* has not finished asynchronously preparing the
+ * model, this call will block until the asynchronous task notifies the
+ * object.
+ *
+ * @return preparedModel Returned model that has been prepared for
+ * execution, nullptr if the model was unable to be prepared.
+ */
+ sp<V1_0::IPreparedModel> getPreparedModel() const;
+
+ private:
+ mutable std::mutex mMutex;
+ mutable std::condition_variable mCondition;
+ bool mNotified GUARDED_BY(mMutex) = false;
+ ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
+ sp<V1_0::IPreparedModel> mPreparedModel;
+};
+
+/**
+ * The ExecutionCallback class is used to receive the results of the execution
+ * from a task executing asynchronously with respect to the runtime. If a
+ * calling thread calls wait or get* on a ExecutionCallback object and the
+ * corresponding asynchronous task has not finished the execution, the calling
+ * thread will block until the asynchronous task has either called notify or
+ * notify_1_2.
+ *
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify* are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IPreparedModel::execute*.
+ */
+class ExecutionCallback : public IExecutionCallback {
+ public:
+ /**
+ * IExecutionCallback::notify marks the callback object with the return
+ * status of the asynchronous execution that held this callback and enables
+ * all prior and future wait calls on the ExecutionCallback object to
+ * proceed.
+ *
+ * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must
+ * be called on a given ExecutionCallback object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify* are used, and the results from subsequent calls
+ * are discarded.
+ *
+ * @param status Error status returned from launching the asynchronous task
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). Must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large
+ * enough to store the resultant values
+ * - INVALID_ARGUMENT if the input request is invalid
+ */
+ Return<void> notify(ErrorStatus status) override;
+
+ /**
+ * IExecutionCallback::notify_1_2 marks the callback object with the results
+ * (error status, dynamic output shapes, and timing information) of the
+ * asynchronous execution that held this callback and enables all prior and
+ * future wait calls on the ExecutionCallback object to proceed.
+ *
+ * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must
+ * be called on a given ExecutionCallback object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify* are used, and the results from subsequent calls
+ * are discarded.
+ *
+ * @param status Error status returned from launching the asynchronous task
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). 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
+ * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is
+ * not large enough to store the corresponding output
+ * - INVALID_ARGUMENT if one of the input arguments to prepareModel is
+ * invalid
+ * @param outputShapes A list of shape information of model output operands.
+ * The index into "outputShapes" corresponds to the index of the output
+ * operand in the Request outputs vector. outputShapes must be empty
+ * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE.
+ * @param Timing Duration of execution. 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<void> notify_1_2(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing) override;
+
+ // An overload of the latest notify interface to hide the version from ExecutionBuilder.
+ Return<void> notify(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing) {
+ return notify_1_2(status, outputShapes, timing);
+ }
+
+ /**
+ * ExecutionCallback::wait blocks until notify* has been called on the
+ * callback object.
+ */
+ void wait() const;
+
+ /**
+ * Retrieves the error status returned from the asynchronous task launched
+ * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If
+ * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished
+ * asynchronously executing, this call will block until the asynchronous
+ * task notifies the object.
+ *
+ * @return status Error status returned from launching the asynchronous task
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). 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
+ * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is
+ * not large enough to store the corresponding output
+ * - INVALID_ARGUMENT if one of the input arguments to prepareModel is
+ * invalid
+ */
+ ErrorStatus getStatus() const;
+
+ /**
+ * Retrieves the output shapes returned from the asynchronous task launched
+ * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not
+ * finished asynchronously executing, this call will block until the
+ * asynchronous task notifies the object.
+ *
+ * If the asynchronous task was launched by IPreparedModel::execute, an
+ * empty vector will be returned.
+ *
+ * @return outputShapes A list of shape information of model output
+ * operands. The index into "outputShapes" corresponds to the index of
+ * the output operand in the Request outputs vector. outputShapes must
+ * be empty unless the status is either NONE or
+ * OUTPUT_INSUFFICIENT_SIZE. outputShaps may be empty if the status is
+ * NONE and all model output operands are fully-specified at execution
+ * time. outputShapes must have the same number of elements as the
+ * number of model output operands if the status is
+ * OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has
+ * at least one output operand that is not fully-specified.
+ */
+ const std::vector<OutputShape>& getOutputShapes() const;
+
+ /**
+ * Retrieves the duration of execution of the asynchronous task launched by
+ * IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not
+ * finished asynchronously executing, this call will block until the
+ * asynchronous task notifies the object.
+ *
+ * If the asynchronous task was launched by IPreparedModel::execute, every
+ * time must be UINT64_MAX.
+ *
+ * @return timing Duration of the execution. Every time must be UINT64_MAX
+ * unless the status is NONE.
+ */
+ Timing getTiming() const;
+
+ private:
+ /*
+ * ExecutionCallback::notifyInternal stores the results of the execution
+ * (status, output shapes, and timing information) in the ExecutionCallback
+ * object before any call to wait or get* return. It then enables all prior
+ * and future wait calls on the ExecutionCallback object to proceed.
+ */
+ void notifyInternal(ErrorStatus errorStatus, const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing);
+
+ // members
+ mutable std::mutex mMutex;
+ mutable std::condition_variable mCondition;
+ bool mNotified GUARDED_BY(mMutex) = false;
+ ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
+ std::vector<OutputShape> mOutputShapes = {};
+ Timing mTiming = {};
+};
+
+} // namespace android::hardware::neuralnetworks::V1_2::implementation
+
+#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H
diff --git a/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py b/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py
deleted file mode 100644
index e8d30f3..0000000
--- a/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py
+++ /dev/null
@@ -1,43 +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.
-#
-
-# This test makes sure that executing STRIDED_SLICE results in a failure when
-# the output dimensions do not match shrinkAxisMask.
-#
-# The test generator does not support generating tests resulting in execution
-# failure, so the gTest part of this test has been written by hand.
-# TODO(b/132155416): Move this under frameworks/ml/nn/runtime/test/specs/V1_2.
-#
-# Based on strided_slice_float_11.mod.py.
-
-model = Model()
-i1 = Input("input", "TENSOR_FLOAT32", "{2, 3}")
-begins = Parameter("begins", "TENSOR_INT32", "{2}", [0, 0])
-# The value "2" below makes the test invalid. See http://b/79856511#comment2.
-ends = Parameter("ends", "TENSOR_INT32", "{2}", [2, 3])
-strides = Parameter("strides", "TENSOR_INT32", "{2}", [1, 1])
-beginMask = Int32Scalar("beginMask", 0)
-endMask = Int32Scalar("endMask", 0)
-shrinkAxisMask = Int32Scalar("shrinkAxisMask", 1)
-
-output = Output("output", "TENSOR_FLOAT32", "{3}")
-
-model = model.Operation("STRIDED_SLICE", i1, begins, ends, strides, beginMask, endMask, shrinkAxisMask).To(output)
-
-Example({
- i1: [1, 2, 3, 4, 5, 6],
- output: [1, 2, 3],
-})
diff --git a/nfc/1.0/default/android.hardware.nfc@1.0-service.rc b/nfc/1.0/default/android.hardware.nfc@1.0-service.rc
index 3a5c776..27e35d2 100644
--- a/nfc/1.0/default/android.hardware.nfc@1.0-service.rc
+++ b/nfc/1.0/default/android.hardware.nfc@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.nfc_hal_service /vendor/bin/hw/android.hardware.nfc@1.0-service
+ interface android.hardware.nfc@1.0::INfc default
class hal
user nfc
group nfc
diff --git a/power/1.0/default/android.hardware.power@1.0-service.rc b/power/1.0/default/android.hardware.power@1.0-service.rc
index 657c733..f3fd303 100644
--- a/power/1.0/default/android.hardware.power@1.0-service.rc
+++ b/power/1.0/default/android.hardware.power@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.power-hal-1-0 /vendor/bin/hw/android.hardware.power@1.0-service
+ interface android.hardware.power@1.0::IPower default
class hal
user system
group system
diff --git a/radio/1.2/default/android.hardware.radio@1.2-radio-service.rc b/radio/1.2/default/android.hardware.radio@1.2-radio-service.rc
index e126cd8..eab37ec 100644
--- a/radio/1.2/default/android.hardware.radio@1.2-radio-service.rc
+++ b/radio/1.2/default/android.hardware.radio@1.2-radio-service.rc
@@ -1,4 +1,13 @@
service vendor.radio-1-2 /vendor/bin/hw/android.hardware.radio@1.2-radio-service
+ interface android.hardware.radio@1.0::IRadio slot1
+ interface android.hardware.radio@1.0::IRadio slot2
+ interface android.hardware.radio@1.0::IRadio slot3
+ interface android.hardware.radio@1.1::IRadio slot1
+ interface android.hardware.radio@1.1::IRadio slot2
+ interface android.hardware.radio@1.1::IRadio slot3
+ interface android.hardware.radio@1.2::IRadio slot1
+ interface android.hardware.radio@1.2::IRadio slot2
+ interface android.hardware.radio@1.2::IRadio slot3
class hal
user system
group system
diff --git a/radio/1.2/default/android.hardware.radio@1.2-sap-service.rc b/radio/1.2/default/android.hardware.radio@1.2-sap-service.rc
index 845e6e5..9f163f6 100644
--- a/radio/1.2/default/android.hardware.radio@1.2-sap-service.rc
+++ b/radio/1.2/default/android.hardware.radio@1.2-sap-service.rc
@@ -1,4 +1,7 @@
service vendor.sap-1-2 /vendor/bin/hw/android.hardware.radio@1.2-sap-service
+ interface android.hardware.radio@1.0::ISap slot1
+ interface android.hardware.radio@1.1::ISap slot1
+ interface android.hardware.radio@1.2::ISap slot1
class hal
user system
group system
diff --git a/radio/1.2/vts/functional/Android.bp b/radio/1.2/vts/functional/Android.bp
index 6782f14..c5838a8 100644
--- a/radio/1.2/vts/functional/Android.bp
+++ b/radio/1.2/vts/functional/Android.bp
@@ -20,6 +20,7 @@
srcs: [
"radio_hidl_hal_api.cpp",
"radio_hidl_hal_test.cpp",
+ "radio_config_response.cpp",
"radio_response.cpp",
"radio_indication.cpp",
"VtsHalRadioV1_2TargetTest.cpp",
@@ -29,6 +30,8 @@
"android.hardware.radio@1.2",
"android.hardware.radio@1.1",
"android.hardware.radio@1.0",
+ "android.hardware.radio.config@1.0",
+ "android.hardware.radio.config@1.1",
],
header_libs: ["radio.util.header@1.0"],
test_suites: ["general-tests"],
diff --git a/radio/1.2/vts/functional/radio_config_response.cpp b/radio/1.2/vts/functional/radio_config_response.cpp
new file mode 100644
index 0000000..71b7497
--- /dev/null
+++ b/radio/1.2/vts/functional/radio_config_response.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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 <radio_hidl_hal_utils_v1_2.h>
+
+RadioConfigResponse::RadioConfigResponse(RadioHidlTest_v1_2& parent) : parent_v1_2(parent) {}
+
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<SimSlotStatus>& slotStatus) {
+ rspInfo = info;
+ simSlotStatus = slotStatus;
+ parent_v1_2.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) {
+ return Void();
+}
+
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
+ const RadioResponseInfo& info, const PhoneCapability& phoneCapability) {
+ rspInfo = info;
+ phoneCap = phoneCapability;
+ parent_v1_2.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioConfigResponse::setPreferredDataModemResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_2.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioConfigResponse::getModemsConfigResponse(const RadioResponseInfo& info,
+ const ModemsConfig& /* mConfig */) {
+ rspInfo = info;
+ parent_v1_2.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_2.notify(info.serial);
+ return Void();
+}
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
index f11f0d8..5184ef9 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
@@ -34,6 +34,15 @@
TEST_F(RadioHidlTest_v1_2, startNetworkScan) {
serial = GetRandomSerialNumber();
+ if (radioConfig != NULL && DDS_LOGICAL_SLOT_INDEX != logicalSlotId) {
+ // Some DSDS devices have a limitation that network scans can only be performed on the
+ // logical modem that currently used for packet data. For now, skip the test on the
+ // non-data SIM. This exemption is removed in HAL version 1.4. See b/135243177 for
+ // additional information.
+ ALOGI("Skip network scan on non-dds SIM, slot id = %d", logicalSlotId);
+ return;
+ }
+
::android::hardware::radio::V1_2::NetworkScanRequest request = {
.type = ScanType::ONE_SHOT,
.interval = 60,
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_test.cpp b/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
index bff7481..21caddb 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <android/hardware/radio/1.1/IRadio.h>
#include <radio_hidl_hal_utils_v1_2.h>
void RadioHidlTest_v1_2::SetUp() {
@@ -37,6 +36,7 @@
ASSERT_NE(nullptr, radioRsp_v1_2.get());
count_ = 0;
+ logicalSlotId = -1;
radioInd_v1_2 = new (std::nothrow) RadioIndication_v1_2(*this);
ASSERT_NE(nullptr, radioInd_v1_2.get());
@@ -50,6 +50,71 @@
/* Enforce Vts Testing with Sim Status Present only. */
EXPECT_EQ(CardState::PRESENT, cardStatus.base.cardState);
+
+ radioConfig = ::testing::VtsHalHidlTargetTestBase::getService<
+ ::android::hardware::radio::config::V1_1::IRadioConfig>();
+
+ /* Enforce Vts tesing with RadioConfig for network scan excemption. */
+ // Some devices can only perform network scan on logical modem that currently used for packet
+ // data. This exemption is removed in HAL version 1.4. See b/135243177 for additional info.
+ if (radioConfig != NULL) {
+ // RadioConfig 1.1 available, some devices fall in excepmtion category.
+ ASSERT_NE(nullptr, radioConfig.get());
+
+ radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this);
+ ASSERT_NE(nullptr, radioConfigRsp.get());
+
+ /* Set radio config response functions */
+ radioConfig->setResponseFunctions(radioConfigRsp, nullptr);
+
+ /* set preferred data modem */
+ setPreferredDataModem();
+
+ /* get current logical sim id */
+ getLogicalSimId();
+ }
+}
+
+void RadioHidlTest_v1_2::getLogicalSimId() {
+ serial = GetRandomSerialNumber();
+ radioConfig->getSimSlotsStatus(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type);
+ EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial);
+
+ ASSERT_TRUE(CheckAnyOfErrors(radioConfigRsp->rspInfo.error,
+ {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
+
+ if (radioConfigRsp->rspInfo.error != RadioError ::NONE) {
+ ALOGI("Failed to get sim slot status, rspInfo.error = %s\n",
+ toString(radioConfigRsp->rspInfo.error).c_str());
+ return;
+ }
+
+ if (cardStatus.physicalSlotId < 0 ||
+ cardStatus.physicalSlotId >= radioConfigRsp->simSlotStatus.size()) {
+ ALOGI("Physical slot id: %d is out of range", cardStatus.physicalSlotId);
+ return;
+ }
+
+ logicalSlotId = radioConfigRsp->simSlotStatus[cardStatus.physicalSlotId].logicalSlotId;
+}
+
+/*
+ * Set preferred data modem
+ */
+void RadioHidlTest_v1_2::setPreferredDataModem() {
+ serial = GetRandomSerialNumber();
+ // Even for single sim device, the setPreferredDataModem should still success. Enforce dds on
+ // first logical modem.
+ radioConfig->setPreferredDataModem(serial, DDS_LOGICAL_SLOT_INDEX);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type);
+ EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial);
+
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioConfigRsp->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR}));
}
/*
@@ -88,25 +153,7 @@
}
void RadioHidlTest_v1_2::stopNetworkScan() {
- sp<::android::hardware::radio::V1_1::IRadio> radio_v1_1;
-
- radio_v1_1 = ::testing::VtsHalHidlTargetTestBase::getService<
- ::android::hardware::radio::V1_1::IRadio>(
- RadioHidlEnvironment::Instance()
- ->getServiceName<::android::hardware::radio::V1_1::IRadio>(
- hidl_string(RADIO_SERVICE_NAME)));
- if (radio_v1_1 == NULL) {
- sleep(60);
- radio_v1_1 = ::testing::VtsHalHidlTargetTestBase::getService<
- ::android::hardware::radio::V1_1::IRadio>(
- RadioHidlEnvironment::Instance()
- ->getServiceName<::android::hardware::radio::V1_1::IRadio>(
- hidl_string(RADIO_SERVICE_NAME)));
- }
- ASSERT_NE(nullptr, radio_v1_1.get());
-
serial = GetRandomSerialNumber();
-
- radio_v1_1->stopNetworkScan(serial);
+ radio_v1_2->stopNetworkScan(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
}
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h b/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h
index 3f780e5..2db1cac 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h
+++ b/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h
@@ -22,6 +22,10 @@
#include <condition_variable>
#include <mutex>
+#include <android/hardware/radio/config/1.1/IRadioConfig.h>
+#include <android/hardware/radio/config/1.1/IRadioConfigResponse.h>
+#include <android/hardware/radio/config/1.1/types.h>
+
#include <android/hardware/radio/1.2/IRadio.h>
#include <android/hardware/radio/1.2/IRadioIndication.h>
#include <android/hardware/radio/1.2/IRadioResponse.h>
@@ -32,13 +36,17 @@
using namespace ::android::hardware::radio::V1_2;
using namespace ::android::hardware::radio::V1_1;
using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config::V1_1;
+using ::android::sp;
using ::android::hardware::hidl_bitfield;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using ::android::sp;
+using ::android::hardware::radio::config::V1_0::SimSlotStatus;
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
+using ::android::hardware::radio::V1_0::RadioResponseType;
#define TIMEOUT_PERIOD 75
#define RADIO_SERVICE_NAME "slot1"
@@ -46,6 +54,36 @@
class RadioHidlTest_v1_2;
extern ::android::hardware::radio::V1_2::CardStatus cardStatus;
+/* Callback class for radio config response */
+class RadioConfigResponse : public IRadioConfigResponse {
+ protected:
+ RadioHidlTest_v1_2& parent_v1_2;
+
+ public:
+ RadioResponseInfo rspInfo;
+ PhoneCapability phoneCap;
+ hidl_vec<SimSlotStatus> simSlotStatus;
+
+ RadioConfigResponse(RadioHidlTest_v1_2& parent_v1_2);
+ virtual ~RadioConfigResponse() = default;
+
+ Return<void> getSimSlotsStatusResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<SimSlotStatus>& slotStatus);
+
+ Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info);
+
+ Return<void> getPhoneCapabilityResponse(const RadioResponseInfo& info,
+ const PhoneCapability& phoneCapability);
+
+ Return<void> setPreferredDataModemResponse(const RadioResponseInfo& info);
+
+ Return<void> getModemsConfigResponse(const RadioResponseInfo& info,
+ const ModemsConfig& mConfig);
+
+ Return<void> setModemsConfigResponse(const RadioResponseInfo& info);
+};
+
/* Callback class for radio response v1_2*/
class RadioResponse_v1_2 : public ::android::hardware::radio::V1_2::IRadioResponse {
protected:
@@ -616,15 +654,27 @@
std::condition_variable cv_;
int count_;
+ /* Preferred data sim id */
+ const int DDS_LOGICAL_SLOT_INDEX = 0;
+
/* Serial number for radio request */
int serial;
+ /* Current logical slot id */
+ int logicalSlotId;
+
/* Update Sim Card Status */
void updateSimCardStatus();
/* Stop Network Scan Command */
void stopNetworkScan();
+ /* Set preferred data modem */
+ void setPreferredDataModem();
+
+ /* get current logical sim id */
+ void getLogicalSimId();
+
public:
virtual void SetUp() override;
@@ -642,4 +692,10 @@
/* radio indication handle */
sp<RadioIndication_v1_2> radioInd_v1_2;
+
+ /* radio config response handle */
+ sp<RadioConfigResponse> radioConfigRsp;
+
+ /* radio config service handle */
+ sp<IRadioConfig> radioConfig;
};
\ No newline at end of file
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
index 696c746..f81af9b 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
@@ -41,6 +41,12 @@
ALOGI("emergencyDial, rspInfo.error = %s\n", toString(radioRsp_v1_4->rspInfo.error).c_str());
EXPECT_EQ(RadioError::NONE, radioRsp_v1_4->rspInfo.error);
+
+ // Give some time for modem to establish the emergency call channel.
+ sleep(MODEM_EMERGENCY_CALL_ESTABLISH_TIME);
+
+ // Disconnect all the potential established calls to prevent them affecting other tests.
+ clearPotentialEstablishedCalls();
}
/*
@@ -67,6 +73,12 @@
ALOGI("emergencyDial_withServices, rspInfo.error = %s\n",
toString(radioRsp_v1_4->rspInfo.error).c_str());
EXPECT_EQ(RadioError::NONE, radioRsp_v1_4->rspInfo.error);
+
+ // Give some time for modem to establish the emergency call channel.
+ sleep(MODEM_EMERGENCY_CALL_ESTABLISH_TIME);
+
+ // Disconnect all the potential established calls to prevent them affecting other tests.
+ clearPotentialEstablishedCalls();
}
/*
@@ -93,6 +105,12 @@
ALOGI("emergencyDial_withEmergencyRouting, rspInfo.error = %s\n",
toString(radioRsp_v1_4->rspInfo.error).c_str());
EXPECT_EQ(RadioError::NONE, radioRsp_v1_4->rspInfo.error);
+
+ // Give some time for modem to establish the emergency call channel.
+ sleep(MODEM_EMERGENCY_CALL_ESTABLISH_TIME);
+
+ // Disconnect all the potential established calls to prevent them affecting other tests.
+ clearPotentialEstablishedCalls();
}
/*
@@ -151,6 +169,11 @@
/*
* Test IRadio.startNetworkScan() for the response returned.
+ *
+ * REQUEST_NOT_SUPPORTED is temporarily returned because of vendors failed to fully implement
+ * startNetworkScan in HAL @1.4 (see b/137298570 and b/135595082). Starting from @1.5, however,
+ * REQUEST_NOT_SUPPORTED will be disallowed for all tests. Modems have "GSM" rat scan need to
+ * support scanning requests combined with some parameters.
*/
TEST_F(RadioHidlTest_v1_4, startNetworkScan) {
serial = GetRandomSerialNumber();
@@ -173,10 +196,17 @@
if (cardStatus.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::SIM_ABSENT}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- // OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do not support the
- // required manual GSM search functionality. This is tracked in b/112206766.
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
- {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED}));
+ // OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do
+ // not support the required manual GSM search functionality. This is
+ // tracked in b/112206766. REQUEST_NOT_SUPPORTED is temporarily added back
+ // because of vendors failed to implement startNetworkScan in HAL 1.4 (see
+ // b/137298570 and b/135595082). Starting from 1.5, however,
+ // REQUEST_NOT_SUPPORTED will be disallowed. Modems have "GSM" rat scan
+ // need to support scanning requests combined with some parameters.
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+ {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED,
+ RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -202,8 +232,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -238,8 +269,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -273,8 +305,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -308,8 +341,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -343,8 +377,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -378,8 +413,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -413,8 +449,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -450,8 +487,10 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::NONE, RadioError::SIM_ABSENT}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
- {RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+ {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
+ RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -489,8 +528,10 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::NONE, RadioError::SIM_ABSENT}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
- {RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+ {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
+ RadioError::REQUEST_NOT_SUPPORTED}));
}
}
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_test.cpp b/radio/1.4/vts/functional/radio_hidl_hal_test.cpp
index d2d21ce..f27749b 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.4/vts/functional/radio_hidl_hal_test.cpp
@@ -87,6 +87,29 @@
return status;
}
+void RadioHidlTest_v1_4::clearPotentialEstablishedCalls() {
+ // Get the current call Id to hangup the established emergency call.
+ serial = GetRandomSerialNumber();
+ radio_v1_4->getCurrentCalls(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+
+ // Hang up to disconnect the established call channels.
+ for (const ::android::hardware::radio::V1_2::Call& call : radioRsp_v1_4->currentCalls) {
+ serial = GetRandomSerialNumber();
+ radio_v1_4->hangup(serial, call.base.index);
+ ALOGI("Hang up to disconnect the established call channel: %d", call.base.index);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ // Give some time for modem to disconnect the established call channel.
+ sleep(MODEM_EMERGENCY_CALL_DISCONNECT_TIME);
+ }
+
+ // Verify there are no more current calls.
+ serial = GetRandomSerialNumber();
+ radio_v1_4->getCurrentCalls(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(0, radioRsp_v1_4->currentCalls.size());
+}
+
void RadioHidlTest_v1_4::updateSimCardStatus() {
serial = GetRandomSerialNumber();
radio_v1_4->getIccCardStatus(serial);
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_utils_v1_4.h b/radio/1.4/vts/functional/radio_hidl_hal_utils_v1_4.h
index f662472..b07f9c3 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_utils_v1_4.h
+++ b/radio/1.4/vts/functional/radio_hidl_hal_utils_v1_4.h
@@ -44,6 +44,9 @@
using ::android::hardware::Void;
#define TIMEOUT_PERIOD 75
+#define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3
+#define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3
+
#define RADIO_SERVICE_NAME "slot1"
class RadioHidlTest_v1_4;
@@ -59,6 +62,9 @@
RadioResponseInfo rspInfo;
+ // Call
+ hidl_vec<::android::hardware::radio::V1_2::Call> currentCalls;
+
// Modem
bool isModemEnabled;
bool enableModemResponseToggle;
@@ -725,6 +731,9 @@
/* Serial number for radio request */
int serial;
+ /* Clear Potential Established Calls */
+ void clearPotentialEstablishedCalls();
+
/* Update Sim Card Status */
void updateSimCardStatus();
diff --git a/radio/1.4/vts/functional/radio_response.cpp b/radio/1.4/vts/functional/radio_response.cpp
index eac0c68..a849926 100644
--- a/radio/1.4/vts/functional/radio_response.cpp
+++ b/radio/1.4/vts/functional/radio_response.cpp
@@ -77,7 +77,9 @@
return Void();
}
-Return<void> RadioResponse_v1_4::hangupConnectionResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_4::hangupConnectionResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_4.notify(info.serial);
return Void();
}
@@ -729,9 +731,10 @@
Return<void> RadioResponse_v1_4::getCurrentCallsResponse_1_2(
const RadioResponseInfo& info,
- const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& /*calls*/) {
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls) {
rspInfo = info;
parent_v1_4.notify(info.serial);
+ currentCalls = calls;
return Void();
}
diff --git a/radio/config/1.0/default/android.hardware.radio.config@1.0-service.rc b/radio/config/1.0/default/android.hardware.radio.config@1.0-service.rc
index fad16b1..94d5edb 100644
--- a/radio/config/1.0/default/android.hardware.radio.config@1.0-service.rc
+++ b/radio/config/1.0/default/android.hardware.radio.config@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.radio-config-hal-1-0 /vendor/bin/hw/android.hardware.radio.config@1.0-service
+ interface android.hardware.radio.config@1.0::IRadioConfig default
class hal
user system
group system
diff --git a/sensors/1.0/default/OWNERS b/sensors/1.0/default/OWNERS
index 2031d84..90c2330 100644
--- a/sensors/1.0/default/OWNERS
+++ b/sensors/1.0/default/OWNERS
@@ -1,2 +1,3 @@
+arthuri@google.com
bduddie@google.com
-bstack@google.com
+stange@google.com
diff --git a/sensors/1.0/default/android.hardware.sensors@1.0-service.rc b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
index b54842d..4faa562 100644
--- a/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
+++ b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.sensors-hal-1-0 /vendor/bin/hw/android.hardware.sensors@1.0-service
+ interface android.hardware.sensors@1.0::ISensors default
class hal
user system
group system wakelock
diff --git a/sensors/1.0/vts/functional/OWNERS b/sensors/1.0/vts/functional/OWNERS
index 759d87b..892da15 100644
--- a/sensors/1.0/vts/functional/OWNERS
+++ b/sensors/1.0/vts/functional/OWNERS
@@ -1,6 +1,7 @@
# Sensors team
+arthuri@google.com
bduddie@google.com
-bstack@google.com
+stange@google.com
# VTS team
trong@google.com
diff --git a/sensors/2.0/default/OWNERS b/sensors/2.0/default/OWNERS
index 2031d84..90c2330 100644
--- a/sensors/2.0/default/OWNERS
+++ b/sensors/2.0/default/OWNERS
@@ -1,2 +1,3 @@
+arthuri@google.com
bduddie@google.com
-bstack@google.com
+stange@google.com
diff --git a/sensors/2.0/vts/functional/OWNERS b/sensors/2.0/vts/functional/OWNERS
index 759d87b..892da15 100644
--- a/sensors/2.0/vts/functional/OWNERS
+++ b/sensors/2.0/vts/functional/OWNERS
@@ -1,6 +1,7 @@
# Sensors team
+arthuri@google.com
bduddie@google.com
-bstack@google.com
+stange@google.com
# VTS team
trong@google.com
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
index 03fcc17..dc54f27 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
@@ -130,8 +130,8 @@
void SensorsHidlEnvironmentV2_0::startPollingThread() {
mStopThread = false;
- mPollThread = std::thread(pollingThread, this);
mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT);
+ mPollThread = std::thread(pollingThread, this);
}
void SensorsHidlEnvironmentV2_0::readEvents() {
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index c6d7cad..6ff393d 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -38,6 +38,10 @@
using ::android::hardware::sensors::V1_0::SensorStatus;
using ::android::hardware::sensors::V1_0::SharedMemType;
using ::android::hardware::sensors::V1_0::Vec3;
+using std::chrono::duration_cast;
+using std::chrono::microseconds;
+using std::chrono::milliseconds;
+using std::chrono::nanoseconds;
constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
@@ -67,9 +71,9 @@
}
void waitForFlushEvents(const std::vector<SensorInfo>& sensorsToWaitFor,
- int32_t numCallsToFlush, int64_t timeoutMs) {
+ int32_t numCallsToFlush, milliseconds timeout) {
std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
- mFlushCV.wait_for(lock, std::chrono::milliseconds(timeoutMs),
+ mFlushCV.wait_for(lock, timeout,
[&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); });
}
@@ -78,10 +82,9 @@
return mEventMap[sensorHandle];
}
- void waitForEvents(const std::vector<SensorInfo>& sensorsToWaitFor, int32_t timeoutMs) {
+ void waitForEvents(const std::vector<SensorInfo>& sensorsToWaitFor, milliseconds timeout) {
std::unique_lock<std::recursive_mutex> lock(mEventMutex);
- mEventCV.wait_for(lock, std::chrono::milliseconds(timeoutMs),
- [&] { return eventsReceived(sensorsToWaitFor); });
+ mEventCV.wait_for(lock, timeout, [&] { return eventsReceived(sensorsToWaitFor); });
}
protected:
@@ -372,7 +375,7 @@
}
// Wait for events to be written back to the Event FMQ
- callback.waitForEvents(sensors, 1000 /* timeoutMs */);
+ callback.waitForEvents(sensors, milliseconds(1000) /* timeout */);
for (const auto& s : sensors) {
auto events = callback.getEvents(s.sensorHandle);
@@ -696,11 +699,16 @@
Result flushResult = flush(sensor.sensorHandle);
ASSERT_EQ(flushResult, expectedResponse);
}
- activate(sensor.sensorHandle, false);
}
// Wait up to one second for the flush events
- callback.waitForFlushEvents(sensors, flushCalls, 1000 /* timeoutMs */);
+ callback.waitForFlushEvents(sensors, flushCalls, milliseconds(1000) /* timeout */);
+
+ // Deactivate all sensors after waiting for flush events so pending flush events are not
+ // abandoned by the HAL.
+ for (const SensorInfo& sensor : sensors) {
+ activate(sensor.sensorHandle, false);
+ }
getEnvironment()->unregisterCallback();
// Check that the correct number of flushes are present for each sensor
@@ -815,17 +823,18 @@
}
TEST_F(SensorsHidlTest, NoStaleEvents) {
- constexpr int64_t kFiveHundredMilliseconds = 500 * 1000;
- constexpr int64_t kOneSecond = 1000 * 1000;
+ constexpr milliseconds kFiveHundredMs(500);
+ constexpr milliseconds kOneSecond(1000);
// Register the callback to receive sensor events
EventCallback callback;
getEnvironment()->registerCallback(&callback);
const std::vector<SensorInfo> sensors = getSensorsList();
- int32_t maxMinDelay = 0;
+ milliseconds maxMinDelay(0);
for (const SensorInfo& sensor : getSensorsList()) {
- maxMinDelay = std::max(maxMinDelay, sensor.minDelay);
+ milliseconds minDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
+ maxMinDelay = milliseconds(std::max(maxMinDelay.count(), minDelay.count()));
}
// Activate the sensors so that they start generating events
@@ -834,7 +843,7 @@
// According to the CDD, the first sample must be generated within 400ms + 2 * sample_time
// and the maximum reporting latency is 100ms + 2 * sample_time. Wait a sufficient amount
// of time to guarantee that a sample has arrived.
- callback.waitForEvents(sensors, kFiveHundredMilliseconds + (5 * maxMinDelay));
+ callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
activateAllSensors(false);
// Save the last received event for each sensor
@@ -846,21 +855,21 @@
}
// Allow some time to pass, reset the callback, then reactivate the sensors
- usleep(kOneSecond + (5 * maxMinDelay));
+ usleep(duration_cast<microseconds>(kOneSecond + (5 * maxMinDelay)).count());
callback.reset();
activateAllSensors(true);
- callback.waitForEvents(sensors, kFiveHundredMilliseconds + (5 * maxMinDelay));
+ callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
activateAllSensors(false);
for (const SensorInfo& sensor : sensors) {
// Ensure that the first event received is not stale by ensuring that its timestamp is
// sufficiently different from the previous event
const Event newEvent = callback.getEvents(sensor.sensorHandle).front();
- int64_t delta = newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle];
- ASSERT_GE(delta, kFiveHundredMilliseconds + (3 * sensor.minDelay));
+ milliseconds delta = duration_cast<milliseconds>(
+ nanoseconds(newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle]));
+ milliseconds sensorMinDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
+ ASSERT_GE(delta, kFiveHundredMs + (3 * sensorMinDelay));
}
-
- getEnvironment()->unregisterCallback();
}
void SensorsHidlTest::checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle,
diff --git a/sensors/common/vts/OWNERS b/sensors/common/vts/OWNERS
index 759d87b..892da15 100644
--- a/sensors/common/vts/OWNERS
+++ b/sensors/common/vts/OWNERS
@@ -1,6 +1,7 @@
# Sensors team
+arthuri@google.com
bduddie@google.com
-bstack@google.com
+stange@google.com
# VTS team
trong@google.com
diff --git a/sensors/common/vts/utils/OWNERS b/sensors/common/vts/utils/OWNERS
index 759d87b..892da15 100644
--- a/sensors/common/vts/utils/OWNERS
+++ b/sensors/common/vts/utils/OWNERS
@@ -1,6 +1,7 @@
# Sensors team
+arthuri@google.com
bduddie@google.com
-bstack@google.com
+stange@google.com
# VTS team
trong@google.com
diff --git a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
index affdf8b..fa0e2e9 100644
--- a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
+++ b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
@@ -29,7 +29,9 @@
void SensorsHidlEnvironmentBase::HidlTearDown() {
mStopThread = true;
- mPollThread.detach();
+ if (mPollThread.joinable()) {
+ mPollThread.detach();
+ }
}
void SensorsHidlEnvironmentBase::catEvents(std::vector<Event>* output) {
diff --git a/tests/libhwbinder/aidl/Android.bp b/tests/libhwbinder/aidl/Android.bp
index 6d49704..c9e09f7 100644
--- a/tests/libhwbinder/aidl/Android.bp
+++ b/tests/libhwbinder/aidl/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
name: "android.hardware.tests.libbinder",
defaults: ["hidl_defaults"],
diff --git a/thermal/1.0/default/android.hardware.thermal@1.0-service.rc b/thermal/1.0/default/android.hardware.thermal@1.0-service.rc
index cf9bdee..ba3ce82 100644
--- a/thermal/1.0/default/android.hardware.thermal@1.0-service.rc
+++ b/thermal/1.0/default/android.hardware.thermal@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.thermal-hal-1-0 /vendor/bin/hw/android.hardware.thermal@1.0-service
+ interface android.hardware.thermal@1.0::IThermal default
class hal
user system
group system
diff --git a/thermal/2.0/default/android.hardware.thermal@2.0-service.rc b/thermal/2.0/default/android.hardware.thermal@2.0-service.rc
index 046c771..4ff8bd6 100644
--- a/thermal/2.0/default/android.hardware.thermal@2.0-service.rc
+++ b/thermal/2.0/default/android.hardware.thermal@2.0-service.rc
@@ -1,4 +1,5 @@
service vendor.thermal-hal-2-0-mock /vendor/bin/hw/android.hardware.thermal@2.0-service.mock
+ interface android.hardware.thermal@1.0::IThermal default
interface android.hardware.thermal@2.0::IThermal default
class hal
user system
diff --git a/tv/cec/1.0/config/sadConfig.xsd b/tv/cec/1.0/config/sadConfig.xsd
new file mode 100644
index 0000000..7f99311
--- /dev/null
+++ b/tv/cec/1.0/config/sadConfig.xsd
@@ -0,0 +1,86 @@
+<?xml version="1.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.
+-->
+<xs:schema version="1.0"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:include schemaLocation="../../../../audio/4.0/config/audio_policy_configuration.xsd"/>
+ <xs:complexType name="config">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ List the config versions supported by Short Audio Descriptor(SAD) config.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="device" type="device" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="version" type="version"/>
+ </xs:complexType>
+ <xs:complexType name="device">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Device section:
+ There is a list of configurations in this SAD config for all the input audio
+ devices that the current Android device supports.
+ Each device has the following attributes:
+ "type": type of the audio device.
+ And the following element
+ <supportedFormat/>: the supported format info of the device. There can be
+ multiple formats supported by one audio device.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="supportedFormat" type="supportedFormat" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="type" type="extendableAudioDevice" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="supportedFormat">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ SupportedFormat section:
+ The details of the short audio descriptor of a specific audio format
+ supported by the audio device. Attributes as follows:
+ "format": format enum of the current supported format.
+ "descriptor": three-byte short audio descriptor for the given format in hex.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="format" type="hdmiAudioFormat" use="required"/>
+ <xs:attribute name="descriptor" type="descriptor" use="required"/>
+ </xs:complexType>
+ <xs:simpleType name="descriptor">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[a-fA-F0-9]{6}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="hdmiAudioFormat">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_FORMAT_NONE"/>
+ <xs:enumeration value="AUDIO_FORMAT_LPCM"/>
+ <xs:enumeration value="AUDIO_FORMAT_DD"/>
+ <xs:enumeration value="AUDIO_FORMAT_MPEG1"/>
+ <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+ <xs:enumeration value="AUDIO_FORMAT_MPEG2"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+ <xs:enumeration value="AUDIO_FORMAT_ATRAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_ONEBITAUDIO"/>
+ <xs:enumeration value="AUDIO_FORMAT_DDP"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTSHD"/>
+ <xs:enumeration value="AUDIO_FORMAT_TRUEHD"/>
+ <xs:enumeration value="AUDIO_FORMAT_DST"/>
+ <xs:enumeration value="AUDIO_FORMAT_WMAPRO"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:element name="config" type="config"/>
+</xs:schema>
diff --git a/tv/cec/1.0/default/Android.bp b/tv/cec/1.0/default/Android.bp
index 069f327..5fe731b 100644
--- a/tv/cec/1.0/default/Android.bp
+++ b/tv/cec/1.0/default/Android.bp
@@ -39,3 +39,26 @@
],
}
+
+cc_binary {
+ name: "android.hardware.tv.cec@1.0-service.mock",
+ vintf_fragments: ["android.hardware.tv.cec@1.0-service.mock.xml"],
+ relative_install_path: "hw",
+ vendor: true,
+ init_rc: ["android.hardware.tv.cec@1.0-service.mock.rc"],
+ srcs: [
+ "serviceMock.cpp",
+ "HdmiCecMock.cpp",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libbase",
+ "libutils",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "android.hardware.tv.cec@1.0",
+ ],
+}
diff --git a/tv/cec/1.0/default/HdmiCecMock.cpp b/tv/cec/1.0/default/HdmiCecMock.cpp
new file mode 100644
index 0000000..eba8f95
--- /dev/null
+++ b/tv/cec/1.0/default/HdmiCecMock.cpp
@@ -0,0 +1,157 @@
+/*
+ * 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 "android.hardware.tv.cec@1.0-mock"
+#include <android-base/logging.h>
+#include <utils/Log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/hdmi_cec.h>
+#include "HdmiCecMock.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace V1_0 {
+namespace implementation {
+
+/*
+ * (*set_option)() passes flags controlling the way HDMI-CEC service works down
+ * to HAL implementation. Those flags will be used in case the feature needs
+ * update in HAL itself, firmware or microcontroller.
+ */
+void HdmiCecMock::cec_set_option(int flag, int value) {
+ // maintain options and set them accordingly
+ switch (flag) {
+ case HDMI_OPTION_WAKEUP:
+ mOptionWakeUp = value;
+ break;
+ case HDMI_OPTION_ENABLE_CEC:
+ mOptionEnableCec = value;
+ break;
+ case HDMI_OPTION_SYSTEM_CEC_CONTROL:
+ mOptionSystemCecControl = value;
+ break;
+ case HDMI_OPTION_SET_LANG:
+ mOptionLanguage = value;
+ }
+}
+
+// Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
+Return<Result> HdmiCecMock::addLogicalAddress(CecLogicalAddress addr) {
+ // have a list to maintain logical addresses
+ int size = mLogicalAddresses.size();
+ mLogicalAddresses.resize(size + 1);
+ mLogicalAddresses[size + 1] = addr;
+ return Result::SUCCESS;
+}
+
+Return<void> HdmiCecMock::clearLogicalAddress() {
+ // remove logical address from the list
+ mLogicalAddresses = {};
+ return Void();
+}
+
+Return<void> HdmiCecMock::getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) {
+ // maintain a physical address and return it
+ // default 0xFFFF, update on hotplug event
+ _hidl_cb(Result::SUCCESS, mPhysicalAddress);
+ return Void();
+}
+
+Return<SendMessageResult> HdmiCecMock::sendMessage(const CecMessage& message) {
+ if (message.body.size() == 0) {
+ return SendMessageResult::NACK;
+ }
+ return SendMessageResult::SUCCESS;
+}
+
+Return<void> HdmiCecMock::setCallback(const sp<IHdmiCecCallback>& callback) {
+ if (mCallback != nullptr) {
+ mCallback = nullptr;
+ }
+
+ if (callback != nullptr) {
+ mCallback = callback;
+ mCallback->linkToDeath(this, 0 /*cookie*/);
+ }
+ return Void();
+}
+
+Return<int32_t> HdmiCecMock::getCecVersion() {
+ // maintain a cec version and return it
+ return mCecVersion;
+}
+
+Return<uint32_t> HdmiCecMock::getVendorId() {
+ return mCecVendorId;
+}
+
+Return<void> HdmiCecMock::getPortInfo(getPortInfo_cb _hidl_cb) {
+ vector<HdmiPortInfo> portInfos;
+ // TODO ready port info from device specific config
+ portInfos.resize(mTotalPorts);
+ for (int i = 0; i < mTotalPorts; ++i) {
+ portInfos[i] = {.type = HdmiPortType::INPUT,
+ .portId = static_cast<uint32_t>(i),
+ .cecSupported = true,
+ .arcSupported = (i == 0),
+ .physicalAddress = static_cast<uint16_t>(i << 12)};
+ }
+ _hidl_cb(portInfos);
+ return Void();
+}
+
+Return<void> HdmiCecMock::setOption(OptionKey key, bool value) {
+ cec_set_option(static_cast<int>(key), value ? 1 : 0);
+ return Void();
+}
+
+Return<void> HdmiCecMock::setLanguage(const hidl_string& language) {
+ if (language.size() != 3) {
+ LOG(ERROR) << "Wrong language code: expected 3 letters, but it was " << language.size()
+ << ".";
+ return Void();
+ }
+ // TODO validate if language is a valid language code
+ const char* languageStr = language.c_str();
+ int convertedLanguage = ((languageStr[0] & 0xFF) << 16) | ((languageStr[1] & 0xFF) << 8) |
+ (languageStr[2] & 0xFF);
+ cec_set_option(HDMI_OPTION_SET_LANG, convertedLanguage);
+ return Void();
+}
+
+Return<void> HdmiCecMock::enableAudioReturnChannel(int32_t portId __unused, bool enable __unused) {
+ // Maintain ARC status
+ return Void();
+}
+
+Return<bool> HdmiCecMock::isConnected(int32_t portId __unused) {
+ // maintain port connection status and update on hotplug event
+ return false;
+}
+
+HdmiCecMock::HdmiCecMock() {
+ ALOGE("Opening a virtual HAL for testing and virtual machine.");
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cec
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/cec/1.0/default/HdmiCecMock.h b/tv/cec/1.0/default/HdmiCecMock.h
new file mode 100644
index 0000000..b2f1113
--- /dev/null
+++ b/tv/cec/1.0/default/HdmiCecMock.h
@@ -0,0 +1,97 @@
+/*
+ * 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_TV_CEC_V1_0_HDMICEC_H
+#define ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H
+
+#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
+#include <hardware/hardware.h>
+#include <hardware/hdmi_cec.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <algorithm>
+#include <vector>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::tv::cec::V1_0::CecLogicalAddress;
+using ::android::hardware::tv::cec::V1_0::CecMessage;
+using ::android::hardware::tv::cec::V1_0::HdmiPortInfo;
+using ::android::hardware::tv::cec::V1_0::IHdmiCec;
+using ::android::hardware::tv::cec::V1_0::IHdmiCecCallback;
+using ::android::hardware::tv::cec::V1_0::MaxLength;
+using ::android::hardware::tv::cec::V1_0::OptionKey;
+using ::android::hardware::tv::cec::V1_0::Result;
+using ::android::hardware::tv::cec::V1_0::SendMessageResult;
+
+struct HdmiCecMock : public IHdmiCec, public hidl_death_recipient {
+ HdmiCecMock();
+ // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
+ Return<Result> addLogicalAddress(CecLogicalAddress addr) override;
+ Return<void> clearLogicalAddress() override;
+ Return<void> getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) override;
+ Return<SendMessageResult> sendMessage(const CecMessage& message) override;
+ Return<void> setCallback(const sp<IHdmiCecCallback>& callback) override;
+ Return<int32_t> getCecVersion() override;
+ Return<uint32_t> getVendorId() override;
+ Return<void> getPortInfo(getPortInfo_cb _hidl_cb) override;
+ Return<void> setOption(OptionKey key, bool value) override;
+ Return<void> setLanguage(const hidl_string& language) override;
+ Return<void> enableAudioReturnChannel(int32_t portId, bool enable) override;
+ Return<bool> isConnected(int32_t portId) override;
+
+ virtual void serviceDied(uint64_t /*cookie*/,
+ const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+ setCallback(nullptr);
+ }
+
+ void cec_set_option(int flag, int value);
+
+ private:
+ sp<IHdmiCecCallback> mCallback;
+ // Variables for the virtual cec hal impl
+ uint16_t mPhysicalAddress = 0xFFFF;
+ vector<CecLogicalAddress> mLogicalAddresses;
+ int32_t mCecVersion = 0;
+ uint32_t mCecVendorId = 0;
+ // Port configuration
+ int mTotalPorts = 4;
+ // CEC Option value
+ int mOptionWakeUp = 0;
+ int mOptionEnableCec = 0;
+ int mOptionSystemCecControl = 0;
+ int mOptionLanguage = 0;
+};
+} // namespace implementation
+} // namespace V1_0
+} // namespace cec
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H
diff --git a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.rc b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.rc
new file mode 100644
index 0000000..170b485
--- /dev/null
+++ b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.rc
@@ -0,0 +1,5 @@
+service vendor.cec-hal-1-0-mock /vendor/bin/hw/android.hardware.tv.cec@1.0-service.mock
+ interface android.hardware.tv.cec@1.0::IHdmiCec default
+ class hal
+ user system
+ group system
diff --git a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.xml b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.xml
new file mode 100644
index 0000000..5afa59d
--- /dev/null
+++ b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.tv.cec</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IHdmiCec</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc
index 8595099..6d25229 100644
--- a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc
+++ b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.cec-hal-1-0 /vendor/bin/hw/android.hardware.tv.cec@1.0-service
+ interface android.hardware.tv.cec@1.0::IHdmiCec default
class hal
user system
group system
diff --git a/tv/cec/1.0/default/serviceMock.cpp b/tv/cec/1.0/default/serviceMock.cpp
new file mode 100644
index 0000000..c0af22f
--- /dev/null
+++ b/tv/cec/1.0/default/serviceMock.cpp
@@ -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.
+ */
+
+#define LOG_TAG "android.hardware.tv.cec@1.0-service-shim"
+
+#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
+#include <hidl/LegacySupport.h>
+#include "HdmiCecMock.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::tv::cec::V1_0::IHdmiCec;
+using android::hardware::tv::cec::V1_0::implementation::HdmiCecMock;
+
+int main() {
+ configureRpcThreadpool(8, true /* callerWillJoin */);
+
+ // Setup hwbinder service
+ android::sp<IHdmiCec> service = new HdmiCecMock();
+ android::status_t status;
+ status = service->registerAsService();
+ LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering mock cec service: %d",
+ status);
+
+ joinRpcThreadpool();
+ return 0;
+}
diff --git a/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc b/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc
index 972c654..6cb9a43 100644
--- a/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc
+++ b/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.tv-input-1-0 /vendor/bin/hw/android.hardware.tv.input@1.0-service
+ interface android.hardware.tv.input@1.0::ITvInput default
class hal
user system
group system
diff --git a/usb/1.0/default/android.hardware.usb@1.0-service.rc b/usb/1.0/default/android.hardware.usb@1.0-service.rc
index b7a0c63..3c44d21 100644
--- a/usb/1.0/default/android.hardware.usb@1.0-service.rc
+++ b/usb/1.0/default/android.hardware.usb@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.usb-hal-1-0 /vendor/bin/hw/android.hardware.usb@1.0-service
+ interface android.hardware.usb@1.0::IUsb default
class hal
user system
group system
diff --git a/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc b/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc
index 1123eab..1bd5c10 100644
--- a/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc
+++ b/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.vibrator-1-0 /vendor/bin/hw/android.hardware.vibrator@1.0-service
+ interface android.hardware.vibrator@1.0::IVibrator default
class hal
user system
group system
diff --git a/vr/1.0/default/android.hardware.vr@1.0-service.rc b/vr/1.0/default/android.hardware.vr@1.0-service.rc
index fc4934c..5486674 100644
--- a/vr/1.0/default/android.hardware.vr@1.0-service.rc
+++ b/vr/1.0/default/android.hardware.vr@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.vr-1-0 /vendor/bin/hw/android.hardware.vr@1.0-service
+ interface android.hardware.vr@1.0::IVr default
class hal
user system
group system
diff --git a/wifi/1.3/default/android.hardware.wifi@1.0-service.rc b/wifi/1.3/default/android.hardware.wifi@1.0-service.rc
index cf849d0..2317bac 100644
--- a/wifi/1.3/default/android.hardware.wifi@1.0-service.rc
+++ b/wifi/1.3/default/android.hardware.wifi@1.0-service.rc
@@ -1,4 +1,7 @@
service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
+ interface android.hardware.wifi@1.0::IWifi default
+ interface android.hardware.wifi@1.1::IWifi default
+ interface android.hardware.wifi@1.2::IWifi default
class hal
capabilities NET_ADMIN NET_RAW SYS_MODULE
user wifi
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
index 26a58b2..ffd4d97 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
@@ -56,6 +56,9 @@
protected:
std::string getPrimaryWlanIfaceName() {
std::array<char, PROPERTY_VALUE_MAX> buffer;
+ auto res = property_get("ro.vendor.wifi.sap.interface",
+ buffer.data(), nullptr);
+ if (res > 0) return buffer.data();
property_get("wifi.interface", buffer.data(), "wlan0");
return buffer.data();
}
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp
index 36bde16..1b78ac3 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp
@@ -127,25 +127,33 @@
});
}
+bool isMacRandomizationSupported(const SupplicantStatus& status) {
+ return status.code != SupplicantStatusCode::FAILURE_ARGS_INVALID;
+}
+
/*
* Verify that setMacRandomization successes.
*/
TEST_F(SupplicantP2pIfaceHidlTest, EnableMacRandomization) {
p2p_iface_->setMacRandomization(true, [](const SupplicantStatus& status) {
+ if (!isMacRandomizationSupported(status)) return;
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
});
// enable twice
p2p_iface_->setMacRandomization(true, [](const SupplicantStatus& status) {
+ if (!isMacRandomizationSupported(status)) return;
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
});
p2p_iface_->setMacRandomization(false, [](const SupplicantStatus& status) {
+ if (!isMacRandomizationSupported(status)) return;
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
});
// disable twice
p2p_iface_->setMacRandomization(false, [](const SupplicantStatus& status) {
+ if (!isMacRandomizationSupported(status)) return;
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
});
}