Merge "wifi: Legacy HAL Thermal API stub"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 76594fb..1eca2a1 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -84,3 +84,4 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.cas@1.1*)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.cas@1.1*)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/vintf/manifest/android.hardware.cas@1.1*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/hardware/interfaces/wifi/1.4/android.hardware.wifi@1.4-adapter_genc++/)
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 0140275..6740bb5 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -2,6 +2,7 @@
ignore_merged_commits = true
[Builtin Hooks]
+bpfmt = true
clang_format = true
[Hook Scripts]
diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal
index 122c550..c2e310c 100644
--- a/audio/6.0/IDevice.hal
+++ b/audio/6.0/IDevice.hal
@@ -168,6 +168,25 @@
generates (Result retval, AudioPatchHandle patch);
/**
+ * Updates an audio patch.
+ *
+ * Use of this function is preferred to releasing and re-creating a patch
+ * as the HAL module can figure out a way of switching the route without
+ * causing audio disruption.
+ *
+ * @param previousPatch handle of the previous patch to update.
+ * @param sources new patch sources.
+ * @param sinks new patch sinks.
+ * @return retval operation completion status.
+ * @return patch updated patch handle.
+ */
+ updateAudioPatch(
+ AudioPatchHandle previousPatch,
+ vec<AudioPortConfig> sources,
+ vec<AudioPortConfig> sinks) generates (
+ Result retval, AudioPatchHandle patch);
+
+ /**
* Release an audio patch.
*
* @param patch patch handle.
@@ -295,4 +314,28 @@
*/
@exit
close() generates (Result retval);
+
+ /**
+ * Applies an audio effect to an audio device.
+ *
+ * @param device identifies the sink or source device this effect must be applied to.
+ * "device" is the AudioPortHandle indicated for the device when the audio
+ * patch connecting that device was created.
+ * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+ * the effect to add.
+ * @return retval operation completion status.
+ */
+ addDeviceEffect(AudioPortHandle device, uint64_t effectId) generates (Result retval);
+
+ /**
+ * Stops applying an audio effect to an audio device.
+ *
+ * @param device identifies the sink or source device this effect was applied to.
+ * "device" is the AudioPortHandle indicated for the device when the audio
+ * patch is created at the audio HAL.
+ * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+ * the effect.
+ * @return retval operation completion status.
+ */
+ removeDeviceEffect(AudioPortHandle device, uint64_t effectId) generates (Result retval);
};
diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal
index d7d3c84..2ea1ab3 100644
--- a/audio/6.0/IStream.hal
+++ b/audio/6.0/IStream.hal
@@ -274,6 +274,7 @@
*
* @param minSizeFrames minimum buffer size requested. The actual buffer
* size returned in struct MmapBufferInfo can be larger.
+ * The size must be a positive value.
* @return retval OK in case the success.
* NOT_SUPPORTED on non mmap mode streams
* NOT_INITIALIZED in case of memory allocation error
diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt
index ddd4d1c..0407d69 100644
--- a/audio/6.0/config/api/current.txt
+++ b/audio/6.0/config/api/current.txt
@@ -361,6 +361,7 @@
method public String getRawName();
enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ACCESSIBILITY;
enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ALARM;
+ enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ASSISTANT;
enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_BLUETOOTH_SCO;
enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_DTMF;
enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ENFORCED_AUDIBLE;
diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd
index 3fab7dc..05c8ab4 100644
--- a/audio/6.0/config/audio_policy_configuration.xsd
+++ b/audio/6.0/config/audio_policy_configuration.xsd
@@ -551,6 +551,7 @@
<xs:enumeration value="AUDIO_STREAM_DTMF"/>
<xs:enumeration value="AUDIO_STREAM_TTS"/>
<xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+ <xs:enumeration value="AUDIO_STREAM_ASSISTANT"/>
<xs:enumeration value="AUDIO_STREAM_REROUTING"/>
<xs:enumeration value="AUDIO_STREAM_PATCH"/>
</xs:restriction>
diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal
index 0c97c36..563e05d 100644
--- a/audio/common/6.0/types.hal
+++ b/audio/common/6.0/types.hal
@@ -106,6 +106,7 @@
TTS = 9, // Transmitted Through Speaker. Plays over speaker
// only, silent on other devices
ACCESSIBILITY = 10, // For accessibility talk back prompts
+ ASSISTANT = 11, // For virtual assistant service
};
@export(name="audio_source_t", value_prefix="AUDIO_SOURCE_")
@@ -156,6 +157,11 @@
@export(name="audio_session_t", value_prefix="AUDIO_SESSION_")
enum AudioSessionConsts : int32_t {
/**
+ * Session for effects attached to a particular sink or source audio device
+ * (e.g an effect only applied to a speaker)
+ */
+ DEVICE = -2,
+ /**
* Session for effects attached to a particular output stream
* (value must be less than 0)
*/
@@ -734,6 +740,7 @@
MMAP_NOIRQ = 0x10, // input operates in MMAP no IRQ mode.
VOIP_TX = 0x20, // preferred input for VoIP calls.
HW_AV_SYNC = 0x40, // input connected to an output that uses a hardware A/V sync
+ DIRECT = 0x80, // for acquiring encoded streams
};
@export(name="audio_usage_t", value_prefix="AUDIO_USAGE_")
@@ -754,6 +761,7 @@
GAME = 14,
VIRTUAL_SOURCE = 15,
ASSISTANT = 16,
+ CALL_ASSISTANT = 17,
};
/** Type of audio generated by an application. */
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
index 4565730..f58a599 100644
--- a/audio/common/all-versions/default/service/Android.bp
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -41,6 +41,7 @@
"android.hardware.soundtrigger@2.0",
"android.hardware.soundtrigger@2.1",
"android.hardware.soundtrigger@2.2",
+ "android.hardware.soundtrigger@2.3",
],
}
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index 2730f3b..00bcb19 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -29,6 +29,7 @@
#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.3/ISoundTriggerHw.h>
#include <binder/ProcessState.h>
#include <cutils/properties.h>
#include <hidl/HidlTransportSupport.h>
@@ -78,9 +79,9 @@
"Could not register audio effect API");
// clang-format on
- ALOGW_IF((registerPassthroughServiceImplementations<soundtrigger::V2_2::ISoundTriggerHw,
- soundtrigger::V2_1::ISoundTriggerHw,
- soundtrigger::V2_0::ISoundTriggerHw>()),
+ ALOGW_IF((registerPassthroughServiceImplementations<
+ soundtrigger::V2_3::ISoundTriggerHw, soundtrigger::V2_2::ISoundTriggerHw,
+ soundtrigger::V2_1::ISoundTriggerHw, soundtrigger::V2_0::ISoundTriggerHw>()),
"Could not register soundtrigger API");
ALOGW_IF(registerPassthroughServiceImplementations<
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index 21dab00..47e31c1 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -18,6 +18,7 @@
#include "core/default/Device.h"
#include <HidlUtils.h>
+#include "common/all-versions/default/EffectMap.h"
#include "core/default/Conversions.h"
#include "core/default/StreamIn.h"
#include "core/default/StreamOut.h"
@@ -25,6 +26,7 @@
//#define LOG_NDEBUG 0
+#include <inttypes.h>
#include <memory.h>
#include <string.h>
#include <algorithm>
@@ -84,26 +86,29 @@
ALOGW("Can not set a master volume (%f) outside [0,1]", volume);
return Result::INVALID_ARGUMENTS;
}
- return analyzeStatus("set_master_volume", mDevice->set_master_volume(mDevice, volume));
+ return analyzeStatus("set_master_volume", mDevice->set_master_volume(mDevice, volume),
+ {ENOSYS} /*ignore*/);
}
Return<void> Device::getMasterVolume(getMasterVolume_cb _hidl_cb) {
Result retval(Result::NOT_SUPPORTED);
float volume = 0;
if (mDevice->get_master_volume != NULL) {
- retval = analyzeStatus("get_master_volume", mDevice->get_master_volume(mDevice, &volume));
+ retval = analyzeStatus("get_master_volume", mDevice->get_master_volume(mDevice, &volume),
+ {ENOSYS} /*ignore*/);
}
_hidl_cb(retval, volume);
return Void();
}
Return<Result> Device::setMicMute(bool mute) {
- return analyzeStatus("set_mic_mute", mDevice->set_mic_mute(mDevice, mute));
+ return analyzeStatus("set_mic_mute", mDevice->set_mic_mute(mDevice, mute), {ENOSYS} /*ignore*/);
}
Return<void> Device::getMicMute(getMicMute_cb _hidl_cb) {
bool mute = false;
- Result retval = analyzeStatus("get_mic_mute", mDevice->get_mic_mute(mDevice, &mute));
+ Result retval = analyzeStatus("get_mic_mute", mDevice->get_mic_mute(mDevice, &mute),
+ {ENOSYS} /*ignore*/);
_hidl_cb(retval, mute);
return Void();
}
@@ -111,7 +116,8 @@
Return<Result> Device::setMasterMute(bool mute) {
Result retval(Result::NOT_SUPPORTED);
if (mDevice->set_master_mute != NULL) {
- retval = analyzeStatus("set_master_mute", mDevice->set_master_mute(mDevice, mute));
+ retval = analyzeStatus("set_master_mute", mDevice->set_master_mute(mDevice, mute),
+ {ENOSYS} /*ignore*/);
}
return retval;
}
@@ -120,7 +126,8 @@
Result retval(Result::NOT_SUPPORTED);
bool mute = false;
if (mDevice->get_master_mute != NULL) {
- retval = analyzeStatus("get_master_mute", mDevice->get_master_mute(mDevice, &mute));
+ retval = analyzeStatus("get_master_mute", mDevice->get_master_mute(mDevice, &mute),
+ {ENOSYS} /*ignore*/);
}
_hidl_cb(retval, mute);
return Void();
@@ -262,12 +269,21 @@
Return<void> Device::createAudioPatch(const hidl_vec<AudioPortConfig>& sources,
const hidl_vec<AudioPortConfig>& sinks,
createAudioPatch_cb _hidl_cb) {
+ auto [retval, patch] = createOrUpdateAudioPatch(
+ static_cast<AudioPatchHandle>(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE), sources,
+ sinks);
+ _hidl_cb(retval, patch);
+ return Void();
+}
+
+std::tuple<Result, AudioPatchHandle> Device::createOrUpdateAudioPatch(
+ AudioPatchHandle patch, const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks) {
Result retval(Result::NOT_SUPPORTED);
- AudioPatchHandle patch = 0;
if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
std::unique_ptr<audio_port_config[]> halSources(HidlUtils::audioPortConfigsToHal(sources));
std::unique_ptr<audio_port_config[]> halSinks(HidlUtils::audioPortConfigsToHal(sinks));
- audio_patch_handle_t halPatch = AUDIO_PATCH_HANDLE_NONE;
+ audio_patch_handle_t halPatch = static_cast<audio_patch_handle_t>(patch);
retval = analyzeStatus("create_audio_patch",
mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0],
sinks.size(), &halSinks[0], &halPatch));
@@ -275,8 +291,7 @@
patch = static_cast<AudioPatchHandle>(halPatch);
}
}
- _hidl_cb(retval, patch);
- return Void();
+ return {retval, patch};
}
Return<Result> Device::releaseAudioPatch(int32_t patch) {
@@ -398,6 +413,52 @@
Return<Result> Device::close() {
return doClose();
}
+
+Return<Result> Device::addDeviceEffect(AudioPortHandle device, uint64_t effectId) {
+ if (version() < AUDIO_DEVICE_API_VERSION_3_1 || mDevice->add_device_effect == nullptr) {
+ return Result::NOT_SUPPORTED;
+ }
+
+ effect_handle_t halEffect = EffectMap::getInstance().get(effectId);
+ if (halEffect != NULL) {
+ return analyzeStatus("add_device_effect",
+ mDevice->add_device_effect(
+ mDevice, static_cast<audio_port_handle_t>(device), halEffect));
+ } else {
+ ALOGW("%s Invalid effect ID passed from client: %" PRIu64 "", __func__, effectId);
+ return Result::INVALID_ARGUMENTS;
+ }
+}
+
+Return<Result> Device::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) {
+ if (version() < AUDIO_DEVICE_API_VERSION_3_1 || mDevice->remove_device_effect == nullptr) {
+ return Result::NOT_SUPPORTED;
+ }
+
+ effect_handle_t halEffect = EffectMap::getInstance().get(effectId);
+ if (halEffect != NULL) {
+ return analyzeStatus("remove_device_effect",
+ mDevice->remove_device_effect(
+ mDevice, static_cast<audio_port_handle_t>(device), halEffect));
+ } else {
+ ALOGW("%s Invalid effect ID passed from client: %" PRIu64 "", __func__, effectId);
+ return Result::INVALID_ARGUMENTS;
+ }
+}
+
+Return<void> Device::updateAudioPatch(int32_t previousPatch,
+ const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks,
+ createAudioPatch_cb _hidl_cb) {
+ if (previousPatch != static_cast<int32_t>(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE)) {
+ auto [retval, patch] = createOrUpdateAudioPatch(previousPatch, sources, sinks);
+ _hidl_cb(retval, patch);
+ } else {
+ _hidl_cb(Result::INVALID_ARGUMENTS, previousPatch);
+ }
+ return Void();
+}
+
#endif
} // namespace implementation
diff --git a/audio/core/all-versions/default/PrimaryDevice.cpp b/audio/core/all-versions/default/PrimaryDevice.cpp
index 3cf0932..679f85d 100644
--- a/audio/core/all-versions/default/PrimaryDevice.cpp
+++ b/audio/core/all-versions/default/PrimaryDevice.cpp
@@ -168,6 +168,21 @@
Return<Result> PrimaryDevice::close() {
return mDevice->close();
}
+
+Return<Result> PrimaryDevice::addDeviceEffect(AudioPortHandle device, uint64_t effectId) {
+ return mDevice->addDeviceEffect(device, effectId);
+}
+
+Return<Result> PrimaryDevice::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) {
+ return mDevice->removeDeviceEffect(device, effectId);
+}
+
+Return<void> PrimaryDevice::updateAudioPatch(int32_t previousPatch,
+ const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks,
+ updateAudioPatch_cb _hidl_cb) {
+ return mDevice->updateAudioPatch(previousPatch, sources, sinks, _hidl_cb);
+}
#endif
// Methods from ::android::hardware::audio::CPP_VERSION::IPrimaryDevice follow.
diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp
index 396d354..1a2a764 100644
--- a/audio/core/all-versions/default/StreamOut.cpp
+++ b/audio/core/all-versions/default/StreamOut.cpp
@@ -318,7 +318,8 @@
ALOGW("Can not set a stream output volume {%f, %f} outside [0,1]", left, right);
return Result::INVALID_ARGUMENTS;
}
- return Stream::analyzeStatus("set_volume", mStream->set_volume(mStream, left, right));
+ return Stream::analyzeStatus("set_volume", mStream->set_volume(mStream, left, right),
+ {ENOSYS} /*ignore*/);
}
Return<void> StreamOut::prepareForWriting(uint32_t frameSize, uint32_t framesCount,
@@ -403,7 +404,8 @@
Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
uint32_t halDspFrames;
Result retval = Stream::analyzeStatus("get_render_position",
- mStream->get_render_position(mStream, &halDspFrames));
+ mStream->get_render_position(mStream, &halDspFrames),
+ {ENOSYS} /*ignore*/);
_hidl_cb(retval, halDspFrames);
return Void();
}
@@ -413,7 +415,8 @@
int64_t timestampUs = 0;
if (mStream->get_next_write_timestamp != NULL) {
retval = Stream::analyzeStatus("get_next_write_timestamp",
- mStream->get_next_write_timestamp(mStream, ×tampUs));
+ mStream->get_next_write_timestamp(mStream, ×tampUs),
+ {ENOSYS} /*ignore*/);
}
_hidl_cb(retval, timestampUs);
return Void();
@@ -427,7 +430,7 @@
if (result == 0) {
mCallback = callback;
}
- return Stream::analyzeStatus("set_callback", result);
+ return Stream::analyzeStatus("set_callback", result, {ENOSYS} /*ignore*/);
}
Return<Result> StreamOut::clearCallback() {
@@ -473,13 +476,15 @@
}
Return<Result> StreamOut::pause() {
- return mStream->pause != NULL ? Stream::analyzeStatus("pause", mStream->pause(mStream))
- : Result::NOT_SUPPORTED;
+ return mStream->pause != NULL
+ ? Stream::analyzeStatus("pause", mStream->pause(mStream), {ENOSYS} /*ignore*/)
+ : Result::NOT_SUPPORTED;
}
Return<Result> StreamOut::resume() {
- return mStream->resume != NULL ? Stream::analyzeStatus("resume", mStream->resume(mStream))
- : Result::NOT_SUPPORTED;
+ return mStream->resume != NULL
+ ? Stream::analyzeStatus("resume", mStream->resume(mStream), {ENOSYS} /*ignore*/)
+ : Result::NOT_SUPPORTED;
}
Return<bool> StreamOut::supportsDrain() {
@@ -488,14 +493,17 @@
Return<Result> StreamOut::drain(AudioDrain type) {
return mStream->drain != NULL
- ? Stream::analyzeStatus(
- "drain", mStream->drain(mStream, static_cast<audio_drain_type_t>(type)))
- : Result::NOT_SUPPORTED;
+ ? Stream::analyzeStatus(
+ "drain",
+ mStream->drain(mStream, static_cast<audio_drain_type_t>(type)),
+ {ENOSYS} /*ignore*/)
+ : Result::NOT_SUPPORTED;
}
Return<Result> StreamOut::flush() {
- return mStream->flush != NULL ? Stream::analyzeStatus("flush", mStream->flush(mStream))
- : Result::NOT_SUPPORTED;
+ return mStream->flush != NULL
+ ? Stream::analyzeStatus("flush", mStream->flush(mStream), {ENOSYS} /*ignore*/)
+ : Result::NOT_SUPPORTED;
}
// static
@@ -505,7 +513,7 @@
// to return it sometimes. EAGAIN may be returned by A2DP audio HAL
// implementation. ENODATA can also be reported while the writer is
// continuously querying it, but the stream has been stopped.
- static const std::vector<int> ignoredErrors{EINVAL, EAGAIN, ENODATA};
+ static const std::vector<int> ignoredErrors{EINVAL, EAGAIN, ENODATA, ENOSYS};
Result retval(Result::NOT_SUPPORTED);
if (stream->get_presentation_position == NULL) return retval;
struct timespec halTimeStamp;
diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h
index 11ab607..b0e72d9 100644
--- a/audio/core/all-versions/default/include/core/default/Device.h
+++ b/audio/core/all-versions/default/include/core/default/Device.h
@@ -116,8 +116,12 @@
#endif
#if MAJOR_VERSION >= 6
Return<Result> close() override;
+ Return<Result> addDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
+ Return<Result> removeDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
+ Return<void> updateAudioPatch(int32_t previousPatch, const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks,
+ createAudioPatch_cb _hidl_cb) override;
#endif
-
Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
// Utility methods for extending interfaces.
@@ -135,6 +139,9 @@
virtual ~Device();
Result doClose();
+ std::tuple<Result, AudioPatchHandle> createOrUpdateAudioPatch(
+ AudioPatchHandle patch, const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks);
// Methods from ParametersUtil.
char* halGetParameters(const char* keys) override;
diff --git a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
index f5f3848..ccdb7b2 100644
--- a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
+++ b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
@@ -98,6 +98,11 @@
#endif
#if MAJOR_VERSION >= 6
Return<Result> close() override;
+ Return<Result> addDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
+ Return<Result> removeDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
+ Return<void> updateAudioPatch(int32_t previousPatch, const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks,
+ updateAudioPatch_cb _hidl_cb) override;
#endif
Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
diff --git a/audio/core/all-versions/default/include/core/default/Stream.h b/audio/core/all-versions/default/include/core/default/Stream.h
index 91df0c7..ce0003b 100644
--- a/audio/core/all-versions/default/include/core/default/Stream.h
+++ b/audio/core/all-versions/default/include/core/default/Stream.h
@@ -157,6 +157,10 @@
native_handle_t* hidlHandle = nullptr;
if (mStream->create_mmap_buffer != NULL) {
+ if (minSizeFrames <= 0) {
+ retval = Result::INVALID_ARGUMENTS;
+ goto exit;
+ }
struct audio_mmap_buffer_info halInfo;
retval = Stream::analyzeStatus(
"create_mmap_buffer", mStream->create_mmap_buffer(mStream, minSizeFrames, &halInfo));
@@ -184,6 +188,7 @@
info.burstSizeFrames = halInfo.burst_size_frames;
}
}
+exit:
_hidl_cb(retval, info);
if (hidlHandle != nullptr) {
native_handle_delete(hidlHandle);
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
index 2afbbb8..09ef330 100644
--- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -181,3 +181,12 @@
ASSERT_OK(getDevice()->close());
ASSERT_TRUE(resetDevice());
}
+
+TEST_P(AudioPatchHidlTest, UpdatePatchInvalidHandle) {
+ doc::test("Verify that passing an invalid handle to updateAudioPatch is checked");
+ AudioPatchHandle ignored;
+ ASSERT_OK(getDevice()->updateAudioPatch(
+ static_cast<int32_t>(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE),
+ hidl_vec<AudioPortConfig>(), hidl_vec<AudioPortConfig>(), returnIn(res, ignored)));
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, res);
+}
diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h
index d849f85..cb6584d 100644
--- a/audio/core/all-versions/vts/functional/DeviceManager.h
+++ b/audio/core/all-versions/vts/functional/DeviceManager.h
@@ -113,7 +113,11 @@
#elif MAJOR_VERSION >= 6
{
sp<IDevice> device = getExisting(std::make_tuple(factoryName, name));
- if (device != nullptr) device->close();
+ if (device != nullptr) {
+ auto ret = device->close();
+ ALOGE_IF(!ret.isOk(), "Device %s::%s close failed: %s", factoryName.c_str(),
+ name.c_str(), ret.description().c_str());
+ }
}
return InterfaceManager::reset(std::make_tuple(factoryName, name), false);
#endif
diff --git a/audio/effect/6.0/IEffectsFactory.hal b/audio/effect/6.0/IEffectsFactory.hal
index e08b2de..4c37bad 100644
--- a/audio/effect/6.0/IEffectsFactory.hal
+++ b/audio/effect/6.0/IEffectsFactory.hal
@@ -48,11 +48,15 @@
* stream.
* @param ioHandle identifies the output or input stream this effect is
* directed to in audio HAL.
+ * @param device identifies the sink or source device this effect is directed to in the
+ * audio HAL. Must be specified if session is AudioSessionConsts.DEVICE.
+ * "device" is the AudioPortHandle used for the device when the audio
+ * patch is created at the audio HAL.
* @return retval operation completion status.
* @return result the interface for the created effect.
* @return effectId the unique ID of the effect to be used with
* IStream::addEffect and IStream::removeEffect methods.
*/
- createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle)
+ createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle, AudioPortHandle device)
generates (Result retval, IEffect result, uint64_t effectId);
};
diff --git a/audio/effect/6.0/xml/api/current.txt b/audio/effect/6.0/xml/api/current.txt
index 2021639..2dfcb9b 100644
--- a/audio/effect/6.0/xml/api/current.txt
+++ b/audio/effect/6.0/xml/api/current.txt
@@ -82,6 +82,7 @@
public enum StreamOutputType {
method public String getRawName();
enum_constant public static final audio.effects.V6_0.StreamOutputType alarm;
+ enum_constant public static final audio.effects.V6_0.StreamOutputType assistant;
enum_constant public static final audio.effects.V6_0.StreamOutputType bluetooth_sco;
enum_constant public static final audio.effects.V6_0.StreamOutputType dtmf;
enum_constant public static final audio.effects.V6_0.StreamOutputType enforced_audible;
diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd
deleted file mode 120000
index 9d85fa7..0000000
--- a/audio/effect/6.0/xml/audio_effects_conf.xsd
+++ /dev/null
@@ -1 +0,0 @@
-../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd
new file mode 100644
index 0000000..a7ff20b
--- /dev/null
+++ b/audio/effect/6.0/xml/audio_effects_conf.xsd
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://schemas.android.com/audio/audio_effects_conf/v2_0"
+ xmlns:aec="http://schemas.android.com/audio/audio_effects_conf/v2_0"
+ elementFormDefault="qualified">
+ <!-- Simple types -->
+ <xs:simpleType name="versionType">
+ <xs:restriction base="xs:decimal">
+ <xs:enumeration value="2.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="uuidType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="streamInputType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="mic"/>
+ <xs:enumeration value="voice_uplink"/>
+ <xs:enumeration value="voice_downlink"/>
+ <xs:enumeration value="voice_call"/>
+ <xs:enumeration value="camcorder"/>
+ <xs:enumeration value="voice_recognition"/>
+ <xs:enumeration value="voice_communication"/>
+ <xs:enumeration value="unprocessed"/>
+ <xs:enumeration value="voice_performance"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="streamOutputType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="voice_call"/>
+ <xs:enumeration value="system"/>
+ <xs:enumeration value="ring"/>
+ <xs:enumeration value="music"/>
+ <xs:enumeration value="alarm"/>
+ <xs:enumeration value="notification"/>
+ <xs:enumeration value="bluetooth_sco"/>
+ <xs:enumeration value="enforced_audible"/>
+ <xs:enumeration value="dtmf"/>
+ <xs:enumeration value="tts"/>
+ <xs:enumeration value="assistant"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="relativePathType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[^/].*"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!-- Complex types -->
+ <xs:complexType name="librariesType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ List of effect libraries to load. Each library element must have "name" and
+ "path" attributes. The latter is giving the path of the library .so file
+ relative to the standard effect folders: /(vendor|odm|system)/lib(64)?/soundfx/
+ Example for a library in "/vendor/lib/soundfx/lib.so":
+ <library name="name" path="lib.so"/>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="library" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="path" type="aec:relativePathType" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="effectImplType">
+ <xs:attribute name="library" type="xs:string" use="required"/>
+ <xs:attribute name="uuid" type="aec:uuidType" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="effectType">
+ <xs:complexContent>
+ <xs:extension base="aec:effectImplType">
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="effectProxyType">
+ <xs:complexContent>
+ <xs:extension base="aec:effectType">
+ <xs:sequence>
+ <xs:element name="libsw" type="aec:effectImplType"/>
+ <xs:element name="libhw" type="aec:effectImplType"/>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="effectsType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ List of effects to load. Each effect element must contain "name",
+ "library", and "uuid" attrs. The value of the "library" attr must
+ correspond to the name of a "library" element. The name of the effect
+ element is indicative, only the value of the "uuid" element designates
+ the effect for the audio framework. The uuid is the implementation
+ specific UUID as specified by the effect vendor. This is not the generic
+ effect type UUID.
+ For effect proxy implementations, SW and HW implemetations of the effect
+ can be specified.
+ Example:
+ <effect name="name" library="lib" uuid="uuuu"/>
+ <effectProxy name="proxied" library="proxy" uuid="xxxx">
+ <libsw library="sw_bundle" uuid="yyyy"/>
+ <libhw library="offload_bundle" uuid="zzzz"/>
+ </effectProxy>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:choice maxOccurs="unbounded">
+ <xs:element name="effect" type="aec:effectType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="effectProxy" type="aec:effectProxyType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:choice>
+ </xs:complexType>
+ <xs:complexType name="streamProcessingType">
+ <xs:sequence>
+ <xs:element name="apply" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="effect" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="streamPreprocessType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio preprocessing configuration. The processing configuration consists
+ of a list of elements each describing processing settings for a given
+ input stream. Valid input stream types are listed in "streamInputType".
+ Each stream element contains a list of "apply" elements. The value of the
+ "effect" attr must correspond to the name of an "effect" element.
+ Example:
+ <stream type="voice_communication">
+ <apply effect="effect1"/>
+ <apply effect="effect2"/>
+ </stream>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="aec:streamProcessingType">
+ <xs:attribute name="type" type="aec:streamInputType" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="streamPostprocessType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio postprocessing configuration. The processing configuration consists
+ of a list of elements each describing processing settings for a given
+ output stream. Valid output stream types are listed in "streamOutputType".
+ Each stream element contains a list of "apply" elements. The value of the
+ "effect" attr must correspond to the name of an "effect" element.
+ Example:
+ <stream type="music">
+ <apply effect="effect1"/>
+ </stream>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="aec:streamProcessingType">
+ <xs:attribute name="type" type="aec:streamOutputType" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <!-- Root element -->
+ <xs:element name="audio_effects_conf">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="libraries" type="aec:librariesType"/>
+ <xs:element name="effects" type="aec:effectsType"/>
+ <xs:element name="postprocess" minOccurs="0" maxOccurs="1">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="stream" type="aec:streamPostprocessType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="preprocess" minOccurs="0" maxOccurs="1">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="stream" type="aec:streamPreprocessType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="version" type="aec:versionType" use="required"/>
+ </xs:complexType>
+ <!-- Keys and references -->
+ <xs:key name="libraryName">
+ <xs:selector xpath="aec:libraries/aec:library"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="libraryNameRef1" refer="aec:libraryName">
+ <xs:selector xpath="aec:effects/aec:effect"/>
+ <xs:field xpath="@library"/>
+ </xs:keyref>
+ <xs:keyref name="libraryNameRef2" refer="aec:libraryName">
+ <xs:selector xpath="aec:effects/aec:effect/aec:libsw"/>
+ <xs:field xpath="@library"/>
+ </xs:keyref>
+ <xs:keyref name="libraryNameRef3" refer="aec:libraryName">
+ <xs:selector xpath="aec:effects/aec:effect/aec:libhw"/>
+ <xs:field xpath="@library"/>
+ </xs:keyref>
+ <xs:key name="effectName">
+ <xs:selector xpath="aec:effects/aec:effect|aec:effects/aec:effectProxy"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="effectNamePreRef" refer="aec:effectName">
+ <xs:selector xpath="aec:preprocess/aec:stream/aec:apply"/>
+ <xs:field xpath="@effect"/>
+ </xs:keyref>
+ <xs:keyref name="effectNamePostRef" refer="aec:effectName">
+ <xs:selector xpath="aec:postprocess/aec:stream/aec:apply"/>
+ <xs:field xpath="@effect"/>
+ </xs:keyref>
+ </xs:element>
+</xs:schema>
\ No newline at end of file
diff --git a/audio/effect/all-versions/default/EffectsFactory.cpp b/audio/effect/all-versions/default/EffectsFactory.cpp
index 6283e7b..acce7de 100644
--- a/audio/effect/all-versions/default/EffectsFactory.cpp
+++ b/audio/effect/all-versions/default/EffectsFactory.cpp
@@ -133,9 +133,9 @@
return Void();
}
-Return<void> EffectsFactory::getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) {
+Return<void> EffectsFactory::getDescriptor(const Uuid& uuid, getDescriptor_cb _hidl_cb) {
effect_uuid_t halUuid;
- HidlUtils::uuidToHal(uid, &halUuid);
+ HidlUtils::uuidToHal(uuid, &halUuid);
effect_descriptor_t halDescriptor;
status_t status = EffectGetDescriptor(&halUuid, &halDescriptor);
EffectDescriptor descriptor;
@@ -154,13 +154,31 @@
return Void();
}
-Return<void> EffectsFactory::createEffect(const Uuid& uid, int32_t session, int32_t ioHandle,
- createEffect_cb _hidl_cb) {
+#if MAJOR_VERSION <= 5
+Return<void> EffectsFactory::createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle,
+ EffectsFactory::createEffect_cb _hidl_cb) {
+ return createEffectImpl(uuid, session, ioHandle, AUDIO_PORT_HANDLE_NONE, _hidl_cb);
+}
+#else
+Return<void> EffectsFactory::createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle,
+ int32_t device,
+ EffectsFactory::createEffect_cb _hidl_cb) {
+ return createEffectImpl(uuid, session, ioHandle, device, _hidl_cb);
+}
+#endif
+
+Return<void> EffectsFactory::createEffectImpl(const Uuid& uuid, int32_t session, int32_t ioHandle,
+ int32_t device, createEffect_cb _hidl_cb) {
effect_uuid_t halUuid;
- HidlUtils::uuidToHal(uid, &halUuid);
+ HidlUtils::uuidToHal(uuid, &halUuid);
effect_handle_t handle;
Result retval(Result::OK);
- status_t status = EffectCreate(&halUuid, session, ioHandle, &handle);
+ status_t status;
+ if (session == AUDIO_SESSION_DEVICE) {
+ status = EffectCreateOnDevice(&halUuid, device, ioHandle, &handle);
+ } else {
+ status = EffectCreate(&halUuid, session, ioHandle, &handle);
+ }
sp<IEffect> effect;
uint64_t effectId = EffectMap::INVALID_ID;
if (status == OK) {
diff --git a/audio/effect/all-versions/default/EffectsFactory.h b/audio/effect/all-versions/default/EffectsFactory.h
index f0d09ec..0b86836 100644
--- a/audio/effect/all-versions/default/EffectsFactory.h
+++ b/audio/effect/all-versions/default/EffectsFactory.h
@@ -47,9 +47,15 @@
struct EffectsFactory : public IEffectsFactory {
// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffectsFactory follow.
Return<void> getAllDescriptors(getAllDescriptors_cb _hidl_cb) override;
- Return<void> getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) override;
- Return<void> createEffect(const Uuid& uid, int32_t session, int32_t ioHandle,
+ Return<void> getDescriptor(const Uuid& uuid, getDescriptor_cb _hidl_cb) override;
+#if MAJOR_VERSION <= 5
+ Return<void> createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle,
createEffect_cb _hidl_cb) override;
+#else
+ Return<void> createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle, int32_t device,
+ createEffect_cb _hidl_cb) override;
+#endif
+
Return<void> debugDump(
const hidl_handle& fd); //< in CPP_VERSION::IEffectsFactory only, alias of debug
Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
@@ -57,6 +63,8 @@
private:
static sp<IEffect> dispatchEffectInstanceCreation(const effect_descriptor_t& halDescriptor,
effect_handle_t handle);
+ Return<void> createEffectImpl(const Uuid& uuid, int32_t session, int32_t ioHandle,
+ int32_t device, createEffect_cb _hidl_cb);
};
extern "C" IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* name);
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index 3c712b5..c151d3a 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -134,13 +134,16 @@
Result retval = Result::NOT_INITIALIZED;
sp<IEffect> effect;
ret = effectsFactory->createEffect(
- effectUuid, 1 /*session*/, 1 /*ioHandle*/,
- [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
- retval = r;
- if (r == Result::OK) {
- effect = result;
- }
- });
+ effectUuid, 1 /*session*/, 1 /*ioHandle*/,
+#if MAJOR_VERSION >= 6
+ 0 /*device*/,
+#endif
+ [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
+ retval = r;
+ if (r == Result::OK) {
+ effect = result;
+ }
+ });
EXPECT_TRUE(ret.isOk());
EXPECT_EQ(Result::OK, retval);
EXPECT_NE(nullptr, effect.get());
@@ -236,12 +239,15 @@
Uuid effectUuid;
findEffectInstance(type, &effectUuid);
Return<void> ret = effectsFactory->createEffect(
- effectUuid, 1 /*session*/, 1 /*ioHandle*/,
- [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
- if (r == Result::OK) {
- effect = result;
- }
- });
+ effectUuid, 1 /*session*/, 1 /*ioHandle*/,
+#if MAJOR_VERSION >= 6
+ 0 /*device*/,
+#endif
+ [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
+ if (r == Result::OK) {
+ effect = result;
+ }
+ });
ASSERT_TRUE(ret.isOk());
}
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
index 42d2e3c..8fb09eb 100644
--- a/automotive/can/1.0/default/CanBus.cpp
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -22,13 +22,10 @@
#include <libnetdevice/can.h>
#include <libnetdevice/libnetdevice.h>
#include <linux/can.h>
+#include <linux/can/error.h>
+#include <linux/can/raw.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
/** Whether to log sent/received packets. */
static constexpr bool kSuperVerbose = false;
@@ -45,6 +42,8 @@
struct canfd_frame frame = {};
frame.can_id = message.id;
+ if (message.isExtendedId) frame.can_id |= CAN_EFF_FLAG;
+ if (message.remoteTransmissionRequest) frame.can_id |= CAN_RTR_FLAG;
frame.len = message.payload.size();
memcpy(frame.data, message.payload.data(), message.payload.size());
@@ -220,6 +219,21 @@
}
/**
+ * Helper function to determine if a flag meets the requirements of a
+ * FilterFlag. See definition of FilterFlag in types.hal
+ *
+ * \param filterFlag FilterFlag object to match flag against
+ * \param flag bool object from CanMessage object
+ */
+static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) {
+ // TODO(b/144458917) add testing for this to VTS tests
+ if (filterFlag == FilterFlag::DONT_CARE) return true;
+ if (filterFlag == FilterFlag::SET) return flag;
+ if (filterFlag == FilterFlag::NOT_SET) return !flag;
+ return false;
+}
+
+/**
* Match the filter set against message id.
*
* For details on the filters syntax, please see CanMessageFilter at
@@ -229,29 +243,76 @@
* \param id Message id to filter
* \return true if the message id matches the filter, false otherwise
*/
-static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id) {
+static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id, bool isRtr,
+ bool isExtendedId) {
if (filter.size() == 0) return true;
- bool anyNonInvertedPresent = false;
- bool anyNonInvertedSatisfied = false;
+ bool anyNonExcludeRulePresent = false;
+ bool anyNonExcludeRuleSatisfied = false;
for (auto& rule : filter) {
- const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted;
- if (rule.inverted) {
- // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set.
- if (!satisfied) return false;
+ const bool satisfied = ((id & rule.mask) == rule.id) &&
+ satisfiesFilterFlag(rule.rtr, isRtr) &&
+ satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
+
+ if (rule.exclude) {
+ // Any excluded (blacklist) rule not being satisfied invalidates the whole filter set.
+ if (satisfied) return false;
} else {
- anyNonInvertedPresent = true;
- if (satisfied) anyNonInvertedSatisfied = true;
+ anyNonExcludeRulePresent = true;
+ if (satisfied) anyNonExcludeRuleSatisfied = true;
}
}
- return !anyNonInvertedPresent || anyNonInvertedSatisfied;
+ return !anyNonExcludeRulePresent || anyNonExcludeRuleSatisfied;
+}
+
+void CanBus::notifyErrorListeners(ErrorEvent err, bool isFatal) {
+ std::lock_guard<std::mutex> lck(mErrListenersGuard);
+ for (auto& listener : mErrListeners) {
+ if (!listener->onError(err, isFatal).isOk()) {
+ LOG(WARNING) << "Failed to notify listener about error";
+ }
+ }
+}
+
+static ErrorEvent parseErrorFrame(const struct canfd_frame& frame) {
+ // decode error frame (to a degree)
+ if ((frame.can_id & (CAN_ERR_BUSERROR | CAN_ERR_BUSOFF)) != 0) {
+ return ErrorEvent::BUS_ERROR;
+ }
+ if ((frame.data[1] & CAN_ERR_CRTL_TX_OVERFLOW) != 0) {
+ return ErrorEvent::TX_OVERFLOW;
+ }
+ if ((frame.data[1] & CAN_ERR_CRTL_RX_OVERFLOW) != 0) {
+ return ErrorEvent::RX_OVERFLOW;
+ }
+ if ((frame.data[2] & CAN_ERR_PROT_OVERLOAD) != 0) {
+ return ErrorEvent::BUS_OVERLOAD;
+ }
+ if ((frame.can_id & CAN_ERR_PROT) != 0) {
+ return ErrorEvent::MALFORMED_INPUT;
+ }
+ if ((frame.can_id & (CAN_ERR_CRTL | CAN_ERR_TRX | CAN_ERR_RESTARTED)) != 0) {
+ // "controller restarted" constitutes a HARDWARE_ERROR imo
+ return ErrorEvent::HARDWARE_ERROR;
+ }
+ return ErrorEvent::UNKNOWN_ERROR;
}
void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) {
+ if ((frame.can_id & CAN_ERR_FLAG) != 0) {
+ // error bit is set
+ LOG(WARNING) << "CAN Error frame received";
+ // TODO(b/144458917) consider providing different values for isFatal, depending on error
+ notifyErrorListeners(parseErrorFrame(frame), false);
+ return;
+ }
+
CanMessage message = {};
- message.id = frame.can_id;
+ message.id = frame.can_id & CAN_EFF_MASK; // mask out eff/rtr/err flags
message.payload = hidl_vec<uint8_t>(frame.data, frame.data + frame.len);
message.timestamp = timestamp.count();
+ message.isExtendedId = (frame.can_id & CAN_EFF_FLAG) != 0;
+ message.remoteTransmissionRequest = (frame.can_id & CAN_RTR_FLAG) != 0;
if (UNLIKELY(kSuperVerbose)) {
LOG(VERBOSE) << "Got message " << toString(message);
@@ -259,7 +320,9 @@
std::lock_guard<std::mutex> lck(mMsgListenersGuard);
for (auto& listener : mMsgListeners) {
- if (!match(listener.filter, message.id)) continue;
+ if (!match(listener.filter, message.id, message.remoteTransmissionRequest,
+ message.isExtendedId))
+ continue;
if (!listener.callback->onReceive(message).isOk() && !listener.failedOnce) {
listener.failedOnce = true;
LOG(WARNING) << "Failed to notify listener about message";
@@ -274,23 +337,10 @@
mDownAfterUse = false;
eventType = ErrorEvent::INTERFACE_DOWN;
}
-
- {
- std::lock_guard<std::mutex> lck(mErrListenersGuard);
- for (auto& listener : mErrListeners) {
- if (!listener->onError(eventType, true).isOk()) {
- LOG(WARNING) << "Failed to notify listener about error";
- }
- }
- }
+ notifyErrorListeners(eventType, true);
const auto errcb = mErrCb;
if (errcb != nullptr) errcb();
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h
index 365e90c..8b73258 100644
--- a/automotive/can/1.0/default/CanBus.h
+++ b/automotive/can/1.0/default/CanBus.h
@@ -26,12 +26,7 @@
#include <atomic>
#include <thread>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
struct CanBus : public ICanBus {
using ErrorCallback = std::function<void()>;
@@ -89,6 +84,8 @@
void clearMsgListeners();
void clearErrListeners();
+ void notifyErrorListeners(ErrorEvent err, bool isFatal);
+
void onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp);
void onError(int errnoVal);
@@ -112,9 +109,4 @@
ErrorCallback mErrCb;
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusNative.cpp b/automotive/can/1.0/default/CanBusNative.cpp
index 365b749..88f9175 100644
--- a/automotive/can/1.0/default/CanBusNative.cpp
+++ b/automotive/can/1.0/default/CanBusNative.cpp
@@ -20,12 +20,7 @@
#include <libnetdevice/can.h>
#include <libnetdevice/libnetdevice.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
CanBusNative::CanBusNative(const std::string& ifname, uint32_t baudrate)
: CanBus(ifname), mBaudrate(baudrate) {}
@@ -49,9 +44,4 @@
return ICanController::Result::OK;
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusNative.h b/automotive/can/1.0/default/CanBusNative.h
index 126f1cb..7eda683 100644
--- a/automotive/can/1.0/default/CanBusNative.h
+++ b/automotive/can/1.0/default/CanBusNative.h
@@ -18,12 +18,7 @@
#include "CanBus.h"
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
struct CanBusNative : public CanBus {
CanBusNative(const std::string& ifname, uint32_t baudrate);
@@ -35,9 +30,4 @@
const uint32_t mBaudrate;
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp
index 7dce838..29d9d3c 100644
--- a/automotive/can/1.0/default/CanBusSlcan.cpp
+++ b/automotive/can/1.0/default/CanBusSlcan.cpp
@@ -25,12 +25,7 @@
#include <sys/stat.h>
#include <termios.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
namespace slcanprotocol {
static const std::string kOpenCommand = "O\r";
@@ -158,9 +153,4 @@
return true;
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusSlcan.h b/automotive/can/1.0/default/CanBusSlcan.h
index 2713da8..3328a9f 100644
--- a/automotive/can/1.0/default/CanBusSlcan.h
+++ b/automotive/can/1.0/default/CanBusSlcan.h
@@ -22,12 +22,7 @@
#include <termios.h>
#include "CanBus.h"
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
struct CanBusSlcan : public CanBus {
CanBusSlcan(const std::string& uartName, uint32_t bitrate);
@@ -42,9 +37,4 @@
base::unique_fd mFd;
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusVirtual.cpp b/automotive/can/1.0/default/CanBusVirtual.cpp
index cc59fa9..32fe8d6 100644
--- a/automotive/can/1.0/default/CanBusVirtual.cpp
+++ b/automotive/can/1.0/default/CanBusVirtual.cpp
@@ -19,12 +19,7 @@
#include <android-base/logging.h>
#include <libnetdevice/libnetdevice.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
CanBusVirtual::CanBusVirtual(const std::string& ifname) : CanBus(ifname) {}
@@ -52,9 +47,4 @@
return true;
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusVirtual.h b/automotive/can/1.0/default/CanBusVirtual.h
index c2d5794..3990b20 100644
--- a/automotive/can/1.0/default/CanBusVirtual.h
+++ b/automotive/can/1.0/default/CanBusVirtual.h
@@ -18,12 +18,7 @@
#include "CanBus.h"
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
struct CanBusVirtual : public CanBus {
CanBusVirtual(const std::string& ifname);
@@ -36,9 +31,4 @@
bool mWasCreated = false;
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp
index ffdc912..cd17dd8 100644
--- a/automotive/can/1.0/default/CanController.cpp
+++ b/automotive/can/1.0/default/CanController.cpp
@@ -25,12 +25,7 @@
#include <regex>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
@@ -139,9 +134,4 @@
return success;
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanController.h b/automotive/can/1.0/default/CanController.h
index 0674d0e..99a551a 100644
--- a/automotive/can/1.0/default/CanController.h
+++ b/automotive/can/1.0/default/CanController.h
@@ -20,12 +20,7 @@
#include <android/hardware/automotive/can/1.0/ICanController.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
struct CanController : public ICanController {
Return<void> getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) override;
@@ -39,9 +34,4 @@
std::map<std::string, sp<CanBus>> mCanBuses GUARDED_BY(mCanBusesGuard);
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp
index 86e12d1..86ccc0e 100644
--- a/automotive/can/1.0/default/CanSocket.cpp
+++ b/automotive/can/1.0/default/CanSocket.cpp
@@ -24,12 +24,7 @@
#include <chrono>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
using namespace std::chrono_literals;
@@ -152,9 +147,4 @@
LOG(VERBOSE) << "Reader thread stopped";
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanSocket.h b/automotive/can/1.0/default/CanSocket.h
index c98330b..fd956b5 100644
--- a/automotive/can/1.0/default/CanSocket.h
+++ b/automotive/can/1.0/default/CanSocket.h
@@ -24,12 +24,7 @@
#include <chrono>
#include <thread>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
/** Wrapper around SocketCAN socket. */
struct CanSocket {
@@ -71,9 +66,4 @@
DISALLOW_COPY_AND_ASSIGN(CanSocket);
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CloseHandle.cpp b/automotive/can/1.0/default/CloseHandle.cpp
index aba2c49..e1ffe2b 100644
--- a/automotive/can/1.0/default/CloseHandle.cpp
+++ b/automotive/can/1.0/default/CloseHandle.cpp
@@ -16,12 +16,7 @@
#include "CloseHandle.h"
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {}
@@ -37,9 +32,4 @@
return {};
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CloseHandle.h b/automotive/can/1.0/default/CloseHandle.h
index eade109..c332d74 100644
--- a/automotive/can/1.0/default/CloseHandle.h
+++ b/automotive/can/1.0/default/CloseHandle.h
@@ -19,12 +19,7 @@
#include <android-base/macros.h>
#include <android/hardware/automotive/can/1.0/ICloseHandle.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
/** Generic ICloseHandle implementation ignoring double-close events. */
struct CloseHandle : public ICloseHandle {
@@ -49,9 +44,4 @@
DISALLOW_COPY_AND_ASSIGN(CloseHandle);
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
index 9845bc7..556debf 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
@@ -18,9 +18,7 @@
#include <android-base/logging.h>
-namespace android {
-namespace netdevice {
-namespace impl {
+namespace android::netdevice::impl {
static struct rtattr* nlmsg_tail(struct nlmsghdr* n) {
return reinterpret_cast<struct rtattr*>( //
@@ -53,6 +51,4 @@
nest->rta_len = nestLen;
}
-} // namespace impl
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice::impl
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
index ba9b65b..3e28d78 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
@@ -21,8 +21,7 @@
#include <string>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
typedef unsigned short rtattrtype_t; // as in rtnetlink.h
typedef __u16 nlmsgtype_t; // as in netlink.h
@@ -151,5 +150,4 @@
}
};
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
index 0514764..6a7f506 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
@@ -18,8 +18,7 @@
#include <android-base/logging.h>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
NetlinkSocket::NetlinkSocket(int protocol) {
mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
@@ -110,5 +109,4 @@
return false;
}
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
index 90e1f3f..2b40ea2 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
@@ -23,8 +23,7 @@
#include <linux/netlink.h>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
/**
* A wrapper around AF_NETLINK sockets.
@@ -64,5 +63,4 @@
DISALLOW_COPY_AND_ASSIGN(NetlinkSocket);
};
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp
index 87617dd..06d45d3 100644
--- a/automotive/can/1.0/default/libnetdevice/can.cpp
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -24,11 +24,13 @@
#include <android-base/unique_fd.h>
#include <linux/can.h>
+#include <linux/can/error.h>
#include <linux/can/netlink.h>
+#include <linux/can/raw.h>
-namespace android {
-namespace netdevice {
-namespace can {
+namespace android::netdevice::can {
+
+static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK;
base::unique_fd socket(const std::string& ifname) {
struct sockaddr_can addr = {};
@@ -45,6 +47,11 @@
return {};
}
+ if (setsockopt(sock.get(), SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &kErrMask, sizeof(kErrMask)) < 0) {
+ LOG(ERROR) << "Can't receive error frames, CAN setsockpt failed: " << strerror(errno);
+ return {};
+ }
+
if (0 != fcntl(sock.get(), F_SETFL, O_RDWR | O_NONBLOCK)) {
LOG(ERROR) << "Couldn't put CAN socket in non-blocking mode";
return {};
@@ -86,6 +93,4 @@
return sock.send(req) && sock.receiveAck();
}
-} // namespace can
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice::can
diff --git a/automotive/can/1.0/default/libnetdevice/common.cpp b/automotive/can/1.0/default/libnetdevice/common.cpp
index 3deac3e..5c62443 100644
--- a/automotive/can/1.0/default/libnetdevice/common.cpp
+++ b/automotive/can/1.0/default/libnetdevice/common.cpp
@@ -20,8 +20,7 @@
#include <net/if.h>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
unsigned int nametoindex(const std::string& ifname) {
const auto ifidx = if_nametoindex(ifname.c_str());
@@ -34,5 +33,4 @@
return 0;
}
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h
index 9bdff4d..8097f37 100644
--- a/automotive/can/1.0/default/libnetdevice/common.h
+++ b/automotive/can/1.0/default/libnetdevice/common.h
@@ -18,8 +18,7 @@
#include <string>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
/**
* Returns the index of a given network interface.
@@ -32,5 +31,4 @@
*/
unsigned int nametoindex(const std::string& ifname);
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
index d75361e..3886acf 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
@@ -20,9 +20,7 @@
#include <string>
-namespace android {
-namespace netdevice {
-namespace can {
+namespace android::netdevice::can {
/**
* Opens and binds SocketCAN socket.
@@ -40,6 +38,4 @@
*/
bool setBitrate(std::string ifname, uint32_t bitrate);
-} // namespace can
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice::can
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
index e22eafb..3818a31 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
@@ -19,8 +19,7 @@
#include <optional>
#include <string>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
/**
* Checks, if the network interface exists.
@@ -71,5 +70,4 @@
*/
bool del(std::string dev);
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index fc2b193..aee8205 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -25,8 +25,7 @@
#include <linux/can.h>
#include <net/if.h>
-namespace android {
-namespace netdevice {
+namespace android::netdevice {
bool exists(std::string ifname) {
return nametoindex(ifname) != 0;
@@ -96,5 +95,4 @@
return sock.send(req) && sock.receiveAck();
}
-} // namespace netdevice
-} // namespace android
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/service.cpp b/automotive/can/1.0/default/service.cpp
index 7ef44fc..b52a54a 100644
--- a/automotive/can/1.0/default/service.cpp
+++ b/automotive/can/1.0/default/service.cpp
@@ -19,12 +19,7 @@
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::automotive::can::V1_0::implementation {
static void canControllerService() {
base::SetDefaultTag("CanController");
@@ -32,8 +27,8 @@
configureRpcThreadpool(16, true);
LOG(DEBUG) << "CAN controller service starting...";
- CanController canController;
- if (canController.registerAsService("socketcan") != OK) {
+ sp<CanController> canController(new CanController);
+ if (canController->registerAsService("socketcan") != OK) {
LOG(FATAL) << "Failed to register CAN controller";
return;
}
@@ -42,12 +37,7 @@
joinRpcThreadpool();
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::implementation
int main() {
::android::hardware::automotive::can::V1_0::implementation::canControllerService();
diff --git a/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h
index 039f971..f63d43c 100644
--- a/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h
+++ b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h
@@ -16,10 +16,7 @@
#pragma once
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace hidl_utils {
+namespace android::hardware::automotive::hidl_utils {
/**
* Helper functor to fetch results from multi-return HIDL calls.
@@ -61,7 +58,4 @@
}
};
-} // namespace hidl_utils
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::hidl_utils
diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp
index fa1048d..5c9849b 100644
--- a/automotive/can/1.0/tools/canhalctrl.cpp
+++ b/automotive/can/1.0/tools/canhalctrl.cpp
@@ -22,10 +22,7 @@
#include <iostream>
#include <string>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
+namespace android::hardware::automotive::can {
using ICanController = V1_0::ICanController;
@@ -170,10 +167,7 @@
}
}
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can
int main(int argc, char* argv[]) {
if (argc < 1) return -1;
diff --git a/automotive/can/1.0/tools/canhaldump.cpp b/automotive/can/1.0/tools/canhaldump.cpp
index 99fd14a..2f5ca61 100644
--- a/automotive/can/1.0/tools/canhaldump.cpp
+++ b/automotive/can/1.0/tools/canhaldump.cpp
@@ -20,16 +20,14 @@
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl-utils/hidl-utils.h>
+#include <linux/can.h>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <string>
#include <thread>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
+namespace android::hardware::automotive::can {
using namespace std::chrono_literals;
@@ -42,12 +40,14 @@
CanMessageListener(std::string name) : name(name) {}
virtual Return<void> onReceive(const V1_0::CanMessage& message) {
- std::cout << " " << name << " " << std::hex << std::uppercase << std::setw(3)
+ int msgIdWidth = 3;
+ if (message.isExtendedId) msgIdWidth = 8;
+ std::cout << " " << name << " " << std::hex << std::uppercase << std::setw(msgIdWidth)
<< std::setfill('0') << message.id << std::setw(0);
+ std::cout << " [" << message.payload.size() << "] ";
if (message.remoteTransmissionRequest) {
- std::cout << " RTR";
+ std::cout << "remote request";
} else {
- std::cout << " [" << message.payload.size() << "] ";
for (const auto byte : message.payload) {
std::cout << " " << std::setfill('0') << std::setw(2) << unsigned(byte);
}
@@ -125,10 +125,7 @@
return candump(argv[0]);
}
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can
int main(int argc, char* argv[]) {
if (argc < 1) return -1;
diff --git a/automotive/can/1.0/tools/canhalsend.cpp b/automotive/can/1.0/tools/canhalsend.cpp
index 29330c9..7e6833a 100644
--- a/automotive/can/1.0/tools/canhalsend.cpp
+++ b/automotive/can/1.0/tools/canhalsend.cpp
@@ -21,10 +21,7 @@
#include <iostream>
#include <string>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
+namespace android::hardware::automotive::can {
using ICanBus = V1_0::ICanBus;
using Result = V1_0::Result;
@@ -125,10 +122,7 @@
return cansend(busname, msgid, payload);
}
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can
int main(int argc, char* argv[]) {
if (argc < 1) return -1;
diff --git a/automotive/can/1.0/types.hal b/automotive/can/1.0/types.hal
index 6f690f7..5eeed53 100644
--- a/automotive/can/1.0/types.hal
+++ b/automotive/can/1.0/types.hal
@@ -58,23 +58,50 @@
* If this flag is set, payload must be empty.
*/
bool remoteTransmissionRequest;
+
+ /**
+ * Flag indicating if the message has an extended ID.
+ *
+ * Extended ID's are 29 bits long, as opposed to the standard 11 bit ID.
+ * It can not simply be inferred from the length of the ID itself, as the
+ * message ID 0x00000123 != message ID 0x123.
+ */
+ bool isExtendedId;
};
/**
* Single filter rule for CAN messages.
*
* A filter is satisfied if:
- * ((receivedId & mask) == (id & mask)) == !inverted
+ * ((receivedId & mask) == (id & mask)) == !exclude
*
- * In order for set of filters to match, at least one non-inverted filters must match (if there is
- * one) and all inverted filters must match. In other words:
- * - a single matching non-inverted filter makes the whole set matching;
- * - a single non-matching inverted filter makes the whole set non-matching.
+ * In order for set of filters to match, at least one non-exclude filters must match (if there is
+ * one) and all exclude filters must match. In other words:
+ * - a single matching non-exclude filter makes the whole set matching;
+ * - a single non-matching excluded filter makes the whole set non-matching.
*/
struct CanMessageFilter {
CanMessageId id;
uint32_t mask;
- bool inverted;
+ /** Remote Transmission Request; another ECU requests <DLC> bytes of data on this message ID */
+ FilterFlag rtr;
+ /** 29 bit message ID is used instead of 11 bits */
+ FilterFlag extendedFormat;
+ /** 'exclude' *DOES* apply to rtr and extendedFormat! */
+ bool exclude;
+};
+
+
+/**
+ * Types of filter that can be applied to a CanMessageFilter
+ */
+enum FilterFlag : uint8_t {
+ /** Default, FilterFlag doesn't effect what messages filtered */
+ DONT_CARE = 0,
+ /** This FilterFlag MUST be present in received messages to pass though the filter */
+ SET,
+ /** This FilterFlag must NOT be present in received messages to pass though the filter */
+ NOT_SET,
};
enum Result : uint8_t {
diff --git a/automotive/can/1.0/vts/functional/Android.bp b/automotive/can/1.0/vts/functional/Android.bp
index b4d9132..e3e770b 100644
--- a/automotive/can/1.0/vts/functional/Android.bp
+++ b/automotive/can/1.0/vts/functional/Android.bp
@@ -16,13 +16,16 @@
cc_defaults {
name: "android.hardware.automotive.can@vts-defaults",
- defaults: ["VtsHalTargetTestDefaults", "android.hardware.automotive.can@defaults"],
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "android.hardware.automotive.can@defaults",
+ ],
header_libs: [
"android.hardware.automotive.can@hidl-utils-lib",
- "android.hardware.automotive.can@vts-utils-lib",
],
static_libs: [
"android.hardware.automotive.can@1.0",
+ "android.hardware.automotive.can@vts-utils-lib",
"libgmock",
],
test_suites: ["general-tests"],
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
index 1a05716..cdea8b6 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
@@ -24,12 +24,7 @@
#include <gmock/gmock.h>
#include <hidl-utils/hidl-utils.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace vts {
+namespace android::hardware::automotive::can::V1_0::vts {
using hardware::hidl_vec;
@@ -83,7 +78,7 @@
TEST_F(CanBusHalTest, SendNoPayload) {
CanMessage msg = {};
msg.id = 0x123;
-
+ ASSERT_NE(mCanBus, nullptr);
const auto result = mCanBus->send(msg);
ASSERT_EQ(Result::OK, result);
}
@@ -123,9 +118,9 @@
TEST_F(CanBusHalTest, ListenSomeFilter) {
hidl_vec<CanMessageFilter> filters = {
- {0x123, 0x1FF, false},
- {0x001, 0x00F, true},
- {0x200, 0x100, false},
+ {0x123, 0x1FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+ {0x001, 0x00F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x200, 0x100, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
};
const auto [result, closeHandle] = listen(filters, new CanMessageListener());
@@ -173,22 +168,23 @@
ASSERT_NE(nullptr, closeHandle.get());
}
-} // namespace vts
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::vts
/**
+ * This test requires that you bring up a valid bus first.
+ *
+ * Before running:
+ * mma -j && adb root && adb remount && adb sync
+ *
* Example manual invocation:
* adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest \
- * --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/test
+ * --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/<NAME_OF_VALID_BUS>
*/
int main(int argc, char** argv) {
using android::hardware::automotive::can::V1_0::ICanBus;
using android::hardware::automotive::can::V1_0::vts::gEnv;
using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+ setenv("TREBLE_TESTING_OVERRIDE", "true", true);
android::base::SetDefaultTag("CanBusVts");
android::base::SetMinimumLogSeverity(android::base::VERBOSE);
gEnv = new SimpleHidlEnvironment<ICanBus>;
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
index 225984d..efaad53 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -21,6 +21,7 @@
#include <android/hardware/automotive/can/1.0/ICanController.h>
#include <android/hardware/automotive/can/1.0/types.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/bus-enumerator.h>
#include <can-vts-utils/can-hal-printers.h>
#include <can-vts-utils/environment-utils.h>
#include <gmock/gmock.h>
@@ -31,12 +32,7 @@
#include <chrono>
#include <thread>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace vts {
+namespace android::hardware::automotive::can::V1_0::vts {
using namespace std::chrono_literals;
@@ -125,6 +121,7 @@
}
void send(const CanMessage& msg) {
+ EXPECT_NE(mBus, nullptr);
const auto result = mBus->send(msg);
EXPECT_EQ(Result::OK, result);
}
@@ -144,18 +141,26 @@
Bus makeBus();
+ protected:
+ static hidl_vec<hidl_string> mBusNames;
+
private:
unsigned mLastIface = 0;
static sp<ICanController> mCanController;
static bool mVirtualSupported;
+ static bool mTestCaseInitialized;
};
sp<ICanController> CanBusVirtualHalTest::mCanController = nullptr;
bool CanBusVirtualHalTest::mVirtualSupported;
+hidl_vec<hidl_string> CanBusVirtualHalTest::mBusNames;
+bool CanBusVirtualHalTest::mTestCaseInitialized = false;
-static CanMessage makeMessage(CanMessageId id) {
+static CanMessage makeMessage(CanMessageId id, bool rtr, bool extended) {
CanMessage msg = {};
msg.id = id;
+ msg.remoteTransmissionRequest = rtr;
+ msg.isExtendedId = extended;
return msg;
}
@@ -165,6 +170,7 @@
void CanBusVirtualHalTest::SetUp() {
if (!mVirtualSupported) GTEST_SKIP();
+ ASSERT_TRUE(mTestCaseInitialized);
}
void CanBusVirtualHalTest::SetUpTestCase() {
@@ -175,6 +181,11 @@
hidl_vec<InterfaceType> supported;
mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).assertOk();
mVirtualSupported = supported.contains(InterfaceType::VIRTUAL);
+
+ mBusNames = utils::getBusNames();
+ ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest";
+
+ mTestCaseInitialized = true;
}
void CanBusVirtualHalTest::TearDownTestCase() {
@@ -182,10 +193,11 @@
}
Bus CanBusVirtualHalTest::makeBus() {
- const auto idx = ++mLastIface;
+ const auto idx = mLastIface++;
+ EXPECT_LT(idx, mBusNames.size());
ICanController::BusConfiguration config = {};
- config.name = "test" + std::to_string(idx);
+ config.name = mBusNames[idx];
config.iftype = InterfaceType::VIRTUAL;
config.interfaceId.address("vcan50");
@@ -212,6 +224,7 @@
}
TEST_F(CanBusVirtualHalTest, SendAndRecv) {
+ if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
auto bus1 = makeBus();
auto bus2 = makeBus();
@@ -231,6 +244,8 @@
}
TEST_F(CanBusVirtualHalTest, DownOneOfTwo) {
+ if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+
auto bus1 = makeBus();
auto bus2 = makeBus();
@@ -239,63 +254,624 @@
bus1.send({});
}
-TEST_F(CanBusVirtualHalTest, Filter) {
+TEST_F(CanBusVirtualHalTest, FilterPositive) {
+ if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
auto bus1 = makeBus();
auto bus2 = makeBus();
+ /* clang-format off */
+ /* id, mask, rtr, eff, exclude */
hidl_vec<CanMessageFilter> filterPositive = {
- {0x101, 0x100, false},
- {0x010, 0x0F0, false},
+ {0x334, 0x73F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+ {0x49D, 0x700, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+ {0x325, 0x7FC, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, false},
+ {0x246, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, false},
+ {0x1A2, 0x7FB, FilterFlag::SET, FilterFlag::NOT_SET, false},
+ {0x607, 0x7C9, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, false},
+ {0x7F4, 0x777, FilterFlag::NOT_SET, FilterFlag::NOT_SET, false},
+ {0x1BF19EAF, 0x10F0F0F0, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+ {0x12E99200, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, false},
+ {0x06B70270, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::DONT_CARE, false},
+ {0x096CFD2B, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, false},
+ {0x1BDCB008, 0x0F0F0F0F, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, false},
+ {0x08318B46, 0x10F0F0F0, FilterFlag::NOT_SET, FilterFlag::SET, false},
+ {0x06B, 0x70F, FilterFlag::DONT_CARE, FilterFlag::SET, false},
+ {0x750, 0x70F, FilterFlag::SET, FilterFlag::SET, false},
+ {0x5CF, 0x70F, FilterFlag::NOT_SET, FilterFlag::SET, false},
};
+ /* clang-format on */
auto listenerPositive = bus2.listen(filterPositive);
- hidl_vec<CanMessageFilter> filterNegative = {
- {0x123, 0x0FF, true},
- {0x004, 0x00F, true},
- };
- auto listenerNegative = bus2.listen(filterNegative);
+ // 334:73F, DNC, DNC
+ bus1.send(makeMessage(0x3F4, false, false));
+ bus1.send(makeMessage(0x334, false, true));
+ bus1.send(makeMessage(0x374, true, false));
+ bus1.send(makeMessage(0x3F4, true, true));
- bus1.send(makeMessage(0));
- bus1.send(makeMessage(0x1A0));
- bus1.send(makeMessage(0x1A1));
- bus1.send(makeMessage(0x2A0));
- bus1.send(makeMessage(0x3A0));
- bus1.send(makeMessage(0x010));
- bus1.send(makeMessage(0x123));
- bus1.send(makeMessage(0x023));
- bus1.send(makeMessage(0x124));
+ // 49D:700, DNC, DNC
+ bus1.send(makeMessage(0x404, false, false));
+ bus1.send(makeMessage(0x4A5, false, true));
+ bus1.send(makeMessage(0x4FF, true, false));
+ bus1.send(makeMessage(0x46B, true, true));
+
+ // 325:7FC, DNC, NS
+ bus1.send(makeMessage(0x324, false, false));
+ bus1.send(makeMessage(0x325, false, true)); // filtered out
+ bus1.send(makeMessage(0x326, true, false));
+ bus1.send(makeMessage(0x327, true, true)); // filtered out
+
+ // 246:7FF, SET, DNC
+ bus1.send(makeMessage(0x246, false, false)); // filtered out
+ bus1.send(makeMessage(0x246, false, true)); // filtered out
+ bus1.send(makeMessage(0x246, true, false));
+ bus1.send(makeMessage(0x246, true, true));
+
+ // 1A2:7FB, SET, NS
+ bus1.send(makeMessage(0x1A2, false, false)); // filtered out
+ bus1.send(makeMessage(0x1A6, false, true)); // filtered out
+ bus1.send(makeMessage(0x1A2, true, false));
+ bus1.send(makeMessage(0x1A6, true, true)); // filtered out
+
+ // 607:7C9, NS, DNC
+ bus1.send(makeMessage(0x607, false, false));
+ bus1.send(makeMessage(0x613, false, true));
+ bus1.send(makeMessage(0x625, true, false)); // filtered out
+ bus1.send(makeMessage(0x631, true, true)); // filtered out
+
+ // 7F4:777, NS, NS
+ bus1.send(makeMessage(0x774, false, false));
+ bus1.send(makeMessage(0x7F4, false, true)); // filtered out
+ bus1.send(makeMessage(0x77C, true, false)); // filtered out
+ bus1.send(makeMessage(0x7FC, true, false)); // filtered out
+
+ // 1BF19EAF:10F0F0F0, DNC, DNC
+ bus1.send(makeMessage(0x11F293A4, false, false));
+ bus1.send(makeMessage(0x15F697A8, false, true));
+ bus1.send(makeMessage(0x19FA9BAC, true, false));
+ bus1.send(makeMessage(0x1DFE9FA0, true, true));
+
+ // 12E99200:1FFFFFFF, DNC, SET
+ bus1.send(makeMessage(0x12E99200, false, false)); // filtered out
+ bus1.send(makeMessage(0x12E99200, false, true));
+ bus1.send(makeMessage(0x12E99200, true, false)); // filtered out
+ bus1.send(makeMessage(0x12E99200, true, true));
+
+ // 06B70270:1FFFFFFF, SET, DNC
+ bus1.send(makeMessage(0x06B70270, false, false)); // filtered out
+ bus1.send(makeMessage(0x06B70270, false, true)); // filtered out
+ bus1.send(makeMessage(0x06B70270, true, false));
+ bus1.send(makeMessage(0x06B70270, true, true));
+
+ // 096CFD2B:1FFFFFFF, SET, SET
+ bus1.send(makeMessage(0x096CFD2B, false, false)); // filtered out
+ bus1.send(makeMessage(0x096CFD2B, false, true)); // filtered out
+ bus1.send(makeMessage(0x096CFD2B, true, false)); // filtered out
+ bus1.send(makeMessage(0x096CFD2B, true, true));
+
+ // 1BDCB008:0F0F0F0F, NS, DNC
+ bus1.send(makeMessage(0x1B2C3048, false, false));
+ bus1.send(makeMessage(0x0B5C6078, false, true));
+ bus1.send(makeMessage(0x1B8C90A8, true, false)); // filtered out
+ bus1.send(makeMessage(0x0BBCC0D8, true, true)); // filtered out
+
+ // 08318B46:10F0F0F0, NS, SET
+ bus1.send(makeMessage(0x0F3E8D4C, false, false)); // filtered out
+ bus1.send(makeMessage(0x0B3A8948, false, true));
+ bus1.send(makeMessage(0x07368544, true, false)); // filtered out
+ bus1.send(makeMessage(0x03328140, true, true)); // filtered out
+
+ // 06B:70F, DNC, SET
+ bus1.send(makeMessage(0x00B, false, false)); // filtered out
+ bus1.send(makeMessage(0x04B, false, true));
+ bus1.send(makeMessage(0x08B, true, false)); // filtered out
+ bus1.send(makeMessage(0x0FB, true, true));
+
+ // 750:70F, SET, SET
+ bus1.send(makeMessage(0x7F0, false, false)); // filtered out
+ bus1.send(makeMessage(0x780, false, true)); // filtered out
+ bus1.send(makeMessage(0x740, true, false)); // filtered out
+ bus1.send(makeMessage(0x700, true, true));
+
+ // 5CF:70F, NS, SET
+ bus1.send(makeMessage(0x51F, false, false)); // filtered out
+ bus1.send(makeMessage(0x53F, false, true));
+ bus1.send(makeMessage(0x57F, true, false)); // filtered out
+ bus1.send(makeMessage(0x5FF, true, true)); // filtered out
std::vector<can::V1_0::CanMessage> expectedPositive{
- makeMessage(0x1A0), //
- makeMessage(0x1A1), //
- makeMessage(0x3A0), //
- makeMessage(0x010), //
- makeMessage(0x123), //
- makeMessage(0x124), //
- };
- std::vector<can::V1_0::CanMessage> expectedNegative{
- makeMessage(0), //
- makeMessage(0x1A0), //
- makeMessage(0x1A1), //
- makeMessage(0x2A0), //
- makeMessage(0x3A0), //
- makeMessage(0x010), //
+ makeMessage(0x3F4, false, false), // 334:73F, DNC, DNC
+ makeMessage(0x334, false, true), // 334:73F, DNC, DNC
+ makeMessage(0x374, true, false), // 334:73F, DNC, DNC
+ makeMessage(0x3F4, true, true), // 334:73F, DNC, DNC
+ makeMessage(0x404, false, false), // 49D:700, DNC, DNC
+ makeMessage(0x4A5, false, true), // 49D:700, DNC, DNC
+ makeMessage(0x4FF, true, false), // 49D:700, DNC, DNC
+ makeMessage(0x46B, true, true), // 49D:700, DNC, DNC
+ makeMessage(0x324, false, false), // 325:7FC, DNC, NS
+ makeMessage(0x326, true, false), // 325:7FC, DNC, NS
+ makeMessage(0x246, true, false), // 246:7FF, SET, DNC
+ makeMessage(0x246, true, true), // 246:7FF, SET, DNC
+ makeMessage(0x1A2, true, false), // 1A2:7FB, SET, NS
+ makeMessage(0x607, false, false), // 607:7C9, NS, DNC
+ makeMessage(0x613, false, true), // 607:7C9, NS, DNC
+ makeMessage(0x774, false, false), // 7F4:777, NS, NS
+ makeMessage(0x11F293A4, false, false), // 1BF19EAF:10F0F0F0, DNC, DNC
+ makeMessage(0x15F697A8, false, true), // 1BF19EAF:10F0F0F0, DNC, DNC
+ makeMessage(0x19FA9BAC, true, false), // 1BF19EAF:10F0F0F0, DNC, DNC
+ makeMessage(0x1DFE9FA0, true, true), // 1BF19EAF:10F0F0F0, DNC, DNC
+ makeMessage(0x12E99200, false, true), // 12E99200:1FFFFFFF, DNC, SET
+ makeMessage(0x12E99200, true, true), // 12E99200:1FFFFFFF, DNC, SET
+ makeMessage(0x06B70270, true, false), // 06B70270:1FFFFFFF, SET, DNC
+ makeMessage(0x06B70270, true, true), // 06B70270:1FFFFFFF, SET, DNC
+ makeMessage(0x096CFD2B, true, true), // 096CFD2B:1FFFFFFF, SET, SET
+ makeMessage(0x1B2C3048, false, false), // 1BDCB008:0F0F0F0F, NS, DNC
+ makeMessage(0x0B5C6078, false, true), // 1BDCB008:0F0F0F0F, NS, DNC
+ makeMessage(0x0B3A8948, false, true), // 08318B46:10F0F0F0, NS, SET
+ makeMessage(0x04B, false, true), // 06B:70F, DNC, SET
+ makeMessage(0x0FB, true, true), // 06B:70F, DNC, SET
+ makeMessage(0x700, true, true), // 750:70F, SET, SET
+ makeMessage(0x53F, false, true), // 5CF:70F, NS, SET
};
- auto messagesNegative = listenerNegative->fetchMessages(100ms, expectedNegative.size());
auto messagesPositive = listenerPositive->fetchMessages(100ms, expectedPositive.size());
- clearTimestamps(messagesNegative);
clearTimestamps(messagesPositive);
- ASSERT_EQ(expectedNegative, messagesNegative);
ASSERT_EQ(expectedPositive, messagesPositive);
}
-} // namespace vts
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+TEST_F(CanBusVirtualHalTest, FilterNegative) {
+ if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+ auto bus1 = makeBus();
+ auto bus2 = makeBus();
+
+ /* clang-format off */
+ /* id, mask, rtr, eff exclude */
+ hidl_vec<CanMessageFilter> filterNegative = {
+ {0x063, 0x7F3, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x0A1, 0x78F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x18B, 0x7E3, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x1EE, 0x7EC, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x23F, 0x7A5, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x31F, 0x77F, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x341, 0x77F, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x196573DB, 0x1FFFFF7F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x1CFCB417, 0x1FFFFFEC, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x17CCC433, 0x1FFFFFEC, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x0BC2F508, 0x1FFFFFC3, FilterFlag::SET, FilterFlag::SET, true},
+ {0x1179B5D2, 0x1FFFFFC3, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x082AF63D, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x66D, 0x76F, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x748, 0x7CC, FilterFlag::SET, FilterFlag::SET, true},
+ {0x784, 0x7CC, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ };
+ /* clang-format on */
+
+ auto listenerNegative = bus2.listen(filterNegative);
+
+ // 063:7F3, DNC, DNC: ~06[3,7,B,F]
+ bus1.send(makeMessage(0x063, false, false)); // filtered out
+ bus1.send(makeMessage(0x060, false, true));
+ bus1.send(makeMessage(0x05B, true, false));
+ bus1.send(makeMessage(0x06F, true, true)); // filtered out
+
+ // 0A1:78F, DNC, DNC: ~0[8-F]1
+ bus1.send(makeMessage(0x081, false, false)); // filtered out
+ bus1.send(makeMessage(0x031, false, true));
+ bus1.send(makeMessage(0x061, true, false));
+ bus1.send(makeMessage(0x071, true, true));
+
+ // 18B:7E3, DNC, NS: ~1[8-9][7,B,F]
+ bus1.send(makeMessage(0x18B, false, false)); // filtered out
+ bus1.send(makeMessage(0x188, false, true));
+ bus1.send(makeMessage(0x123, true, false));
+ bus1.send(makeMessage(0x1D5, true, true));
+
+ // 1EE:7EC, SET, DNC: ~1[E-F][C-F]
+ bus1.send(makeMessage(0x17E, false, false));
+ bus1.send(makeMessage(0x138, false, true));
+ bus1.send(makeMessage(0x123, true, false));
+ bus1.send(makeMessage(0x1EC, true, true)); // filtered out
+
+ // 23F:7A5, SET, NS: ~2[2,3,6,7][5,7,D,F]
+ bus1.send(makeMessage(0x222, false, false));
+ bus1.send(makeMessage(0x275, false, true));
+ bus1.send(makeMessage(0x23f, true, false)); // filtered out
+ bus1.send(makeMessage(0x241, true, false));
+ bus1.send(makeMessage(0x2FF, true, true));
+
+ // 31F:77F, NS, DNC: ~3[1,9]F
+ bus1.send(makeMessage(0x32F, false, false));
+ bus1.send(makeMessage(0x31F, false, true)); // filtered out
+ bus1.send(makeMessage(0x36F, false, true));
+ bus1.send(makeMessage(0x31F, true, false));
+ bus1.send(makeMessage(0x3F3, true, true));
+
+ // 341:77F, NS, NS: ~3[4,C]1
+ bus1.send(makeMessage(0x341, false, false)); // filtered out
+ bus1.send(makeMessage(0x352, false, false));
+ bus1.send(makeMessage(0x3AA, false, true));
+ bus1.send(makeMessage(0x3BC, true, false));
+ bus1.send(makeMessage(0x3FF, true, true));
+
+ // 196573DB:1FFFFF7F, DNC, DNC: ~196573[5,D]B
+ bus1.send(makeMessage(0x1965733B, false, false));
+ bus1.send(makeMessage(0x1965734B, false, true));
+ bus1.send(makeMessage(0x1965735B, true, false)); // filtered out
+ bus1.send(makeMessage(0x1965736B, true, true));
+
+ // 1CFCB417:1FFFFFEC, DNC, SET: ~1CFCB4[0-1][4-7]
+ bus1.send(makeMessage(0x1CFCB407, false, false));
+ bus1.send(makeMessage(0x1CFCB4FF, false, true));
+ bus1.send(makeMessage(0x1CFCB414, true, false));
+ bus1.send(makeMessage(0x1CFCB407, true, true)); // filtered out
+
+ // 17CCC433:1FFFFFEC, SET, DNC: ~17CCC4[2-3][0-3]
+ bus1.send(makeMessage(0x17CCC430, false, false));
+ bus1.send(makeMessage(0x17CCC423, false, true));
+ bus1.send(makeMessage(0x17CCC420, true, false)); // filtered out
+ bus1.send(makeMessage(0x17CCC444, true, true));
+
+ // 0BC2F508:1FFFFFC3, SET, SET: ~5[0-3][0,4,8,C]
+ bus1.send(makeMessage(0x0BC2F504, false, false));
+ bus1.send(makeMessage(0x0BC2F518, false, true));
+ bus1.send(makeMessage(0x0BC2F52C, true, false));
+ bus1.send(makeMessage(0x0BC2F500, true, true)); // filtered out
+ bus1.send(makeMessage(0x0BC2F543, true, true));
+
+ // 1179B5D2:1FFFFFC3, NS, DNC: ~5[C-F][2,6,A,E]
+ bus1.send(makeMessage(0x1179B5BB, false, false));
+ bus1.send(makeMessage(0x1179B5EA, false, true)); // filtered out
+ bus1.send(makeMessage(0x1179B5C2, true, false));
+ bus1.send(makeMessage(0x1179B5DA, true, true));
+
+ // 082AF63D:1FFFFF6F, NS, SET: ~6[2,3,A,B]D
+ bus1.send(makeMessage(0x082AF62D, false, false));
+ bus1.send(makeMessage(0x082AF63D, false, true)); // filtered out
+ bus1.send(makeMessage(0x082AF60D, false, true));
+ bus1.send(makeMessage(0x082AF6AD, true, false));
+ bus1.send(makeMessage(0x082AF6BD, true, true));
+
+ // 66D:76F, DNC, SET: ~6[6,7,E,F]D
+ bus1.send(makeMessage(0x66D, false, false));
+ bus1.send(makeMessage(0x68D, false, true));
+ bus1.send(makeMessage(0x67D, true, false));
+ bus1.send(makeMessage(0x6ED, true, true)); // filtered out
+
+ // 748:7CC, SET, SET: ~0x7[4-7][8-F]
+ bus1.send(makeMessage(0x749, false, false));
+ bus1.send(makeMessage(0x75A, false, true));
+ bus1.send(makeMessage(0x76B, true, false));
+ bus1.send(makeMessage(0x748, true, true)); // filtered out
+ bus1.send(makeMessage(0x788, true, true));
+
+ // 784:7CC, NS, SET: ~0x7[8-F][4-7]
+ bus1.send(makeMessage(0x795, false, false));
+ bus1.send(makeMessage(0x784, false, true)); // filtered out
+ bus1.send(makeMessage(0x71B, false, true));
+ bus1.send(makeMessage(0x769, true, false));
+ bus1.send(makeMessage(0x784, true, true));
+
+ std::vector<can::V1_0::CanMessage> expectedNegative{
+ makeMessage(0x060, false, true), // 063:7F3, DNC, DNC
+ makeMessage(0x05B, true, false), // 063:7F3, DNC, DNC
+ makeMessage(0x031, false, true), // 0A1:78F, DNC, DNC
+ makeMessage(0x061, true, false), // 0A1:78F, DNC, DNC
+ makeMessage(0x071, true, true), // 0A1:78F, DNC, DNC
+ makeMessage(0x188, false, true), // 18B:7E3, DNC, NS
+ makeMessage(0x123, true, false), // 18B:7E3, DNC, NS
+ makeMessage(0x1D5, true, true), // 18B:7E3, DNC, NS
+ makeMessage(0x17E, false, false), // 1EE:7EC, SET, DNC
+ makeMessage(0x138, false, true), // 1EE:7EC, SET, DNC
+ makeMessage(0x123, true, false), // 1EE:7EC, SET, DNC
+ makeMessage(0x222, false, false), // 23F:7A5, SET, NS
+ makeMessage(0x275, false, true), // 23F:7A5, SET, NS
+ makeMessage(0x241, true, false), // 23F:7A5, SET, NS
+ makeMessage(0x2FF, true, true), // 23F:7A5, SET, NS
+ makeMessage(0x32F, false, false), // 31F:77F, NS, DNC
+ makeMessage(0x36F, false, true), // 31F:77F, NS, DNC
+ makeMessage(0x31F, true, false), // 31F:77F, NS, DNC
+ makeMessage(0x3F3, true, true), // 31F:77F, NS, DNC
+ makeMessage(0x352, false, false), // 341:77F, NS, NS
+ makeMessage(0x3AA, false, true), // 341:77F, NS, NS
+ makeMessage(0x3BC, true, false), // 341:77F, NS, NS
+ makeMessage(0x3FF, true, true), // 341:77F, NS, NS
+ makeMessage(0x1965733B, false, false), // 196573DB:1FFFFF7F, DNC, DNC
+ makeMessage(0x1965734B, false, true), // 196573DB:1FFFFF7F, DNC, DNC
+ makeMessage(0x1965736B, true, true), // 196573DB:1FFFFF7F, DNC, DNC
+ makeMessage(0x1CFCB407, false, false), // 1CFCB417:1FFFFFEC, DNC, SET
+ makeMessage(0x1CFCB4FF, false, true), // 1CFCB417:1FFFFFEC, DNC, SET
+ makeMessage(0x1CFCB414, true, false), // 1CFCB417:1FFFFFEC, DNC, SET
+ makeMessage(0x17CCC430, false, false), // 17CCC433:1FFFFFEC, SET, DNC
+ makeMessage(0x17CCC423, false, true), // 17CCC433:1FFFFFEC, SET, DNC
+ makeMessage(0x17CCC444, true, true), // 17CCC433:1FFFFFEC, SET, DNC
+ makeMessage(0x0BC2F504, false, false), // 0BC2F508:1FFFFFC3, SET, SET
+ makeMessage(0x0BC2F518, false, true), // 0BC2F508:1FFFFFC3, SET, SET
+ makeMessage(0x0BC2F52C, true, false), // 0BC2F508:1FFFFFC3, SET, SET
+ makeMessage(0x0BC2F543, true, true), // 0BC2F508:1FFFFFC3, SET, SET
+ makeMessage(0x1179B5BB, false, false), // 1179B5D2:1FFFFFC3, NS, DNC
+ makeMessage(0x1179B5C2, true, false), // 1179B5D2:1FFFFFC3, NS, DNC
+ makeMessage(0x1179B5DA, true, true), // 1179B5D2:1FFFFFC3, NS, DNC
+ makeMessage(0x082AF62D, false, false), // 082AF63D:1FFFFF6F, NS, SET
+ makeMessage(0x082AF60D, false, true), // 082AF63D:1FFFFF6F, NS, SET
+ makeMessage(0x082AF6AD, true, false), // 082AF63D:1FFFFF6F, NS, SET
+ makeMessage(0x082AF6BD, true, true), // 082AF63D:1FFFFF6F, NS, SET
+ makeMessage(0x66D, false, false), // 66D:76F, DNC, SET
+ makeMessage(0x68D, false, true), // 66D:76F, DNC, SET
+ makeMessage(0x67D, true, false), // 66D:76F, DNC, SET
+ makeMessage(0x749, false, false), // 748:7CC, SET, SET
+ makeMessage(0x75A, false, true), // 748:7CC, SET, SET
+ makeMessage(0x76B, true, false), // 748:7CC, SET, SET
+ makeMessage(0x788, true, true), // 748:7CC, SET, SET
+ makeMessage(0x795, false, false), // 784:7CC, NS, SET
+ makeMessage(0x71B, false, true), // 784:7CC, NS, SET
+ makeMessage(0x769, true, false), // 784:7CC, NS, SET
+ makeMessage(0x784, true, true), // 784:7CC, NS, SET
+ };
+
+ auto messagesNegative = listenerNegative->fetchMessages(100ms, expectedNegative.size());
+ clearTimestamps(messagesNegative);
+ ASSERT_EQ(expectedNegative, messagesNegative);
+}
+
+TEST_F(CanBusVirtualHalTest, FilterMixed) {
+ if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+ auto bus1 = makeBus();
+ auto bus2 = makeBus();
+
+ /* clang-format off */
+ /* id, mask, rtr, eff exclude */
+ hidl_vec<CanMessageFilter> filterMixed = {
+ {0x000, 0x700, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+ {0x0D5, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x046, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x11D89097, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x0AB, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x00D, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x0F82400E, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x08F, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x0BE, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x0A271011, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x0BE, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x100, 0x700, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, false},
+ {0x138, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x1BF, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x13AB6165, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x17A, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x13C, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x102C5197, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x19B, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x1B8, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x0D6D5185, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x1B8, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x096A2200, 0x1FFFFF00, FilterFlag::DONT_CARE, FilterFlag::SET, false},
+ {0x201, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x22A, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x1D1C3238, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x2C0, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x23C, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x016182C6, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x27B, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x2A5, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x160EB24B, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x2A5, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x300, 0x700, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, false},
+ {0x339, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x3D4, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x182263BE, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x327, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x36B, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x1A1D8374, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x319, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x39E, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x1B657332, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x39E, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x06C5D400, 0x1FFFFF00, FilterFlag::NOT_SET, FilterFlag::SET, false},
+ {0x492, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x4EE, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x07725454, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x4D5, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x402, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x139714A7, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x464, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x454, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x0EF4B46F, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x454, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x500, 0x700, FilterFlag::SET, FilterFlag::DONT_CARE, false},
+ {0x503, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x566, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x137605E7, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x564, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x58E, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x05F9052D, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x595, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x563, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x13358537, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x563, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x600, 0x700, FilterFlag::SET, FilterFlag::NOT_SET, false},
+ {0x64D, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x620, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x1069A676, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x62D, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x6C4, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x14C76629, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x689, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x6A4, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x0BCCA6C2, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x6A4, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+ {0x04BB1700, 0x1FFFFF00, FilterFlag::SET, FilterFlag::SET, false},
+ {0x784, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+ {0x7F9, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::NOT_SET, true},
+ {0x0200F77D, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET, true},
+ {0x783, 0x7FF, FilterFlag::NOT_SET, FilterFlag::DONT_CARE, true},
+ {0x770, 0x7FF, FilterFlag::NOT_SET, FilterFlag::NOT_SET, true},
+ {0x06602719, 0x1FFFFFFF, FilterFlag::NOT_SET, FilterFlag::SET, true},
+ {0x76B, 0x7FF, FilterFlag::SET, FilterFlag::DONT_CARE, true},
+ {0x7DF, 0x7FF, FilterFlag::SET, FilterFlag::NOT_SET, true},
+ {0x1939E736, 0x1FFFFFFF, FilterFlag::SET, FilterFlag::SET, true},
+ {0x7DF, 0x7FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+ };
+ /* clang-format on */
+
+ auto listenerMixed = bus2.listen(filterMixed);
+
+ bus1.send(makeMessage(0x000, true, true)); // positive filter
+ bus1.send(makeMessage(0x0D5, false, false));
+ bus1.send(makeMessage(0x046, true, false));
+ bus1.send(makeMessage(0x046, false, false));
+ bus1.send(makeMessage(0x11D89097, true, true));
+ bus1.send(makeMessage(0x11D89097, false, true));
+ bus1.send(makeMessage(0x0AB, false, false));
+ bus1.send(makeMessage(0x0AB, false, true));
+ bus1.send(makeMessage(0x00D, false, false));
+ bus1.send(makeMessage(0x0F82400E, false, true));
+ bus1.send(makeMessage(0x08F, true, false));
+ bus1.send(makeMessage(0x08F, true, true));
+ bus1.send(makeMessage(0x0BE, true, false));
+ bus1.send(makeMessage(0x0A271011, true, true));
+ bus1.send(makeMessage(0x0BE, false, true)); // not filtered
+ bus1.send(makeMessage(0x100, false, false)); // positive filter
+ bus1.send(makeMessage(0x138, false, true));
+ bus1.send(makeMessage(0x138, true, false));
+ bus1.send(makeMessage(0x1BF, false, false));
+ bus1.send(makeMessage(0x1BF, true, false));
+ bus1.send(makeMessage(0x13AB6165, false, true));
+ bus1.send(makeMessage(0x13AB6165, true, true));
+ bus1.send(makeMessage(0x17A, false, false));
+ bus1.send(makeMessage(0x17A, false, true));
+ bus1.send(makeMessage(0x13C, false, false));
+ bus1.send(makeMessage(0x102C5197, false, true));
+ bus1.send(makeMessage(0x19B, true, false));
+ bus1.send(makeMessage(0x19B, true, true));
+ bus1.send(makeMessage(0x1B8, true, false));
+ bus1.send(makeMessage(0x0D6D5185, true, true));
+ bus1.send(makeMessage(0x1B8, false, true)); // not filtered
+ bus1.send(makeMessage(0x096A2200, false, true)); // positive filter
+ bus1.send(makeMessage(0x201, false, true));
+ bus1.send(makeMessage(0x201, true, false));
+ bus1.send(makeMessage(0x22A, false, false));
+ bus1.send(makeMessage(0x22A, true, false));
+ bus1.send(makeMessage(0x1D1C3238, false, true));
+ bus1.send(makeMessage(0x1D1C3238, true, true));
+ bus1.send(makeMessage(0x2C0, false, false));
+ bus1.send(makeMessage(0x2C0, false, true));
+ bus1.send(makeMessage(0x23C, false, false));
+ bus1.send(makeMessage(0x016182C6, false, true));
+ bus1.send(makeMessage(0x27B, true, false));
+ bus1.send(makeMessage(0x27B, true, true));
+ bus1.send(makeMessage(0x2A5, true, false));
+ bus1.send(makeMessage(0x160EB24B, true, true));
+ bus1.send(makeMessage(0x2A5, false, true)); // not filtereed
+ bus1.send(makeMessage(0x300, false, false)); // positive filter
+ bus1.send(makeMessage(0x339, false, true));
+ bus1.send(makeMessage(0x339, false, false));
+ bus1.send(makeMessage(0x3D4, true, false));
+ bus1.send(makeMessage(0x182263BE, false, true));
+ bus1.send(makeMessage(0x182263BE, true, true));
+ bus1.send(makeMessage(0x327, false, false));
+ bus1.send(makeMessage(0x327, false, true));
+ bus1.send(makeMessage(0x36B, false, false));
+ bus1.send(makeMessage(0x1A1D8374, false, true));
+ bus1.send(makeMessage(0x319, true, false));
+ bus1.send(makeMessage(0x319, true, true));
+ bus1.send(makeMessage(0x39E, true, false));
+ bus1.send(makeMessage(0x1B657332, true, true));
+ bus1.send(makeMessage(0x39E, false, true)); // not filtered
+ bus1.send(makeMessage(0x06C5D400, false, true)); // positive filter
+ bus1.send(makeMessage(0x492, false, true));
+ bus1.send(makeMessage(0x492, true, false));
+ bus1.send(makeMessage(0x4EE, false, false));
+ bus1.send(makeMessage(0x4EE, true, false));
+ bus1.send(makeMessage(0x07725454, false, true));
+ bus1.send(makeMessage(0x07725454, true, true));
+ bus1.send(makeMessage(0x4D5, false, false));
+ bus1.send(makeMessage(0x4D5, false, true));
+ bus1.send(makeMessage(0x402, false, false));
+ bus1.send(makeMessage(0x139714A7, false, true));
+ bus1.send(makeMessage(0x464, true, false));
+ bus1.send(makeMessage(0x464, true, true));
+ bus1.send(makeMessage(0x454, true, false));
+ bus1.send(makeMessage(0x0EF4B46F, true, true));
+ bus1.send(makeMessage(0x454, false, true)); // not filtered
+ bus1.send(makeMessage(0x500, true, false)); // positive filter
+ bus1.send(makeMessage(0x503, false, true));
+ bus1.send(makeMessage(0x503, true, false));
+ bus1.send(makeMessage(0x566, false, false));
+ bus1.send(makeMessage(0x566, true, false));
+ bus1.send(makeMessage(0x137605E7, false, true));
+ bus1.send(makeMessage(0x137605E7, true, true));
+ bus1.send(makeMessage(0x564, false, false));
+ bus1.send(makeMessage(0x564, false, true));
+ bus1.send(makeMessage(0x58E, false, false));
+ bus1.send(makeMessage(0x05F9052D, false, true));
+ bus1.send(makeMessage(0x595, true, false));
+ bus1.send(makeMessage(0x595, true, true));
+ bus1.send(makeMessage(0x563, true, false));
+ bus1.send(makeMessage(0x13358537, true, true));
+ bus1.send(makeMessage(0x563, false, true)); // not filtered
+ bus1.send(makeMessage(0x600, true, false)); // positive filter
+ bus1.send(makeMessage(0x64D, false, true));
+ bus1.send(makeMessage(0x64D, true, false));
+ bus1.send(makeMessage(0x620, false, false));
+ bus1.send(makeMessage(0x620, true, false));
+ bus1.send(makeMessage(0x1069A676, false, true));
+ bus1.send(makeMessage(0x1069A676, true, true));
+ bus1.send(makeMessage(0x62D, false, false));
+ bus1.send(makeMessage(0x62D, false, true));
+ bus1.send(makeMessage(0x6C4, false, false));
+ bus1.send(makeMessage(0x14C76629, false, true));
+ bus1.send(makeMessage(0x689, true, false));
+ bus1.send(makeMessage(0x689, true, true));
+ bus1.send(makeMessage(0x6A4, true, false));
+ bus1.send(makeMessage(0x0BCCA6C2, true, true));
+ bus1.send(makeMessage(0x6A4, false, true)); // not filtered
+ bus1.send(makeMessage(0x04BB1700, true, true)); // positive filter
+ bus1.send(makeMessage(0x784, false, true));
+ bus1.send(makeMessage(0x784, true, false));
+ bus1.send(makeMessage(0x7F9, false, false));
+ bus1.send(makeMessage(0x7F9, true, false));
+ bus1.send(makeMessage(0x0200F77D, false, true));
+ bus1.send(makeMessage(0x0200F77D, true, true));
+ bus1.send(makeMessage(0x783, false, false));
+ bus1.send(makeMessage(0x783, false, true));
+ bus1.send(makeMessage(0x770, false, false));
+ bus1.send(makeMessage(0x06602719, false, true));
+ bus1.send(makeMessage(0x76B, true, false));
+ bus1.send(makeMessage(0x76B, true, true));
+ bus1.send(makeMessage(0x7DF, true, false));
+ bus1.send(makeMessage(0x1939E736, true, true));
+ bus1.send(makeMessage(0x7DF, false, true)); // not filtered
+
+ std::vector<can::V1_0::CanMessage> expectedMixed{
+ makeMessage(0x000, true, true), // 0x000:0x700, DONT_CARE, DONT_CARE
+ makeMessage(0x0BE, false, true),
+ makeMessage(0x100, false, false), // 0x100:0x700, DONT_CARE, NOT_SET
+ makeMessage(0x1B8, false, true),
+ makeMessage(0x096A2200, false, true), // 0x096A2200:0x1FFFFF00, DONT_CARE, SET
+ makeMessage(0x2A5, false, true),
+ makeMessage(0x300, false, false), // 0x300:0x700, NOT_SET, DONT_CARE
+ makeMessage(0x39E, false, true),
+ makeMessage(0x06C5D400, false, true), // 0x06C5D400:0x1FFFFF00, NOT_SET, SET
+ makeMessage(0x454, false, true),
+ makeMessage(0x500, true, false), // 0x500:0x700, SET, DONT_CARE
+ makeMessage(0x563, false, true),
+ makeMessage(0x600, true, false), // 0x600:0x700, SET, NOT_SET
+ makeMessage(0x6A4, false, true),
+ makeMessage(0x04BB1700, true, true), // 0x04BB1700:0x1FFFFF00, SET, SET
+ makeMessage(0x7DF, false, true),
+ };
+
+ auto messagesMixed = listenerMixed->fetchMessages(100ms, expectedMixed.size());
+ clearTimestamps(messagesMixed);
+ ASSERT_EQ(expectedMixed, messagesMixed);
+}
+
+} // namespace android::hardware::automotive::can::V1_0::vts
/**
* Example manual invocation:
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
index 64e7a96..9bc789a 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -21,17 +21,13 @@
#include <android/hardware/automotive/can/1.0/ICanController.h>
#include <android/hardware/automotive/can/1.0/types.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/bus-enumerator.h>
#include <can-vts-utils/can-hal-printers.h>
#include <can-vts-utils/environment-utils.h>
#include <gmock/gmock.h>
#include <hidl-utils/hidl-utils.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace vts {
+namespace android::hardware::automotive::can::V1_0::vts {
using hardware::hidl_vec;
using InterfaceType = ICanController::InterfaceType;
@@ -42,6 +38,7 @@
protected:
virtual void SetUp() override;
virtual void TearDown() override;
+ static void SetUpTestCase();
hidl_vec<InterfaceType> getSupportedInterfaceTypes();
bool isSupported(InterfaceType iftype);
@@ -51,9 +48,18 @@
void assertRegistered(const std::string srvname, bool expectRegistered);
sp<ICanController> mCanController;
+ static hidl_vec<hidl_string> mBusNames;
+
+ private:
+ static bool mTestCaseInitialized;
};
+hidl_vec<hidl_string> CanControllerHalTest::mBusNames;
+bool CanControllerHalTest::mTestCaseInitialized = false;
+
void CanControllerHalTest::SetUp() {
+ ASSERT_TRUE(mTestCaseInitialized);
+
const auto serviceName = gEnv->getServiceName<ICanController>();
mCanController = getService<ICanController>(serviceName);
ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName;
@@ -63,6 +69,13 @@
mCanController.clear();
}
+void CanControllerHalTest::SetUpTestCase() {
+ mBusNames = utils::getBusNames();
+ ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest";
+
+ mTestCaseInitialized = true;
+}
+
hidl_vec<InterfaceType> CanControllerHalTest::getSupportedInterfaceTypes() {
hidl_vec<InterfaceType> iftypesResult;
mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&iftypesResult)).assertOk();
@@ -109,7 +122,7 @@
}
TEST_F(CanControllerHalTest, BringUpDown) {
- const std::string name = "dummy";
+ const std::string name = mBusNames[0];
assertRegistered(name, false);
if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::OK)) GTEST_SKIP();
@@ -127,7 +140,7 @@
}
TEST_F(CanControllerHalTest, UpTwice) {
- const std::string name = "dummy";
+ const std::string name = mBusNames[0];
assertRegistered(name, false);
if (!up(InterfaceType::VIRTUAL, name, "vcan72", ICanController::Result::OK)) GTEST_SKIP();
@@ -216,7 +229,7 @@
}
TEST_F(CanControllerHalTest, FailBadVirtualAddress) {
- const std::string name = "dummy";
+ const std::string name = mBusNames[0];
assertRegistered(name, false);
if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_ADDRESS)) GTEST_SKIP();
@@ -224,7 +237,7 @@
}
TEST_F(CanControllerHalTest, FailBadSocketcanAddress) {
- const std::string name = "dummy";
+ const std::string name = mBusNames[0];
assertRegistered(name, false);
if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_ADDRESS)) {
@@ -233,12 +246,7 @@
assertRegistered(name, false);
}
-} // namespace vts
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::vts
/**
* Example manual invocation:
diff --git a/automotive/can/1.0/vts/utils/Android.bp b/automotive/can/1.0/vts/utils/Android.bp
index e925c8f..d03ead3 100644
--- a/automotive/can/1.0/vts/utils/Android.bp
+++ b/automotive/can/1.0/vts/utils/Android.bp
@@ -14,7 +14,17 @@
// limitations under the License.
//
-cc_library_headers {
+cc_library_static {
name: "android.hardware.automotive.can@vts-utils-lib",
+ defaults: ["android.hardware.automotive.can@defaults"],
+ srcs: [
+ "bus-enumerator.cpp",
+ ],
export_include_dirs: ["include"],
+ header_libs: [
+ "android.hardware.automotive.can@hidl-utils-lib",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can@1.0",
+ ],
}
diff --git a/automotive/can/1.0/vts/utils/bus-enumerator.cpp b/automotive/can/1.0/vts/utils/bus-enumerator.cpp
new file mode 100644
index 0000000..c012dd2
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/bus-enumerator.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/bus-enumerator.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android::hardware::automotive::can::V1_0::vts::utils {
+
+hidl_vec<hidl_string> getBusNames() {
+ auto manager = hidl::manager::V1_2::IServiceManager::getService();
+ hidl_vec<hidl_string> services;
+ manager->listManifestByInterface(ICanBus::descriptor, hidl_utils::fill(&services));
+ return services;
+}
+
+} // namespace android::hardware::automotive::can::V1_0::vts::utils
diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h
new file mode 100644
index 0000000..ef385eb
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+
+namespace android::hardware::automotive::can::V1_0::vts::utils {
+
+hidl_vec<hidl_string> getBusNames();
+
+} // namespace android::hardware::automotive::can::V1_0::vts::utils
diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
index 0923998..3c30744 100644
--- a/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
@@ -18,11 +18,7 @@
#include <android/hardware/automotive/can/1.0/ICanController.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
+namespace android::hardware::automotive::can::V1_0 {
/**
* Define gTest printer for a given HIDL type, but skip definition for Return<T>.
@@ -48,8 +44,4 @@
#undef DEFINE_CAN_HAL_PRINTER
#undef DEFINE_CAN_HAL_PRINTER_SIMPLE
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0
diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h
index a722dd0..3eb9cc1 100644
--- a/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h
@@ -18,13 +18,7 @@
#include <VtsHalHidlTargetTestEnvBase.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace can {
-namespace V1_0 {
-namespace vts {
-namespace utils {
+namespace android::hardware::automotive::can::V1_0::vts::utils {
/**
* Simple test environment.
@@ -63,10 +57,4 @@
}
};
-} // namespace utils
-} // namespace vts
-} // namespace V1_0
-} // namespace can
-} // namespace automotive
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::automotive::can::V1_0::vts::utils
diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal
index 975b6c6..fc68e60 100644
--- a/automotive/evs/1.1/IEvsCamera.hal
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -34,6 +34,23 @@
getCameraInfo_1_1() generates (CameraDesc info);
/**
+ * Returns the description of the physical camera device that backs this
+ * logical camera.
+ *
+ * If a requested device does not either exist or back this logical device,
+ * this method returns a null camera descriptor. And, if this is called on
+ * a physical camera device, this method is the same as getCameraInfo_1_1()
+ * method if a given device ID is matched. Otherwise, this will return a
+ * null camera descriptor.
+ *
+ * @param deviceId Physical camera device identifier string.
+ * @return info The description of a member physical camera device.
+ * This must be the same value as reported by
+ * EvsEnumerator::getCameraList_1_1().
+ */
+ getPhysicalCameraInfo(string deviceId) generates (CameraDesc info);
+
+ /**
* Requests to pause EVS camera stream events.
*
* Like stopVideoStream(), events may continue to arrive for some time
@@ -51,7 +68,7 @@
resumeVideoStream() generates (EvsResult result);
/**
- * Returns a frame that was delivered by to the IEvsCameraStream.
+ * Returns frame that were delivered by to the IEvsCameraStream.
*
* When done consuming a frame delivered to the IEvsCameraStream
* interface, it must be returned to the IEvsCamera for reuse.
@@ -59,10 +76,10 @@
* 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.
+ * @param buffer Buffers to be returned.
* @return result Return EvsResult::OK if this call is successful.
*/
- doneWithFrame_1_1(BufferDesc buffer) generates (EvsResult result);
+ doneWithFrame_1_1(vec<BufferDesc> buffer) generates (EvsResult result);
/**
* Requests to be a master client.
@@ -127,8 +144,13 @@
generates (int32_t min, int32_t max, int32_t step);
/**
- * Requests to set a camera parameter. Only a request from the master
- * client will be processed successfully.
+ * Requests to set a camera parameter.
+ *
+ * Only a request from the master client will be processed successfully.
+ * When this method is called on a logical camera device, it will be forwarded
+ * to each physical device and, if it fails to program any physical device,
+ * it will return an error code with the same number of effective values as
+ * the number of backing camera devices.
*
* @param id The identifier of camera parameter, CameraParam enum.
* value A desired parameter value.
@@ -138,21 +160,22 @@
* parameter is not supported.
* EvsResult::UNDERLYING_SERVICE_ERROR if it fails to
* program a value by any other reason.
- * effectiveValue A programmed parameter value. This may differ
+ * effectiveValue Programmed parameter values. This may differ
* from what the client gives if, for example, the
* driver does not support a target parameter.
*/
setIntParameter(CameraParam id, int32_t value)
- generates (EvsResult result, int32_t effectiveValue);
+ generates (EvsResult result, vec<int32_t> effectiveValue);
/**
- * Retrieves a value of given camera parameter.
+ * Retrieves values of given camera parameter.
*
* @param id The identifier of camera parameter, CameraParam enum.
* @return result EvsResult::OK if it succeeds to read a parameter.
* EvsResult::INVALID_ARG if either a requested parameter is
* not supported.
- * value A value of requested camera parameter.
+ * value Values of requested camera parameter, the same number of
+ * values as backing camera devices.
*/
- getIntParameter(CameraParam id) generates(EvsResult result, int32_t value);
+ getIntParameter(CameraParam id) generates(EvsResult result, vec<int32_t> value);
};
diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal
index 9e4ea19..aa35c62 100644
--- a/automotive/evs/1.1/IEvsCameraStream.hal
+++ b/automotive/evs/1.1/IEvsCameraStream.hal
@@ -18,7 +18,7 @@
import @1.0::IEvsCameraStream;
import @1.1::BufferDesc;
-import @1.1::EvsEvent;
+import @1.1::EvsEventDesc;
/**
* Implemented on client side to receive asynchronous streaming event deliveries.
@@ -26,7 +26,7 @@
interface IEvsCameraStream extends @1.0::IEvsCameraStream {
/**
- * Receives calls from the HAL each time a video frame is ready for inspection.
+ * Receives calls from the HAL each time video frames is ready for inspection.
* Buffer handles received by this method must be returned via calls to
* IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call
* to IEvsCamera::stopVideoStream(), this callback may continue to happen for
@@ -35,14 +35,19 @@
* event must be delivered. No further frame deliveries may happen
* thereafter.
*
- * @param buffer a buffer descriptor of a delivered image frame.
+ * A camera device will deliver the same number of frames as number of
+ * backing physical camera devices; it means, a physical camera device
+ * sends always a single frame and a logical camera device sends multiple
+ * frames as many as number of backing physical camera devices.
+ *
+ * @param buffer Buffer descriptors of delivered image frames.
*/
- oneway deliverFrame_1_1(BufferDesc buffer);
+ oneway deliverFrame_1_1(vec<BufferDesc> buffer);
/**
* Receives calls from the HAL each time an event happens.
*
* @param event EVS event with possible event information.
*/
- oneway notify(EvsEvent event);
+ oneway notify(EvsEventDesc event);
};
diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp
index 41cb426..88fd657 100644
--- a/automotive/evs/1.1/default/Android.bp
+++ b/automotive/evs/1.1/default/Android.bp
@@ -16,7 +16,7 @@
shared_libs: [
"android.hardware.automotive.evs@1.0",
"android.hardware.automotive.evs@1.1",
- "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
"libbase",
"libbinder",
"liblog",
diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp
index 96a2f98..986793e 100644
--- a/automotive/evs/1.1/default/ConfigManager.cpp
+++ b/automotive/evs/1.1/default/ConfigManager.cpp
@@ -42,55 +42,32 @@
while (curElem != nullptr) {
if (!strcmp(curElem->Name(), "group")) {
/* camera group identifier */
- const char *group_id = curElem->FindAttribute("group_id")->Value();
+ const char *id = curElem->FindAttribute("id")->Value();
- /* create CameraGroup */
- unique_ptr<ConfigManager::CameraGroup> aCameraGroup(new ConfigManager::CameraGroup());
+ /* create a camera group to be filled */
+ CameraGroupInfo *aCamera = new CameraGroupInfo();
- /* add a camera device to its group */
- addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup);
-
- /* a list of camera stream configurations */
- const XMLElement *childElem =
- curElem->FirstChildElement("caps")->FirstChildElement("stream");
- while (childElem != nullptr) {
- /* read 5 attributes */
- const XMLAttribute *idAttr = childElem->FindAttribute("id");
- const XMLAttribute *widthAttr = childElem->FindAttribute("width");
- const XMLAttribute *heightAttr = childElem->FindAttribute("height");
- const XMLAttribute *fmtAttr = childElem->FindAttribute("format");
- const XMLAttribute *fpsAttr = childElem->FindAttribute("framerate");
-
- const int32_t id = stoi(idAttr->Value());
- int32_t framerate = 0;
- if (fpsAttr != nullptr) {
- framerate = stoi(fpsAttr->Value());
- }
-
- int32_t pixFormat;
- if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
- pixFormat)) {
- RawStreamConfiguration cfg = {
- id,
- stoi(widthAttr->Value()),
- stoi(heightAttr->Value()),
- pixFormat,
- ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
- framerate
- };
- aCameraGroup->streamConfigurations[id] = cfg;
- }
-
- childElem = childElem->NextSiblingElement("stream");
+ /* read camera device information */
+ if (!readCameraDeviceInfo(aCamera, curElem)) {
+ ALOGW("Failed to read a camera information of %s", id);
+ delete aCamera;
+ continue;
}
/* camera group synchronization */
const char *sync = curElem->FindAttribute("synchronized")->Value();
- aCameraGroup->synchronized =
- static_cast<bool>(strcmp(sync, "false"));
+ if (!strcmp(sync, "CALIBRATED")) {
+ aCamera->synchronized =
+ ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED;
+ } else if (!strcmp(sync, "APPROXIMATE")) {
+ aCamera->synchronized =
+ ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE;
+ } else {
+ aCamera->synchronized = 0; // Not synchronized
+ }
/* add a group to hash map */
- mCameraGroups[group_id] = std::move(aCameraGroup);
+ mCameraGroupInfos.insert_or_assign(id, unique_ptr<CameraGroupInfo>(aCamera));
} else if (!strcmp(curElem->Name(), "device")) {
/* camera unique identifier */
const char *id = curElem->FindAttribute("id")->Value();
@@ -98,8 +75,18 @@
/* camera mount location */
const char *pos = curElem->FindAttribute("position")->Value();
+ /* create a camera device to be filled */
+ CameraInfo *aCamera = new CameraInfo();
+
+ /* read camera device information */
+ if (!readCameraDeviceInfo(aCamera, curElem)) {
+ ALOGW("Failed to read a camera information of %s", id);
+ delete aCamera;
+ continue;
+ }
+
/* store read camera module information */
- mCameraInfo[id] = readCameraDeviceInfo(curElem);
+ mCameraInfo.insert_or_assign(id, unique_ptr<CameraInfo>(aCamera));
/* assign a camera device to a position group */
mCameraPosition[pos].emplace(id);
@@ -113,15 +100,13 @@
}
-unique_ptr<ConfigManager::CameraInfo>
-ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) {
- if (aDeviceElem == nullptr) {
- return nullptr;
+bool
+ConfigManager::readCameraDeviceInfo(CameraInfo *aCamera,
+ const XMLElement *aDeviceElem) {
+ if (aCamera == nullptr || aDeviceElem == nullptr) {
+ return false;
}
- /* create a CameraInfo to be filled */
- unique_ptr<ConfigManager::CameraInfo> aCamera(new ConfigManager::CameraInfo());
-
/* size information to allocate camera_metadata_t */
size_t totalEntries = 0;
size_t totalDataSize = 0;
@@ -145,14 +130,15 @@
"allocated memory was not large enough");
}
- return aCamera;
+ return true;
}
-size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
- unique_ptr<ConfigManager::CameraInfo> &aCamera,
- size_t &dataSize) {
- if (aCapElem == nullptr) {
+size_t
+ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
+ CameraInfo *aCamera,
+ size_t &dataSize) {
+ if (aCapElem == nullptr || aCamera == nullptr) {
return 0;
}
@@ -214,7 +200,7 @@
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
framerate
};
- aCamera->streamConfigurations[id] = cfg;
+ aCamera->streamConfigurations.insert_or_assign(id, cfg);
}
curElem = curElem->NextSiblingElement("stream");
@@ -232,10 +218,11 @@
}
-size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
- unique_ptr<ConfigManager::CameraInfo> &aCamera,
- size_t &dataSize) {
- if (aParamElem == nullptr) {
+size_t
+ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
+ CameraInfo *aCamera,
+ size_t &dataSize) {
+ if (aParamElem == nullptr || aCamera == nullptr) {
return 0;
}
@@ -258,8 +245,9 @@
count
);
- aCamera->cameraMetadata[tag] =
- make_pair(make_unique<void *>(data), count);
+ aCamera->cameraMetadata.insert_or_assign(
+ tag, make_pair(make_unique<void *>(data), count)
+ );
++numEntries;
dataSize += calculate_camera_metadata_entry_data_size(
@@ -269,6 +257,52 @@
break;
}
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: {
+ camera_metadata_enum_android_request_available_capabilities_t *data =
+ new camera_metadata_enum_android_request_available_capabilities_t[1];
+ if (ConfigManagerUtil::convertToCameraCapability(
+ curElem->FindAttribute("value")->Value(), *data)) {
+ curElem->FindAttribute("value")->Value(),
+ aCamera->cameraMetadata.insert_or_assign(
+ tag, make_pair(make_unique<void *>(data), 1)
+ );
+
+ ++numEntries;
+ dataSize += calculate_camera_metadata_entry_data_size(
+ get_camera_metadata_tag_type(tag), 1
+ );
+ }
+ break;
+ }
+
+ case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: {
+ /* a comma-separated list of physical camera devices */
+ size_t len = strlen(curElem->FindAttribute("value")->Value());
+ char *data = new char[len + 1];
+ memcpy(data,
+ curElem->FindAttribute("value")->Value(),
+ len * sizeof(char));
+
+ /* replace commas with null char */
+ char *p = data;
+ while (*p != '\0') {
+ if (*p == ',') {
+ *p = '\0';
+ }
+ ++p;
+ }
+
+ aCamera->cameraMetadata.insert_or_assign(
+ tag, make_pair(make_unique<void *>(data), len)
+ );
+
+ ++numEntries;
+ dataSize += calculate_camera_metadata_entry_data_size(
+ get_camera_metadata_tag_type(tag), len
+ );
+ break;
+ }
+
default:
ALOGW("Parameter %s is not supported",
curElem->FindAttribute("name")->Value());
@@ -283,10 +317,11 @@
}
-bool ConfigManager::constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
- const size_t totalEntries,
- const size_t totalDataSize) {
- if (!aCamera->allocate(totalEntries, totalDataSize)) {
+bool
+ConfigManager::constructCameraMetadata(CameraInfo *aCamera,
+ const size_t totalEntries,
+ const size_t totalDataSize) {
+ if (aCamera == nullptr || !aCamera->allocate(totalEntries, totalDataSize)) {
ALOGE("Failed to allocate memory for camera metadata");
return false;
}
@@ -401,14 +436,14 @@
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
0 // unused
};
- dpy->streamConfigurations[id] = cfg;
+ dpy->streamConfigurations.insert_or_assign(id, cfg);
}
curStream = curStream->NextSiblingElement("stream");
}
}
- mDisplayInfo[id] = std::move(dpy);
+ mDisplayInfo.insert_or_assign(id, std::move(dpy));
curDev = curDev->NextSiblingElement("device");
}
@@ -457,16 +492,6 @@
}
-void ConfigManager::addCameraDevices(const char *devices,
- unique_ptr<CameraGroup> &aGroup) {
- stringstream device_list(devices);
- string token;
- while (getline(device_list, token, ',')) {
- aGroup->devices.emplace(token);
- }
-}
-
-
std::unique_ptr<ConfigManager> ConfigManager::Create(const char *path) {
unique_ptr<ConfigManager> cfgMgr(new ConfigManager(path));
diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h
index 0275f90..870af1c 100644
--- a/automotive/evs/1.1/default/ConfigManager.h
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -82,9 +82,6 @@
unordered_map<CameraParam,
tuple<int32_t, int32_t, int32_t>> controls;
- /* List of supported frame rates */
- unordered_set<int32_t> frameRates;
-
/*
* List of supported output stream configurations; each array stores
* format, width, height, and direction values in the order.
@@ -102,21 +99,15 @@
camera_metadata_t *characteristics;
};
- class CameraGroup {
+ class CameraGroupInfo : public CameraInfo {
public:
- CameraGroup() {}
+ CameraGroupInfo() {}
/* ID of member camera devices */
unordered_set<string> devices;
/* The capture operation of member camera devices are synchronized */
bool synchronized = false;
-
- /*
- * List of stream configurations that are supposed by all camera devices
- * in this group.
- */
- unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
};
class SystemInfo {
@@ -165,11 +156,11 @@
/*
* Return a list of cameras
*
- * @return CameraGroup
+ * @return CameraGroupInfo
* A pointer to a camera group identified by a given id.
*/
- unique_ptr<CameraGroup>& getCameraGroup(const string& gid) {
- return mCameraGroups[gid];
+ unique_ptr<CameraGroupInfo>& getCameraGroupInfo(const string& gid) {
+ return mCameraGroupInfos[gid];
}
@@ -203,8 +194,8 @@
/* Internal data structure for camera device information */
unordered_map<string, unique_ptr<DisplayInfo>> mDisplayInfo;
- /* Camera groups are stored in <groud id, CameraGroup> hash map */
- unordered_map<string, unique_ptr<CameraGroup>> mCameraGroups;
+ /* Camera groups are stored in <groud id, CameraGroupInfo> hash map */
+ unordered_map<string, unique_ptr<CameraGroupInfo>> mCameraGroupInfos;
/*
* Camera positions are stored in <position, camera id set> hash map.
@@ -253,16 +244,19 @@
/*
* read camera device information
*
- * @param aDeviceElem
+ * @param aCamera
+ * A pointer to CameraInfo that will be completed by this
+ * method.
+ * aDeviceElem
* A pointer to "device" XML element that contains camera module
* capability info and its characteristics.
*
- * @return unique_ptr<CameraInfo>
- * A pointer to CameraInfo class that contains camera module
- * capability and characteristics. Please note that this transfers
- * the ownership of created CameraInfo to the caller.
+ * @return bool
+ * Return false upon any failure in reading and processing camera
+ * device information.
*/
- unique_ptr<CameraInfo> readCameraDeviceInfo(const XMLElement *aDeviceElem);
+ bool readCameraDeviceInfo(CameraInfo *aCamera,
+ const XMLElement *aDeviceElem);
/*
* read camera metadata
@@ -280,7 +274,7 @@
* Number of camera metadata entries
*/
size_t readCameraCapabilities(const XMLElement * const aCapElem,
- unique_ptr<CameraInfo> &aCamera,
+ CameraInfo *aCamera,
size_t &dataSize);
/*
@@ -298,7 +292,7 @@
* Number of camera metadata entries
*/
size_t readCameraMetadata(const XMLElement * const aParamElem,
- unique_ptr<CameraInfo> &aCamera,
+ CameraInfo *aCamera,
size_t &dataSize);
/*
@@ -316,21 +310,9 @@
* or its size is not large enough to add all found camera metadata
* entries.
*/
- bool constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
+ bool constructCameraMetadata(CameraInfo *aCamera,
const size_t totalEntries,
const size_t totalDataSize);
-
- /*
- * parse a comma-separated list of camera devices and add them to
- * CameraGroup.
- *
- * @param devices
- * A comma-separated list of camera device identifiers.
- * @param aGroup
- * Camera group which cameras will be added to.
- */
- void addCameraDevices(const char *devices,
- unique_ptr<CameraGroup> &aGroup);
};
#endif // CONFIG_MANAGER_H
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
index 8206daa..d10f236 100644
--- a/automotive/evs/1.1/default/ConfigManagerUtil.cpp
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
@@ -90,6 +90,30 @@
aTag = ANDROID_LENS_POSE_ROTATION;
} else if (!strcmp(name, "LENS_POSE_TRANSLATION")) {
aTag = ANDROID_LENS_POSE_TRANSLATION;
+ } else if (!strcmp(name, "REQUEST_AVAILABLE_CAPABILITIES")) {
+ aTag = ANDROID_REQUEST_AVAILABLE_CAPABILITIES;
+ } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA_PHYSICAL_IDS")) {
+ aTag = ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+
+bool ConfigManagerUtil::convertToCameraCapability(
+ const char *name,
+ camera_metadata_enum_android_request_available_capabilities_t &cap) {
+
+ if (!strcmp(name, "DEPTH_OUTPUT")) {
+ cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT;
+ } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA")) {
+ cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA;
+ } else if (!strcmp(name, "MONOCHROME")) {
+ cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME;
+ } else if (!strcmp(name, "SECURE_IMAGE_DATA")) {
+ cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA;
} else {
return false;
}
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h
index 8c89ae7..1710cac 100644
--- a/automotive/evs/1.1/default/ConfigManagerUtil.h
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.h
@@ -55,6 +55,14 @@
*/
static string trimString(const string &src,
const string &ws = " \n\r\t\f\v");
+
+ /**
+ * Convert a given string to corresponding camera capabilities
+ */
+ static bool convertToCameraCapability(
+ const char *name,
+ camera_metadata_enum_android_request_available_capabilities_t &cap);
+
};
#endif // CONFIG_MANAGER_UTIL_H
diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp
index 5ba753d..b7e4efa 100644
--- a/automotive/evs/1.1/default/EvsCamera.cpp
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -21,7 +21,7 @@
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
-
+#include <utils/SystemClock.h>
namespace android {
namespace hardware {
@@ -240,9 +240,23 @@
}
-Return<EvsResult> EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) {
+Return<void> EvsCamera::getPhysicalCameraInfo(const hidl_string& id,
+ getCameraInfo_1_1_cb _hidl_cb) {
+ ALOGD("%s", __FUNCTION__);
+
+ // This works exactly same as getCameraInfo_1_1() in default implementation.
+ (void)id;
+ _hidl_cb(mDescription);
+ return Void();
+}
+
+
+Return<EvsResult> EvsCamera::doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers) {
std::lock_guard <std::mutex> lock(mAccessLock);
- returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle);
+
+ for (auto&& buffer : buffers) {
+ returnBuffer(buffer.bufferId, buffer.buffer.nativeHandle);
+ }
return EvsResult::OK;
}
@@ -490,12 +504,17 @@
newBuffer.buffer.nativeHandle = mBuffers[idx].handle;
newBuffer.pixelSize = sizeof(uint32_t);
newBuffer.bufferId = idx;
+ newBuffer.deviceId = mDescription.v1.cameraId;
+ newBuffer.timestamp = elapsedRealtimeNano();
// Write test data into the image buffer
fillTestFrame(newBuffer);
// Issue the (asynchronous) callback to the client -- can't be holding the lock
- auto result = mStream->deliverFrame_1_1(newBuffer);
+ hidl_vec<BufferDesc_1_1> frames;
+ frames.resize(1);
+ frames[0] = newBuffer;
+ auto result = mStream->deliverFrame_1_1(frames);
if (result.isOk()) {
ALOGD("Delivered %p as id %d",
newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId);
@@ -527,7 +546,7 @@
}
// If we've been asked to stop, send an event to signal the actual end of stream
- EvsEvent event;
+ EvsEventDesc event;
event.aType = EvsEventType::STREAM_STOPPED;
auto result = mStream->notify(event);
if (!result.isOk()) {
diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h
index c15b4b1..72a1b57 100644
--- a/automotive/evs/1.1/default/EvsCamera.h
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -62,9 +62,11 @@
// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
Return<void> getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override;
+ Return<void> getPhysicalCameraInfo(const hidl_string& id,
+ getPhysicalCameraInfo_cb _hidl_cb) override;
Return<EvsResult> pauseVideoStream() override;
Return<EvsResult> resumeVideoStream() override;
- Return<EvsResult> doneWithFrame_1_1(const BufferDesc_1_1& buffer) override;
+ Return<EvsResult> doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
Return<EvsResult> setMaster() override;
Return<EvsResult> forceMaster(const sp<IEvsDisplay>& display) override;
Return<EvsResult> unsetMaster() override;
diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
index 692102e..a79e7c2 100644
--- a/automotive/evs/1.1/default/resources/evs_default_configuration.xml
+++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
@@ -28,8 +28,31 @@
<num_cameras value='1'/>
</system>
- <!-- camera device information -->
+ <!-- camera information -->
<camera>
+ <!-- camera group starts -->
+ <group id='group1' synchronized='APPROXIMATE'>
+ <caps>
+ <stream id='0' width='640' height='360' format='RGBA_8888' framerate='30'/>
+ </caps>
+
+ <!-- list of parameters -->
+ <characteristics>
+ <parameter
+ name='REQUEST_AVAILABLE_CAPABILITIES'
+ type='enum'
+ size='1'
+ value='LOGICAL_MULTI_CAMERA'
+ />
+ <parameter
+ name='LOGICAL_MULTI_CAMERA_PHYSICAL_IDS'
+ type='byte[]'
+ size='1'
+ value='/dev/video1'
+ />
+ </characteristics>
+ </group>
+
<!-- camera device starts -->
<device id='/dev/video1' position='rear'>
<caps>
diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal
index dcb2abb..f88d223 100644
--- a/automotive/evs/1.1/types.hal
+++ b/automotive/evs/1.1/types.hal
@@ -61,6 +61,14 @@
* Opaque value from driver
*/
uint32_t bufferId;
+ /**
+ * Unique identifier of the physical camera device that produces this buffer.
+ */
+ string deviceId;
+ /**
+ * Time that this buffer is being filled.
+ */
+ int64_t timestamp;
};
/**
@@ -97,12 +105,16 @@
/**
* Structure that describes informative events occurred during EVS is streaming
*/
-struct EvsEvent {
+struct EvsEventDesc {
/**
* Type of an informative event
*/
EvsEventType aType;
/**
+ * Device identifier
+ */
+ string deviceId;
+ /**
* Possible additional information
*/
uint32_t[4] payload;
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
index 6d53652..ebf488a 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
@@ -80,7 +80,7 @@
asyncStopStream();
// Wait until the stream has actually stopped
- std::unique_lock<std::mutex> lock(mLock);
+ std::unique_lock<std::mutex> lock(mEventLock);
if (mRunning) {
mEventSignal.wait(lock, [this]() { return !mRunning; });
}
@@ -88,7 +88,7 @@
bool FrameHandler::returnHeldBuffer() {
- std::unique_lock<std::mutex> lock(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
// Return the oldest buffer we're holding
if (mHeldBuffers.empty()) {
@@ -96,16 +96,16 @@
return false;
}
- BufferDesc_1_1 buffer = mHeldBuffers.front();
+ hidl_vec<BufferDesc_1_1> buffers = mHeldBuffers.front();
mHeldBuffers.pop();
- mCamera->doneWithFrame_1_1(buffer);
+ mCamera->doneWithFrame_1_1(buffers);
return true;
}
bool FrameHandler::isRunning() {
- std::unique_lock<std::mutex> lock(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
return mRunning;
}
@@ -120,7 +120,7 @@
void FrameHandler::getFramesCounters(unsigned* received, unsigned* displayed) {
- std::unique_lock<std::mutex> lock(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
if (received) {
*received = mFramesReceived;
@@ -138,11 +138,17 @@
}
-Return<void> FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) {
+Return<void> FrameHandler::deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers) {
+ mLock.lock();
+ // For VTS tests, FrameHandler uses a single frame among delivered frames.
+ auto bufferIdx = mFramesDisplayed % buffers.size();
+ auto buffer = buffers[bufferIdx];
+ mLock.unlock();
+
const AHardwareBuffer_Desc* pDesc =
- reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description);
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&buffer.buffer.description);
ALOGD("Received a frame from the camera (%p)",
- bufDesc.buffer.nativeHandle.getNativeHandle());
+ buffer.buffer.nativeHandle.getNativeHandle());
// Store a dimension of a received frame.
mFrameWidth = pDesc->width;
@@ -150,6 +156,7 @@
// If we were given an opened display at construction time, then send the received
// image back down the camera.
+ bool displayed = false;
if (mDisplay.get()) {
// Get the output buffer we'll use to display the imagery
BufferDesc_1_0 tgtBuffer = {};
@@ -163,7 +170,7 @@
ALOGE("Didn't get requested output buffer -- skipping this frame.");
} else {
// Copy the contents of the of buffer.memHandle into tgtBuffer
- copyBufferContents(tgtBuffer, bufDesc);
+ copyBufferContents(tgtBuffer, buffer);
// Send the target buffer back for display
Return<EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
@@ -179,40 +186,42 @@
} else {
// Everything looks good!
// Keep track so tests or watch dogs can monitor progress
- mLock.lock();
- mFramesDisplayed++;
- mLock.unlock();
+ displayed = true;
}
}
}
+ mLock.lock();
+ // increases counters
+ ++mFramesReceived;
+ mFramesDisplayed += (int)displayed;
+ mLock.unlock();
+ mFrameSignal.notify_all();
switch (mReturnMode) {
case eAutoReturn:
// Send the camera buffer back now that the client has seen it
ALOGD("Calling doneWithFrame");
- mCamera->doneWithFrame_1_1(bufDesc);
+ mCamera->doneWithFrame_1_1(buffers);
break;
case eNoAutoReturn:
- // Hang onto the buffer handle for now -- the client will return it explicitly later
- mHeldBuffers.push(bufDesc);
+ // Hang onto the buffer handles for now -- the client will return it explicitly later
+ mHeldBuffers.push(buffers);
+ break;
}
- mLock.lock();
- ++mFramesReceived;
- mLock.unlock();
- mFrameSignal.notify_all();
-
ALOGD("Frame handling complete");
return Void();
}
-Return<void> FrameHandler::notify(const EvsEvent& event) {
+Return<void> FrameHandler::notify(const EvsEventDesc& event) {
// Local flag we use to keep track of when the stream is stopping
- mLock.lock();
- mLatestEventDesc = event;
+ std::unique_lock<std::mutex> lock(mEventLock);
+ mLatestEventDesc.aType = event.aType;
+ mLatestEventDesc.payload[0] = event.payload[0];
+ mLatestEventDesc.payload[1] = event.payload[1];
if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) {
// Signal that the last frame has been received and the stream is stopped
mRunning = false;
@@ -222,8 +231,8 @@
} else {
ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
}
- mLock.unlock();
- mEventSignal.notify_all();
+ lock.unlock();
+ mEventSignal.notify_one();
return Void();
}
@@ -342,25 +351,34 @@
}
}
-bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent,
- EvsEvent &event) {
+bool FrameHandler::waitForEvent(const EvsEventDesc& aTargetEvent,
+ EvsEventDesc& aReceivedEvent,
+ bool ignorePayload) {
// Wait until we get an expected parameter change event.
- std::unique_lock<std::mutex> lock(mLock);
+ std::unique_lock<std::mutex> lock(mEventLock);
auto now = std::chrono::system_clock::now();
- bool result = mEventSignal.wait_until(lock, now + 5s,
- [this, aTargetEvent, &event](){
- bool flag = mLatestEventDesc.aType == aTargetEvent;
- if (flag) {
- event.aType = mLatestEventDesc.aType;
- event.payload[0] = mLatestEventDesc.payload[0];
- event.payload[1] = mLatestEventDesc.payload[1];
+ bool found = false;
+ while (!found) {
+ bool result = mEventSignal.wait_until(lock, now + 5s,
+ [this, aTargetEvent, ignorePayload, &aReceivedEvent, &found](){
+ found = (mLatestEventDesc.aType == aTargetEvent.aType) &&
+ (ignorePayload || (mLatestEventDesc.payload[0] == aTargetEvent.payload[0] &&
+ mLatestEventDesc.payload[1] == aTargetEvent.payload[1]));
+
+ aReceivedEvent.aType = mLatestEventDesc.aType;
+ aReceivedEvent.payload[0] = mLatestEventDesc.payload[0];
+ aReceivedEvent.payload[1] = mLatestEventDesc.payload[1];
+ return found;
}
+ );
- return flag;
+ if (!result) {
+ ALOGW("A timer is expired before a target event has happened.");
+ break;
}
- );
+ }
- return !result;
+ return found;
}
const char *FrameHandler::eventToString(const EvsEventType aType) {
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h
index e5f1b8f..21e85fe 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.h
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.h
@@ -73,8 +73,9 @@
bool isRunning();
void waitForFrameCount(unsigned frameCount);
- bool waitForEvent(const EvsEventType aTargetEvent,
- EvsEvent &eventDesc);
+ bool waitForEvent(const EvsEventDesc& aTargetEvent,
+ EvsEventDesc& aReceivedEvent,
+ bool ignorePayload = false);
void getFramesCounters(unsigned* received, unsigned* displayed);
void getFrameDimension(unsigned* width, unsigned* height);
@@ -83,8 +84,8 @@
Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
// Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
- Return<void> deliverFrame_1_1(const BufferDesc_1_1& buffer) override;
- Return<void> notify(const EvsEvent& event) override;
+ Return<void> deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
+ Return<void> notify(const EvsEventDesc& event) override;
// Local implementation details
bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer);
@@ -99,17 +100,18 @@
// 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 mEventSignal;
- std::condition_variable mFrameSignal;
+ std::mutex mLock;
+ std::mutex mEventLock;
+ std::condition_variable mEventSignal;
+ std::condition_variable mFrameSignal;
+ std::queue<hidl_vec<BufferDesc_1_1>> mHeldBuffers;
- 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;
- EvsEvent mLatestEventDesc;
+ EvsEventDesc mLatestEventDesc;
};
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 1d3fd87..4fc4e4c 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -41,6 +41,8 @@
#include <cstdio>
#include <cstring>
#include <cstdlib>
+#include <thread>
+#include <unordered_set>
#include <hidl/HidlTransportSupport.h>
#include <hwbinder/ProcessState.h>
@@ -67,6 +69,7 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::sp;
+using ::android::wp;
using ::android::hardware::camera::device::V3_2::Stream;
using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
using ::android::hardware::automotive::evs::V1_0::DisplayState;
@@ -117,7 +120,15 @@
mIsHwModule = !service_name.compare(kEnumeratorName);
}
- virtual void TearDown() override {}
+ virtual void TearDown() override {
+ // Attempt to close any active camera
+ for (auto &&c : activeCameras) {
+ sp<IEvsCamera_1_1> cam = c.promote();
+ if (cam != nullptr) {
+ pEnumerator->closeCamera(cam);
+ }
+ }
+ }
protected:
void loadCameraList() {
@@ -141,10 +152,90 @@
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.
+ bool isLogicalCamera(const camera_metadata_t *metadata) {
+ if (metadata == nullptr) {
+ // A logical camera device must have a valid camera metadata.
+ return false;
+ }
+
+ // Looking for LOGICAL_MULTI_CAMERA capability from metadata.
+ camera_metadata_ro_entry_t entry;
+ int rc = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+ &entry);
+ if (0 != rc) {
+ // No capabilities are found.
+ return false;
+ }
+
+ for (size_t i = 0; i < entry.count; ++i) {
+ uint8_t cap = entry.data.u8[i];
+ if (cap == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ std::unordered_set<std::string> getPhysicalCameraIds(const std::string& id,
+ bool& flag) {
+ std::unordered_set<std::string> physicalCameras;
+
+ auto it = cameraInfo.begin();
+ while (it != cameraInfo.end()) {
+ if (it->v1.cameraId == id) {
+ break;
+ }
+ ++it;
+ }
+
+ if (it == cameraInfo.end()) {
+ // Unknown camera is requested. Return an empty list.
+ return physicalCameras;
+ }
+
+ const camera_metadata_t *metadata =
+ reinterpret_cast<camera_metadata_t *>(&it->metadata[0]);
+ flag = isLogicalCamera(metadata);
+ if (!flag) {
+ // EVS assumes that the device w/o a valid metadata is a physical
+ // device.
+ ALOGI("%s is not a logical camera device.", id.c_str());
+ physicalCameras.emplace(id);
+ return physicalCameras;
+ }
+
+ // Look for physical camera identifiers
+ camera_metadata_ro_entry entry;
+ int rc = find_camera_metadata_ro_entry(metadata,
+ ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
+ &entry);
+ ALOGE_IF(rc, "No physical camera ID is found for a logical camera device");
+
+ const uint8_t *ids = entry.data.u8;
+ size_t start = 0;
+ for (size_t i = 0; i < entry.count; ++i) {
+ if (ids[i] == '\0') {
+ if (start != i) {
+ std::string id(reinterpret_cast<const char *>(ids + start));
+ physicalCameras.emplace(id);
+ }
+ start = i + 1;
+ }
+ }
+
+ ALOGI("%s consists of %d physical camera devices.", id.c_str(), (int)physicalCameras.size());
+ return physicalCameras;
+ }
+
+
+ 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.
+ std::deque<wp<IEvsCamera_1_1>> activeCameras; // A list of active camera handles that are
+ // needed to be cleaned up.
};
@@ -168,12 +259,32 @@
// Open and close each camera twice
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+ continue;
+ }
+
for (int pass = 0; pass < 2; pass++) {
+ activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ for (auto&& devName : devices) {
+ bool matched = false;
+ pCam->getPhysicalCameraInfo(devName,
+ [&devName, &matched](const CameraDesc& info) {
+ matched = devName == info.v1.cameraId;
+ });
+ ASSERT_TRUE(matched);
+ }
+
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam);
+
// Verify that this camera self-identifies correctly
pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
ALOGD("Found camera %s", desc.v1.cameraId.c_str());
@@ -206,11 +317,22 @@
// Open and close each camera twice
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+ continue;
+ }
+
+ activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam);
+
// Verify that this camera self-identifies correctly
pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
ALOGD("Found camera %s", desc.v1.cameraId.c_str());
@@ -221,9 +343,13 @@
sp<IEvsCamera_1_1> pCam2 =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
- ASSERT_NE(pCam, pCam2);
ASSERT_NE(pCam2, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam2);
+
+ ASSERT_NE(pCam, pCam2);
+
Return<EvsResult> result = pCam->setMaxFramesInFlight(2);
if (mIsHwModule) {
// Verify that the old camera rejects calls via HW module.
@@ -268,11 +394,22 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+ continue;
+ }
+
+ activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam);
+
// Set up a frame receiver object which will fire up its own thread
sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
nullptr,
@@ -280,6 +417,7 @@
// Start the camera's video stream
nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC);
+
bool startResult = frameHandler->startStream();
ASSERT_TRUE(startResult);
@@ -287,9 +425,17 @@
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);
+
+ // Extra delays are expected when we attempt to start a video stream on
+ // the logical camera device. The amount of delay is expected the
+ // number of physical camera devices multiplied by
+ // kMaxStreamStartMilliseconds at most.
+ EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame),
+ kMaxStreamStartMilliseconds * devices.size());
+ printf("%s: Measured time to first frame %0.2f ms\n",
+ cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds);
+ ALOGI("%s: Measured time to first frame %0.2f ms",
+ cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds);
// Check aspect ratio
unsigned width = 0, height = 0;
@@ -299,6 +445,13 @@
// Wait a bit, then ensure we get at least the required minimum number of frames
sleep(5);
nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // 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();
+
unsigned framesReceived = 0;
frameHandler->getFramesCounters(&framesReceived, nullptr);
framesReceived = framesReceived - 1; // Back out the first frame we already waited for
@@ -308,12 +461,6 @@
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);
}
@@ -340,12 +487,22 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+ continue;
+ }
+ activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam);
+
// 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);
@@ -366,7 +523,7 @@
// 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
+ sleep(1); // 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";
@@ -416,11 +573,22 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (mIsHwModule && isLogicalCam) {
+ ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+ continue;
+ }
+
+ activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam);
+
// Set up a frame receiver object which will fire up its own thread.
sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
pDisplay,
@@ -484,17 +652,24 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ activeCameras.clear();
// Create two camera clients.
sp<IEvsCamera_1_1> pCam0 =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam0, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam0);
+
sp<IEvsCamera_1_1> pCam1 =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam1, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam1);
+
// Set up per-client frame receiver objects which will fire up its own thread
sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
nullptr,
@@ -554,6 +729,11 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCam0);
pEnumerator->closeCamera(pCam1);
+
+ // TODO(b/145459970, b/145457727): below sleep() is added to ensure the
+ // destruction of active camera objects; this may be related with two
+ // issues.
+ sleep(1);
}
}
@@ -575,12 +755,25 @@
// Test each reported camera
Return<EvsResult> result = EvsResult::OK;
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (isLogicalCam) {
+ // TODO(b/145465724): Support camera parameter programming on
+ // logical devices.
+ ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+ continue;
+ }
+
+ activeCameras.clear();
// Create a camera client
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Store a camera
+ activeCameras.push_back(pCam);
+
// Get the parameter list
std::vector<CameraParam> cmds;
pCam->getParameterList([&cmds](hidl_vec<CameraParam> cmdList) {
@@ -626,48 +819,54 @@
EvsResult result = EvsResult::OK;
if (cmd == CameraParam::ABSOLUTE_FOCUS) {
// Try to turn off auto-focus
- int32_t val1 = 0;
- pCam->getIntParameter(CameraParam::AUTO_FOCUS,
- [&result, &val1](auto status, auto value) {
+ std::vector<int32_t> values;
+ pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
- val1 = value;
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
}
});
- if (val1 != 0) {
- pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val1, 0);
+ ASSERT_EQ(EvsResult::OK, result);
+ for (auto &&v : values) {
+ ASSERT_EQ(v, 0);
}
}
// Try to program a parameter with a random value [minVal, maxVal]
int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
- int32_t val1 = 0;
+ std::vector<int32_t> values;
// Rounding down
val0 = val0 - (val0 % step);
pCam->setIntParameter(cmd, val0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::OK, result);
+ values.clear();
pCam->getIntParameter(cmd,
- [&result, &val1](auto status, auto value) {
+ [&result, &values](auto status, auto readValues) {
result = status;
if (status == EvsResult::OK) {
- val1 = value;
+ for (auto &&v : readValues) {
+ values.push_back(v);
+ }
}
});
ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val0, val1) << "Values are not matched.";
+ for (auto &&v : values) {
+ ASSERT_EQ(val0, v) << "Values are not matched.";
+ }
}
result = pCam->unsetMaster();
@@ -704,16 +903,33 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (isLogicalCam) {
+ // TODO(b/145465724): Support camera parameter programming on
+ // logical devices.
+ ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+ continue;
+ }
+
+ activeCameras.clear();
// Create two camera clients.
sp<IEvsCamera_1_1> pCamMaster =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamMaster, nullptr);
+
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCamMaster);
+
sp<IEvsCamera_1_1> pCamNonMaster =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamNonMaster, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCamNonMaster);
+
// Set up per-client frame receiver objects which will fire up its own thread
sp<FrameHandler> frameHandlerMaster =
new FrameHandler(pCamMaster, cam,
@@ -750,13 +966,45 @@
// Non-master client expects to receive a master role relesed
// notification.
- EvsEvent aNotification = {};
+ EvsEventDesc aTargetEvent = {};
+ EvsEventDesc aNotification = {};
+
+ bool listening = false;
+ std::mutex eventLock;
+ std::condition_variable eventCond;
+ std::thread listener = std::thread(
+ [&aNotification, &frameHandlerNonMaster, &listening, &eventCond]() {
+ // Notify that a listening thread is running.
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+ if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+
+ }
+ );
+
+ // Wait until a listening thread starts.
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening) {
+ timer += 1s;
+ eventCond.wait_until(lock, timer);
+ }
+ lock.unlock();
// Release a master role.
pCamMaster->unsetMaster();
- // Verify a change notification.
- frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+ // Join a listening thread.
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Verify change notifications.
ASSERT_EQ(EvsEventType::MASTER_RELEASED,
static_cast<EvsEventType>(aNotification.aType));
@@ -768,23 +1016,49 @@
result = pCamMaster->setMaster();
ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+ listening = false;
+ listener = std::thread(
+ [&aNotification, &frameHandlerMaster, &listening, &eventCond]() {
+ // Notify that a listening thread is running.
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+ if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+
+ }
+ );
+
+ // Wait until a listening thread starts.
+ timer = std::chrono::system_clock::now();
+ lock.lock();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
// Closing current master client.
frameHandlerNonMaster->shutdown();
- // Verify a change notification.
- frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+ // Join a listening thread.
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Verify change notifications.
ASSERT_EQ(EvsEventType::MASTER_RELEASED,
static_cast<EvsEventType>(aNotification.aType));
- // Closing another stream.
+ // Closing streams.
frameHandlerMaster->shutdown();
// Explicitly release the camera
pEnumerator->closeCamera(pCamMaster);
pEnumerator->closeCamera(pCamNonMaster);
}
-
-
}
@@ -810,16 +1084,33 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (isLogicalCam) {
+ // TODO(b/145465724): Support camera parameter programming on
+ // logical devices.
+ ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+ continue;
+ }
+
+ activeCameras.clear();
// Create two camera clients.
sp<IEvsCamera_1_1> pCamMaster =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamMaster, nullptr);
+
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCamMaster);
+
sp<IEvsCamera_1_1> pCamNonMaster =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCamNonMaster, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCamNonMaster);
+
// Get the parameter list
std::vector<CameraParam> camMasterCmds, camNonMasterCmds;
pCamMaster->getParameterList([&camMasterCmds](hidl_vec<CameraParam> cmdList) {
@@ -879,7 +1170,9 @@
frameHandlerNonMaster->waitForFrameCount(1);
int32_t val0 = 0;
- int32_t val1 = 0;
+ std::vector<int32_t> values;
+ EvsEventDesc aNotification0 = {};
+ EvsEventDesc aNotification1 = {};
for (auto &cmd : camMasterCmds) {
// Get a valid parameter value range
int32_t minVal, maxVal, step;
@@ -895,60 +1188,143 @@
EvsResult result = EvsResult::OK;
if (cmd == CameraParam::ABSOLUTE_FOCUS) {
// Try to turn off auto-focus
- int32_t val1 = 1;
+ values.clear();
pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val1, 0);
+ for (auto &&v : values) {
+ ASSERT_EQ(v, 0);
+ }
}
- // Try to program a parameter
+ // Calculate a parameter value to program.
val0 = minVal + (std::rand() % (maxVal - minVal));
-
- // Rounding down
val0 = val0 - (val0 % step);
+
+ // Prepare and start event listeners.
+ bool listening0 = false;
+ bool listening1 = false;
+ std::condition_variable eventCond;
+ std::thread listener0 = std::thread(
+ [cmd, val0,
+ &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+ listening0 = true;
+ if (listening1) {
+ eventCond.notify_all();
+ }
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+ std::thread listener1 = std::thread(
+ [cmd, val0,
+ &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+ listening1 = true;
+ if (listening0) {
+ eventCond.notify_all();
+ }
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a listening thread starts.
+ std::mutex eventLock;
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening0 || !listening1) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ // Try to program a parameter
+ values.clear();
pCamMaster->setIntParameter(cmd, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_EQ(EvsResult::OK, result);
-
- // Wait a moment
- sleep(1);
-
- // Non-master client expects to receive a parameter change notification
- // whenever a master client adjusts it.
- EvsEvent aNotification = {};
-
- pCamMaster->getIntParameter(cmd,
- [&result, &val1](auto status, auto value) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
- val1 = value;
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
+ });
+
+ ASSERT_EQ(EvsResult::OK, result);
+ for (auto &&v : values) {
+ ASSERT_EQ(val0, v) << "Values are not matched.";
+ }
+
+ // Join a listening thread.
+ if (listener0.joinable()) {
+ listener0.join();
+ }
+ if (listener1.joinable()) {
+ listener1.join();
+ }
+
+ // Verify a change notification
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification0.aType));
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification1.aType));
+ ASSERT_EQ(cmd,
+ static_cast<CameraParam>(aNotification0.payload[0]));
+ ASSERT_EQ(cmd,
+ static_cast<CameraParam>(aNotification1.payload[0]));
+ for (auto &&v : values) {
+ ASSERT_EQ(v,
+ static_cast<int32_t>(aNotification0.payload[1]));
+ ASSERT_EQ(v,
+ static_cast<int32_t>(aNotification1.payload[1]));
+ }
+
+ // Clients expects to receive a parameter change notification
+ // whenever a master client adjusts it.
+ values.clear();
+ pCamMaster->getIntParameter(cmd,
+ [&result, &values](auto status, auto readValues) {
+ result = status;
+ if (status == EvsResult::OK) {
+ for (auto &&v : readValues) {
+ values.push_back(v);
+ }
}
});
ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val0, val1) << "Values are not matched.";
-
- // Verify a change notification
- frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
- static_cast<EvsEventType>(aNotification.aType));
- ASSERT_EQ(cmd,
- static_cast<CameraParam>(aNotification.payload[0]));
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
+ for (auto &&v : values) {
+ ASSERT_EQ(val0, v) << "Values are not matched.";
+ }
}
// Try to adjust a parameter via non-master client
+ values.clear();
pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::INVALID_ARG, result);
@@ -957,14 +1333,48 @@
ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
// Master client retires from a master role
+ bool listening = false;
+ std::condition_variable eventCond;
+ std::thread listener = std::thread(
+ [&aNotification0, &frameHandlerNonMaster, &listening, &eventCond]() {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+ if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification0, true)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ std::mutex eventLock;
+ auto timer = std::chrono::system_clock::now();
+ unique_lock<std::mutex> lock(eventLock);
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
result = pCamMaster->unsetMaster();
ASSERT_EQ(EvsResult::OK, result);
+ if (listener.joinable()) {
+ listener.join();
+ }
+ ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+ static_cast<EvsEventType>(aNotification0.aType));
+
// Try to adjust a parameter after being retired
+ values.clear();
pCamMaster->setIntParameter(camMasterCmds[0], val0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::INVALID_ARG, result);
@@ -986,55 +1396,128 @@
);
EvsResult result = EvsResult::OK;
+ values.clear();
if (cmd == CameraParam::ABSOLUTE_FOCUS) {
// Try to turn off auto-focus
- int32_t val1 = 1;
+ values.clear();
pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val1, 0);
+ for (auto &&v : values) {
+ ASSERT_EQ(v, 0);
+ }
}
- // Try to program a parameter
+ // Calculate a parameter value to program. This is being rounding down.
val0 = minVal + (std::rand() % (maxVal - minVal));
-
- // Rounding down
val0 = val0 - (val0 % step);
+
+ // Prepare and start event listeners.
+ bool listening0 = false;
+ bool listening1 = false;
+ std::condition_variable eventCond;
+ std::thread listener0 = std::thread(
+ [&cmd, &val0, &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+ listening0 = true;
+ if (listening1) {
+ eventCond.notify_all();
+ }
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+ std::thread listener1 = std::thread(
+ [&cmd, &val0, &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+ listening1 = true;
+ if (listening0) {
+ eventCond.notify_all();
+ }
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a listening thread starts.
+ std::mutex eventLock;
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening0 || !listening1) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ // Try to program a parameter
+ values.clear();
pCamNonMaster->setIntParameter(cmd, val0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_EQ(EvsResult::OK, result);
-
- // Wait a moment
- sleep(1);
-
- // Non-master client expects to receive a parameter change notification
- // whenever a master client adjusts it.
- EvsEvent aNotification = {};
-
- pCamNonMaster->getIntParameter(cmd,
- [&result, &val1](auto status, auto value) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
- val1 = value;
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
}
});
ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val0, val1) << "Values are not matched.";
+
+ // Clients expects to receive a parameter change notification
+ // whenever a master client adjusts it.
+ values.clear();
+ pCamNonMaster->getIntParameter(cmd,
+ [&result, &values](auto status, auto readValues) {
+ result = status;
+ if (status == EvsResult::OK) {
+ for (auto &&v : readValues) {
+ values.push_back(v);
+ }
+ }
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ for (auto &&v : values) {
+ ASSERT_EQ(val0, v) << "Values are not matched.";
+ }
+
+ // Join a listening thread.
+ if (listener0.joinable()) {
+ listener0.join();
+ }
+ if (listener1.joinable()) {
+ listener1.join();
+ }
// Verify a change notification
- frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
- static_cast<EvsEventType>(aNotification.aType));
+ static_cast<EvsEventType>(aNotification0.aType));
+ ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+ static_cast<EvsEventType>(aNotification1.aType));
ASSERT_EQ(cmd,
- static_cast<CameraParam>(aNotification.payload[0]));
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
+ static_cast<CameraParam>(aNotification0.payload[0]));
+ ASSERT_EQ(cmd,
+ static_cast<CameraParam>(aNotification1.payload[0]));
+ for (auto &&v : values) {
+ ASSERT_EQ(v,
+ static_cast<int32_t>(aNotification0.payload[1]));
+ ASSERT_EQ(v,
+ static_cast<int32_t>(aNotification1.payload[1]));
+ }
}
// New master retires from a master role
@@ -1078,17 +1561,25 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ activeCameras.clear();
+
// Create two clients
sp<IEvsCamera_1_1> pCam0 =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam0, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam0);
+
sp<IEvsCamera_1_1> pCam1 =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
ASSERT_NE(pCam1, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam1);
+
// Get the parameter list; this test will use the first command in both
// lists.
std::vector<CameraParam> cam0Cmds, cam1Cmds;
@@ -1144,108 +1635,260 @@
}
);
- if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
- // Try to turn off auto-focus
- int32_t val1 = 0;
- pCam1->getIntParameter(CameraParam::AUTO_FOCUS,
- [&result, &val1](auto status, auto value) {
- result = status;
- if (status == EvsResult::OK) {
- val1 = value;
- }
- });
- if (val1 != 0) {
- pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val1, 0);
- }
- }
-
- // Try to program a parameter with a random value [minVal, maxVal]
- int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
- int32_t val1 = 0;
-
- // Rounding down
- val0 = val0 - (val0 % step);
-
+ // Client1 becomes a master
result = pCam1->setMaster();
ASSERT_EQ(EvsResult::OK, result);
+ std::vector<int32_t> values;
+ EvsEventDesc aTargetEvent = {};
+ EvsEventDesc aNotification = {};
+ bool listening = false;
+ std::mutex eventLock;
+ std::condition_variable eventCond;
+ if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+ std::thread listener = std::thread(
+ [&frameHandler0, &aNotification, &listening, &eventCond] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
+ aTargetEvent.payload[1] = 0;
+ if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a lister starts.
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ // Try to turn off auto-focus
+ pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &values](auto status, auto effectiveValues) {
+ result = status;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+ for (auto &&v : values) {
+ ASSERT_EQ(v, 0);
+ }
+
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Make sure AUTO_FOCUS is off.
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::PARAMETER_CHANGED);
+ }
+
+ // Try to program a parameter with a random value [minVal, maxVal] after
+ // rounding it down.
+ int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
+ val0 = val0 - (val0 % step);
+
+ std::thread listener = std::thread(
+ [&frameHandler1, &aNotification, &listening, &eventCond, &cam1Cmds, val0] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cam1Cmds[0]);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a lister starts.
+ listening = false;
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ values.clear();
pCam1->setIntParameter(cam1Cmds[0], val0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::OK, result);
+ for (auto &&v : values) {
+ ASSERT_EQ(val0, v);
+ }
+
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
// Verify a change notification
- EvsEvent aNotification = {};
- bool timeout =
- frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_FALSE(timeout) << "Expected event does not arrive";
ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
EvsEventType::PARAMETER_CHANGED);
ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
cam1Cmds[0]);
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
+ for (auto &&v : values) {
+ ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+ }
+
+ listener = std::thread(
+ [&frameHandler1, &aNotification, &listening, &eventCond] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+ if (!frameHandler1->waitForEvent(aTargetEvent, aNotification, true)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a lister starts.
+ listening = false;
+ lock.lock();
+ timer = std::chrono::system_clock::now();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
// Client 0 steals a master role
ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
- frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
+
ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
EvsEventType::MASTER_RELEASED);
// Client 0 programs a parameter
val0 = minVal + (std::rand() % (maxVal - minVal));
- val1 = 0;
// Rounding down
val0 = val0 - (val0 % step);
if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+ std::thread listener = std::thread(
+ [&frameHandler1, &aNotification, &listening, &eventCond] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
+ aTargetEvent.payload[1] = 0;
+ if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a lister starts.
+ std::unique_lock<std::mutex> lock(eventLock);
+ auto timer = std::chrono::system_clock::now();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
// Try to turn off auto-focus
- int32_t val1 = 0;
- pCam0->getIntParameter(CameraParam::AUTO_FOCUS,
- [&result, &val1](auto status, auto value) {
+ values.clear();
+ pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
if (status == EvsResult::OK) {
- val1 = value;
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
}
});
- if (val1 != 0) {
- pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0,
- [&result, &val1](auto status, auto effectiveValue) {
- result = status;
- val1 = effectiveValue;
- });
- ASSERT_EQ(EvsResult::OK, result);
- ASSERT_EQ(val1, 0);
+ ASSERT_EQ(EvsResult::OK, result);
+ for (auto &&v : values) {
+ ASSERT_EQ(v, 0);
}
+
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Make sure AUTO_FOCUS is off.
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::PARAMETER_CHANGED);
}
+ listener = std::thread(
+ [&frameHandler0, &aNotification, &listening, &eventCond, &cam0Cmds, val0] {
+ listening = true;
+ eventCond.notify_all();
+
+ EvsEventDesc aTargetEvent;
+ aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+ aTargetEvent.payload[0] = static_cast<uint32_t>(cam0Cmds[0]);
+ aTargetEvent.payload[1] = val0;
+ if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
+ ALOGW("A timer is expired before a target event is fired.");
+ }
+ }
+ );
+
+ // Wait until a lister starts.
+ listening = false;
+ timer = std::chrono::system_clock::now();
+ lock.lock();
+ while (!listening) {
+ eventCond.wait_until(lock, timer + 1s);
+ }
+ lock.unlock();
+
+ values.clear();
pCam0->setIntParameter(cam0Cmds[0], val0,
- [&result, &val1](auto status, auto effectiveValue) {
+ [&result, &values](auto status, auto effectiveValues) {
result = status;
- val1 = effectiveValue;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
});
ASSERT_EQ(EvsResult::OK, result);
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
// Verify a change notification
- timeout =
- frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
- ASSERT_FALSE(timeout) << "Expected event does not arrive";
ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
EvsEventType::PARAMETER_CHANGED);
ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
cam0Cmds[0]);
- ASSERT_EQ(val1,
- static_cast<int32_t>(aNotification.payload[1]));
+ for (auto &&v : values) {
+ ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+ }
// Turn off the display (yes, before the stream stops -- it should be handled)
pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
@@ -1282,6 +1925,7 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ activeCameras.clear();
// choose a configuration that has a frame rate faster than minReqFps.
Stream targetCfg = {};
const int32_t minReqFps = 15;
@@ -1324,6 +1968,9 @@
.withDefault(nullptr);
ASSERT_NE(pCam, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam);
+
// Set up a frame receiver object which will fire up its own thread.
sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
pDisplay,
@@ -1383,6 +2030,7 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ activeCameras.clear();
// choose a configuration that has a frame rate faster than minReqFps.
Stream targetCfg = {};
const int32_t minReqFps = 15;
@@ -1427,6 +2075,9 @@
.withDefault(nullptr);
ASSERT_NE(pCam0, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam0);
+
// Try to create the second camera client with different stream
// configuration.
int32_t id = targetCfg.id;
@@ -1436,6 +2087,9 @@
.withDefault(nullptr);
ASSERT_EQ(pCam1, nullptr);
+ // Store a camera handle for a clean-up
+ activeCameras.push_back(pCam0);
+
// Try again with same stream configuration.
targetCfg.id = id;
pCam1 =
@@ -1506,6 +2160,30 @@
}
+/*
+ * LogicalCameraMetadata:
+ * Opens logical camera reported by the enumerator and validate its metadata by
+ * checking its capability and locating supporting physical camera device
+ * identifiers.
+ */
+TEST_F(EvsHidlTest, LogicalCameraMetadata) {
+ ALOGI("Starting LogicalCameraMetadata test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Open and close each camera twice
+ for (auto&& cam: cameraInfo) {
+ bool isLogicalCam = false;
+ auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+ if (isLogicalCam) {
+ ASSERT_GE(devices.size(), 1) <<
+ "Logical camera device must have at least one physical camera device ID in its metadata.";
+ }
+ }
+}
+
+
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
diff --git a/automotive/evs/common/utils/default/Android.bp b/automotive/evs/common/utils/default/Android.bp
index 7734f5c..776ef81 100644
--- a/automotive/evs/common/utils/default/Android.bp
+++ b/automotive/evs/common/utils/default/Android.bp
@@ -15,6 +15,7 @@
//
cc_library_static {
+ host_supported: true,
name: "android.hardware.automotive.evs@common-default-lib",
vendor_available: true,
relative_install_path: "hw",
diff --git a/automotive/evs/common/utils/default/test/fuzz/Android.bp b/automotive/evs/common/utils/default/test/fuzz/Android.bp
new file mode 100644
index 0000000..105ec68
--- /dev/null
+++ b/automotive/evs/common/utils/default/test/fuzz/Android.bp
@@ -0,0 +1,99 @@
+//
+// 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_fuzz {
+ host_supported: true,
+ name : "FormatConvertFuzzer_copyNV21toRGB32",
+ srcs: [
+ "FormatConvertFuzzer.cpp",
+ ],
+ static_libs: [
+ "android.hardware.automotive.evs@common-default-lib"
+ ],
+ cflags: [
+ "-DCOPY_NV21_TO_RGB32",
+ ],
+}
+
+cc_fuzz {
+ host_supported: true,
+ name : "FormatConvertFuzzer_copyNV21toBGR32",
+ srcs: [
+ "FormatConvertFuzzer.cpp",
+ ],
+ static_libs: [
+ "android.hardware.automotive.evs@common-default-lib"
+ ],
+ cflags: [
+ "-DCOPY_NV21_TO_BGR32",
+ ],
+}
+
+cc_fuzz {
+ host_supported: true,
+ name : "FormatConvertFuzzer_copyYV12toRGB32",
+ srcs: [
+ "FormatConvertFuzzer.cpp",
+ ],
+ static_libs: [
+ "android.hardware.automotive.evs@common-default-lib"
+ ],
+ cflags: [
+ "-DCOPY_YV12_TO_RGB32",
+ ],
+}
+
+cc_fuzz {
+ host_supported: true,
+ name : "FormatConvertFuzzer_copyYV12toBGR32",
+ srcs: [
+ "FormatConvertFuzzer.cpp",
+ ],
+ static_libs: [
+ "android.hardware.automotive.evs@common-default-lib"
+ ],
+ cflags: [
+ "-DCOPY_YV12_TO_BGR32",
+ ],
+}
+
+cc_fuzz {
+ host_supported: true,
+ name : "FormatConvertFuzzer_copyYUYVtoRGB32",
+ srcs: [
+ "FormatConvertFuzzer.cpp",
+ ],
+ static_libs: [
+ "android.hardware.automotive.evs@common-default-lib"
+ ],
+ cflags: [
+ "-DCOPY_YUYV_TO_RGB32",
+ ],
+}
+
+cc_fuzz {
+ host_supported: true,
+ name : "FormatConvertFuzzer_copyYUYVtoBGR32",
+ srcs: [
+ "FormatConvertFuzzer.cpp",
+ ],
+ static_libs: [
+ "android.hardware.automotive.evs@common-default-lib"
+ ],
+ cflags: [
+ "-DCOPY_YUYV_TO_BGR32",
+ ],
+}
diff --git a/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp b/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp
new file mode 100644
index 0000000..583a455
--- /dev/null
+++ b/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp
@@ -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.
+ */
+
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include "FormatConvert.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, std::size_t size) {
+ if (size < 256) {
+ return 0;
+ }
+
+ std::srand(std::time(nullptr)); // use current time as seed for random generator
+ int random_variable = std::rand() % 10;
+ int width = (int)sqrt(size);
+ int height = width * ((float)random_variable / 10.0);
+
+ uint8_t* src = (uint8_t*)malloc(sizeof(uint8_t) * size);
+ memcpy(src, data, sizeof(uint8_t) * (size));
+ uint32_t* tgt = (uint32_t*)malloc(sizeof(uint32_t) * size);
+
+#ifdef COPY_NV21_TO_RGB32
+ android::hardware::automotive::evs::common::Utils::copyNV21toRGB32(width, height, src, tgt, 0);
+#elif COPY_NV21_TO_BGR32
+ android::hardware::automotive::evs::common::Utils::copyNV21toBGR32(width, height, src, tgt, 0);
+#elif COPY_YV12_TO_RGB32
+ android::hardware::automotive::evs::common::Utils::copyYV12toRGB32(width, height, src, tgt, 0);
+#elif COPY_YV12_TO_BGR32
+ android::hardware::automotive::evs::common::Utils::copyYV12toBGR32(width, height, src, tgt, 0);
+#elif COPY_YUYV_TO_RGB32
+ android::hardware::automotive::evs::common::Utils::copyYUYVtoRGB32(width, height, src, 0, tgt,
+ 0);
+#elif COPY_YUYV_TO_BGR32
+ android::hardware::automotive::evs::common::Utils::copyYUYVtoBGR32(width, height, src, 0, tgt,
+ 0);
+#endif
+
+ free(src);
+ free(tgt);
+
+ return 0;
+}
diff --git a/automotive/occupant_awareness/aidl/Android.bp b/automotive/occupant_awareness/aidl/Android.bp
index 6e9e8aa..face235 100644
--- a/automotive/occupant_awareness/aidl/Android.bp
+++ b/automotive/occupant_awareness/aidl/Android.bp
@@ -7,7 +7,12 @@
stability: "vintf",
backend: {
java: {
- enabled: false,
+ platform_apis: true,
},
- }
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ },
}
diff --git a/automotive/occupant_awareness/aidl/mock/Android.bp b/automotive/occupant_awareness/aidl/mock/Android.bp
new file mode 100644
index 0000000..4b30866
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/mock/Android.bp
@@ -0,0 +1,32 @@
+/*
+ * 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_binary {
+ name: "android.hardware.automotive.occupant_awareness@1.0-service_mock",
+ relative_install_path: "hw",
+ vendor: true,
+ srcs: [
+ "service.cpp",
+ "OccupantAwareness.cpp",
+ "DetectionGenerator.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libutils",
+ "android.hardware.automotive.occupant_awareness-ndk_platform",
+ ],
+}
diff --git a/automotive/occupant_awareness/aidl/mock/DetectionGenerator.cpp b/automotive/occupant_awareness/aidl/mock/DetectionGenerator.cpp
new file mode 100644
index 0000000..79d4dbc
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/mock/DetectionGenerator.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/SystemClock.h>
+
+#include "DetectionGenerator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace occupant_awareness {
+namespace V1_0 {
+namespace implementation {
+
+using ::aidl::android::hardware::automotive::occupant_awareness::ConfidenceLevel;
+using ::aidl::android::hardware::automotive::occupant_awareness::DriverMonitoringDetection;
+using ::aidl::android::hardware::automotive::occupant_awareness::OccupantDetection;
+using ::aidl::android::hardware::automotive::occupant_awareness::PresenceDetection;
+
+static int64_t kNanoSecondsPerMilliSecond = 1000 * 1000;
+
+OccupantDetections DetectionGenerator::GetNextDetections() {
+ OccupantDetections detections;
+ detections.timeStampMillis = android::elapsedRealtimeNano() / kNanoSecondsPerMilliSecond;
+ int remainingRoles = getSupportedRoles();
+ while (remainingRoles) {
+ int currentRole = remainingRoles & (~(remainingRoles - 1));
+ remainingRoles = remainingRoles & (remainingRoles - 1);
+
+ OccupantDetection occupantDetection;
+ occupantDetection.role = static_cast<Role>(currentRole);
+
+ // Add presence detection object for this occupant.
+ PresenceDetection presenceDetection;
+ presenceDetection.isOccupantDetected = true;
+ presenceDetection.detectionDurationMillis = detections.timeStampMillis;
+ occupantDetection.presenceData.emplace_back(presenceDetection);
+
+ if (occupantDetection.role == Role::DRIVER) {
+ // Add driver monitoring detection object for this occupant.
+ DriverMonitoringDetection driverMonitoringDetection;
+ driverMonitoringDetection.confidenceScore = ConfidenceLevel::HIGH;
+ driverMonitoringDetection.isLookingOnRoad = 0;
+ driverMonitoringDetection.gazeDurationMillis = detections.timeStampMillis;
+ occupantDetection.attentionData.emplace_back(driverMonitoringDetection);
+ }
+
+ detections.detections.emplace_back(occupantDetection);
+ }
+ return detections;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace occupant_awareness
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/occupant_awareness/aidl/mock/DetectionGenerator.h b/automotive/occupant_awareness/aidl/mock/DetectionGenerator.h
new file mode 100644
index 0000000..0884685
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/mock/DetectionGenerator.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/automotive/occupant_awareness/BnOccupantAwareness.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace occupant_awareness {
+namespace V1_0 {
+namespace implementation {
+
+using ::aidl::android::hardware::automotive::occupant_awareness::BnOccupantAwareness;
+using ::aidl::android::hardware::automotive::occupant_awareness::OccupantDetections;
+using ::aidl::android::hardware::automotive::occupant_awareness::Role;
+
+class DetectionGenerator {
+ public:
+ static int getSupportedRoles() {
+ return static_cast<int>(Role::DRIVER) | static_cast<int>(Role::FRONT_PASSENGER);
+ }
+ static int getSupportedCapabilities() {
+ return static_cast<int>(BnOccupantAwareness::CAP_PRESENCE_DETECTION) |
+ static_cast<int>(BnOccupantAwareness::CAP_DRIVER_MONITORING_DETECTION);
+ }
+
+ OccupantDetections GetNextDetections();
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace occupant_awareness
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/occupant_awareness/aidl/mock/OccupantAwareness.cpp b/automotive/occupant_awareness/aidl/mock/OccupantAwareness.cpp
new file mode 100644
index 0000000..910760a
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/mock/OccupantAwareness.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/SystemClock.h>
+
+#include "OccupantAwareness.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace occupant_awareness {
+namespace V1_0 {
+namespace implementation {
+
+using ndk::ScopedAStatus;
+
+static const int32_t kAllCapabilities = OccupantAwareness::CAP_PRESENCE_DETECTION |
+ OccupantAwareness::CAP_GAZE_DETECTION |
+ OccupantAwareness::CAP_DRIVER_MONITORING_DETECTION;
+
+constexpr int64_t kNanoSecondsPerMilliSecond = 1000 * 1000;
+
+ScopedAStatus OccupantAwareness::startDetection(OccupantAwarenessStatus* status) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mStatus != OccupantAwarenessStatus::NOT_INITIALIZED) {
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
+
+ mStatus = OccupantAwarenessStatus::READY;
+ mWorkerThread = std::thread(startWorkerThread, this);
+ if (mCallback) {
+ mCallback->onSystemStatusChanged(kAllCapabilities, mStatus);
+ }
+
+ *status = mStatus;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::stopDetection(OccupantAwarenessStatus* status) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mStatus != OccupantAwarenessStatus::READY) {
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
+
+ mStatus = OccupantAwarenessStatus::NOT_INITIALIZED;
+ mWorkerThread.join();
+ if (mCallback) {
+ mCallback->onSystemStatusChanged(kAllCapabilities, mStatus);
+ }
+
+ *status = mStatus;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::getCapabilityForRole(Role occupantRole, int32_t* capabilities) {
+ if (!isValidRole(occupantRole)) {
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
+
+ int intVal = static_cast<int>(occupantRole);
+ if ((intVal & DetectionGenerator::getSupportedRoles()) == intVal) {
+ int capabilities_ = DetectionGenerator::getSupportedCapabilities();
+ if (occupantRole != Role::DRIVER) {
+ capabilities_ &= ~CAP_DRIVER_MONITORING_DETECTION;
+ }
+ *capabilities = capabilities_;
+ } else {
+ *capabilities = 0;
+ }
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::getState(Role occupantRole, int detectionCapability,
+ OccupantAwarenessStatus* status) {
+ if (!isValidRole(occupantRole)) {
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
+
+ if (!isValidDetectionCapabilities(detectionCapability) ||
+ !isSingularCapability(detectionCapability)) {
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
+
+ int roleVal = static_cast<int>(occupantRole);
+
+ if (((roleVal & DetectionGenerator::getSupportedRoles()) != roleVal) ||
+ ((detectionCapability & DetectionGenerator::getSupportedCapabilities()) !=
+ detectionCapability)) {
+ *status = OccupantAwarenessStatus::NOT_SUPPORTED;
+ return ScopedAStatus::ok();
+ }
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ *status = mStatus;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::setCallback(
+ const std::shared_ptr<IOccupantAwarenessClientCallback>& callback) {
+ if (callback == nullptr) {
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ mCallback = callback;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::getLatestDetection(OccupantDetections* detections) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (mStatus != OccupantAwarenessStatus::READY) {
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
+
+ *detections = mLatestDetections;
+ return ScopedAStatus::ok();
+}
+
+bool OccupantAwareness::isValidRole(Role occupantRole) {
+ int intVal = static_cast<int>(occupantRole);
+ int allOccupants = static_cast<int>(Role::ALL_OCCUPANTS);
+ return (occupantRole != Role::INVALID) && ((intVal & (~allOccupants)) == 0);
+}
+
+bool OccupantAwareness::isValidDetectionCapabilities(int detectionCapabilities) {
+ return (detectionCapabilities != OccupantAwareness::CAP_NONE) &&
+ ((detectionCapabilities & (~kAllCapabilities)) == 0);
+}
+
+bool OccupantAwareness::isSingularCapability(int detectionCapability) {
+ // Check whether the value is 0, or the value has only one bit set.
+ return (detectionCapability & (detectionCapability - 1)) == 0;
+}
+
+void OccupantAwareness::startWorkerThread(OccupantAwareness* occupantAwareness) {
+ occupantAwareness->workerThreadFunction();
+}
+
+void OccupantAwareness::workerThreadFunction() {
+ bool isFirstDetection = true;
+ int64_t prevDetectionTimeMs;
+ while (mStatus == OccupantAwarenessStatus::READY) {
+ int64_t currentTimeMs = android::elapsedRealtimeNano() / kNanoSecondsPerMilliSecond;
+ if ((isFirstDetection) || (currentTimeMs - prevDetectionTimeMs > mDetectionDurationMs)) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mLatestDetections = mGenerator.GetNextDetections();
+ if (mCallback != nullptr) {
+ mCallback->onDetectionEvent(mLatestDetections);
+ }
+ isFirstDetection = false;
+ prevDetectionTimeMs = currentTimeMs;
+ }
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace occupant_awareness
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/occupant_awareness/aidl/mock/OccupantAwareness.h b/automotive/occupant_awareness/aidl/mock/OccupantAwareness.h
new file mode 100644
index 0000000..c5f6dd6
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/mock/OccupantAwareness.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <thread>
+
+#include <aidl/android/hardware/automotive/occupant_awareness/BnOccupantAwareness.h>
+#include <aidl/android/hardware/automotive/occupant_awareness/BnOccupantAwarenessClientCallback.h>
+#include <utils/StrongPointer.h>
+
+#include "DetectionGenerator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace occupant_awareness {
+namespace V1_0 {
+namespace implementation {
+
+using ::aidl::android::hardware::automotive::occupant_awareness::BnOccupantAwareness;
+using ::aidl::android::hardware::automotive::occupant_awareness::IOccupantAwarenessClientCallback;
+using ::aidl::android::hardware::automotive::occupant_awareness::OccupantAwarenessStatus;
+using ::aidl::android::hardware::automotive::occupant_awareness::OccupantDetections;
+using ::aidl::android::hardware::automotive::occupant_awareness::Role;
+
+/**
+ * The mock HAL can detect presence of Driver and front passenger, and driver awareness detection
+ * for driver.
+ **/
+class OccupantAwareness : public BnOccupantAwareness {
+ public:
+ // Methods from ::android::hardware::automotive::occupant_awareness::IOccupantAwareness
+ // follow.
+ ndk::ScopedAStatus startDetection(OccupantAwarenessStatus* status) override;
+ ndk::ScopedAStatus stopDetection(OccupantAwarenessStatus* status) override;
+ ndk::ScopedAStatus getCapabilityForRole(Role occupantRole, int32_t* capabilities) override;
+ ndk::ScopedAStatus getState(Role occupantRole, int detectionCapability,
+ OccupantAwarenessStatus* status) override;
+ ndk::ScopedAStatus setCallback(
+ const std::shared_ptr<IOccupantAwarenessClientCallback>& callback) override;
+ ndk::ScopedAStatus getLatestDetection(OccupantDetections* detections) override;
+
+ private:
+ bool isValidRole(Role occupantRole);
+ bool isValidDetectionCapabilities(int detectionCapabilities);
+ bool isSingularCapability(int detectionCapability);
+
+ void workerThreadFunction();
+ static void startWorkerThread(OccupantAwareness* occupantAwareness);
+
+ std::mutex mMutex;
+ std::shared_ptr<IOccupantAwarenessClientCallback> mCallback = nullptr;
+ OccupantAwarenessStatus mStatus = OccupantAwarenessStatus::NOT_INITIALIZED;
+
+ OccupantDetections mLatestDetections;
+ std::thread mWorkerThread;
+
+ DetectionGenerator mGenerator;
+
+ // Generate a new detection every 1ms.
+ const int64_t mDetectionDurationMs = 1;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace occupant_awareness
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/occupant_awareness/aidl/mock/service.cpp b/automotive/occupant_awareness/aidl/mock/service.cpp
new file mode 100644
index 0000000..d8860df
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/mock/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.automotive.occupant_awareness@1.0-service_mock"
+
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "OccupantAwareness.h"
+
+using ::aidl::android::hardware::automotive::occupant_awareness::IOccupantAwareness;
+using ::android::hardware::automotive::occupant_awareness::V1_0::implementation::OccupantAwareness;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
+
+const static char kOccupantAwarenessServiceName[] = "default";
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ LOG(INFO) << "Occupant Awareness service is starting";
+ std::shared_ptr<OccupantAwareness> occupantAwareness = SharedRefBase::make<OccupantAwareness>();
+
+ const std::string instance =
+ std::string() + IOccupantAwareness::descriptor + "/" + kOccupantAwarenessServiceName;
+
+ binder_status_t status =
+ AServiceManager_addService(occupantAwareness->asBinder().get(), instance.c_str());
+ if (status == STATUS_OK) {
+ LOG(INFO) << "Service " << kOccupantAwarenessServiceName << " is ready";
+ ABinderProcess_joinThreadPool();
+ } else {
+ LOG(ERROR) << "Could not register service " << kOccupantAwarenessServiceName
+ << ", status: " << status;
+ }
+
+ // In normal operation, we don't expect the thread pool to exit.
+ LOG(ERROR) << "Occupant Awareness service is shutting down";
+ return 1;
+}
diff --git a/automotive/occupant_awareness/aidl/vts/functional/Android.bp b/automotive/occupant_awareness/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..1256b69
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/vts/functional/Android.bp
@@ -0,0 +1,17 @@
+cc_test {
+ name: "VtsHalOccupantAwarenessV1_0TargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalOccupantAwarenessV1_0TargetTest.cpp"],
+ shared_libs: [
+ "libbinder",
+ ],
+ static_libs: [
+ "android.hardware.automotive.occupant_awareness-cpp",
+ ],
+ test_suites: [
+ "vts-core",
+ ],
+}
diff --git a/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp b/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp
new file mode 100644
index 0000000..c431f9d
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp
@@ -0,0 +1,203 @@
+/*
+ * 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 "**** HAL log ****"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android/hardware/automotive/occupant_awareness/BnOccupantAwarenessClientCallback.h>
+#include <android/hardware/automotive/occupant_awareness/IOccupantAwareness.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <future>
+#include <vector>
+
+using namespace android::hardware::automotive::occupant_awareness;
+using android::hardware::automotive::occupant_awareness::IOccupantAwareness;
+
+using android::ProcessState;
+using android::sp;
+using android::String16;
+using android::binder::Status;
+
+constexpr auto kTimeout = std::chrono::seconds(3);
+
+#define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk())
+
+class OccupantAwarenessCallback : public BnOccupantAwarenessClientCallback {
+ public:
+ OccupantAwarenessCallback(const std::function<void(int, OccupantAwarenessStatus)>& callback)
+ : mCallback(callback) {}
+ Status onSystemStatusChanged(int detectionFlags, OccupantAwarenessStatus status) override {
+ mCallback(detectionFlags, status);
+ return Status::ok();
+ }
+
+ Status onDetectionEvent(const OccupantDetections& detections) override {
+ (void)detections;
+ return Status::ok();
+ }
+
+ private:
+ std::function<void(int, OccupantAwarenessStatus)> mCallback;
+};
+
+class OccupantAwarenessAidl : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ mOccupantAwarenessService =
+ android::waitForDeclaredService<IOccupantAwareness>(String16(GetParam().c_str()));
+ ASSERT_NE(mOccupantAwarenessService, nullptr);
+ }
+
+ sp<IOccupantAwareness> mOccupantAwarenessService;
+};
+
+// Test that startDetection() returns within the timeout.
+TEST_P(OccupantAwarenessAidl, StartDetectionTest) {
+ auto start = std::chrono::system_clock::now();
+ OccupantAwarenessStatus occupantAwarenessStatus;
+ Status status = mOccupantAwarenessService->startDetection(&occupantAwarenessStatus);
+ auto elapsed = std::chrono::system_clock::now() - start;
+ EXPECT_OK(status);
+ ASSERT_LE(elapsed, kTimeout);
+
+ EXPECT_OK(mOccupantAwarenessService->stopDetection(&occupantAwarenessStatus));
+}
+
+// Test that getCapabilityForRole() returns supported capabilities for the role. The test only
+// verifies that the IPC call returns successfully and does not verify the supported capabilities.
+TEST_P(OccupantAwarenessAidl, GetCapabilityTest) {
+ std::vector<Role> rolesToTest = {Role::FRONT_PASSENGER, Role::DRIVER,
+ Role::ROW_2_PASSENGER_LEFT, Role::ROW_2_PASSENGER_CENTER,
+ Role::ROW_2_PASSENGER_RIGHT, Role::ROW_3_PASSENGER_LEFT,
+ Role::ROW_3_PASSENGER_CENTER, Role::ROW_3_PASSENGER_RIGHT,
+ Role::FRONT_OCCUPANTS, Role::ROW_2_OCCUPANTS,
+ Role::ROW_3_OCCUPANTS, Role::ALL_OCCUPANTS};
+
+ for (auto role : rolesToTest) {
+ int32_t capabilities;
+ EXPECT_OK(mOccupantAwarenessService->getCapabilityForRole(role, &capabilities));
+ }
+}
+
+// Test that getCapabilityForRole() returns failure when arguments are invalid.
+TEST_P(OccupantAwarenessAidl, GetCapabilityFailureTest) {
+ int32_t capabilities;
+ EXPECT_FALSE(
+ mOccupantAwarenessService->getCapabilityForRole(Role::INVALID, &capabilities).isOk());
+
+ Role invalidRole = static_cast<Role>(static_cast<int>(Role::ALL_OCCUPANTS) + 1);
+ EXPECT_FALSE(
+ mOccupantAwarenessService->getCapabilityForRole(invalidRole, &capabilities).isOk());
+}
+
+// Test that getState() returns within the timeout. The test do not attempt to verify the state, but
+// only checks that the IPC call returns successfully.
+TEST_P(OccupantAwarenessAidl, GetStateTest) {
+ std::vector<Role> rolesToTest = {Role::FRONT_PASSENGER, Role::DRIVER,
+ Role::ROW_2_PASSENGER_LEFT, Role::ROW_2_PASSENGER_CENTER,
+ Role::ROW_2_PASSENGER_RIGHT, Role::ROW_3_PASSENGER_LEFT,
+ Role::ROW_3_PASSENGER_CENTER, Role::ROW_3_PASSENGER_RIGHT,
+ Role::FRONT_OCCUPANTS, Role::ROW_2_OCCUPANTS,
+ Role::ROW_3_OCCUPANTS, Role::ALL_OCCUPANTS};
+
+ std::vector<int> detectionCapabilities = {IOccupantAwareness::CAP_PRESENCE_DETECTION,
+ IOccupantAwareness::CAP_GAZE_DETECTION,
+ IOccupantAwareness::CAP_DRIVER_MONITORING_DETECTION};
+
+ for (auto role : rolesToTest) {
+ for (auto detectionCapability : detectionCapabilities) {
+ OccupantAwarenessStatus oasStatus;
+ EXPECT_OK(mOccupantAwarenessService->getState(role, detectionCapability, &oasStatus));
+ }
+ }
+}
+
+// Test that getState() returns failure with invalid args.
+TEST_P(OccupantAwarenessAidl, GetStateFailureTest) {
+ // Verify that getState() returns error when role is invalid (0).
+ OccupantAwarenessStatus oasStatus;
+ EXPECT_FALSE(mOccupantAwarenessService
+ ->getState(Role::INVALID, IOccupantAwareness::CAP_PRESENCE_DETECTION,
+ &oasStatus)
+ .isOk());
+
+ // Verify that getState() returns error when role is invalid (invalid flag).
+ int invalidRole = static_cast<int>(Role::ALL_OCCUPANTS) + 1;
+ EXPECT_FALSE(mOccupantAwarenessService
+ ->getState(static_cast<Role>(invalidRole),
+ IOccupantAwareness::CAP_PRESENCE_DETECTION, &oasStatus)
+ .isOk());
+
+ // Verify that getState() returns error when capability is invalid (none).
+ EXPECT_FALSE(mOccupantAwarenessService
+ ->getState(Role::FRONT_PASSENGER, IOccupantAwareness::CAP_NONE, &oasStatus)
+ .isOk());
+
+ // Verify that getState() returns error when capability is invalid (invalid flag).
+ int invalidDetectionFlags = 0x10;
+ EXPECT_FALSE(mOccupantAwarenessService
+ ->getState(Role::FRONT_PASSENGER, invalidDetectionFlags, &oasStatus)
+ .isOk());
+}
+
+// Test that setCallback() returns within the timeout.
+TEST_P(OccupantAwarenessAidl, SetCallbackTest) {
+ sp<OccupantAwarenessCallback> callback =
+ new OccupantAwarenessCallback([](int detectionFlags, OccupantAwarenessStatus status) {
+ (void)detectionFlags;
+ (void)status;
+ });
+ auto start = std::chrono::system_clock::now();
+ Status status = mOccupantAwarenessService->setCallback(callback);
+ auto elapsed = std::chrono::system_clock::now() - start;
+ EXPECT_OK(status);
+ ASSERT_LE(elapsed, kTimeout);
+}
+
+// Test that setCallback() returns failure with invalid args.
+TEST_P(OccupantAwarenessAidl, SetCallbackFailureTest) {
+ sp<OccupantAwarenessCallback> callback = nullptr;
+ Status status = mOccupantAwarenessService->setCallback(callback);
+ EXPECT_FALSE(status.isOk());
+}
+
+// Test that getLatestDetection() returns within the timeout.
+TEST_P(OccupantAwarenessAidl, GetLatestDetectionTest) {
+ auto start = std::chrono::system_clock::now();
+ OccupantDetections detections;
+ // Do not check status here, since error status is returned when no detection is present.
+ (void)mOccupantAwarenessService->getLatestDetection(&detections);
+ auto elapsed = std::chrono::system_clock::now() - start;
+ ASSERT_LE(elapsed, kTimeout);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ InstantiationName, OccupantAwarenessAidl,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IOccupantAwareness::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ ProcessState::self()->startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index f9c25d1..2050038 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -62,6 +62,7 @@
"impl/vhal_v2_0/EmulatedVehicleHal.cpp",
"impl/vhal_v2_0/VehicleEmulator.cpp",
"impl/vhal_v2_0/PipeComm.cpp",
+ "impl/vhal_v2_0/ProtoMessageConverter.cpp",
"impl/vhal_v2_0/SocketComm.cpp",
"impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
"impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
@@ -98,6 +99,21 @@
test_suites: ["general-tests"],
}
+cc_test {
+ name: "android.hardware.automotive.vehicle@2.0-default-impl-unit-tests",
+ vendor: true,
+ defaults: ["vhal_v2_0_defaults"],
+ srcs: [
+ "impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp",
+ ],
+ static_libs: [
+ "android.hardware.automotive.vehicle@2.0-default-impl-lib",
+ "android.hardware.automotive.vehicle@2.0-libproto-native",
+ "libprotobuf-cpp-lite",
+ ],
+ test_suites: ["general-tests"],
+}
+
cc_binary {
name: "android.hardware.automotive.vehicle@2.0-service",
defaults: ["vhal_v2_0_defaults"],
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
index 56ecd67..d40f122 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
@@ -57,10 +57,14 @@
virtual std::vector<VehiclePropConfig> getAllPropertyConfig() const = 0;
// Send the set property request to server
- virtual StatusCode setProperty(const VehiclePropValue& value) = 0;
+ // updateStatus indicate if VHal should change the status of the value
+ // it should be false except injecting values for e2e tests
+ virtual StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) = 0;
// Receive a new property value from server
- virtual void onPropertyValue(const VehiclePropValue& value) = 0;
+ // updateStatus is true if and only if the value is
+ // generated by car (ECU/fake generator/injected)
+ virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0;
};
/**
@@ -84,11 +88,15 @@
// Receive the set property request from HAL.
// Process the setting and return the status code
- virtual StatusCode onSetProperty(const VehiclePropValue& value) = 0;
+ // updateStatus indicate if VHal should change the status of the value
+ // it should be false except injecting values for e2e tests
+ virtual StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) = 0;
// Receive a new property value from car (via direct connection to the car bus or the emulator)
// and forward the value to HAL
- virtual void onPropertyValueFromCar(const VehiclePropValue& value) = 0;
+ // updateStatus is true if and only if the value is
+ // generated by car (ECU/fake generator/injected)
+ virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0;
};
/**
@@ -118,12 +126,12 @@
return this->onGetAllPropertyConfig();
}
- StatusCode setProperty(const VehiclePropValue& value) override {
- return this->onSetProperty(value);
+ StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override {
+ return this->onSetProperty(value, updateStatus);
}
- void onPropertyValueFromCar(const VehiclePropValue& value) override {
- return this->onPropertyValue(value);
+ void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override {
+ return this->onPropertyValue(value, updateStatus);
}
// To be implemented:
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
index bf1de81..136b2e0 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
@@ -41,7 +41,7 @@
}
}
-void CommConn::sendMessage(emulator::EmulatorMessage const& msg) {
+void CommConn::sendMessage(vhal_proto::EmulatorMessage const& msg) {
int numBytes = msg.ByteSize();
std::vector<uint8_t> buffer(static_cast<size_t>(numBytes));
if (!msg.SerializeToArray(buffer.data(), numBytes)) {
@@ -61,9 +61,9 @@
break;
}
- emulator::EmulatorMessage rxMsg;
+ vhal_proto::EmulatorMessage rxMsg;
if (rxMsg.ParseFromArray(buffer.data(), static_cast<int32_t>(buffer.size()))) {
- emulator::EmulatorMessage respMsg;
+ vhal_proto::EmulatorMessage respMsg;
mMessageProcessor->processMessage(rxMsg, respMsg);
sendMessage(respMsg);
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
index 87b0dfc..6d36da4 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
@@ -44,8 +44,8 @@
* Process a single message received over a CommConn. Populate the given respMsg with the reply
* message we should send.
*/
- virtual void processMessage(emulator::EmulatorMessage const& rxMsg,
- emulator::EmulatorMessage& respMsg) = 0;
+ virtual void processMessage(vhal_proto::EmulatorMessage const& rxMsg,
+ vhal_proto::EmulatorMessage& respMsg) = 0;
};
/**
@@ -93,7 +93,7 @@
/**
* Serialized and send the given message to the other side.
*/
- void sendMessage(emulator::EmulatorMessage const& msg);
+ void sendMessage(vhal_proto::EmulatorMessage const& msg);
protected:
std::unique_ptr<std::thread> mReadThread;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
index 168999d..222fe5e 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
@@ -30,12 +30,12 @@
namespace impl {
-void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value) {
+void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
if (!mPropCallback) {
LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
return;
}
- return mPropCallback(value);
+ return mPropCallback(value, updateStatus);
}
void EmulatedVehicleClient::registerPropertyValueCallback(PropertyCallBackType&& callback) {
@@ -65,12 +65,13 @@
}
void EmulatedVehicleServer::onFakeValueGenerated(const VehiclePropValue& value) {
+ constexpr bool updateStatus = true;
LOG(DEBUG) << __func__ << ": " << toString(value);
auto updatedPropValue = getValuePool()->obtain(value);
if (updatedPropValue) {
updatedPropValue->timestamp = value.timestamp;
updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
- onPropertyValueFromCar(*updatedPropValue);
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
}
}
@@ -86,6 +87,8 @@
}
StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
+ constexpr bool updateStatus = true;
+
LOG(INFO) << __func__;
const auto& v = request.value;
if (!v.int32Values.size()) {
@@ -153,9 +156,11 @@
int32_t display = request.value.int32Values[3];
// Send back to HAL
onPropertyValueFromCar(
- *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display));
+ *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
+ updateStatus);
onPropertyValueFromCar(
- *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
+ *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
+ updateStatus);
break;
}
default: {
@@ -191,9 +196,41 @@
return keyEvent;
}
-StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value) {
+StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) {
// Some properties need to be treated non-trivially
switch (value.prop) {
+ case kGenerateFakeDataControllingProperty:
+ return handleGenerateFakeDataRequest(value);
+
+ // set the value from vehcile side, used in end to end test.
+ case kSetIntPropertyFromVehcileForTest: {
+ auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
+ updatedPropValue->prop = value.value.int32Values[0];
+ updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
+ updatedPropValue->timestamp = value.value.int64Values[0];
+ updatedPropValue->areaId = value.areaId;
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
+ }
+ case kSetFloatPropertyFromVehcileForTest: {
+ auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
+ updatedPropValue->prop = value.value.int32Values[0];
+ updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
+ updatedPropValue->timestamp = value.value.int64Values[0];
+ updatedPropValue->areaId = value.areaId;
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
+ }
+ case kSetBooleanPropertyFromVehcileForTest: {
+ auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
+ updatedPropValue->prop = value.value.int32Values[1];
+ updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
+ updatedPropValue->timestamp = value.value.int64Values[0];
+ updatedPropValue->areaId = value.areaId;
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
+ }
+
case AP_POWER_STATE_REPORT:
switch (value.value.int32Values[0]) {
case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
@@ -201,15 +238,18 @@
case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
// CPMS is in WAIT_FOR_VHAL state, simply move to ON
// Send back to HAL
- onPropertyValueFromCar(
- *createApPowerStateReq(VehicleApPowerStateReq::ON, 0));
+ // ALWAYS update status for generated property value
+ onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0),
+ true /* updateStatus */);
break;
case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
// CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
// Send back to HAL
+ // ALWAYS update status for generated property value
onPropertyValueFromCar(
- *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0));
+ *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0),
+ true /* updateStatus */);
break;
case toInt(VehicleApPowerStateReport::ON):
case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
@@ -226,19 +266,12 @@
}
// In the real vhal, the value will be sent to Car ECU.
- // We just pretend it is done here.
- return StatusCode::OK;
-}
+ // We just pretend it is done here and send back to HAL
+ auto updatedPropValue = getValuePool()->obtain(value);
+ updatedPropValue->timestamp = elapsedRealtimeNano();
-StatusCode EmulatedVehicleServer::onSetPropertyFromVehicle(const VehiclePropValue& value) {
- if (value.prop == kGenerateFakeDataControllingProperty) {
- auto status = handleGenerateFakeDataRequest(value);
- return status;
- } else {
- // Send back to HAL
- onPropertyValueFromCar(value);
- return StatusCode::OK;
- }
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
}
EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
index d424cd8..5fc6493 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
@@ -35,13 +35,10 @@
class EmulatedVehicleClient : public IVehicleClient {
public:
// Type of callback function for handling the new property values
- using PropertyCallBackType = std::function<void(const VehiclePropValue&)>;
+ using PropertyCallBackType = std::function<void(const VehiclePropValue&, bool updateStatus)>;
// Method from IVehicleClient
- void onPropertyValue(const VehiclePropValue& value) override;
-
- // Request to change the value on the VEHICLE side (for testing)
- virtual StatusCode setPropertyFromVehicle(const VehiclePropValue& value) = 0;
+ void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override;
void registerPropertyValueCallback(PropertyCallBackType&& callback);
@@ -55,10 +52,7 @@
std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;
- StatusCode onSetProperty(const VehiclePropValue& value) override;
-
- // Process the request to change the value on the VEHICLE side (for testing)
- StatusCode onSetPropertyFromVehicle(const VehiclePropValue& value);
+ StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;
// Set the Property Value Pool used in this server
void setValuePool(VehiclePropValuePool* valuePool);
@@ -85,16 +79,10 @@
VehiclePropValuePool* mValuePool{nullptr};
};
-class EmulatedPassthroughConnector
- : public IPassThroughConnector<EmulatedVehicleClient, EmulatedVehicleServer> {
- public:
- StatusCode setPropertyFromVehicle(const VehiclePropValue& value) override {
- return this->onSetPropertyFromVehicle(value);
- }
-};
-
// Helper functions
+using EmulatedPassthroughConnector =
+ IPassThroughConnector<EmulatedVehicleClient, EmulatedVehicleServer>;
using EmulatedPassthroughConnectorPtr = std::unique_ptr<EmulatedPassthroughConnector>;
EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector();
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 6508efe..5c16bf7 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -98,8 +98,9 @@
for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
mPropStore->registerProperty(kVehicleProperties[i].config);
}
- mVehicleClient->registerPropertyValueCallback(
- std::bind(&EmulatedVehicleHal::onPropertyValue, this, std::placeholders::_1));
+ mVehicleClient->registerPropertyValueCallback(std::bind(&EmulatedVehicleHal::onPropertyValue,
+ this, std::placeholders::_1,
+ std::placeholders::_2));
}
VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
@@ -131,41 +132,15 @@
}
StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
- static constexpr bool shouldUpdateStatus = false;
-
- // set the value from vehcile side, used in end to end test.
- if (propValue.prop == kSetIntPropertyFromVehcileForTest) {
- auto mockValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
- mockValue->prop = propValue.value.int32Values[0];
- mockValue->value.int32Values[0] = propValue.value.int32Values[1];
- mockValue->timestamp = propValue.value.int64Values[0];
- mockValue->areaId = propValue.areaId;
- setPropertyFromVehicle(*mockValue);
- return StatusCode::OK;
- }
-
- if (propValue.prop == kSetFloatPropertyFromVehcileForTest) {
- auto mockValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
- mockValue->prop = propValue.value.int32Values[0];
- mockValue->value.floatValues[0] = propValue.value.floatValues[0];
- mockValue->timestamp = propValue.value.int64Values[0];
- mockValue->areaId = propValue.areaId;
- setPropertyFromVehicle(*mockValue);
- return StatusCode::OK;
- }
- if (propValue.prop == kSetBooleanPropertyFromVehcileForTest) {
- auto mockValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
- mockValue->prop = propValue.value.int32Values[1];
- mockValue->value.int32Values[0] = propValue.value.int32Values[0];
- mockValue->timestamp = propValue.value.int64Values[0];
- mockValue->areaId = propValue.areaId;
- setPropertyFromVehicle(*mockValue);
- return StatusCode::OK;
- }
+ constexpr bool updateStatus = false;
if (propValue.prop == kGenerateFakeDataControllingProperty) {
- // send the generator controlling request to the server
- auto status = mVehicleClient->setPropertyFromVehicle(propValue);
+ // Send the generator controlling request to the server.
+ // 'updateStatus' flag is only for the value sent by setProperty (propValue in this case)
+ // instead of the generated values triggered by it. 'propValue' works as a control signal
+ // here, since we never send the control signal back, the value of 'updateStatus' flag
+ // does not matter here.
+ auto status = mVehicleClient->setProperty(propValue, updateStatus);
if (status != StatusCode::OK) {
return status;
}
@@ -212,22 +187,13 @@
* After checking all conditions, such as the property is available, a real vhal will
* sent the events to Car ECU to take actions.
*/
- VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(propValue);
- updatedPropValue->timestamp = elapsedRealtimeNano();
// Send the value to the vehicle server, the server will talk to the (real or emulated) car
- auto setValueStatus = mVehicleClient->setProperty(*updatedPropValue);
+ auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus);
if (setValueStatus != StatusCode::OK) {
return setValueStatus;
}
- if (!mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) {
- return StatusCode::INTERNAL_ERROR;
- }
-
- getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue);
- doHalEvent(std::move(updatedPropValue));
-
return StatusCode::OK;
}
@@ -314,7 +280,6 @@
}
if (v.get()) {
- v->timestamp = elapsedRealtimeNano();
doHalEvent(std::move(v));
}
}
@@ -347,18 +312,19 @@
}
bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
- return mVehicleClient->setPropertyFromVehicle(propValue) == StatusCode::OK;
+ constexpr bool updateStatus = true;
+ return mVehicleClient->setProperty(propValue, updateStatus) == StatusCode::OK;
}
std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const {
return mPropStore->readAllValues();
}
-void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value) {
- static constexpr bool shouldUpdateStatus = true;
+void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
- if (mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) {
+ if (mPropStore->writeValue(*updatedPropValue, updateStatus)) {
+ getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue);
doHalEvent(std::move(updatedPropValue));
}
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index 98315ec..a8378da 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -68,7 +68,7 @@
}
StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
- void onPropertyValue(const VehiclePropValue& value);
+ void onPropertyValue(const VehiclePropValue& value, bool updateStatus);
void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
bool isContinuousProperty(int32_t propId) const;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp
new file mode 100644
index 0000000..77cb114
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp
@@ -0,0 +1,216 @@
+/*
+ * 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 "ProtoMsgConverter"
+
+#include <memory>
+#include <vector>
+
+#include <log/log.h>
+
+#include <vhal_v2_0/VehicleUtils.h>
+
+#include "ProtoMessageConverter.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+namespace proto_msg_converter {
+
+// If protobuf class PROTO_VALUE has value in field PROTO_VARNAME,
+// then casting the value by CAST and copying it to VHAL_TYPE_VALUE->VHAL_TYPE_VARNAME
+#define CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, \
+ VHAL_TYPE_VARNAME, CAST) \
+ if (PROTO_VALUE.has_##PROTO_VARNAME()) { \
+ (VHAL_TYPE_VALUE)->VHAL_TYPE_VARNAME = CAST(PROTO_VALUE.PROTO_VARNAME()); \
+ }
+
+// Copying the vector PROTO_VECNAME of protobuf class PROTO_VALUE to
+// VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME, every element of PROTO_VECNAME
+// is casted by CAST
+#define CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, \
+ VHAL_TYPE_VECNAME, CAST) \
+ do { \
+ (VHAL_TYPE_VALUE)->VHAL_TYPE_VECNAME.resize(PROTO_VALUE.PROTO_VECNAME##_size()); \
+ size_t idx = 0; \
+ for (auto& value : PROTO_VALUE.PROTO_VECNAME()) { \
+ VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME[idx++] = CAST(value); \
+ } \
+ } while (0)
+
+// If protobuf message has value in field PROTO_VARNAME,
+// then copying it to VHAL_TYPE_VALUE->VHAL_TYPE_VARNAME
+#define CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, \
+ VHAL_TYPE_VARNAME) \
+ CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE( \
+ PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VARNAME, /*NO CAST*/)
+
+// Copying the vector PROTO_VECNAME of protobuf class PROTO_VALUE to
+// VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME
+#define COPY_PROTOBUF_VEC_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, \
+ VHAL_TYPE_VECNAME) \
+ CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE( \
+ PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VECNAME, /*NO CAST*/)
+
+void toProto(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg) {
+ protoCfg->set_prop(cfg.prop);
+ protoCfg->set_access(toInt(cfg.access));
+ protoCfg->set_change_mode(toInt(cfg.changeMode));
+ protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
+
+ for (auto& configElement : cfg.configArray) {
+ protoCfg->add_config_array(configElement);
+ }
+
+ if (cfg.configString.size() > 0) {
+ protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
+ }
+
+ protoCfg->clear_area_configs();
+ for (auto& areaConfig : cfg.areaConfigs) {
+ auto* protoACfg = protoCfg->add_area_configs();
+ protoACfg->set_area_id(areaConfig.areaId);
+
+ switch (getPropType(cfg.prop)) {
+ case VehiclePropertyType::STRING:
+ case VehiclePropertyType::BOOLEAN:
+ case VehiclePropertyType::INT32_VEC:
+ case VehiclePropertyType::INT64_VEC:
+ case VehiclePropertyType::FLOAT_VEC:
+ case VehiclePropertyType::BYTES:
+ case VehiclePropertyType::MIXED:
+ // Do nothing. These types don't have min/max values
+ break;
+ case VehiclePropertyType::INT64:
+ protoACfg->set_min_int64_value(areaConfig.minInt64Value);
+ protoACfg->set_max_int64_value(areaConfig.maxInt64Value);
+ break;
+ case VehiclePropertyType::FLOAT:
+ protoACfg->set_min_float_value(areaConfig.minFloatValue);
+ protoACfg->set_max_float_value(areaConfig.maxFloatValue);
+ break;
+ case VehiclePropertyType::INT32:
+ protoACfg->set_min_int32_value(areaConfig.minInt32Value);
+ protoACfg->set_max_int32_value(areaConfig.maxInt32Value);
+ break;
+ default:
+ ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop)));
+ break;
+ }
+ }
+
+ protoCfg->set_min_sample_rate(cfg.minSampleRate);
+ protoCfg->set_max_sample_rate(cfg.maxSampleRate);
+}
+
+void fromProto(VehiclePropConfig* cfg, const vhal_proto::VehiclePropConfig& protoCfg) {
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, prop, cfg, prop);
+ CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, access, cfg, access,
+ static_cast<VehiclePropertyAccess>);
+ CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, change_mode, cfg, changeMode,
+ static_cast<VehiclePropertyChangeMode>);
+ COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, config_array, cfg, configArray);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, config_string, cfg, configString);
+
+ auto cast_to_acfg = [](const vhal_proto::VehicleAreaConfig& protoAcfg) {
+ VehicleAreaConfig acfg;
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, area_id, &acfg, areaId);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int32_value, &acfg, minInt32Value);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_int32_value, &acfg, maxInt32Value);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int64_value, &acfg, minInt64Value);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_int64_value, &acfg, maxInt64Value);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_float_value, &acfg, minFloatValue);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_float_value, &acfg, maxFloatValue);
+ return acfg;
+ };
+
+ CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, area_configs, cfg, areaConfigs, cast_to_acfg);
+
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, min_sample_rate, cfg, minSampleRate);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, max_sample_rate, cfg, maxSampleRate);
+}
+
+void toProto(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue& val) {
+ protoVal->set_prop(val.prop);
+ protoVal->set_value_type(toInt(getPropType(val.prop)));
+ protoVal->set_timestamp(val.timestamp);
+ protoVal->set_status((vhal_proto::VehiclePropStatus)(val.status));
+ protoVal->set_area_id(val.areaId);
+
+ // Copy value data if it is set.
+ // - for bytes and strings, this is indicated by size > 0
+ // - for int32, int64, and float, copy the values if vectors have data
+ if (val.value.stringValue.size() > 0) {
+ protoVal->set_string_value(val.value.stringValue.c_str(), val.value.stringValue.size());
+ }
+
+ if (val.value.bytes.size() > 0) {
+ protoVal->set_bytes_value(val.value.bytes.data(), val.value.bytes.size());
+ }
+
+ for (auto& int32Value : val.value.int32Values) {
+ protoVal->add_int32_values(int32Value);
+ }
+
+ for (auto& int64Value : val.value.int64Values) {
+ protoVal->add_int64_values(int64Value);
+ }
+
+ for (auto& floatValue : val.value.floatValues) {
+ protoVal->add_float_values(floatValue);
+ }
+}
+
+void fromProto(VehiclePropValue* val, const vhal_proto::VehiclePropValue& protoVal) {
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, prop, val, prop);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, timestamp, val, timestamp);
+ CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, status, val, status,
+ static_cast<VehiclePropertyStatus>);
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, area_id, val, areaId);
+
+ // Copy value data
+ CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, string_value, val, value.stringValue);
+
+ auto cast_proto_bytes_to_vec = [](auto&& bytes) {
+ return std::vector<uint8_t>(bytes.begin(), bytes.end());
+ };
+ CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, bytes_value, val, value.bytes,
+ cast_proto_bytes_to_vec);
+
+ COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, int32_values, val, value.int32Values);
+ COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, int64_values, val, value.int64Values);
+ COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, float_values, val, value.floatValues);
+}
+
+#undef COPY_PROTOBUF_VEC_TO_VHAL_TYPE
+#undef CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE
+#undef CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE
+#undef CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE
+
+} // namespace proto_msg_converter
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h
new file mode 100644
index 0000000..01f3beb
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.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_automotive_vehicle_V2_0_impl_ProtoMessageConverter_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_ProtoMessageConverter_H_
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+#include "VehicleHalProto.pb.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+namespace proto_msg_converter {
+
+// VehiclePropConfig
+
+void toProto(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg);
+
+void fromProto(VehiclePropConfig* cfg, const vhal_proto::VehiclePropConfig& protoCfg);
+
+// VehiclePropValue
+
+void toProto(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue& val);
+
+void fromProto(VehiclePropValue* val, const vhal_proto::VehiclePropValue& protoVal);
+
+} // namespace proto_msg_converter
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_VehicleHalEmulator_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
index 068333c..916c320 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
@@ -60,7 +60,7 @@
}
}
-void SocketComm::sendMessage(emulator::EmulatorMessage const& msg) {
+void SocketComm::sendMessage(vhal_proto::EmulatorMessage const& msg) {
std::lock_guard<std::mutex> lock(mMutex);
for (std::unique_ptr<SocketConn> const& conn : mOpenConnections) {
conn->sendMessage(msg);
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
index 88b852b..52326b9 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
@@ -47,7 +47,7 @@
/**
* Serialized and send the given message to all connected clients.
*/
- void sendMessage(emulator::EmulatorMessage const& msg);
+ void sendMessage(vhal_proto::EmulatorMessage const& msg);
private:
int mListenFd;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
index 9dc7085..263ca62 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
@@ -24,6 +24,7 @@
#include <vhal_v2_0/VehicleUtils.h>
#include "PipeComm.h"
+#include "ProtoMessageConverter.h"
#include "SocketComm.h"
#include "VehicleEmulator.h"
@@ -62,11 +63,11 @@
* changed.
*/
void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) {
- emulator::EmulatorMessage msg;
- emulator::VehiclePropValue *val = msg.add_value();
+ vhal_proto::EmulatorMessage msg;
+ vhal_proto::VehiclePropValue* val = msg.add_value();
populateProtoVehiclePropValue(val, &propValue);
- msg.set_status(emulator::RESULT_OK);
- msg.set_msg_type(emulator::SET_PROPERTY_ASYNC);
+ msg.set_status(vhal_proto::RESULT_OK);
+ msg.set_msg_type(vhal_proto::SET_PROPERTY_ASYNC);
mSocketComm->sendMessage(msg);
if (mPipeComm) {
@@ -77,17 +78,17 @@
void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage const& rxMsg,
VehicleEmulator::EmulatorMessage& respMsg) {
std::vector<VehiclePropConfig> configs = mHal->listProperties();
- emulator::VehiclePropGet getProp = rxMsg.prop(0);
+ vhal_proto::VehiclePropGet getProp = rxMsg.prop(0);
- respMsg.set_msg_type(emulator::GET_CONFIG_RESP);
- respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
+ respMsg.set_msg_type(vhal_proto::GET_CONFIG_RESP);
+ respMsg.set_status(vhal_proto::ERROR_INVALID_PROPERTY);
for (auto& config : configs) {
// Find the config we are looking for
if (config.prop == getProp.prop()) {
- emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+ vhal_proto::VehiclePropConfig* protoCfg = respMsg.add_config();
populateProtoVehicleConfig(protoCfg, config);
- respMsg.set_status(emulator::RESULT_OK);
+ respMsg.set_status(vhal_proto::RESULT_OK);
break;
}
}
@@ -97,11 +98,11 @@
VehicleEmulator::EmulatorMessage& respMsg) {
std::vector<VehiclePropConfig> configs = mHal->listProperties();
- respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP);
- respMsg.set_status(emulator::RESULT_OK);
+ respMsg.set_msg_type(vhal_proto::GET_CONFIG_ALL_RESP);
+ respMsg.set_status(vhal_proto::RESULT_OK);
for (auto& config : configs) {
- emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+ vhal_proto::VehiclePropConfig* protoCfg = respMsg.add_config();
populateProtoVehicleConfig(protoCfg, config);
}
}
@@ -109,11 +110,11 @@
void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage const& rxMsg,
VehicleEmulator::EmulatorMessage& respMsg) {
int32_t areaId = 0;
- emulator::VehiclePropGet getProp = rxMsg.prop(0);
+ vhal_proto::VehiclePropGet getProp = rxMsg.prop(0);
int32_t propId = getProp.prop();
- emulator::Status status = emulator::ERROR_INVALID_PROPERTY;
+ vhal_proto::Status status = vhal_proto::ERROR_INVALID_PROPERTY;
- respMsg.set_msg_type(emulator::GET_PROPERTY_RESP);
+ respMsg.set_msg_type(vhal_proto::GET_PROPERTY_RESP);
if (getProp.has_area_id()) {
areaId = getProp.area_id();
@@ -127,9 +128,9 @@
StatusCode halStatus;
auto val = mHal->get(request, &halStatus);
if (val != nullptr) {
- emulator::VehiclePropValue* protoVal = respMsg.add_value();
+ vhal_proto::VehiclePropValue* protoVal = respMsg.add_value();
populateProtoVehiclePropValue(protoVal, val.get());
- status = emulator::RESULT_OK;
+ status = vhal_proto::RESULT_OK;
}
}
@@ -138,12 +139,12 @@
void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage const& /* rxMsg */,
VehicleEmulator::EmulatorMessage& respMsg) {
- respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP);
- respMsg.set_status(emulator::RESULT_OK);
+ respMsg.set_msg_type(vhal_proto::GET_PROPERTY_ALL_RESP);
+ respMsg.set_status(vhal_proto::RESULT_OK);
{
for (const auto& prop : mHal->getAllProperties()) {
- emulator::VehiclePropValue* protoVal = respMsg.add_value();
+ vhal_proto::VehiclePropValue* protoVal = respMsg.add_value();
populateProtoVehiclePropValue(protoVal, &prop);
}
}
@@ -151,7 +152,7 @@
void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage const& rxMsg,
VehicleEmulator::EmulatorMessage& respMsg) {
- emulator::VehiclePropValue protoVal = rxMsg.value(0);
+ vhal_proto::VehiclePropValue protoVal = rxMsg.value(0);
VehiclePropValue val = {
.timestamp = elapsedRealtimeNano(),
.areaId = protoVal.area_id(),
@@ -159,7 +160,7 @@
.status = (VehiclePropertyStatus)protoVal.status(),
};
- respMsg.set_msg_type(emulator::SET_PROPERTY_RESP);
+ respMsg.set_msg_type(vhal_proto::SET_PROPERTY_RESP);
// Copy value data if it is set. This automatically handles complex data types if needed.
if (protoVal.has_string_value()) {
@@ -187,120 +188,42 @@
}
bool halRes = mHal->setPropertyFromVehicle(val);
- respMsg.set_status(halRes ? emulator::RESULT_OK : emulator::ERROR_INVALID_PROPERTY);
+ respMsg.set_status(halRes ? vhal_proto::RESULT_OK : vhal_proto::ERROR_INVALID_PROPERTY);
}
-void VehicleEmulator::processMessage(emulator::EmulatorMessage const& rxMsg,
- emulator::EmulatorMessage& respMsg) {
+void VehicleEmulator::processMessage(vhal_proto::EmulatorMessage const& rxMsg,
+ vhal_proto::EmulatorMessage& respMsg) {
switch (rxMsg.msg_type()) {
- case emulator::GET_CONFIG_CMD:
+ case vhal_proto::GET_CONFIG_CMD:
doGetConfig(rxMsg, respMsg);
break;
- case emulator::GET_CONFIG_ALL_CMD:
+ case vhal_proto::GET_CONFIG_ALL_CMD:
doGetConfigAll(rxMsg, respMsg);
break;
- case emulator::GET_PROPERTY_CMD:
+ case vhal_proto::GET_PROPERTY_CMD:
doGetProperty(rxMsg, respMsg);
break;
- case emulator::GET_PROPERTY_ALL_CMD:
+ case vhal_proto::GET_PROPERTY_ALL_CMD:
doGetPropertyAll(rxMsg, respMsg);
break;
- case emulator::SET_PROPERTY_CMD:
+ case vhal_proto::SET_PROPERTY_CMD:
doSetProperty(rxMsg, respMsg);
break;
default:
ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
- respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
+ respMsg.set_status(vhal_proto::ERROR_UNIMPLEMENTED_CMD);
break;
}
}
-void VehicleEmulator::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+void VehicleEmulator::populateProtoVehicleConfig(vhal_proto::VehiclePropConfig* protoCfg,
const VehiclePropConfig& cfg) {
- protoCfg->set_prop(cfg.prop);
- protoCfg->set_access(toInt(cfg.access));
- protoCfg->set_change_mode(toInt(cfg.changeMode));
- protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
-
- for (auto& configElement : cfg.configArray) {
- protoCfg->add_config_array(configElement);
- }
-
- if (cfg.configString.size() > 0) {
- protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
- }
-
- // Populate the min/max values based on property type
- switch (getPropType(cfg.prop)) {
- case VehiclePropertyType::STRING:
- case VehiclePropertyType::BOOLEAN:
- case VehiclePropertyType::INT32_VEC:
- case VehiclePropertyType::INT64_VEC:
- case VehiclePropertyType::FLOAT_VEC:
- case VehiclePropertyType::BYTES:
- case VehiclePropertyType::MIXED:
- // Do nothing. These types don't have min/max values
- break;
- case VehiclePropertyType::INT64:
- if (cfg.areaConfigs.size() > 0) {
- emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
- aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value);
- aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value);
- }
- break;
- case VehiclePropertyType::FLOAT:
- if (cfg.areaConfigs.size() > 0) {
- emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
- aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue);
- aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue);
- }
- break;
- case VehiclePropertyType::INT32:
- if (cfg.areaConfigs.size() > 0) {
- emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
- aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value);
- aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value);
- }
- break;
- default:
- ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop)));
- break;
- }
-
- protoCfg->set_min_sample_rate(cfg.minSampleRate);
- protoCfg->set_max_sample_rate(cfg.maxSampleRate);
+ return proto_msg_converter::toProto(protoCfg, cfg);
}
-void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+void VehicleEmulator::populateProtoVehiclePropValue(vhal_proto::VehiclePropValue* protoVal,
const VehiclePropValue* val) {
- protoVal->set_prop(val->prop);
- protoVal->set_value_type(toInt(getPropType(val->prop)));
- protoVal->set_timestamp(val->timestamp);
- protoVal->set_status((emulator::VehiclePropStatus)(val->status));
- protoVal->set_area_id(val->areaId);
-
- // Copy value data if it is set.
- // - for bytes and strings, this is indicated by size > 0
- // - for int32, int64, and float, copy the values if vectors have data
- if (val->value.stringValue.size() > 0) {
- protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size());
- }
-
- if (val->value.bytes.size() > 0) {
- protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size());
- }
-
- for (auto& int32Value : val->value.int32Values) {
- protoVal->add_int32_values(int32Value);
- }
-
- for (auto& int64Value : val->value.int64Values) {
- protoVal->add_int64_values(int64Value);
- }
-
- for (auto& floatValue : val->value.floatValues) {
- protoVal->add_float_values(floatValue);
- }
+ return proto_msg_converter::toProto(protoVal, *val);
}
} // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
index 58e387a..82947be 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
@@ -72,21 +72,21 @@
virtual ~VehicleEmulator();
void doSetValueFromClient(const VehiclePropValue& propValue);
- void processMessage(emulator::EmulatorMessage const& rxMsg,
- emulator::EmulatorMessage& respMsg) override;
+ void processMessage(vhal_proto::EmulatorMessage const& rxMsg,
+ vhal_proto::EmulatorMessage& respMsg) override;
private:
friend class ConnectionThread;
- using EmulatorMessage = emulator::EmulatorMessage;
+ using EmulatorMessage = vhal_proto::EmulatorMessage;
void doGetConfig(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
void doGetConfigAll(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
void doGetProperty(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
void doGetPropertyAll(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
void doSetProperty(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
- void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+ void populateProtoVehicleConfig(vhal_proto::VehiclePropConfig* protoCfg,
const VehiclePropConfig& cfg);
- void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+ void populateProtoVehiclePropValue(vhal_proto::VehiclePropValue* protoVal,
const VehiclePropValue* val);
private:
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
index 04df5a8..4902a5d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
@@ -16,7 +16,7 @@
syntax = "proto2";
-package emulator;
+package vhal_proto;
// CMD messages are from workstation --> VHAL
// RESP messages are from VHAL --> workstation
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
index 7ce3c32..2cc6595 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-syntax = "proto2";
+syntax = "proto3";
-package emulator;
+package vhal_proto;
import "google/protobuf/empty.proto";
import "VehicleHalProto.proto";
@@ -32,7 +32,7 @@
}
message VehicleHalCallStatus {
- required VehicleHalStatusCode status_code = 1;
+ VehicleHalStatusCode status_code = 1;
}
service VehicleServer {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp
new file mode 100644
index 0000000..3817e44
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <utils/SystemClock.h>
+
+#include "vhal_v2_0/DefaultConfig.h"
+#include "vhal_v2_0/ProtoMessageConverter.h"
+#include "vhal_v2_0/VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace impl {
+namespace proto_msg_converter {
+
+namespace {
+
+void CheckPropConfigConversion(const VehiclePropConfig& config) {
+ vhal_proto::VehiclePropConfig protoCfg;
+ VehiclePropConfig tmpConfig;
+
+ toProto(&protoCfg, config);
+ fromProto(&tmpConfig, protoCfg);
+
+ EXPECT_EQ(config.prop, tmpConfig.prop);
+ EXPECT_EQ(config.access, tmpConfig.access);
+ EXPECT_EQ(config.changeMode, tmpConfig.changeMode);
+ EXPECT_EQ(config.configString, tmpConfig.configString);
+ EXPECT_EQ(config.minSampleRate, tmpConfig.minSampleRate);
+ EXPECT_EQ(config.maxSampleRate, tmpConfig.maxSampleRate);
+ EXPECT_EQ(config.configArray, tmpConfig.configArray);
+
+ EXPECT_EQ(config.areaConfigs.size(), tmpConfig.areaConfigs.size());
+
+ auto cfgType = getPropType(config.prop);
+ for (size_t idx = 0; idx < std::min(config.areaConfigs.size(), tmpConfig.areaConfigs.size());
+ ++idx) {
+ auto& lhs = config.areaConfigs[idx];
+ auto& rhs = tmpConfig.areaConfigs[idx];
+ EXPECT_EQ(lhs.areaId, rhs.areaId);
+ switch (cfgType) {
+ case VehiclePropertyType::INT64:
+ EXPECT_EQ(lhs.minInt64Value, rhs.minInt64Value);
+ EXPECT_EQ(lhs.maxInt64Value, rhs.maxInt64Value);
+ break;
+ case VehiclePropertyType::FLOAT:
+ EXPECT_EQ(lhs.minFloatValue, rhs.minFloatValue);
+ EXPECT_EQ(lhs.maxFloatValue, rhs.maxFloatValue);
+ break;
+ case VehiclePropertyType::INT32:
+ EXPECT_EQ(lhs.minInt32Value, rhs.minInt32Value);
+ EXPECT_EQ(lhs.maxInt32Value, rhs.maxInt32Value);
+ break;
+ default:
+ // ignore min/max values
+ break;
+ }
+ }
+}
+
+void CheckPropValueConversion(const VehiclePropValue& val) {
+ vhal_proto::VehiclePropValue protoVal;
+ VehiclePropValue tmpVal;
+
+ toProto(&protoVal, val);
+ fromProto(&tmpVal, protoVal);
+
+ EXPECT_EQ(val, tmpVal);
+}
+
+TEST(ProtoMessageConverterTest, basic) {
+ for (auto& property : impl::kVehicleProperties) {
+ CheckPropConfigConversion(property.config);
+
+ VehiclePropValue prop;
+ prop.timestamp = elapsedRealtimeNano();
+ prop.areaId = 123;
+ prop.prop = property.config.prop;
+ prop.value = property.initialValue;
+ prop.status = VehiclePropertyStatus::ERROR;
+ CheckPropValueConversion(prop);
+ }
+}
+
+} // namespace
+
+} // namespace proto_msg_converter
+} // namespace impl
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/2.0/vts/OWNERS b/broadcastradio/2.0/vts/OWNERS
index 12adf57..1ff7407 100644
--- a/broadcastradio/2.0/vts/OWNERS
+++ b/broadcastradio/2.0/vts/OWNERS
@@ -3,5 +3,4 @@
twasilczyk@google.com
# VTS team
-yuexima@google.com
-yim@google.com
+dshi@google.com
diff --git a/broadcastradio/2.0/vts/functional/Android.bp b/broadcastradio/2.0/vts/functional/Android.bp
index 3e18a54..49bb665 100644
--- a/broadcastradio/2.0/vts/functional/Android.bp
+++ b/broadcastradio/2.0/vts/functional/Android.bp
@@ -17,9 +17,6 @@
cc_test {
name: "VtsHalBroadcastradioV2_0TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
- cppflags: [
- "-std=c++1z",
- ],
srcs: ["VtsHalBroadcastradioV2_0TargetTest.cpp"],
static_libs: [
"android.hardware.broadcastradio@2.0",
@@ -28,5 +25,8 @@
"android.hardware.broadcastradio@vts-utils-lib",
"libgmock",
],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
index e36f4d9..d170a6d 100644
--- a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
+++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
@@ -16,7 +16,6 @@
#define EGMOCK_VERBOSE 1
-#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
#include <android/hardware/broadcastradio/2.0/IBroadcastRadio.h>
@@ -25,11 +24,13 @@
#include <android/hardware/broadcastradio/2.0/types.h>
#include <broadcastradio-utils-2x/Utils.h>
#include <broadcastradio-vts-utils/call-barrier.h>
-#include <broadcastradio-vts-utils/environment-utils.h>
#include <broadcastradio-vts-utils/mock-timeout.h>
#include <broadcastradio-vts-utils/pointer-utils.h>
#include <cutils/bitops.h>
#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <chrono>
#include <optional>
@@ -52,7 +53,6 @@
using testing::Invoke;
using testing::SaveArg;
-using broadcastradio::vts::BroadcastRadioHidlEnvironment;
using broadcastradio::vts::CallBarrier;
using broadcastradio::vts::clearAndWait;
using utils::make_identifier;
@@ -100,10 +100,8 @@
MOCK_METHOD1(onListUpdated, Return<void>(const hidl_vec<Announcement>&));
};
-static BroadcastRadioHidlEnvironment<IBroadcastRadio>* gEnv = nullptr;
-
-class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase {
- protected:
+class BroadcastRadioHalTest : public ::testing::TestWithParam<std::string> {
+ protected:
virtual void SetUp() override;
virtual void TearDown() override;
@@ -185,7 +183,7 @@
EXPECT_EQ(nullptr, mModule.get()) << "Module is already open";
// lookup HIDL service (radio module)
- mModule = getService<IBroadcastRadio>(gEnv->getServiceName<IBroadcastRadio>());
+ mModule = IBroadcastRadio::getService(GetParam());
ASSERT_NE(nullptr, mModule.get()) << "Couldn't find broadcast radio HAL implementation";
// get module properties
@@ -243,10 +241,10 @@
auto startResult = mSession->startProgramListUpdates({});
if (startResult == Result::NOT_SUPPORTED) {
printSkipped("Program list not supported");
- return nullopt;
+ return std::nullopt;
}
EXPECT_EQ(Result::OK, startResult);
- if (startResult != Result::OK) return nullopt;
+ if (startResult != Result::OK) return std::nullopt;
EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onProgramListReady, timeout::programListScan);
@@ -264,7 +262,7 @@
* - the method succeeds when called for the second time without
* closing previous session.
*/
-TEST_F(BroadcastRadioHalTest, OpenSession) {
+TEST_P(BroadcastRadioHalTest, OpenSession) {
// simply open session for the first time
ASSERT_TRUE(openSession());
@@ -308,7 +306,7 @@
* - all channel grids (frequency ranges and spacings) are valid;
* - seek spacing is a multiple of the manual spacing value.
*/
-TEST_F(BroadcastRadioHalTest, GetAmFmRegionConfig) {
+TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfig) {
AmFmRegionConfig config;
bool supported = getAmFmRegionConfig(false, &config);
if (!supported) {
@@ -341,7 +339,7 @@
* - all channel grids (frequency ranges and spacings) are valid;
* - seek spacing is not set.
*/
-TEST_F(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilities) {
+TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilities) {
AmFmRegionConfig config;
bool supported = getAmFmRegionConfig(true, &config);
if (!supported) {
@@ -369,7 +367,7 @@
* - all channel labels match correct format;
* - all channel frequencies are in correct range.
*/
-TEST_F(BroadcastRadioHalTest, GetDabRegionConfig) {
+TEST_P(BroadcastRadioHalTest, GetDabRegionConfig) {
Result halResult;
hidl_vec<DabTableEntry> config;
auto cb = [&](Result result, hidl_vec<DabTableEntry> configCb) {
@@ -411,7 +409,7 @@
* invoked carrying a proper selector;
* - program changes exactly to what was requested.
*/
-TEST_F(BroadcastRadioHalTest, FmTune) {
+TEST_P(BroadcastRadioHalTest, FmTune) {
ASSERT_TRUE(openSession());
uint64_t freq = 100100; // 100.1 FM
@@ -458,7 +456,7 @@
* - if the selector is not supported, it's ignored;
* - if it is supported, an invalid value results with INVALID_ARGUMENTS;
*/
-TEST_F(BroadcastRadioHalTest, TuneFailsWithInvalid) {
+TEST_P(BroadcastRadioHalTest, TuneFailsWithInvalid) {
ASSERT_TRUE(openSession());
vector<ProgramIdentifier> invalid = {
@@ -489,7 +487,7 @@
* Verifies that:
* - tune fails with NOT_SUPPORTED when program selector is not initialized.
*/
-TEST_F(BroadcastRadioHalTest, TuneFailsWithEmpty) {
+TEST_P(BroadcastRadioHalTest, TuneFailsWithEmpty) {
ASSERT_TRUE(openSession());
// Program type is 1-based, so 0 will always be invalid.
@@ -506,7 +504,7 @@
* - the program info is changed within timeout::tune;
* - works both directions and with or without skipping sub-channel.
*/
-TEST_F(BroadcastRadioHalTest, Seek) {
+TEST_P(BroadcastRadioHalTest, Seek) {
ASSERT_TRUE(openSession());
// TODO(b/69958777): see FmTune workaround
@@ -531,7 +529,7 @@
* - the program info is changed within timeout::tune if the method succeeded;
* - works both directions.
*/
-TEST_F(BroadcastRadioHalTest, Step) {
+TEST_P(BroadcastRadioHalTest, Step) {
ASSERT_TRUE(openSession());
// TODO(b/69958777): see FmTune workaround
@@ -558,7 +556,7 @@
* Verifies that:
* - the method does not crash after being invoked multiple times.
*/
-TEST_F(BroadcastRadioHalTest, Cancel) {
+TEST_P(BroadcastRadioHalTest, Cancel) {
ASSERT_TRUE(openSession());
for (int i = 0; i < 10; i++) {
@@ -576,7 +574,7 @@
* Verifies that:
* - callback is called for empty parameters set.
*/
-TEST_F(BroadcastRadioHalTest, NoParameters) {
+TEST_P(BroadcastRadioHalTest, NoParameters) {
ASSERT_TRUE(openSession());
hidl_vec<VendorKeyValue> halResults = {};
@@ -605,7 +603,7 @@
* - unknown parameters are ignored;
* - callback is called also for empty results set.
*/
-TEST_F(BroadcastRadioHalTest, UnknownParameters) {
+TEST_P(BroadcastRadioHalTest, UnknownParameters) {
ASSERT_TRUE(openSession());
hidl_vec<VendorKeyValue> halResults = {};
@@ -633,7 +631,7 @@
* Verifies that:
* - the method does not crash after being invoked multiple times.
*/
-TEST_F(BroadcastRadioHalTest, Close) {
+TEST_P(BroadcastRadioHalTest, Close) {
ASSERT_TRUE(openSession());
for (int i = 0; i < 10; i++) {
@@ -648,7 +646,7 @@
* Verifies that:
* - getImage call handles argument 0 gracefully.
*/
-TEST_F(BroadcastRadioHalTest, GetNoImage) {
+TEST_P(BroadcastRadioHalTest, GetNoImage) {
size_t len = 0;
auto result = mModule->getImage(0, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); });
@@ -663,7 +661,7 @@
* - isConfigFlagSet either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
* - call success or failure is consistent with setConfigFlag.
*/
-TEST_F(BroadcastRadioHalTest, FetchConfigFlags) {
+TEST_P(BroadcastRadioHalTest, FetchConfigFlags) {
ASSERT_TRUE(openSession());
for (auto flag : gConfigFlagValues) {
@@ -691,7 +689,7 @@
* - setConfigFlag either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
* - isConfigFlagSet reflects the state requested immediately after the set call.
*/
-TEST_F(BroadcastRadioHalTest, SetConfigFlags) {
+TEST_P(BroadcastRadioHalTest, SetConfigFlags) {
ASSERT_TRUE(openSession());
auto get = [&](ConfigFlag flag) {
@@ -743,7 +741,7 @@
* - the complete list is fetched within timeout::programListScan;
* - stopProgramListUpdates does not crash.
*/
-TEST_F(BroadcastRadioHalTest, GetProgramList) {
+TEST_P(BroadcastRadioHalTest, GetProgramList) {
ASSERT_TRUE(openSession());
getProgramList();
@@ -757,7 +755,7 @@
* - the identifier matches the name;
* - there is only one identifier of that type.
*/
-TEST_F(BroadcastRadioHalTest, HdRadioStationNameId) {
+TEST_P(BroadcastRadioHalTest, HdRadioStationNameId) {
ASSERT_TRUE(openSession());
auto list = getProgramList();
@@ -785,7 +783,7 @@
* - if it succeeds, it returns a valid close handle (which is a nullptr otherwise);
* - closing handle does not crash.
*/
-TEST_F(BroadcastRadioHalTest, AnnouncementListenerRegistration) {
+TEST_P(BroadcastRadioHalTest, AnnouncementListenerRegistration) {
sp<AnnouncementListenerMock> listener = new AnnouncementListenerMock();
Result halResult = Result::UNKNOWN_ERROR;
@@ -811,6 +809,11 @@
closeHandle->close();
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, BroadcastRadioHalTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBroadcastRadio::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
} // namespace vts
} // namespace V2_0
} // namespace broadcastradio
@@ -818,14 +821,8 @@
} // namespace android
int main(int argc, char** argv) {
- using android::hardware::broadcastradio::V2_0::vts::gEnv;
- using android::hardware::broadcastradio::V2_0::IBroadcastRadio;
- using android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment;
android::base::SetDefaultTag("BcRadio.vts");
android::base::SetMinimumLogSeverity(android::base::VERBOSE);
- gEnv = new BroadcastRadioHidlEnvironment<IBroadcastRadio>;
- ::testing::AddGlobalTestEnvironment(gEnv);
::testing::InitGoogleTest(&argc, argv);
- gEnv->init(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/pointer-utils.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/pointer-utils.h
index 0b6f5eb..1d76008 100644
--- a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/pointer-utils.h
+++ b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/pointer-utils.h
@@ -19,6 +19,8 @@
#include <chrono>
#include <thread>
+using namespace std::chrono_literals;
+
namespace android {
namespace hardware {
namespace broadcastradio {
diff --git a/camera/device/3.6/Android.bp b/camera/device/3.6/Android.bp
new file mode 100644
index 0000000..8766b93
--- /dev/null
+++ b/camera/device/3.6/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.camera.device@3.6",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "ICameraDeviceSession.hal",
+ "ICameraOfflineSession.hal",
+ ],
+ interfaces: [
+ "android.hardware.camera.common@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
+ "android.hardware.camera.device@3.4",
+ "android.hardware.camera.device@3.5",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/camera/device/3.6/ICameraDeviceSession.hal b/camera/device/3.6/ICameraDeviceSession.hal
new file mode 100644
index 0000000..00ebcc3
--- /dev/null
+++ b/camera/device/3.6/ICameraDeviceSession.hal
@@ -0,0 +1,132 @@
+/*
+ * 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.camera.device@3.6;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.5::ICameraDeviceSession;
+import @3.5::StreamConfiguration;
+import ICameraOfflineSession;
+
+/**
+ * Camera device active session interface.
+ *
+ * Obtained via ICameraDevice::open(), this interface contains the methods to
+ * configure and request captures from an active camera device.
+ */
+interface ICameraDeviceSession extends @3.5::ICameraDeviceSession {
+ /**
+ * configureStreams_3_6:
+ *
+ * Identical to @3.5::ICameraDeviceSession.configureStreams, except that:
+ *
+ * - a boolean supportOffline is added to HalStreamConfiguration to indicate
+ * if this stream can be switched to offline mode later.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On successful stream configuration.
+ * INTERNAL_ERROR:
+ * If there has been a fatal error and the device is no longer
+ * operational. Only close() can be called successfully by the
+ * framework after this error is returned.
+ * ILLEGAL_ARGUMENT:
+ * If the requested stream configuration is invalid. Some examples
+ * of invalid stream configurations include:
+ * - Including more than 1 INPUT stream
+ * - Not including any OUTPUT streams
+ * - Including streams with unsupported formats, or an unsupported
+ * size for that format.
+ * - Including too many output streams of a certain format.
+ * - Unsupported rotation configuration
+ * - Stream sizes/formats don't satisfy the
+ * StreamConfigurationMode requirements
+ * for non-NORMAL mode, or the requested operation_mode is not
+ * supported by the HAL.
+ * - Unsupported usage flag
+ * The camera service cannot filter out all possible illegal stream
+ * configurations, since some devices may support more simultaneous
+ * streams or larger stream resolutions than the minimum required
+ * for a given camera device hardware level. The HAL must return an
+ * ILLEGAL_ARGUMENT for any unsupported stream set, and then be
+ * ready to accept a future valid stream configuration in a later
+ * configureStreams call.
+ * @return halConfiguration The stream parameters desired by the HAL for
+ * each stream, including maximum buffers, the usage flags, and the
+ * override format.
+ */
+ configureStreams_3_6(@3.5::StreamConfiguration requestedConfiguration)
+ generates (Status status, HalStreamConfiguration halConfiguration);
+
+ /**
+ * switchToOffline:
+ *
+ * Switch the current running session from actively streaming mode to the
+ * offline mode. See ICameraOfflineSession for more details.
+ *
+ * The streamsToKeep argument contains list of streams IDs where application
+ * still needs its output. For all streams application does not need anymore,
+ * camera HAL can send ERROR_BUFFER to speed up the transition, or even send
+ * ERROR_REQUEST if all output targets of a request is not needed. By the
+ * time this call returns, camera HAL must have returned all buffers coming
+ * from streams no longer needed and have erased buffer caches of such streams.
+ *
+ * For all requests that are going to be transferred to offline session,
+ * the ICameraDeviceSession is responsible to capture all input buffers from
+ * the image sensor before the switchToOffline call returns. Before
+ * switchToOffline returns, camera HAL must have completed all requests not
+ * switching to offline mode, and collected information on what streams and
+ * requests are going to continue in the offline session, in the
+ * offlineSessionInfo output argument.
+ *
+ * If there are no requests qualified to be transferred to offline session,
+ * the camera HAL must return a null ICameraOfflineSession object with OK
+ * status. In this scenario, the camera HAL still must flush all inflight
+ * requests and unconfigure all streams before returning this call.
+ *
+ * After switchToOffline returns, the ICameraDeviceSession must be back to
+ * unconfigured state as if it is just created and no streams are configured.
+ * Also, camera HAL must not call any methods in ICameraDeviceCallback since
+ * all unfinished requests are now transferred to the offline session.
+ * After the call returns, camera service may then call close to close
+ * the camera device, or call configureStream* again to reconfigure the
+ * camera and then send new capture requests with processCaptureRequest. In
+ * the latter case, it is legitimate for camera HAL to call methods in
+ * ICameraDeviceCallback again in response to the newly submitted capture
+ * requests.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On switching to offline session and unconfiguring streams
+ * successfully.
+ * ILLEGAL_ARGUMENT:
+ * If camera does not support offline mode in any one of streams
+ * in streamsToKeep argument. Note that the camera HAL must report
+ * if a stream supports offline mode in HalStreamConfiguration
+ * output of configureStreams_3_6 method. If all streams in
+ * streamsToKeep argument support offline mode, then the camera HAL
+ * must not return this error.
+ *
+ *
+ * @return offlineSessionInfo Information on what streams and requests will
+ * be transferred to offline session to continue processing.
+ *
+ * @return offlineSession The offline session object camera service will use
+ * to interact with.
+ */
+ switchToOffline(vec<int32_t> streamsToKeep) generates (Status status,
+ CameraOfflineSessionInfo offlineSessionInfo, ICameraOfflineSession offlineSession);
+};
diff --git a/camera/device/3.6/ICameraOfflineSession.hal b/camera/device/3.6/ICameraOfflineSession.hal
new file mode 100644
index 0000000..03cea64
--- /dev/null
+++ b/camera/device/3.6/ICameraOfflineSession.hal
@@ -0,0 +1,80 @@
+/*
+ * 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.camera.device@3.6;
+
+import @3.5::ICameraDeviceCallback;
+
+/**
+ * Camera device offline session interface.
+ *
+ * Obtained via ICameraDeviceSession::switchToOffline(), this interface contains
+ * the methods and callback interfaces that define how camera service interacts
+ * with an offline session.
+ *
+ * An offline session contains some unfinished capture requests that were submitted
+ * to the parent ICameraDeviceSession before calling switchToOffline, and is
+ * responsible for delivering these capture results back to camera service regardless
+ * of whether the parent camera device is still opened or not. An offline session must
+ * not have access to the camera device's image sensor. During switchToOffline
+ * call, camera HAL must capture all necessary frames from the image sensor that
+ * is needed for completing the requests offline later.
+ */
+interface ICameraOfflineSession {
+ /**
+ * Set the callbacks for offline session to communicate with camera service.
+ *
+ * Offline session is responsible to store all callbacks the camera HAL
+ * generated after the return of ICameraDeviceSession::switchToOffline, and
+ * send them to camera service once this method is called.
+ *
+ * Camera service must not call this method more than once, so these
+ * callbacks can be assumed to be constant after the first setCallback call.
+ */
+ setCallback(ICameraDeviceCallback cb);
+
+ /**
+ * getCaptureResultMetadataQueue:
+ *
+ * Retrieves the queue used along with
+ * ICameraDeviceCallback#processCaptureResult.
+ *
+ * Clients to ICameraOfflineSession must:
+ * - Call getCaptureRequestMetadataQueue to retrieve the fast message queue;
+ * - In implementation of ICameraDeviceCallback, test whether
+ * .fmqResultSize field is zero.
+ * - If .fmqResultSize != 0, read result metadata from the fast message
+ * queue;
+ * - otherwise, read result metadata in CaptureResult.result.
+ *
+ * @return queue the queue that implementation writes result metadata to.
+ */
+ getCaptureResultMetadataQueue() generates (fmq_sync<uint8_t> queue);
+
+ /**
+ * Close the offline session and release all resources.
+ *
+ * Camera service may call this method before or after the offline session
+ * has finished all requests it needs to handle. If there are still unfinished
+ * requests when close is called, camera HAL must send ERROR_REQUEST for
+ * all unfinished requests and return all buffers via
+ * ICameraDeviceCallback#processCaptureResult or
+ * ICameraDeviceCallback#returnStreamBuffers.
+ * Also, all buffer caches maintained by the offline session must be erased
+ * before the close call returns.
+ */
+ close();
+};
diff --git a/camera/device/3.6/types.hal b/camera/device/3.6/types.hal
new file mode 100644
index 0000000..743b139
--- /dev/null
+++ b/camera/device/3.6/types.hal
@@ -0,0 +1,143 @@
+/*
+ * 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.camera.device@3.6;
+
+import @3.2::BufferCache;
+import @3.4::HalStream;
+
+/**
+ * OfflineRequest:
+ *
+ * Information about a capture request being switched to offline mode via the
+ * ICameraDeviceSession#switchToOffline method.
+ *
+ */
+struct OfflineRequest {
+ /**
+ * Must match a inflight CaptureRequest sent by camera service
+ */
+ uint32_t frameNumber;
+
+ /**
+ * Stream IDs for outputs that will be returned via ICameraDeviceCallback.
+ * The stream ID must be within one of offline stream listed in
+ * CameraOfflineSessionInfo.
+ * Camera service will validate these pending buffers are matching camera
+ * service's record to make sure no buffers are leaked during the
+ * switchToOffline call.
+ */
+ vec<int32_t> pendingStreams;
+};
+
+/**
+ * OfflineStream:
+ *
+ * Information about a stream being switched to offline mode via the
+ * ICameraDeviceSession#switchToOffline method.
+ *
+ */
+struct OfflineStream {
+ /**
+ * IDs of a stream to be transferred to offline session.
+ *
+ * For devices that do not support HAL buffer management, this must be
+ * one of stream ID listed in streamsToKeep argument of the
+ * switchToOffline call.
+ * For devices that support HAL buffer management, this could be any stream
+ * that was configured right before calling switchToOffline.
+ */
+ int32_t id;
+
+ /**
+ * Number of outstanding buffers that will be returned via offline session
+ */
+ uint32_t numOutstandingBuffers;
+
+ /**
+ * Buffer ID of buffers currently cached between camera service and this
+ * stream, which may or may not be owned by the camera HAL right now.
+ * See StreamBuffer#bufferId for more details.
+ */
+ vec<uint64_t> circulatingBufferIds;
+};
+
+/**
+ * CameraOfflineSessionInfo:
+ *
+ * Information about pending outputs that's being transferred to an offline
+ * session from an active session using the
+ * ICameraDeviceSession#switchToOffline method.
+ *
+ */
+struct CameraOfflineSessionInfo {
+ /**
+ * Information on what streams will be preserved in offline session.
+ * Streams not listed here will be removed by camera service after
+ * switchToOffline call returns.
+ */
+ vec<OfflineStream> offlineStreams;
+
+ /**
+ * Information for requests that will be handled by offline session
+ * Camera service will validate this matches what camera service has on
+ * record.
+ */
+ vec<OfflineRequest> offlineRequests;
+};
+
+/**
+ * HalStream:
+ *
+ * The camera HAL's response to each requested stream configuration.
+ *
+ * This version extends the @3.4 HalStream with the physicalCameraId
+ * field
+ */
+struct HalStream {
+ /**
+ * The definition of HalStream from the prior version.
+ */
+ @3.4::HalStream v3_4;
+
+ /**
+ * Whether this stream can be switch to offline mode.
+ *
+ * For devices that does not support the OFFLINE_PROCESSING capability, this
+ * fields will always be false.
+ *
+ * For devices support the OFFLINE_PROCESSING capability: any input stream
+ * and any output stream that can be output of the input stream must set
+ * this field to true. Also any stream of YUV420_888 format or JPEG format,
+ * with CPU_READ usage flag, must set this field to true. All other streams
+ * are up to camera HAL to advertise support or not, though it is not
+ * recommended to list support for streams with hardware composer or video
+ * encoder usage flags as these streams tend to be targeted continuously and
+ * can lead to long latency when trying to switch to offline.
+ *
+ */
+ bool supportOffline;
+};
+
+/**
+ * HalStreamConfiguration:
+ *
+ * Identical to @3.4::HalStreamConfiguration, except that it contains @3.6::HalStream entries.
+ *
+ */
+struct HalStreamConfiguration {
+ vec<HalStream> streams;
+};
diff --git a/camera/metadata/3.2/types.hal b/camera/metadata/3.2/types.hal
index cef0397..f5034cc 100644
--- a/camera/metadata/3.2/types.hal
+++ b/camera/metadata/3.2/types.hal
@@ -410,7 +410,7 @@
*
* <p>List of the maximum number of regions that can be used for metering in
* auto-exposure (AE), auto-white balance (AWB), and auto-focus (AF);
- * this corresponds to the the maximum number of elements in
+ * this corresponds to the maximum number of elements in
* ANDROID_CONTROL_AE_REGIONS, ANDROID_CONTROL_AWB_REGIONS,
* and ANDROID_CONTROL_AF_REGIONS.</p>
*
diff --git a/camera/metadata/3.5/Android.bp b/camera/metadata/3.5/Android.bp
index 4ebd069..224c369 100644
--- a/camera/metadata/3.5/Android.bp
+++ b/camera/metadata/3.5/Android.bp
@@ -16,4 +16,3 @@
],
gen_java: true,
}
-
diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal
index b9451c8..62899ec 100644
--- a/camera/metadata/3.5/types.hal
+++ b/camera/metadata/3.5/types.hal
@@ -35,12 +35,22 @@
* '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
*/
enum CameraMetadataTag : @3.4::CameraMetadataTag {
- /** android.control.availableBokehCapabilities [static, int32[], public]
+ /** android.control.availableBokehMaxSizes [static, int32[], ndk_public]
*
- * <p>The list of bokeh modes that are supported by this camera device, and each bokeh mode's
- * maximum streaming (non-stall) size with bokeh effect.</p>
+ * <p>The list of bokeh modes for ANDROID_CONTROL_BOKEH_MODE that are supported by this camera
+ * device, and each bokeh mode's maximum streaming (non-stall) size with bokeh effect.</p>
+ *
+ * @see ANDROID_CONTROL_BOKEH_MODE
*/
- ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
+ ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
+
+ /** android.control.availableBokehZoomRatioRanges [static, float[], ndk_public]
+ *
+ * <p>The ranges of supported zoom ratio for non-OFF ANDROID_CONTROL_BOKEH_MODE.</p>
+ *
+ * @see ANDROID_CONTROL_BOKEH_MODE
+ */
+ ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES,
/** android.control.bokehMode [dynamic, enum, public]
*
@@ -48,6 +58,18 @@
*/
ANDROID_CONTROL_BOKEH_MODE,
+ /** android.control.zoomRatioRange [static, float[], public]
+ *
+ * <p>Minimum and maximum zoom ratios supported by this camera device.</p>
+ */
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE,
+
+ /** android.control.zoomRatio [dynamic, float, public]
+ *
+ * <p>The desired zoom ratio</p>
+ */
+ ANDROID_CONTROL_ZOOM_RATIO,
+
ANDROID_CONTROL_END_3_5,
};
@@ -71,4 +93,5 @@
enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
@3.4::CameraMetadataEnumAndroidRequestAvailableCapabilities {
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING,
};
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 080fa19..d14ccfa 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -25,7 +25,6 @@
"libcamera_metadata",
"libcutils",
"libfmq",
- "libgralloctypes",
"libgui",
"libui",
],
@@ -46,6 +45,7 @@
"android.hidl.allocator@1.0",
"libgrallocusage",
"libhidlmemory",
+ "libgralloctypes",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 9416a54..650ec8b 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -20,6 +20,7 @@
#include <chrono>
#include <mutex>
#include <regex>
+#include <string>
#include <unordered_map>
#include <unordered_set>
#include <condition_variable>
@@ -47,8 +48,12 @@
#include <gui/BufferItemConsumer.h>
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
+#include <gtest/gtest.h>
#include <hardware/gralloc.h>
#include <hardware/gralloc1.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
#include <system/camera.h>
#include <system/camera_metadata.h>
#include <ui/GraphicBuffer.h>
@@ -59,9 +64,6 @@
#include <android/hidl/memory/1.0/IMapper.h>
#include <android/hidl/memory/1.0/IMemory.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
using namespace ::android::hardware::camera::device;
using ::android::hardware::Return;
using ::android::hardware::Void;
@@ -283,27 +285,6 @@
}
}
-// Test environment for camera
-class CameraHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static CameraHidlEnvironment* Instance() {
- static CameraHidlEnvironment* instance = new CameraHidlEnvironment;
- return instance;
- }
-
- virtual void HidlSetUp() override { ALOGI("SetUp CameraHidlEnvironment"); }
-
- virtual void HidlTearDown() override { ALOGI("TearDown CameraHidlEnvironment"); }
-
- virtual void registerTestServices() override { registerTestService<ICameraProvider>(); }
-
- private:
- CameraHidlEnvironment() {}
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(CameraHidlEnvironment);
-};
-
struct BufferItemHander: public BufferItemConsumer::FrameAvailableListener {
BufferItemHander(wp<BufferItemConsumer> consumer) : mConsumer(consumer) {}
@@ -544,12 +525,13 @@
}
// The main test class for camera HIDL HAL.
-class CameraHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class CameraHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- string service_name = CameraHidlEnvironment::Instance()->getServiceName<ICameraProvider>();
+ std::string service_name = GetParam();
ALOGI("get service with name: %s", service_name.c_str());
- mProvider = ::testing::VtsHalHidlTargetTestBase::getService<ICameraProvider>(service_name);
+ mProvider = ICameraProvider::getService(service_name);
+
ASSERT_NE(mProvider, nullptr);
uint32_t id;
@@ -774,6 +756,7 @@
const hidl_vec<hidl_string>& deviceNames);
void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
void verifyBokehCharacteristics(const camera_metadata_t* metadata);
+ void verifyZoomCharacteristics(const camera_metadata_t* metadata);
void verifyRecommendedConfigs(const CameraMetadata& metadata);
void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion);
void verifyMonochromeCameraResult(
@@ -795,6 +778,8 @@
void verifySessionReconfigurationQuery(sp<device::V3_5::ICameraDeviceSession> session3_5,
camera_metadata* oldSessionParams, camera_metadata* newSessionParams);
+ void verifyRequestTemplate(const camera_metadata_t* metadata, RequestTemplate requestTemplate);
+
bool isDepthOnly(camera_metadata_t* staticMeta);
static Status getAvailableOutputStreams(const camera_metadata_t *staticMeta,
@@ -878,7 +863,7 @@
// return from HAL but framework.
::android::Vector<StreamBuffer> resultOutputBuffers;
- std::unordered_set<string> expectedPhysicalResults;
+ std::unordered_set<std::string> expectedPhysicalResults;
InFlightRequest() :
shutterTimestamp(0),
@@ -912,7 +897,7 @@
InFlightRequest(ssize_t numBuffers, bool hasInput,
bool partialResults, uint32_t partialCount,
- const std::unordered_set<string>& extraPhysicalResult,
+ const std::unordered_set<std::string>& extraPhysicalResult,
std::shared_ptr<ResultMetadataQueue> queue = nullptr) :
shutterTimestamp(0),
errorCodeValid(false),
@@ -1573,7 +1558,7 @@
}
// Test devices with first_api_level >= P does not advertise device@1.0
-TEST_F(CameraHidlTest, noHal1AfterP) {
+TEST_P(CameraHidlTest, noHal1AfterP) {
constexpr int32_t HAL1_PHASE_OUT_API_LEVEL = 28;
int32_t firstApiLevel = 0;
getFirstApiLevel(&firstApiLevel);
@@ -1598,7 +1583,7 @@
// Test if ICameraProvider::isTorchModeSupported returns Status::OK
// Also if first_api_level >= Q torch API must be supported.
-TEST_F(CameraHidlTest, isTorchModeSupported) {
+TEST_P(CameraHidlTest, isTorchModeSupported) {
constexpr int32_t API_LEVEL_Q = 29;
int32_t firstApiLevel = 0;
getFirstApiLevel(&firstApiLevel);
@@ -1615,7 +1600,7 @@
}
// TODO: consider removing this test if getCameraDeviceNames() has the same coverage
-TEST_F(CameraHidlTest, getCameraIdList) {
+TEST_P(CameraHidlTest, getCameraIdList) {
Return<void> ret;
ret = mProvider->getCameraIdList([&](auto status, const auto& idList) {
ALOGI("getCameraIdList returns status:%d", (int)status);
@@ -1628,7 +1613,7 @@
}
// Test if ICameraProvider::getVendorTags returns Status::OK
-TEST_F(CameraHidlTest, getVendorTags) {
+TEST_P(CameraHidlTest, getVendorTags) {
Return<void> ret;
ret = mProvider->getVendorTags([&](auto status, const auto& vendorTagSecs) {
ALOGI("getVendorTags returns status:%d numSections %zu", (int)status, vendorTagSecs.size());
@@ -1646,7 +1631,7 @@
}
// Test if ICameraProvider::setCallback returns Status::OK
-TEST_F(CameraHidlTest, setCallback) {
+TEST_P(CameraHidlTest, setCallback) {
struct ProviderCb : public ICameraProviderCallback {
virtual Return<void> cameraDeviceStatusChange(
const hidl_string& cameraDeviceName,
@@ -1674,7 +1659,7 @@
}
// Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device
-TEST_F(CameraHidlTest, getCameraDeviceInterface) {
+TEST_P(CameraHidlTest, getCameraDeviceInterface) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -1716,7 +1701,7 @@
// Verify that the device resource cost can be retrieved and the values are
// sane.
-TEST_F(CameraHidlTest, getResourceCost) {
+TEST_P(CameraHidlTest, getResourceCost) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -1786,7 +1771,7 @@
// Verify that the static camera info can be retrieved
// successfully.
-TEST_F(CameraHidlTest, getCameraInfo) {
+TEST_P(CameraHidlTest, getCameraInfo) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -1834,7 +1819,7 @@
}
// Check whether preview window can be configured
-TEST_F(CameraHidlTest, setPreviewWindow) {
+TEST_P(CameraHidlTest, setPreviewWindow) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -1854,7 +1839,7 @@
}
// Verify that setting preview window fails in case device is not open
-TEST_F(CameraHidlTest, setPreviewWindowInvalid) {
+TEST_P(CameraHidlTest, setPreviewWindowInvalid) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -1879,7 +1864,7 @@
}
// Start and stop preview checking whether it gets enabled in between.
-TEST_F(CameraHidlTest, startStopPreview) {
+TEST_P(CameraHidlTest, startStopPreview) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -1904,7 +1889,7 @@
// Start preview without active preview window. Preview should start as soon
// as a valid active window gets configured.
-TEST_F(CameraHidlTest, startStopPreviewDelayed) {
+TEST_P(CameraHidlTest, startStopPreviewDelayed) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -1934,7 +1919,7 @@
}
// Verify that image capture behaves as expected along with preview callbacks.
-TEST_F(CameraHidlTest, takePicture) {
+TEST_P(CameraHidlTest, takePicture) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -1983,7 +1968,7 @@
}
// Image capture should fail in case preview didn't get enabled first.
-TEST_F(CameraHidlTest, takePictureFail) {
+TEST_P(CameraHidlTest, takePictureFail) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -2003,7 +1988,7 @@
}
// Verify that image capture can be cancelled.
-TEST_F(CameraHidlTest, cancelPicture) {
+TEST_P(CameraHidlTest, cancelPicture) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -2030,7 +2015,7 @@
}
// Image capture cancel is a no-op when image capture is not running.
-TEST_F(CameraHidlTest, cancelPictureNOP) {
+TEST_P(CameraHidlTest, cancelPictureNOP) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -2053,7 +2038,7 @@
}
// Test basic video recording.
-TEST_F(CameraHidlTest, startStopRecording) {
+TEST_P(CameraHidlTest, startStopRecording) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -2131,7 +2116,7 @@
}
// It shouldn't be possible to start recording without enabling preview first.
-TEST_F(CameraHidlTest, startRecordingFail) {
+TEST_P(CameraHidlTest, startRecordingFail) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -2155,7 +2140,7 @@
}
// Check autofocus support if available.
-TEST_F(CameraHidlTest, autoFocus) {
+TEST_P(CameraHidlTest, autoFocus) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
std::vector<const char*> focusModes = {CameraParameters::FOCUS_MODE_AUTO,
CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE,
@@ -2216,7 +2201,7 @@
}
// In case autofocus is supported verify that it can be cancelled.
-TEST_F(CameraHidlTest, cancelAutoFocus) {
+TEST_P(CameraHidlTest, cancelAutoFocus) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -2262,7 +2247,7 @@
}
// Check whether face detection is available and try to enable&disable.
-TEST_F(CameraHidlTest, sendCommandFaceDetection) {
+TEST_P(CameraHidlTest, sendCommandFaceDetection) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -2317,7 +2302,7 @@
}
// Check whether smooth zoom is available and try to enable&disable.
-TEST_F(CameraHidlTest, sendCommandSmoothZoom) {
+TEST_P(CameraHidlTest, sendCommandSmoothZoom) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -2365,7 +2350,7 @@
}
// Basic sanity tests related to camera parameters.
-TEST_F(CameraHidlTest, getSetParameters) {
+TEST_P(CameraHidlTest, getSetParameters) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -2457,7 +2442,7 @@
// Verify that the static camera characteristics can be retrieved
// successfully.
-TEST_F(CameraHidlTest, getCameraCharacteristics) {
+TEST_P(CameraHidlTest, getCameraCharacteristics) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -2523,7 +2508,7 @@
//In case it is supported verify that torch can be enabled.
//Check for corresponding toch callbacks as well.
-TEST_F(CameraHidlTest, setTorchMode) {
+TEST_P(CameraHidlTest, setTorchMode) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
bool torchControlSupported = false;
Return<void> ret;
@@ -2661,7 +2646,7 @@
}
// Check dump functionality.
-TEST_F(CameraHidlTest, dumpState) {
+TEST_P(CameraHidlTest, dumpState) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
Return<void> ret;
@@ -2726,7 +2711,7 @@
}
// Open, dumpStates, then close
-TEST_F(CameraHidlTest, openClose) {
+TEST_P(CameraHidlTest, openClose) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
Return<void> ret;
@@ -2819,7 +2804,7 @@
// Check whether all common default request settings can be sucessfully
// constructed.
-TEST_F(CameraHidlTest, constructDefaultRequestSettings) {
+TEST_P(CameraHidlTest, constructDefaultRequestSettings) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -2876,13 +2861,7 @@
metadata, &expectedSize);
ASSERT_TRUE((result == 0) ||
(result == CAMERA_METADATA_VALIDATION_SHIFTED));
- size_t entryCount =
- get_camera_metadata_entry_count(metadata);
- // TODO: we can do better than 0 here. Need to check how many required
- // request keys we've defined for each template
- ASSERT_GT(entryCount, 0u);
- ALOGI("template %u metadata entry count is %zu",
- t, entryCount);
+ verifyRequestTemplate(metadata, reqTemplate);
} else {
ASSERT_EQ(0u, req.size());
}
@@ -2909,7 +2888,7 @@
// Verify that all supported stream formats and sizes can be configured
// successfully.
-TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) {
+TEST_P(CameraHidlTest, configureStreamsAvailableOutputs) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
std::vector<AvailableStream> outputStreams;
@@ -3017,7 +2996,7 @@
}
// Check for correct handling of invalid/incorrect configuration parameters.
-TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) {
+TEST_P(CameraHidlTest, configureStreamsInvalidOutputs) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
std::vector<AvailableStream> outputStreams;
@@ -3213,7 +3192,7 @@
// Check whether all supported ZSL output stream combinations can be
// configured successfully.
-TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) {
+TEST_P(CameraHidlTest, configureStreamsZSLInputOutputs) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
std::vector<AvailableStream> inputStreams;
std::vector<AvailableZSLInputOutput> inputOutputMap;
@@ -3379,7 +3358,7 @@
// Check whether session parameters are supported. If Hal support for them
// exist, then try to configure a preview stream using them.
-TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) {
+TEST_P(CameraHidlTest, configureStreamsWithSessionParameters) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
std::vector<AvailableStream> outputPreviewStreams;
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -3498,7 +3477,7 @@
// Verify that all supported preview + still capture stream combinations
// can be configured successfully.
-TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) {
+TEST_P(CameraHidlTest, configureStreamsPreviewStillOutputs) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
std::vector<AvailableStream> outputBlobStreams;
std::vector<AvailableStream> outputPreviewStreams;
@@ -3621,7 +3600,7 @@
// In case constrained mode is supported, test whether it can be
// configured. Additionally check for common invalid inputs when
// using this mode.
-TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) {
+TEST_P(CameraHidlTest, configureStreamsConstrainedOutputs) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -3826,7 +3805,7 @@
// Verify that all supported video + snapshot stream combinations can
// be configured successfully.
-TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) {
+TEST_P(CameraHidlTest, configureStreamsVideoStillOutputs) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
std::vector<AvailableStream> outputBlobStreams;
std::vector<AvailableStream> outputVideoStreams;
@@ -3947,7 +3926,7 @@
}
// Generate and verify a camera capture request
-TEST_F(CameraHidlTest, processCaptureRequestPreview) {
+TEST_P(CameraHidlTest, processCaptureRequestPreview) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
@@ -4115,7 +4094,7 @@
}
// Generate and verify a multi-camera capture request
-TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) {
+TEST_P(CameraHidlTest, processMultiCaptureRequestPreview) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
@@ -4184,7 +4163,7 @@
// Leave only 2 physical devices in the id set.
auto it = physicalIds.begin();
- string physicalDeviceId = *it; it++;
+ std::string physicalDeviceId = *it; it++;
physicalIds.erase(++it, physicalIds.end());
ASSERT_EQ(physicalIds.size(), 2u);
@@ -4362,7 +4341,7 @@
}
// Generate and verify a burst containing alternating sensor sensitivity values
-TEST_F(CameraHidlTest, processCaptureRequestBurstISO) {
+TEST_P(CameraHidlTest, processCaptureRequestBurstISO) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
@@ -4520,7 +4499,7 @@
// Test whether an incorrect capture request with missing settings will
// be reported correctly.
-TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) {
+TEST_P(CameraHidlTest, processCaptureRequestInvalidSinglePreview) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
std::vector<AvailableStream> outputPreviewStreams;
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -4595,7 +4574,7 @@
// Check whether an invalid capture request with missing output buffers
// will be reported correctly.
-TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) {
+TEST_P(CameraHidlTest, processCaptureRequestInvalidBuffer) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
std::vector<AvailableStream> outputBlobStreams;
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -4660,7 +4639,7 @@
}
// Generate, trigger and flush a preview request
-TEST_F(CameraHidlTest, flushPreviewRequest) {
+TEST_P(CameraHidlTest, flushPreviewRequest) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
std::vector<AvailableStream> outputPreviewStreams;
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -4803,7 +4782,7 @@
}
// Verify that camera flushes correctly without any pending requests.
-TEST_F(CameraHidlTest, flushEmpty) {
+TEST_P(CameraHidlTest, flushEmpty) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
std::vector<AvailableStream> outputPreviewStreams;
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -4848,7 +4827,7 @@
}
// Test camera provider@2.5 notify method
-TEST_F(CameraHidlTest, providerDeviceStateNotification) {
+TEST_P(CameraHidlTest, providerDeviceStateNotification) {
notifyDeviceState(provider::V2_5::DeviceState::BACK_COVERED);
notifyDeviceState(provider::V2_5::DeviceState::NORMAL);
@@ -5690,6 +5669,11 @@
return;
}
+ camera_metadata_ro_entry entry;
+ int retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+ bool hasZoomRatioRange = (0 == retcode && entry.count == 2);
+
std::string version, cameraId;
ASSERT_TRUE(::matchDeviceName(cameraName, mProviderType, &version, &cameraId));
std::unordered_set<std::string> physicalIds;
@@ -5697,15 +5681,37 @@
for (auto physicalId : physicalIds) {
ASSERT_NE(physicalId, cameraId);
bool isPublicId = false;
+ std::string fullPublicId;
for (auto& deviceName : deviceNames) {
std::string publicVersion, publicId;
ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
if (physicalId == publicId) {
isPublicId = true;
+ fullPublicId = deviceName;
break;
}
}
if (isPublicId) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> subDevice;
+ Return<void> ret;
+ ret = mProvider->getCameraDeviceInterface_V3_x(
+ fullPublicId, [&](auto status, const auto& device) {
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ subDevice = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = subDevice->getCameraCharacteristics(
+ [&](auto status, const auto& chars) {
+ ASSERT_EQ(Status::OK, status);
+ retcode = find_camera_metadata_ro_entry(
+ (const camera_metadata_t *)chars.data(),
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+ bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
+ ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
+ });
+ ASSERT_TRUE(ret.isOk());
continue;
}
@@ -5721,6 +5727,12 @@
[&](auto status, const auto& chars) {
verifyCameraCharacteristics(status, chars);
verifyMonochromeCharacteristics(chars, deviceVersion);
+
+ retcode = find_camera_metadata_ro_entry(
+ (const camera_metadata_t *)chars.data(),
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+ bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
+ ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
});
ASSERT_TRUE(ret.isOk());
@@ -5740,8 +5752,7 @@
// Make sure ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID is available in
// result keys.
if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5) {
- camera_metadata_ro_entry entry;
- int retcode = find_camera_metadata_ro_entry(metadata,
+ retcode = find_camera_metadata_ro_entry(metadata,
ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
if ((0 == retcode) && (entry.count > 0)) {
ASSERT_NE(std::find(entry.data.i32, entry.data.i32 + entry.count,
@@ -5841,6 +5852,7 @@
}
verifyBokehCharacteristics(metadata);
+ verifyZoomCharacteristics(metadata);
}
void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadata) {
@@ -5871,38 +5883,51 @@
retcode = find_camera_metadata_ro_entry(metadata,
ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
- bool hasBokehCharacteristicsKey = false;
+ bool hasBokehMaxSizesKey = false;
+ bool hasBokehZoomRatioRangesKey = false;
if ((0 == retcode) && (entry.count > 0)) {
- hasBokehCharacteristicsKey = std::find(entry.data.i32, entry.data.i32+entry.count,
- ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES) != entry.data.i32+entry.count;
+ hasBokehMaxSizesKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+ ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES) != entry.data.i32+entry.count;
+ hasBokehZoomRatioRangesKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+ ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES) != entry.data.i32+entry.count;
} else {
ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
}
+
+ camera_metadata_ro_entry maxSizesEntry;
retcode = find_camera_metadata_ro_entry(metadata,
- ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES, &entry);
- bool hasAvailableBokehCaps = (0 == retcode && entry.count > 0);
+ ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES, &maxSizesEntry);
+ bool hasBokehMaxSizes = (0 == retcode && maxSizesEntry.count > 0);
+
+ camera_metadata_ro_entry zoomRatioRangesEntry;
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES, &zoomRatioRangesEntry);
+ bool hasBokehZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0);
// Bokeh keys must all be available, or all be unavailable.
- bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehCharacteristicsKey &&
- !hasAvailableBokehCaps;
+ bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehMaxSizesKey &&
+ !hasBokehZoomRatioRangesKey && !hasBokehMaxSizes && !hasBokehZoomRatioRanges;
if (noBokeh) {
return;
}
- bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehCharacteristicsKey &&
- hasAvailableBokehCaps;
+ bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehMaxSizesKey &&
+ hasBokehZoomRatioRangesKey && hasBokehMaxSizes && hasBokehZoomRatioRanges;
ASSERT_TRUE(hasBokeh);
// Must have OFF, and must have one of STILL_CAPTURE and CONTINUOUS.
- ASSERT_TRUE(entry.count == 6 || entry.count == 9);
+ // Only valid combinations: {OFF, CONTINUOUS}, {OFF, STILL_CAPTURE}, and
+ // {OFF, CONTINUOUS, STILL_CAPTURE}.
+ ASSERT_TRUE((maxSizesEntry.count == 6 && zoomRatioRangesEntry.count == 2) ||
+ (maxSizesEntry.count == 9 && zoomRatioRangesEntry.count == 4));
bool hasOffMode = false;
bool hasStillCaptureMode = false;
bool hasContinuousMode = false;
std::vector<AvailableStream> outputStreams;
ASSERT_EQ(Status::OK, getAvailableOutputStreams(metadata, outputStreams));
- for (int i = 0; i < entry.count; i += 3) {
- int32_t mode = entry.data.i32[i];
- int32_t maxWidth = entry.data.i32[i+1];
- int32_t maxHeight = entry.data.i32[i+2];
+ for (int i = 0, j = 0; i < maxSizesEntry.count && j < zoomRatioRangesEntry.count; i += 3) {
+ int32_t mode = maxSizesEntry.data.i32[i];
+ int32_t maxWidth = maxSizesEntry.data.i32[i+1];
+ int32_t maxHeight = maxSizesEntry.data.i32[i+2];
switch (mode) {
case ANDROID_CONTROL_BOKEH_MODE_OFF:
hasOffMode = true;
@@ -5910,9 +5935,11 @@
break;
case ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE:
hasStillCaptureMode = true;
+ j += 2;
break;
case ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS:
hasContinuousMode = true;
+ j += 2;
break;
default:
ADD_FAILURE() << "Invalid bokehMode advertised: " << mode;
@@ -5920,6 +5947,7 @@
}
if (mode != ANDROID_CONTROL_BOKEH_MODE_OFF) {
+ // Make sure size is supported.
bool sizeSupported = false;
for (const auto& stream : outputStreams) {
if ((stream.format == static_cast<int32_t>(PixelFormat::YCBCR_420_888) ||
@@ -5930,12 +5958,102 @@
}
}
ASSERT_TRUE(sizeSupported);
+
+ // Make sure zoom range is valid
+ float minZoomRatio = zoomRatioRangesEntry.data.f[0];
+ float maxZoomRatio = zoomRatioRangesEntry.data.f[1];
+ ASSERT_GT(minZoomRatio, 0.0f);
+ ASSERT_LE(minZoomRatio, maxZoomRatio);
}
}
ASSERT_TRUE(hasOffMode);
ASSERT_TRUE(hasStillCaptureMode || hasContinuousMode);
}
+void CameraHidlTest::verifyZoomCharacteristics(const camera_metadata_t* metadata) {
+ camera_metadata_ro_entry entry;
+ int retcode = 0;
+
+ // Check key availability in capabilities, request and result.
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &entry);
+ float maxDigitalZoom = 1.0;
+ if ((0 == retcode) && (entry.count == 1)) {
+ maxDigitalZoom = entry.data.f[0];
+ } else {
+ ADD_FAILURE() << "Get camera scalerAvailableMaxDigitalZoom failed!";
+ }
+
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+ bool hasZoomRequestKey = false;
+ if ((0 == retcode) && (entry.count > 0)) {
+ hasZoomRequestKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+ ANDROID_CONTROL_ZOOM_RATIO) != entry.data.i32+entry.count;
+ } else {
+ ADD_FAILURE() << "Get camera availableRequestKeys failed!";
+ }
+
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
+ bool hasZoomResultKey = false;
+ if ((0 == retcode) && (entry.count > 0)) {
+ hasZoomResultKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+ ANDROID_CONTROL_ZOOM_RATIO) != entry.data.i32+entry.count;
+ } else {
+ ADD_FAILURE() << "Get camera availableResultKeys failed!";
+ }
+
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
+ bool hasZoomCharacteristicsKey = false;
+ if ((0 == retcode) && (entry.count > 0)) {
+ hasZoomCharacteristicsKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE) != entry.data.i32+entry.count;
+ } else {
+ ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
+ }
+
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+ bool hasZoomRatioRange = (0 == retcode && entry.count == 2);
+
+ // Zoom keys must all be available, or all be unavailable.
+ bool noZoomRatio = !hasZoomRequestKey && !hasZoomResultKey && !hasZoomCharacteristicsKey &&
+ !hasZoomRatioRange;
+ if (noZoomRatio) {
+ return;
+ }
+ bool hasZoomRatio = hasZoomRequestKey && hasZoomResultKey && hasZoomCharacteristicsKey &&
+ hasZoomRatioRange;
+ ASSERT_TRUE(hasZoomRatio);
+
+ float minZoomRatio = entry.data.f[0];
+ float maxZoomRatio = entry.data.f[1];
+ if (maxDigitalZoom != maxZoomRatio) {
+ ADD_FAILURE() << "Maximum zoom ratio is different than maximum digital zoom!";
+ }
+ if (minZoomRatio > maxZoomRatio) {
+ ADD_FAILURE() << "Maximum zoom ratio is less than minimum zoom ratio!";
+ }
+ if (minZoomRatio > 1.0f) {
+ ADD_FAILURE() << "Minimum zoom ratio is more than 1.0!";
+ }
+ if (maxZoomRatio < 1.0f) {
+ ADD_FAILURE() << "Maximum zoom ratio is less than 1.0!";
+ }
+
+ // Make sure CROPPING_TYPE is CENTER_ONLY
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_SCALER_CROPPING_TYPE, &entry);
+ if ((0 == retcode) && (entry.count == 1)) {
+ int8_t croppingType = entry.data.u8[0];
+ ASSERT_EQ(croppingType, ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY);
+ } else {
+ ADD_FAILURE() << "Get camera scalerCroppingType failed!";
+ }
+}
+
void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars,
int deviceVersion) {
const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
@@ -6309,7 +6427,7 @@
buffer_handle_t buffer;
uint32_t stride;
- android::status_t err = android::GraphicBufferAllocator::get().allocate(
+ android::status_t err = android::GraphicBufferAllocator::get().allocateRawHandle(
width, height, static_cast<int32_t>(format), 1u /*layerCount*/, usage, &buffer, &stride,
"VtsHalCameraProviderV2_4");
ASSERT_EQ(err, android::NO_ERROR);
@@ -6434,11 +6552,27 @@
}
}
-int main(int argc, char **argv) {
- ::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- CameraHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
+void CameraHidlTest::verifyRequestTemplate(const camera_metadata_t* metadata,
+ RequestTemplate requestTemplate) {
+ ASSERT_NE(nullptr, metadata);
+ size_t entryCount =
+ get_camera_metadata_entry_count(metadata);
+ ALOGI("template %u metadata entry count is %zu", (int32_t)requestTemplate, entryCount);
+ // TODO: we can do better than 0 here. Need to check how many required
+ // request keys we've defined for each template
+ ASSERT_GT(entryCount, 0u);
+
+ // Check zoomRatio
+ camera_metadata_ro_entry zoomRatioEntry;
+ int foundZoomRatio = find_camera_metadata_ro_entry(metadata,
+ ANDROID_CONTROL_ZOOM_RATIO, &zoomRatioEntry);
+ if (foundZoomRatio == 0) {
+ ASSERT_EQ(zoomRatioEntry.count, 1);
+ ASSERT_EQ(zoomRatioEntry.data.f[0], 1.0f);
+ }
}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, CameraHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ICameraProvider::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
new file mode 100644
index 0000000..f55e799
--- /dev/null
+++ b/common/aidl/Android.bp
@@ -0,0 +1,21 @@
+aidl_interface {
+ name: "android.hardware.common",
+ host_supported: true,
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ srcs: [
+ "android/hardware/common/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ enabled: false,
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
+}
diff --git a/common/aidl/android/hardware/common/NativeHandle.aidl b/common/aidl/android/hardware/common/NativeHandle.aidl
new file mode 100644
index 0000000..2c250a2
--- /dev/null
+++ b/common/aidl/android/hardware/common/NativeHandle.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.common;
+
+/**
+ * Representation of a native handle.
+ */
+@VintfStability
+parcelable NativeHandle {
+ ParcelFileDescriptor[] fds;
+ int[] ints;
+}
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 8abbd48..1e3f743 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -388,6 +388,13 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.rebootescrow</name>
+ <interface>
+ <name>IRebootEscrow</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.secure_element</name>
<version>1.0</version>
@@ -408,7 +415,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.soundtrigger</name>
- <version>2.0-2</version>
+ <version>2.0-3</version>
<interface>
<name>ISoundTriggerHw</name>
<instance>default</instance>
@@ -512,7 +519,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.wifi.hostapd</name>
- <version>1.0-1</version>
+ <version>1.0-2</version>
<interface>
<name>IHostapd</name>
<instance>default</instance>
diff --git a/contexthub/1.0/vts/functional/Android.bp b/contexthub/1.0/vts/functional/Android.bp
index aef0340..9e99c33 100644
--- a/contexthub/1.0/vts/functional/Android.bp
+++ b/contexthub/1.0/vts/functional/Android.bp
@@ -19,6 +19,8 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalContexthubV1_0TargetTest.cpp"],
static_libs: ["android.hardware.contexthub@1.0"],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
-
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/1.0/vts/functional/OWNERS
index 045cc4e..161b2f0 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/1.0/vts/functional/OWNERS
@@ -4,5 +4,5 @@
stange@google.com
#VTS team
-yim@google.com
+dshi@google.com
trong@google.com
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index 629477a..a1d173b 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -16,13 +16,14 @@
#define LOG_TAG "contexthub_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/contexthub/1.0/IContexthub.h>
#include <android/hardware/contexthub/1.0/IContexthubCallback.h>
#include <android/hardware/contexthub/1.0/types.h>
#include <android/log.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <log/log.h>
#include <cinttypes>
@@ -76,69 +77,44 @@
}
// Gets a list of valid hub IDs in the system
-std::vector<uint32_t> getHubIds() {
- static std::vector<uint32_t> hubIds;
+std::vector<std::string> getHubIds(const std::string& service_name) {
+ std::vector<std::string> hubIds;
- if (hubIds.size() == 0) {
- sp<IContexthub> hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>();
+ sp<IContexthub> hubApi = IContexthub::getService(service_name);
if (hubApi != nullptr) {
- for (const ContextHub& hub : getHubsSync(hubApi)) {
- hubIds.push_back(hub.hubId);
- }
+ for (const ContextHub& hub : getHubsSync(hubApi)) {
+ hubIds.push_back(std::to_string(hub.hubId));
+ }
}
- }
- ALOGD("Running tests against all %zu reported hubs", hubIds.size());
- return hubIds;
+ ALOGD("Running tests against all %zu reported hubs for service %s", hubIds.size(),
+ service_name.c_str());
+ return hubIds;
}
-// Test environment for Contexthub HIDL HAL.
-class ContexthubHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static ContexthubHidlEnvironment* Instance() {
- static ContexthubHidlEnvironment* instance = new ContexthubHidlEnvironment;
- return instance;
- }
+// Test fixture parameterized by hub ID, initializes the HAL and makes the context hub API handle
+// available.
+class ContexthubHidlTest : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+ public:
+ virtual void SetUp() override {
+ hubApi = IContexthub::getService(std::get<0>(GetParam()));
+ ASSERT_NE(hubApi, nullptr);
- virtual void registerTestServices() override { registerTestService<IContexthub>(); }
- private:
- ContexthubHidlEnvironment() {}
-};
+ // getHubs() must be called at least once for proper initialization of the
+ // HAL implementation
+ getHubsSync(hubApi);
+ }
-// Base test fixture that initializes the HAL and makes the context hub API
-// handle available
-class ContexthubHidlTestBase : public ::testing::VtsHalHidlTargetTestBase {
- public:
- virtual void SetUp() override {
- hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>(
- ContexthubHidlEnvironment::Instance()->getServiceName<IContexthub>());
- ASSERT_NE(hubApi, nullptr);
+ uint32_t getHubId() { return std::stoi(std::get<1>(GetParam())); }
- // getHubs() must be called at least once for proper initialization of the
- // HAL implementation
- getHubsSync(hubApi);
- }
+ Result registerCallback(sp<IContexthubCallback> cb) {
+ Result result = hubApi->registerCallback(getHubId(), cb);
+ ALOGD("Registered callback, result %" PRIu32, result);
+ return result;
+ }
- virtual void TearDown() override {}
-
- sp<IContexthub> hubApi;
-};
-
-// Test fixture parameterized by hub ID
-class ContexthubHidlTest : public ContexthubHidlTestBase,
- public ::testing::WithParamInterface<uint32_t> {
- public:
- uint32_t getHubId() {
- return GetParam();
- }
-
- Result registerCallback(sp<IContexthubCallback> cb) {
- Result result = hubApi->registerCallback(getHubId(), cb);
- ALOGD("Registered callback, result %" PRIu32, result);
- return result;
- }
+ sp<IContexthub> hubApi;
};
// Base callback implementation that just logs all callbacks by default
@@ -202,24 +178,24 @@
}
// Ensures that the metadata reported in getHubs() is sane
-TEST_F(ContexthubHidlTestBase, TestGetHubs) {
- hidl_vec<ContextHub> hubs = getHubsSync(hubApi);
- ALOGD("System reports %zu hubs", hubs.size());
+TEST_P(ContexthubHidlTest, TestGetHubs) {
+ hidl_vec<ContextHub> hubs = getHubsSync(hubApi);
+ ALOGD("System reports %zu hubs", hubs.size());
- for (const ContextHub& hub : hubs) {
- ALOGD("Checking hub ID %" PRIu32, hub.hubId);
+ for (const ContextHub& hub : hubs) {
+ ALOGD("Checking hub ID %" PRIu32, hub.hubId);
- EXPECT_FALSE(hub.name.empty());
- EXPECT_FALSE(hub.vendor.empty());
- EXPECT_FALSE(hub.toolchain.empty());
- EXPECT_GT(hub.peakMips, 0);
- EXPECT_GE(hub.stoppedPowerDrawMw, 0);
- EXPECT_GE(hub.sleepPowerDrawMw, 0);
- EXPECT_GT(hub.peakPowerDrawMw, 0);
+ EXPECT_FALSE(hub.name.empty());
+ EXPECT_FALSE(hub.vendor.empty());
+ EXPECT_FALSE(hub.toolchain.empty());
+ EXPECT_GT(hub.peakMips, 0);
+ EXPECT_GE(hub.stoppedPowerDrawMw, 0);
+ EXPECT_GE(hub.sleepPowerDrawMw, 0);
+ EXPECT_GT(hub.peakPowerDrawMw, 0);
- // Minimum 128 byte MTU as required by CHRE API v1.0
- EXPECT_GE(hub.maxSupportedMsgLen, UINT32_C(128));
- }
+ // Minimum 128 byte MTU as required by CHRE API v1.0
+ EXPECT_GE(hub.maxSupportedMsgLen, UINT32_C(128));
+ }
}
TEST_P(ContexthubHidlTest, TestRegisterCallback) {
@@ -388,20 +364,28 @@
cb->promise.get_future()));
}
-// Parameterize all SingleContexthubTest tests against each valid hub ID
-INSTANTIATE_TEST_CASE_P(HubIdSpecificTests, ContexthubHidlTest,
- ::testing::ValuesIn(getHubIds()));
-INSTANTIATE_TEST_CASE_P(HubIdSpecificTests, ContexthubTxnTest,
- ::testing::ValuesIn(getHubIds()));
+// Return the test parameters of a vecter of tuples for all IContexthub services and each of its hub
+// id: <service name of IContexthub, hub id of the IContexthub service>
+static std::vector<std::tuple<std::string, std::string>> get_parameters() {
+ std::vector<std::tuple<std::string, std::string>> parameters;
+ std::vector<std::string> service_names =
+ android::hardware::getAllHalInstanceNames(IContexthub::descriptor);
+ for (const std::string& service_name : service_names) {
+ std::vector<std::string> ids = getHubIds(service_name);
+ for (const std::string& id : ids) {
+ parameters.push_back(std::make_tuple(service_name, id));
+ }
+ }
-} // anonymous namespace
-
-int main(int argc, char **argv) {
- ::testing::AddGlobalTestEnvironment(ContexthubHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- ContexthubHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI ("Test result = %d", status);
- return status;
+ return parameters;
}
+static std::vector<std::tuple<std::string, std::string>> kTestParameters = get_parameters();
+
+INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
+ android::hardware::PrintInstanceTupleNameToString<>);
+
+INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubTxnTest, testing::ValuesIn(kTestParameters),
+ android::hardware::PrintInstanceTupleNameToString<>);
+
+} // anonymous namespace
diff --git a/current.txt b/current.txt
index 6d1e6c6..8bf63c7 100644
--- a/current.txt
+++ b/current.txt
@@ -298,7 +298,13 @@
3661fa0623056922fdc4235ac5a9c91a2d066ab6f1ab4297e3b240fe302ba500 android.hardware.audio.effect@4.0::IPresetReverbEffect
e88e520f8c98a62fccd8d5316c6687808f775de145d1405a7a9a66587ee6a001 android.hardware.audio.effect@4.0::IVirtualizerEffect
fe28829dab10d171783b79ac9cc45412739f8ff275e90228d7c6370ef189b859 android.hardware.audio.effect@4.0::IVisualizerEffect
-21c8a702579356480236c6851b5b2c16b9bd369ce12bdd6ffdc4626a89f34f73 android.hardware.audio.effect@4.0::types
+21c8a702579356480236c6851b5b2c16b9bd369ce12bdd6ffdc4626a89f34f73 android.hardware.audio.effect@4.0::types
+a0f93c768c353cecee6237fe479bce47404eb10b629fafe07e32a054fd67f2af android.hardware.automotive.audiocontrol@1.0::IAudioControl
+f2904a4c108ad1b93eb2fa4e43b82bd01ce1ff26156316e49d1d9fc80dfecaad android.hardware.automotive.evs@1.0::IEvsCamera
+94cba6ad04c83aa840de2ed52b74ba2126a26dd960225e61ac36703315279a80 android.hardware.automotive.evs@1.0::IEvsCameraStream
+5ea36fb043d9e3b413219de3dfd7b046b48af4fda39f167f3528652e986cb76d android.hardware.automotive.evs@1.0::IEvsDisplay
+b15c5d8f28be4f0469c11d184ebca616895f109d553a6c31018789d8c1bc0ac5 android.hardware.automotive.evs@1.0::IEvsEnumerator
+3b17c1fdfc389e0abe626c37054954b07201127d890c2bc05d47613ec1f4de4f android.hardware.automotive.evs@1.0::types
42a06dc288f61b0690580f3d37b30b663c31d74d50bb58d0772386b550d5faab android.hardware.authsecret@1.0::IAuthSecret
32cc50cc2a7658ec613c0c2dd2accbf6a05113b749852879e818b8b7b438db19 android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioHost
ff4be64d7992f8bec97dff37f35450e79b3430c61f85f54322ce45bef229dc3b android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioOffload
@@ -572,19 +578,50 @@
cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardware.wifi.supplicant@1.2::types
# ABI preserving changes to HALs during Android R
+c3ec182ce325862b7d79e526f3e170c02cfee1497ed309d7c60d0de4ca636b0b android.hardware.automotive.audiocontrol@1.0::IAudioControl
+1b6d0927615ddbf4c56a993fa1845bca15543e315fb6f48c77276e2fa2918ac5 android.hardware.automotive.evs@1.0::IEvsCamera
+3901859d36b7b4d32910d61cd1e8982b0ffeb8fb77b457ac6349e8bf1abcd595 android.hardware.automotive.evs@1.0::IEvsCameraStream
+578f640c653726d58f99c84a7e1bb63862e21ef7cbb4f7d95c3cc62de00dca35 android.hardware.automotive.evs@1.0::IEvsDisplay
+f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardware.automotive.evs@1.0::IEvsEnumerator
+d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types
2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types
+cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types
b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
-f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardware.neuralnetworks@1.0::types
+8eac60e1f724d141c71c69f06d4544acb720a55dfbbcd97fa01bb3d25ee4e2f5 android.hardware.neuralnetworks@1.0::types
5f6d3097ba84cb63c430787123f4de1b31c11f90b531b98eae9a8623a5ae962a android.hardware.neuralnetworks@1.1::types
fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice
40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel
-2d5483fbf59d5fd2de94665a6df05da5c3d09de67561d0db5e9f09e59e9aea46 android.hardware.neuralnetworks@1.2::types
+7f7ef383268c95a1b8fe4e55c662bc806bb0ac11a154f6b049a113a44b0f024f android.hardware.neuralnetworks@1.2::types
a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types
1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
# HALs released in Android R
+e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types
+dd3e9280be60a5e042331c1046d13938e2cc323dc4b267cc74d544bf62fc0314 android.hardware.audio@6.0::IDevice
+2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory
+bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice
+fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardware.audio@6.0::IStream
+2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn
+78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut
+997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback
+8c4232772efeb9905b4c287723e0ee8b2c4bf5ba11728d051171b070e3d79144 android.hardware.audio.common@6.0::types
+817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types
+525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect
+8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect
+461b1114cb35d89f87e5694e0792ba53c112a7fa9a14d9b95188cf9c4764be23 android.hardware.audio.effect@6.0::IBassBoostEffect
+8bc597d166e07e9eba633267fc2872c4c53d13d3f0025b778c98e13324a165de android.hardware.audio.effect@6.0::IDownmixEffect
+9ee022c81e79da6051fde0836c1c1c4d5414e0c9a6cccc0ce17a90346ceb1391 android.hardware.audio.effect@6.0::IEffect
+75c99a70577d543359910a0b378bcbf5a0d6076712e58e6864cd8803f76c8684 android.hardware.audio.effect@6.0::IEffectBufferProviderCallback
+b138d519696f23af2c7cb92c532178c35f4b3a5c1b689260b1c308fe00249f8b android.hardware.audio.effect@6.0::IEffectsFactory
+dd377f404a8e71f6191d295e10067db629b0f0c28e594af906f2bea5d87fe2cc android.hardware.audio.effect@6.0::IEnvironmentalReverbEffect
+455e085e136767302ec34d02b51a085c310e79bf500b76dda7c96a7f3637f11a android.hardware.audio.effect@6.0::IEqualizerEffect
+24b5e107a0cbd2b322f764a4d5f7fb8b5d8c337a060b9a4a26b9af050c57b5d0 android.hardware.audio.effect@6.0::ILoudnessEnhancerEffect
+4aae0a13f53a8ce20fad372de2d1d864a0bae194b0f1b1d2c090367af8615af2 android.hardware.audio.effect@6.0::INoiseSuppressionEffect
+5237c42d3913ef569f07bec802568084b615155d05a7951e75085da54856508c android.hardware.audio.effect@6.0::IPresetReverbEffect
+282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect
+0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect
79e115c8f8970b8b914bafc66df5425e065fda4dcda97222966ef12451d2a1cc android.hardware.bluetooth@1.1::IBluetoothHci
40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks
07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
@@ -595,8 +632,9 @@
4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types
66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory
994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory
-1bd8028b974bf1d65cfa102196a2b008afc5d42fe73fed2cb94fa7533d07f581 android.hardware.gnss@2.1::IGnss
+3dacec7801968e1e4479724dc0180442d9e915466bff051f80996266b1a51c2c android.hardware.gnss@2.1::IGnss
ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback
+ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration
5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement
0bfb291708dd4a7c6ec6b9883e2b8592357edde8d7e962ef83918e4a2154ce69 android.hardware.gnss@2.1::IGnssMeasurementCallback
ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
@@ -608,20 +646,24 @@
df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice
-4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel
+258825966435b3ed08832055bb736d81516013e405f161d9ccde9a90cfcdde83 android.hardware.neuralnetworks@1.3::IPreparedModel
94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types
+35668befe89fc7f84d58fc1dab7dd3e4d6067c7eeccbae154fe36cd964dfaef7 android.hardware.neuralnetworks@1.3::types
3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
+7d136c169b62abdee0bb6abafb97638acd792ce2102dfccddaa5df98d4bd3df9 android.hardware.wifi.hostapd@1.2::IHostapd
+11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types
a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
-44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
-619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
-c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
-9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types
-35cd6586225912718c599421606d69260707e43732d874f2064e28de45c87fac android.hardware.radio@1.5::types
-3f1e2410d9bed4e7d41c6a589fe3a7943bc904b0066e40e0199a7c58427ac4e9 android.hardware.radio@1.5::IRadio
-3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication
-caf00e0d942b77b17d7061b38de11e5b19e1da90d4818434cb4916ba89e30686 android.hardware.radio@1.5::IRadioResponse
+c72cb37b3f66ef65aeb5c6438a3fbe17bbe847fdf62d1a76eafd7f3a8a526105 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
+342a8e12db4dca643f2755eb4167e8f103d96502053a25a1f51f42107a4530f1 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
+5477f8bafb29548875622fa83f1c0a29cee641acee613315eb747731001f4aff android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
+91015479f5a0fba9872e98d3cca4680995de64f42ae71461b4b7e5acc5a196ab android.hardware.wifi.supplicant@1.3::types
+d9044563a5ac5a17a239303b8dec1e51167761ac46e965f61e31654cc034d31b android.hardware.radio@1.5::types
+afa2d6cf4c0ba4b8482d5bcc097594ad5bc49be0bf3003034f75955cdaf66045 android.hardware.radio@1.5::IRadio
+bc59237dbd93949238081f762710552e76670cb648c0e198138551460ac54b1e android.hardware.radio@1.5::IRadioIndication
+f4888f9676890b43a459c6380f335fea7a6ad32ed3bafafeb018a88d6c0be8a4 android.hardware.radio@1.5::IRadioResponse
55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types
b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig
742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse
+c411dc16855fcb786cd5e08fe2889acbd72fd54217bd27fe0373813de230ce5f android.hardware.soundtrigger@2.3::types
+5abad7b54d3400fab633cb7a36ffc1747e037bf805d3d9e3517cb6aabf26b002 android.hardware.soundtrigger@2.3::ISoundTriggerHw
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index 2c8a7b1..88fbff8 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -172,7 +172,54 @@
hasGnssHalVersion_2_0 = registered.size() != 0;
});
- return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0;
+ bool hasGnssHalVersion_2_1 = false;
+ manager->listManifestByInterface(
+ "android.hardware.gnss@2.1::IGnss",
+ [&hasGnssHalVersion_2_1](const hidl_vec<hidl_string>& registered) {
+ hasGnssHalVersion_2_1 = registered.size() != 0;
+ });
+
+ return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0 && !hasGnssHalVersion_2_1;
+}
+
+GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation(
+ const int locations_to_await, const int gnss_sv_info_list_timeout) {
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(locations_to_await);
+ const int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+ EXPECT_GE(sv_status_cbq_size + 1, locations_to_await);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size,
+ locations_to_await, location_called_count);
+
+ // Find first non-GPS constellation to blacklist
+ GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
+ for (int i = 0; i < sv_status_cbq_size; ++i) {
+ IGnssCallback::GnssSvStatus gnss_sv_status;
+ gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, gnss_sv_info_list_timeout);
+ 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) &&
+ (gnss_sv.constellation != GnssConstellationType::UNKNOWN) &&
+ (gnss_sv.constellation != GnssConstellationType::GPS)) {
+ // found a non-GPS constellation
+ constellation_to_blacklist = gnss_sv.constellation;
+ break;
+ }
+ }
+ if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
+ break;
+ }
+ }
+
+ if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
+ ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
+ // Proceed functionally to blacklist something.
+ constellation_to_blacklist = GnssConstellationType::GLONASS;
+ }
+ return constellation_to_blacklist;
}
GnssHalTest::GnssCallback::GnssCallback()
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index 169cd62..88b7723 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -28,6 +28,7 @@
using android::hardware::gnss::V1_0::GnssLocation;
using android::hardware::gnss::common::GnssCallbackEventQueue;
+using android::hardware::gnss::V1_0::GnssConstellationType;
using android::hardware::gnss::V1_0::GnssLocationFlags;
using android::hardware::gnss::V1_1::IGnss;
using android::hardware::gnss::V1_1::IGnssCallback;
@@ -139,6 +140,17 @@
*/
bool IsGnssHalVersion_1_1() const;
+ /*
+ * startLocationAndGetNonGpsConstellation:
+ * 1. Start location
+ * 2. Find and return first non-GPS constellation
+ *
+ * Note that location is not stopped in this method. The client should call
+ * StopAndClearLocations() after the call.
+ */
+ GnssConstellationType startLocationAndGetNonGpsConstellation(
+ const int locations_to_await, const int gnss_sv_info_list_timeout);
+
sp<IGnss> gnss_hal_; // GNSS HAL to call into
sp<GnssCallback> gnss_cb_; // Primary callback interface
};
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 79da84a..e0d8b54 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -352,7 +352,7 @@
}
/*
- * BlacklistConstellation:
+ * BlacklistConstellationWithLocationOff:
*
* 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus for any non-GPS constellations.
@@ -361,50 +361,22 @@
* GnssStatus does not use any constellation but GPS.
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
-TEST_P(GnssHalTest, BlacklistConstellation) {
+TEST_P(GnssHalTest, BlacklistConstellationWithLocationOff) {
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.
- 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);
+ const int kGnssSvStatusTimeout = 2;
// Find first non-GPS constellation to blacklist
- const int kGnssSvStatusTimeout = 2;
- GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
- 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) &&
- (gnss_sv.constellation != GnssConstellationType::UNKNOWN) &&
- (gnss_sv.constellation != GnssConstellationType::GPS)) {
- // found a non-GPS constellation
- constellation_to_blacklist = gnss_sv.constellation;
- break;
- }
- }
- if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
- break;
- }
- }
+ GnssConstellationType constellation_to_blacklist =
+ startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvStatusTimeout);
- if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
- ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
- // Proceed functionally to blacklist something.
- constellation_to_blacklist = GnssConstellationType::GLONASS;
- }
+ // Turns off location
+ StopAndClearLocations();
+
IGnssConfiguration::BlacklistedSource source_to_blacklist;
source_to_blacklist.constellation = constellation_to_blacklist;
source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation
@@ -418,6 +390,7 @@
sources.resize(1);
sources[0] = source_to_blacklist;
+ // setBlacklist when location is off.
auto result = gnss_configuration_hal->setBlacklist(sources);
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
@@ -429,7 +402,80 @@
StartAndCheckLocations(kLocationsToAwait);
// Tolerate 1 less sv status to handle edge cases in reporting.
- sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+ 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", sv_status_cbq_size,
+ kLocationsToAwait);
+ 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) &&
+ (gnss_sv.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);
+}
+
+/*
+ * BlacklistConstellationWithLocationOn:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Blacklist first non-GPS constellation, and turn off location.
+ * 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_P(GnssHalTest, BlacklistConstellationWithLocationOn) {
+ if (!IsGnssHalVersion_1_1()) {
+ ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
+ return;
+ }
+
+ const int kLocationsToAwait = 3;
+ const int kGnssSvStatusTimeout = 2;
+
+ // Find first non-GPS constellation to blacklist
+ GnssConstellationType constellation_to_blacklist =
+ startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvStatusTimeout);
+
+ IGnssConfiguration::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> gnss_configuration_hal = gnss_configuration_hal_return;
+ ASSERT_NE(gnss_configuration_hal, nullptr);
+
+ hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
+ sources.resize(1);
+ sources[0] = source_to_blacklist;
+
+ // setBlacklist when location is still on
+ auto result = gnss_configuration_hal->setBlacklist(sources);
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ // Turns off location
+ StopAndClearLocations();
+
+ // retry and ensure constellation not used
+ gnss_cb_->sv_status_cbq_.reset();
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ 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", sv_status_cbq_size,
kLocationsToAwait);
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp
index 8ca3f68..b3a3203 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -16,11 +16,14 @@
#define LOG_TAG "GnssHalTest"
+#include <android/hidl/manager/1.2/IServiceManager.h>
#include <gnss_hal_test.h>
+#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
#include <chrono>
#include "Utils.h"
-#include <gtest/gtest.h>
+using ::android::hardware::hidl_string;
using ::android::hardware::gnss::common::Utils;
@@ -99,7 +102,6 @@
EXPECT_TRUE(result.isOk());
EXPECT_TRUE(result);
-
/*
* GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
* so allow time to demodulate ephemeris over the air.
@@ -148,6 +150,27 @@
}
}
+bool GnssHalTest::IsGnssHalVersion_2_0() const {
+ using ::android::hidl::manager::V1_2::IServiceManager;
+ sp<IServiceManager> manager = ::android::hardware::defaultServiceManager1_2();
+
+ 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;
+ });
+
+ bool hasGnssHalVersion_2_1 = false;
+ manager->listManifestByInterface(
+ "android.hardware.gnss@2.1::IGnss",
+ [&hasGnssHalVersion_2_1](const hidl_vec<hidl_string>& registered) {
+ hasGnssHalVersion_2_1 = registered.size() != 0;
+ });
+
+ return hasGnssHalVersion_2_0 && !hasGnssHalVersion_2_1;
+}
+
GnssHalTest::GnssCallback::GnssCallback()
: info_cbq_("system_info"),
name_cbq_("name"),
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h
index 4f7b87a..55dc1bc 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.h
+++ b/gnss/2.0/vts/functional/gnss_hal_test.h
@@ -181,6 +181,12 @@
void StopAndClearLocations();
/*
+ * IsGnssHalVersion_2_0:
+ * returns true if the GNSS HAL version is exactly 2.0.
+ */
+ bool IsGnssHalVersion_2_0() const;
+
+ /*
* SetPositionMode:
* Helper function to set positioning mode and verify output
*/
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 c442cc6..0fa08b9 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -182,6 +182,10 @@
* 3. state is valid.
*/
TEST_P(GnssHalTest, TestGnssMeasurementFields) {
+ if (!IsGnssHalVersion_2_0()) {
+ ALOGI("Test GnssMeasurementFields skipped. GNSS HAL version is greater than 2.0.");
+ return;
+ }
const int kFirstGnssMeasurementTimeoutSeconds = 10;
auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0();
@@ -464,7 +468,7 @@
}
EXPECT_LE(location_called_count, i);
if (location_called_count != i) {
- ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
+ ALOGW("GetLocationLowPower test - too many locations received. %d vs. %d expected ",
location_called_count, i);
}
@@ -601,6 +605,11 @@
* formerly strongest satellite
*/
TEST_P(GnssHalTest, BlacklistIndividualSatellites) {
+ if (!IsGnssHalVersion_2_0()) {
+ ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 2.0.");
+ return;
+ }
+
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability"
" not supported.");
@@ -746,6 +755,11 @@
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
TEST_P(GnssHalTest, BlacklistConstellation) {
+ if (!IsGnssHalVersion_2_0()) {
+ ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 2.0.");
+ return;
+ }
+
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
return;
diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp
index 5d3d62d..8b0c374 100644
--- a/gnss/2.1/Android.bp
+++ b/gnss/2.1/Android.bp
@@ -11,6 +11,7 @@
"IGnssCallback.hal",
"IGnssMeasurement.hal",
"IGnssMeasurementCallback.hal",
+ "IGnssConfiguration.hal",
],
interfaces: [
"android.hardware.gnss.measurement_corrections@1.0",
diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal
index 812f9cc..2d63392 100644
--- a/gnss/2.1/IGnss.hal
+++ b/gnss/2.1/IGnss.hal
@@ -20,6 +20,7 @@
import IGnssCallback;
import IGnssMeasurement;
+import IGnssConfiguration;
/**
* Represents the standard GNSS (Global Navigation Satellite System) interface.
@@ -50,4 +51,15 @@
* @return gnssMeasurementIface Handle to the IGnssMeasurement interface.
*/
getExtensionGnssMeasurement_2_1() generates (IGnssMeasurement gnssMeasurementIface);
+
+ /**
+ * This method returns the IGnssConfiguration interface.
+ *
+ * At least one of getExtensionGnssConfiguration(), getExtensionGnssConfiguration_1_1(),
+ * getExtensionGnssConfiguration_2_0(), and getExtensionGnssConfiguration_2_1() methods must
+ * return a non-null handle, and the other methods must return nullptr.
+ *
+ * @return gnssConfigurationIface Handle to the IGnssConfiguration interface.
+ */
+ getExtensionGnssConfiguration_2_1() generates (IGnssConfiguration gnssConfigurationIface);
};
\ No newline at end of file
diff --git a/gnss/2.1/IGnssConfiguration.hal b/gnss/2.1/IGnssConfiguration.hal
new file mode 100644
index 0000000..8360ba9
--- /dev/null
+++ b/gnss/2.1/IGnssConfiguration.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@2.1;
+
+import @2.0::IGnssConfiguration;
+import @2.0::GnssConstellationType;
+
+/**
+ * Extended interface for GNSS Configuration support.
+ */
+interface IGnssConfiguration extends @2.0::IGnssConfiguration {
+ /**
+ * Represents a blacklisted source, updating the GnssConstellationType to 2.0, which supports
+ * IRNSS.
+ */
+ struct BlacklistedSource {
+ /**
+ * Defines the constellation of the given satellite(s).
+ */
+ GnssConstellationType constellation;
+
+ /**
+ * Satellite (space vehicle) ID number, as defined in GnssSvInfo::svid
+ *
+ * Or 0 to blacklist all svid's for the specified constellation
+ */
+ int16_t svid;
+ };
+
+ /**
+ * Injects a vector of BlacklistedSource(s) which the HAL must not use to calculate the
+ * GNSS location output.
+ *
+ * The superset of all satellite sources provided, including wildcards, in the latest call
+ * to this method, is the set of satellites sources that must not be used in calculating
+ * location.
+ *
+ * All measurements from the specified satellites, across frequency bands, are blacklisted
+ * together.
+ *
+ * If this method is never called after the IGnssConfiguration.hal connection is made on boot,
+ * or is called with an empty vector, then no satellites are to be blacklisted as a result of
+ * this API.
+ *
+ * This blacklist must be considered as an additional source of which satellites
+ * should not be trusted for location on top of existing sources of similar information
+ * such as satellite broadcast health being unhealthy and measurement outlier removal.
+ *
+ * @param blacklist The BlacklistedSource(s) of satellites the HAL must not use.
+ *
+ * @return success Whether the HAL accepts and abides by the provided blacklist.
+ */
+ setBlacklist_2_1(vec<BlacklistedSource> blacklist) generates (bool success);
+};
\ No newline at end of file
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
index a7cf63d..7ef9990 100644
--- a/gnss/2.1/default/Android.bp
+++ b/gnss/2.1/default/Android.bp
@@ -23,7 +23,9 @@
srcs: [
"Gnss.cpp",
"GnssMeasurement.cpp",
- "service.cpp"
+ "GnssMeasurementCorrections.cpp",
+ "GnssConfiguration.cpp",
+ "service.cpp",
],
shared_libs: [
"libhidlbase",
diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp
index 2771f27..6b61a82 100644
--- a/gnss/2.1/default/Gnss.cpp
+++ b/gnss/2.1/default/Gnss.cpp
@@ -18,11 +18,14 @@
#include "Gnss.h"
#include "GnssMeasurement.h"
+#include "GnssMeasurementCorrections.h"
#include "Utils.h"
#include <log/log.h>
using ::android::hardware::gnss::common::Utils;
+using ::android::hardware::gnss::measurement_corrections::V1_0::implementation::
+ GnssMeasurementCorrections;
namespace android {
namespace hardware {
@@ -31,8 +34,9 @@
namespace implementation {
sp<V2_1::IGnssCallback> Gnss::sGnssCallback_2_1 = nullptr;
+sp<V2_0::IGnssCallback> Gnss::sGnssCallback_2_0 = nullptr;
-Gnss::Gnss() : mMinIntervalMs(1000) {}
+Gnss::Gnss() : mMinIntervalMs(1000), mGnssConfiguration{new GnssConfiguration()} {}
Gnss::~Gnss() {
stop();
@@ -48,7 +52,7 @@
mIsActive = true;
mThread = std::thread([this]() {
while (mIsActive == true) {
- auto svStatus = Utils::getMockSvInfoListV2_1();
+ auto svStatus = filterBlacklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
this->reportSvStatus(svStatus);
const auto location = Utils::getMockLocationV2_0();
@@ -60,6 +64,16 @@
return true;
}
+hidl_vec<GnssSvInfo> Gnss::filterBlacklistedSatellitesV2_1(hidl_vec<GnssSvInfo> gnssSvInfoList) {
+ for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
+ if (mGnssConfiguration->isBlacklistedV2_1(gnssSvInfoList[i])) {
+ gnssSvInfoList[i].v2_0.v1_0.svFlag &=
+ ~static_cast<uint8_t>(V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX);
+ }
+ }
+ return gnssSvInfoList;
+}
+
Return<bool> Gnss::stop() {
ALOGD("stop");
mIsActive = false;
@@ -76,7 +90,8 @@
}
Return<void> Gnss::cleanup() {
- // TODO implement
+ sGnssCallback_2_1 = nullptr;
+ sGnssCallback_2_0 = nullptr;
return Void();
}
@@ -159,8 +174,9 @@
}
Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode,
- V1_0::IGnss::GnssPositionRecurrence, uint32_t, uint32_t,
- uint32_t, bool) {
+ V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs,
+ uint32_t, uint32_t, bool) {
+ mMinIntervalMs = minIntervalMs;
return true;
}
@@ -180,14 +196,42 @@
}
// Methods from V2_0::IGnss follow.
-Return<bool> Gnss::setCallback_2_0(const sp<V2_0::IGnssCallback>&) {
- // TODO implement
- return bool{};
+Return<bool> Gnss::setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) {
+ ALOGD("Gnss::setCallback_2_0");
+ if (callback == nullptr) {
+ ALOGE("%s: Null callback ignored", __func__);
+ return false;
+ }
+
+ sGnssCallback_2_0 = callback;
+
+ using Capabilities = V2_0::IGnssCallback::Capabilities;
+ const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
+ Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST;
+ auto ret = sGnssCallback_2_0->gnssSetCapabilitiesCb_2_0(capabilities);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2019};
+
+ ret = sGnssCallback_2_0->gnssSetSystemInfoCb(gnssInfo);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ auto gnssName = "Google Mock GNSS Implementation v2.1";
+ ret = sGnssCallback_2_0->gnssNameCb(gnssName);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ return true;
}
Return<sp<V2_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_0() {
- // TODO implement
- return ::android::sp<V2_0::IGnssConfiguration>{};
+ ALOGD("Gnss::getExtensionGnssConfiguration_2_0");
+ return mGnssConfiguration;
}
Return<sp<V2_0::IGnssDebug>> Gnss::getExtensionGnssDebug_2_0() {
@@ -206,14 +250,14 @@
}
Return<sp<V2_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_0() {
- // TODO implement
- return ::android::sp<V2_0::IGnssMeasurement>{};
+ ALOGD("Gnss::getExtensionGnssMeasurement_2_0");
+ return new GnssMeasurement();
}
Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
Gnss::getExtensionMeasurementCorrections() {
- // TODO implement
- return ::android::sp<measurement_corrections::V1_0::IMeasurementCorrections>{};
+ ALOGD("Gnss::getExtensionMeasurementCorrections()");
+ return new GnssMeasurementCorrections();
}
Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> Gnss::getExtensionVisibilityControl() {
@@ -227,7 +271,7 @@
}
Return<bool> Gnss::injectBestLocation_2_0(const V2_0::GnssLocation&) {
- // TODO implement
+ // TODO(b/124012850): Implement function.
return bool{};
}
@@ -270,8 +314,14 @@
return new GnssMeasurement();
}
+Return<sp<V2_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_1() {
+ ALOGD("Gnss::getExtensionGnssConfiguration_2_1");
+ return mGnssConfiguration;
+}
+
void Gnss::reportSvStatus(const hidl_vec<GnssSvInfo>& svInfoList) const {
std::unique_lock<std::mutex> lock(mMutex);
+ // TODO(skz): update this to call 2_0 callback if non-null
if (sGnssCallback_2_1 == nullptr) {
ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
return;
@@ -284,13 +334,20 @@
void Gnss::reportLocation(const V2_0::GnssLocation& location) const {
std::unique_lock<std::mutex> lock(mMutex);
- if (sGnssCallback_2_1 == nullptr) {
- ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
+ if (sGnssCallback_2_1 != nullptr) {
+ auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback v2.1", __func__);
+ }
return;
}
- auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location);
+ if (sGnssCallback_2_0 == nullptr) {
+ ALOGE("%s: No non-null callback", __func__);
+ return;
+ }
+ auto ret = sGnssCallback_2_0->gnssLocationCb_2_0(location);
if (!ret.isOk()) {
- ALOGE("%s: Unable to invoke callback", __func__);
+ ALOGE("%s: Unable to invoke callback v2.0", __func__);
}
}
diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h
index a61f71c..7917bbd 100644
--- a/gnss/2.1/default/Gnss.h
+++ b/gnss/2.1/default/Gnss.h
@@ -22,6 +22,7 @@
#include <atomic>
#include <mutex>
#include <thread>
+#include "GnssConfiguration.h"
namespace android {
namespace hardware {
@@ -87,16 +88,20 @@
// Methods from V2_1::IGnss follow.
Return<bool> setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) override;
Return<sp<V2_1::IGnssMeasurement>> getExtensionGnssMeasurement_2_1() override;
+ Return<sp<V2_1::IGnssConfiguration>> getExtensionGnssConfiguration_2_1() override;
private:
void reportLocation(const V2_0::GnssLocation&) const;
void reportSvStatus(const hidl_vec<GnssSvInfo>&) const;
static sp<V2_1::IGnssCallback> sGnssCallback_2_1;
+ static sp<V2_0::IGnssCallback> sGnssCallback_2_0;
std::atomic<long> mMinIntervalMs;
+ sp<GnssConfiguration> mGnssConfiguration;
std::atomic<bool> mIsActive;
std::thread mThread;
mutable std::mutex mMutex;
+ hidl_vec<GnssSvInfo> filterBlacklistedSatellitesV2_1(hidl_vec<GnssSvInfo> gnssSvInfoList);
};
} // namespace implementation
diff --git a/gnss/2.1/default/GnssConfiguration.cpp b/gnss/2.1/default/GnssConfiguration.cpp
new file mode 100644
index 0000000..cd8f07f
--- /dev/null
+++ b/gnss/2.1/default/GnssConfiguration.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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 "GnssConfiguration"
+
+#include "GnssConfiguration.h"
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setSuplEs(bool enable) {
+ ALOGD("setSuplEs enable: %d", enable);
+ // Method deprecated in 2.0 and not expected to be called by the framework.
+ return false;
+}
+
+Return<bool> GnssConfiguration::setSuplVersion(uint32_t) {
+ return true;
+}
+
+Return<bool> GnssConfiguration::setSuplMode(hidl_bitfield<SuplMode>) {
+ return true;
+}
+
+Return<bool> GnssConfiguration::setGpsLock(hidl_bitfield<GpsLock> gpsLock) {
+ ALOGD("setGpsLock gpsLock: %hhu", static_cast<GpsLock>(gpsLock));
+ // Method deprecated in 2.0 and not expected to be called by the framework.
+ return false;
+}
+
+Return<bool> GnssConfiguration::setLppProfile(hidl_bitfield<LppProfile>) {
+ return true;
+}
+
+Return<bool> GnssConfiguration::setGlonassPositioningProtocol(hidl_bitfield<GlonassPosProtocol>) {
+ return true;
+}
+
+Return<bool> GnssConfiguration::setEmergencySuplPdn(bool) {
+ return true;
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setBlacklist(
+ const hidl_vec<V1_1::IGnssConfiguration::BlacklistedSource>&) {
+ // TODO (b/122463906): Reuse 1.1 implementation.
+ return bool{};
+}
+
+// Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setEsExtensionSec(uint32_t emergencyExtensionSeconds) {
+ ALOGD("setEsExtensionSec emergencyExtensionSeconds: %d", emergencyExtensionSeconds);
+ return true;
+}
+
+// Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setBlacklist_2_1(
+ const hidl_vec<V2_1::IGnssConfiguration::BlacklistedSource>& sourceList) {
+ std::unique_lock<std::recursive_mutex> lock(mMutex);
+ mBlacklistedConstellationSet.clear();
+ mBlacklistedSourceSet.clear();
+ for (auto source : sourceList) {
+ if (source.svid == 0) {
+ // Wildcard blacklist, i.e., blacklist entire constellation.
+ mBlacklistedConstellationSet.insert(source.constellation);
+ } else {
+ mBlacklistedSourceSet.insert(source);
+ }
+ }
+ return true;
+}
+
+Return<bool> GnssConfiguration::isBlacklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const {
+ std::unique_lock<std::recursive_mutex> lock(mMutex);
+ if (mBlacklistedConstellationSet.find(gnssSvInfo.v2_0.constellation) !=
+ mBlacklistedConstellationSet.end()) {
+ return true;
+ }
+ BlacklistedSourceV2_1 source = {.constellation = gnssSvInfo.v2_0.constellation,
+ .svid = gnssSvInfo.v2_0.v1_0.svid};
+ return (mBlacklistedSourceSet.find(source) != mBlacklistedSourceSet.end());
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
\ No newline at end of file
diff --git a/gnss/2.1/default/GnssConfiguration.h b/gnss/2.1/default/GnssConfiguration.h
new file mode 100644
index 0000000..662d61d
--- /dev/null
+++ b/gnss/2.1/default/GnssConfiguration.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
+#define ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
+
+#include <android/hardware/gnss/2.1/IGnssCallback.h>
+#include <android/hardware/gnss/2.1/IGnssConfiguration.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <mutex>
+#include <unordered_set>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using BlacklistedSourceV2_1 =
+ ::android::hardware::gnss::V2_1::IGnssConfiguration::BlacklistedSource;
+using GnssConstellationTypeV2_0 = V2_0::GnssConstellationType;
+using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo;
+
+struct BlacklistedSourceHashV2_1 {
+ inline int operator()(const BlacklistedSourceV2_1& source) const {
+ return int(source.constellation) * 1000 + int(source.svid);
+ }
+};
+
+struct BlacklistedSourceEqualV2_1 {
+ inline bool operator()(const BlacklistedSourceV2_1& s1, const BlacklistedSourceV2_1& s2) const {
+ return (s1.constellation == s2.constellation) && (s1.svid == s2.svid);
+ }
+};
+
+using BlacklistedSourceSetV2_1 =
+ std::unordered_set<BlacklistedSourceV2_1, BlacklistedSourceHashV2_1,
+ BlacklistedSourceEqualV2_1>;
+using BlacklistedConstellationSetV2_1 = std::unordered_set<GnssConstellationTypeV2_0>;
+
+struct GnssConfiguration : public IGnssConfiguration {
+ // Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+ Return<bool> setSuplEs(bool enabled) override;
+ Return<bool> setSuplVersion(uint32_t version) override;
+ Return<bool> setSuplMode(hidl_bitfield<SuplMode> mode) override;
+ Return<bool> setGpsLock(hidl_bitfield<GpsLock> lock) override;
+ Return<bool> setLppProfile(hidl_bitfield<LppProfile> lppProfile) override;
+ Return<bool> setGlonassPositioningProtocol(hidl_bitfield<GlonassPosProtocol> protocol) override;
+ Return<bool> setEmergencySuplPdn(bool enable) override;
+
+ // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+ Return<bool> setBlacklist(
+ const hidl_vec<V1_1::IGnssConfiguration::BlacklistedSource>& blacklist) override;
+
+ std::recursive_mutex& getMutex() const;
+
+ // Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
+ Return<bool> setEsExtensionSec(uint32_t emergencyExtensionSeconds) override;
+
+ // Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow.
+ Return<bool> setBlacklist_2_1(
+ const hidl_vec<V2_1::IGnssConfiguration::BlacklistedSource>& blacklist) override;
+
+ Return<bool> isBlacklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const;
+
+ private:
+ mutable std::recursive_mutex mMutex;
+
+ BlacklistedSourceSetV2_1 mBlacklistedSourceSet;
+ BlacklistedConstellationSetV2_1 mBlacklistedConstellationSet;
+};
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
\ No newline at end of file
diff --git a/gnss/2.1/default/GnssMeasurement.cpp b/gnss/2.1/default/GnssMeasurement.cpp
index ebfa7dd..34e20e5 100644
--- a/gnss/2.1/default/GnssMeasurement.cpp
+++ b/gnss/2.1/default/GnssMeasurement.cpp
@@ -29,7 +29,8 @@
namespace V2_1 {
namespace implementation {
-sp<V2_1::IGnssMeasurementCallback> GnssMeasurement::sCallback = nullptr;
+sp<V2_1::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_1 = nullptr;
+sp<V2_0::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_0 = nullptr;
GnssMeasurement::GnssMeasurement() : mMinIntervalMillis(1000) {}
@@ -48,7 +49,8 @@
ALOGD("close");
std::unique_lock<std::mutex> lock(mMutex);
stop();
- sCallback = nullptr;
+ sCallback_2_1 = nullptr;
+ sCallback_2_0 = nullptr;
return Void();
}
@@ -61,9 +63,18 @@
// Methods from V2_0::IGnssMeasurement follow.
Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_0(
- const sp<V2_0::IGnssMeasurementCallback>&, bool) {
- // TODO implement
- return V1_0::IGnssMeasurement::GnssMeasurementStatus{};
+ const sp<V2_0::IGnssMeasurementCallback>& callback, bool) {
+ ALOGD("setCallback_2_0");
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback_2_0 = callback;
+
+ if (mIsActive) {
+ ALOGW("GnssMeasurement callback already set. Resetting the callback...");
+ stop();
+ }
+ start();
+
+ return V1_0::IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
}
// Methods from V2_1::IGnssMeasurement follow.
@@ -71,7 +82,7 @@
const sp<V2_1::IGnssMeasurementCallback>& callback, bool) {
ALOGD("setCallback_2_1");
std::unique_lock<std::mutex> lock(mMutex);
- sCallback = callback;
+ sCallback_2_1 = callback;
if (mIsActive) {
ALOGW("GnssMeasurement callback already set. Resetting the callback...");
@@ -87,8 +98,13 @@
mIsActive = true;
mThread = std::thread([this]() {
while (mIsActive == true) {
- auto measurement = Utils::getMockMeasurementV2_1();
- this->reportMeasurement(measurement);
+ if (sCallback_2_1 != nullptr) {
+ auto measurement = Utils::getMockMeasurementV2_1();
+ this->reportMeasurement(measurement);
+ } else {
+ auto measurement = Utils::getMockMeasurementV2_0();
+ this->reportMeasurement(measurement);
+ }
std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
}
@@ -103,14 +119,27 @@
}
}
+void GnssMeasurement::reportMeasurement(const GnssDataV2_0& data) {
+ ALOGD("reportMeasurement()");
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (sCallback_2_0 == nullptr) {
+ ALOGE("%s: GnssMeasurement::sCallback_2_0 is null.", __func__);
+ return;
+ }
+ auto ret = sCallback_2_0->gnssMeasurementCb_2_0(data);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
void GnssMeasurement::reportMeasurement(const GnssDataV2_1& data) {
ALOGD("reportMeasurement()");
std::unique_lock<std::mutex> lock(mMutex);
- if (sCallback == nullptr) {
- ALOGE("%s: GnssMeasurement::sCallback is null.", __func__);
+ if (sCallback_2_1 == nullptr) {
+ ALOGE("%s: GnssMeasurement::sCallback_2_1 is null.", __func__);
return;
}
- auto ret = sCallback->gnssMeasurementCb_2_1(data);
+ auto ret = sCallback_2_1->gnssMeasurementCb_2_1(data);
if (!ret.isOk()) {
ALOGE("%s: Unable to invoke callback", __func__);
}
diff --git a/gnss/2.1/default/GnssMeasurement.h b/gnss/2.1/default/GnssMeasurement.h
index ee32903..3ed7bc5 100644
--- a/gnss/2.1/default/GnssMeasurement.h
+++ b/gnss/2.1/default/GnssMeasurement.h
@@ -30,6 +30,7 @@
namespace implementation {
using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData;
+using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData;
using ::android::sp;
using ::android::hardware::hidl_array;
@@ -62,9 +63,11 @@
private:
void start();
void stop();
+ void reportMeasurement(const GnssDataV2_0&);
void reportMeasurement(const GnssDataV2_1&);
- static sp<IGnssMeasurementCallback> sCallback;
+ static sp<V2_1::IGnssMeasurementCallback> sCallback_2_1;
+ static sp<V2_0::IGnssMeasurementCallback> sCallback_2_0;
std::atomic<long> mMinIntervalMillis;
std::atomic<bool> mIsActive;
std::thread mThread;
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.cpp b/gnss/2.1/default/GnssMeasurementCorrections.cpp
new file mode 100644
index 0000000..2bf5601
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurementCorrections.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "GnssMeasurementCorrections"
+
+#include "GnssMeasurementCorrections.h"
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from V1_0::IMeasurementCorrections follow.
+Return<bool> GnssMeasurementCorrections::setCorrections(const MeasurementCorrections& corrections) {
+ ALOGD("setCorrections");
+ ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu, "
+ "satCorrections.size: %d",
+ corrections.latitudeDegrees, corrections.longitudeDegrees, corrections.altitudeMeters,
+ corrections.horizontalPositionUncertaintyMeters,
+ corrections.verticalPositionUncertaintyMeters,
+ static_cast<unsigned long long>(corrections.toaGpsNanosecondsOfWeek),
+ static_cast<int>(corrections.satCorrections.size()));
+ for (auto singleSatCorrection : corrections.satCorrections) {
+ ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d, cfHz: %f, probLos: %f,"
+ " epl: %f, eplUnc: %f",
+ static_cast<int>(singleSatCorrection.singleSatCorrectionFlags),
+ static_cast<int>(singleSatCorrection.constellation),
+ static_cast<int>(singleSatCorrection.svid), singleSatCorrection.carrierFrequencyHz,
+ singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters,
+ singleSatCorrection.excessPathLengthUncertaintyMeters);
+ ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
+ singleSatCorrection.reflectingPlane.latitudeDegrees,
+ singleSatCorrection.reflectingPlane.longitudeDegrees,
+ singleSatCorrection.reflectingPlane.altitudeMeters,
+ singleSatCorrection.reflectingPlane.azimuthDegrees);
+ }
+
+ return true;
+}
+
+Return<bool> GnssMeasurementCorrections::setCallback(
+ const sp<V1_0::IMeasurementCorrectionsCallback>& callback) {
+ using Capabilities = V1_0::IMeasurementCorrectionsCallback::Capabilities;
+ auto ret =
+ callback->setCapabilitiesCb(Capabilities::LOS_SATS | Capabilities::EXCESS_PATH_LENGTH |
+ Capabilities::REFLECTING_PLANE);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ return false;
+ }
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace measurement_corrections
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.h b/gnss/2.1/default/GnssMeasurementCorrections.h
new file mode 100644
index 0000000..4339bed
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurementCorrections.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct GnssMeasurementCorrections : public IMeasurementCorrections {
+ // Methods from V1_0::IMeasurementCorrections follow.
+ Return<bool> setCorrections(const MeasurementCorrections& corrections) override;
+ Return<bool> setCallback(const sp<V1_0::IMeasurementCorrectionsCallback>& callback) override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace measurement_corrections
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp
index 7cfe0db..22268f6 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp
@@ -148,6 +148,47 @@
}
}
+GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation(
+ const int locations_to_await, const int gnss_sv_info_list_timeout) {
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(locations_to_await);
+ 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, locations_to_await);
+ ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
+ sv_info_list_cbq_size, locations_to_await, location_called_count);
+
+ // Find first non-GPS constellation to blacklist
+ GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
+ for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+ hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, gnss_sv_info_list_timeout);
+ for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+ const auto& gnss_sv = sv_info_vec[iSv];
+ if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) &&
+ (gnss_sv.v2_0.constellation != GnssConstellationType::UNKNOWN) &&
+ (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) {
+ // found a non-GPS constellation
+ constellation_to_blacklist = gnss_sv.v2_0.constellation;
+ break;
+ }
+ }
+ if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
+ break;
+ }
+ }
+
+ if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
+ ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
+ // Proceed functionally to blacklist something.
+ constellation_to_blacklist = GnssConstellationType::GLONASS;
+ }
+
+ return constellation_to_blacklist;
+}
+
GnssHalTest::GnssCallback::GnssCallback()
: info_cbq_("system_info"),
name_cbq_("name"),
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h
index 2e1add0..6b67e13 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test.h
+++ b/gnss/2.1/vts/functional/gnss_hal_test.h
@@ -28,6 +28,7 @@
using android::hardware::gnss::common::GnssCallbackEventQueue;
using android::hardware::gnss::V1_0::GnssLocationFlags;
+using android::hardware::gnss::V2_0::GnssConstellationType;
using android::hardware::gnss::V2_1::IGnss;
using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation;
@@ -184,6 +185,17 @@
*/
void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
+ /*
+ * startLocationAndGetNonGpsConstellation:
+ * 1. Start location
+ * 2. Find and return first non-GPS constellation
+ *
+ * Note that location is not stopped in this method. The client should call
+ * StopAndClearLocations() after the call.
+ */
+ GnssConstellationType startLocationAndGetNonGpsConstellation(
+ const int locations_to_await, const int gnss_sv_info_list_timeout);
+
sp<IGnss> gnss_hal_; // GNSS HAL to call into
sp<GnssCallback> gnss_cb_; // Primary callback interface
};
diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
index ef8249b..2c51717 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
@@ -30,6 +30,13 @@
using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
+using IGnssConfiguration_2_1 = android::hardware::gnss::V2_1::IGnssConfiguration;
+using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
+using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
+using IGnssConfiguration_1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
+
+using android::hardware::gnss::V2_0::GnssConstellationType;
+using android::hardware::gnss::V2_1::IGnssConfiguration;
/*
* SetupTeardownCreateCleanup:
@@ -61,6 +68,27 @@
}
/*
+ * TestGnssConfigurationExtension:
+ * Gets the GnssConfigurationExtension and verifies that it returns an actual extension.
+ */
+TEST_P(GnssHalTest, TestGnssConfigurationExtension) {
+ auto gnssConfiguration_2_1 = gnss_hal_->getExtensionGnssConfiguration_2_1();
+ auto gnssConfiguration_2_0 = gnss_hal_->getExtensionGnssConfiguration_2_0();
+ auto gnssConfiguration_1_1 = gnss_hal_->getExtensionGnssConfiguration_1_1();
+ auto gnssConfiguration_1_0 = gnss_hal_->getExtensionGnssConfiguration();
+ ASSERT_TRUE(gnssConfiguration_2_1.isOk() && gnssConfiguration_2_0.isOk() &&
+ gnssConfiguration_1_1.isOk() && gnssConfiguration_1_0.isOk());
+ sp<IGnssConfiguration_2_1> iGnssConfig_2_1 = gnssConfiguration_2_1;
+ sp<IGnssConfiguration_2_0> iGnssConfig_2_0 = gnssConfiguration_2_0;
+ sp<IGnssConfiguration_1_1> iGnssConfig_1_1 = gnssConfiguration_1_1;
+ sp<IGnssConfiguration_1_0> iGnssConfig_1_0 = gnssConfiguration_1_0;
+ // At least one interface is non-null.
+ int numNonNull = (int)(iGnssConfig_2_1 != nullptr) + (int)(iGnssConfig_2_0 != nullptr) +
+ (int)(iGnssConfig_1_1 != nullptr) + (int)(iGnssConfig_1_0 != nullptr);
+ ASSERT_TRUE(numNonNull >= 1);
+}
+
+/*
* TestGnssMeasurementFields:
* Sets a GnssMeasurementCallback, waits for a measurement, and verifies
* 1. basebandCN0DbHz is valid
@@ -126,3 +154,383 @@
ASSERT_TRUE(nonZeroCn0Found);
StopAndClearLocations();
}
+
+/*
+ * 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
+ * TODO(skz): create a template for this to reduce code duplication of v2.1 and v2.0 since both
+ * are using vectors.
+ */
+IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource(
+ const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list,
+ const int min_observations) {
+ struct ComparableBlacklistedSource {
+ IGnssConfiguration::BlacklistedSource id;
+
+ ComparableBlacklistedSource() {
+ id.constellation = GnssConstellationType::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_vec : sv_info_list) {
+ for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+ const auto& gnss_sv = sv_info_vec[iSv];
+ if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) &&
+ (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) {
+ ComparableBlacklistedSource source;
+ source.id.svid = gnss_sv.v2_0.v1_0.svid;
+ source.id.constellation = gnss_sv.v2_0.constellation;
+
+ const auto& itSignal = mapSignals.find(source);
+ if (itSignal == mapSignals.end()) {
+ SignalCounts counts;
+ counts.observations = 1;
+ counts.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
+ mapSignals.insert(
+ std::pair<ComparableBlacklistedSource, SignalCounts>(source, counts));
+ } else {
+ itSignal->second.observations++;
+ if (itSignal->second.max_cn0_dbhz < gnss_sv.v2_0.v1_0.cN0Dbhz) {
+ itSignal->second.max_cn0_dbhz = gnss_sv.v2_0.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_P(GnssHalTest, BlacklistIndividualSatellites) {
+ 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 GnssSvInfo, 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 kGnssSvInfoListTimeout = 2;
+ std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_vec_list;
+ int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec_list, sv_info_list_cbq_size,
+ kGnssSvInfoListTimeout);
+
+ ASSERT_EQ(count, sv_info_list_cbq_size);
+
+ IGnssConfiguration::BlacklistedSource source_to_blacklist =
+ FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1);
+
+ if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) {
+ // Cannot find a non-GPS satellite. Let the test pass.
+ ALOGD("Cannot find a non-GPS satellite. Letting the test pass.");
+ return;
+ }
+
+ // Stop locations, blacklist the common SV
+ StopAndClearLocations();
+
+ auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_1();
+ ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+ sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
+ ASSERT_NE(gnss_configuration_hal, nullptr);
+
+ hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
+ sources.resize(1);
+ sources[0] = source_to_blacklist;
+
+ auto result = gnss_configuration_hal->setBlacklist_2_1(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 GnssSvInfo, 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_1::GnssSvInfo> sv_info_vec;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+ for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+ const auto& gnss_sv = sv_info_vec[iSv];
+ EXPECT_FALSE((gnss_sv.v2_0.v1_0.svid == source_to_blacklist.svid) &&
+ (gnss_sv.v2_0.constellation == source_to_blacklist.constellation) &&
+ (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::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_2_1(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 GnssSvInfo, 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_1::GnssSvInfo> sv_info_vec;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+ for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+ const auto& gnss_sv = sv_info_vec[iSv];
+ if ((gnss_sv.v2_0.v1_0.svid == source_to_blacklist.svid) &&
+ (gnss_sv.v2_0.constellation == source_to_blacklist.constellation) &&
+ (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)) {
+ strongest_sv_is_reobserved = true;
+ break;
+ }
+ }
+ if (strongest_sv_is_reobserved) break;
+ }
+ }
+ EXPECT_TRUE(strongest_sv_is_reobserved);
+ StopAndClearLocations();
+}
+
+/*
+ * BlacklistConstellationLocationOff:
+ *
+ * 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_P(GnssHalTest, BlacklistConstellationLocationOff) {
+ const int kLocationsToAwait = 3;
+ const int kGnssSvInfoListTimeout = 2;
+
+ // Find first non-GPS constellation to blacklist
+ GnssConstellationType constellation_to_blacklist =
+ startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout);
+
+ // Turns off location
+ StopAndClearLocations();
+
+ IGnssConfiguration::BlacklistedSource source_to_blacklist_1;
+ source_to_blacklist_1.constellation = constellation_to_blacklist;
+ source_to_blacklist_1.svid = 0; // documented wildcard for all satellites in this constellation
+
+ // IRNSS was added in 2.0. Always attempt to blacklist IRNSS to verify that the new enum is
+ // supported.
+ IGnssConfiguration::BlacklistedSource source_to_blacklist_2;
+ source_to_blacklist_2.constellation = GnssConstellationType::IRNSS;
+ source_to_blacklist_2.svid = 0; // documented wildcard for all satellites in this constellation
+
+ auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_1();
+ ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+ sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
+ ASSERT_NE(gnss_configuration_hal, nullptr);
+
+ hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
+ sources.resize(2);
+ sources[0] = source_to_blacklist_1;
+ sources[1] = source_to_blacklist_2;
+
+ auto result = gnss_configuration_hal->setBlacklist_2_1(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.
+ 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 GnssSvInfo, 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_1::GnssSvInfo> sv_info_vec;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+ for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+ const auto& gnss_sv = sv_info_vec[iSv];
+ EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_1.constellation) &&
+ (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+ EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_2.constellation) &&
+ (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+ }
+ }
+
+ // clean up
+ StopAndClearLocations();
+ sources.resize(0);
+ result = gnss_configuration_hal->setBlacklist_2_1(sources);
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+}
+
+/*
+ * BlacklistConstellationLocationOn:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Blacklist first non-GPS constellation, and turn off location.
+ * 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_P(GnssHalTest, BlacklistConstellationLocationOn) {
+ const int kLocationsToAwait = 3;
+ const int kGnssSvInfoListTimeout = 2;
+
+ // Find first non-GPS constellation to blacklist
+ GnssConstellationType constellation_to_blacklist =
+ startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout);
+
+ IGnssConfiguration::BlacklistedSource source_to_blacklist_1;
+ source_to_blacklist_1.constellation = constellation_to_blacklist;
+ source_to_blacklist_1.svid = 0; // documented wildcard for all satellites in this constellation
+
+ // IRNSS was added in 2.0. Always attempt to blacklist IRNSS to verify that the new enum is
+ // supported.
+ IGnssConfiguration::BlacklistedSource source_to_blacklist_2;
+ source_to_blacklist_2.constellation = GnssConstellationType::IRNSS;
+ source_to_blacklist_2.svid = 0; // documented wildcard for all satellites in this constellation
+
+ auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_1();
+ ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+ sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
+ ASSERT_NE(gnss_configuration_hal, nullptr);
+
+ hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
+ sources.resize(2);
+ sources[0] = source_to_blacklist_1;
+ sources[1] = source_to_blacklist_2;
+
+ auto result = gnss_configuration_hal->setBlacklist_2_1(sources);
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ // Turns off location
+ StopAndClearLocations();
+
+ // 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.
+ 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 GnssSvInfo, 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_1::GnssSvInfo> sv_info_vec;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+ for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+ const auto& gnss_sv = sv_info_vec[iSv];
+ EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_1.constellation) &&
+ (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+ EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_2.constellation) &&
+ (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+ }
+ }
+
+ // clean up
+ StopAndClearLocations();
+ sources.resize(0);
+ result = gnss_configuration_hal->setBlacklist_2_1(sources);
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+}
\ No newline at end of file
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index 6c6d696..ccb91b1 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -175,6 +175,11 @@
25.0, 66.0, 247.0),
V2_0::GnssConstellationType::GLONASS),
20.0),
+ getMockSvInfoV2_1(
+ getMockSvInfoV2_0(getMockSvInfoV1_0(3, V1_0::GnssConstellationType::UNKNOWN,
+ 22.0, 35.0, 112.0),
+ V2_0::GnssConstellationType::IRNSS),
+ 19.7),
};
return gnssSvInfoList;
}
diff --git a/graphics/allocator/4.0/IAllocator.hal b/graphics/allocator/4.0/IAllocator.hal
index 9931685..7934867 100644
--- a/graphics/allocator/4.0/IAllocator.hal
+++ b/graphics/allocator/4.0/IAllocator.hal
@@ -20,14 +20,6 @@
interface IAllocator {
/**
- * Retrieves implementation-defined debug information, which will be
- * displayed during, for example, `dumpsys SurfaceFlinger`.
- *
- * @return debugInfo is a string of debug information.
- */
- dumpDebugInfo() generates (string debugInfo);
-
- /**
* Allocates buffers with the properties specified by the descriptor.
*
* Allocations should be optimized for usage bits provided in the
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index e0c7674..601cabc 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -1,5 +1,5 @@
aidl_interface {
- name: "vintf-graphics-common",
+ name: "android.hardware.graphics.common",
host_supported: true,
vendor_available: true,
vndk: {
@@ -10,6 +10,9 @@
"android/hardware/graphics/common/*.aidl",
],
stability: "vintf",
+ imports: [
+ "android.hardware.common",
+ ],
backend: {
java: {
enabled: false,
diff --git a/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
new file mode 100644
index 0000000..5f9888a
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
@@ -0,0 +1,114 @@
+/*
+ * 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.common;
+
+/**
+ * Buffer usage definitions.
+ */
+@VintfStability
+@Backing(type="long")
+enum BufferUsage {
+ /** bit 0-3 is an enum */
+ CPU_READ_MASK = 0xf,
+ /** buffer is never read by CPU */
+ CPU_READ_NEVER = 0,
+ /** buffer is rarely read by CPU */
+ CPU_READ_RARELY = 2,
+ /** buffer is often read by CPU */
+ CPU_READ_OFTEN = 3,
+
+ /** bit 4-7 is an enum */
+ CPU_WRITE_MASK = 0xf << 4,
+ /** buffer is never written by CPU */
+ CPU_WRITE_NEVER = 0 << 4,
+ /** buffer is rarely written by CPU */
+ CPU_WRITE_RARELY = 2 << 4,
+ /** buffer is often written by CPU */
+ CPU_WRITE_OFTEN = 3 << 4,
+
+ /** buffer is used as a GPU texture */
+ GPU_TEXTURE = 1 << 8,
+
+ /** buffer is used as a GPU render target */
+ GPU_RENDER_TARGET = 1 << 9,
+
+ /** bit 10 must be zero */
+
+ /** buffer is used as a composer HAL overlay layer */
+ COMPOSER_OVERLAY = 1 << 11,
+ /** buffer is used as a composer HAL client target */
+ COMPOSER_CLIENT_TARGET = 1 << 12,
+
+ /** bit 13 must be zero */
+
+ /**
+ * Buffer is allocated with hardware-level protection against copying the
+ * contents (or information derived from the contents) into unprotected
+ * memory.
+ */
+ PROTECTED = 1 << 14,
+
+ /** buffer is used as a hwcomposer HAL cursor layer */
+ COMPOSER_CURSOR = 1 << 15,
+
+ /** buffer is used as a video encoder input */
+ VIDEO_ENCODER = 1 << 16,
+
+ /** buffer is used as a camera HAL output */
+ CAMERA_OUTPUT = 1 << 17,
+
+ /** buffer is used as a camera HAL input */
+ CAMERA_INPUT = 1 << 18,
+
+ /** bit 19 must be zero */
+
+ /** buffer is used as a renderscript allocation */
+ RENDERSCRIPT = 1 << 20,
+
+ /** bit 21 must be zero */
+
+ /** buffer is used as a video decoder output */
+ VIDEO_DECODER = 1 << 22,
+
+ /** buffer is used as a sensor direct report output */
+ SENSOR_DIRECT_DATA = 1 << 23,
+
+ /** buffer is used as a cube map texture */
+ GPU_CUBE_MAP = 1 << 25,
+
+ /** buffer contains a complete mipmap hierarchy */
+ GPU_MIPMAP_COMPLETE = 1 << 26,
+
+ /**
+ * Buffer is used as input for HEIC encoder.
+ */
+ HW_IMAGE_ENCODER = 1 << 27,
+
+ /**
+ * buffer is used as as an OpenGL shader storage or uniform
+ * buffer object
+ */
+ GPU_DATA_BUFFER = 1 << 24,
+
+ /** bits 25-27 must be zero and are reserved for future versions */
+ /** bits 28-31 are reserved for vendor extensions */
+ VENDOR_MASK = 0xf << 28,
+
+ /** bits 32-47 must be zero and are reserved for future versions */
+ /** bits 48-63 are reserved for vendor extensions */
+ VENDOR_MASK_HI = 0xffff << 48,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl
new file mode 100644
index 0000000..4fbc6b2
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl
@@ -0,0 +1,34 @@
+/**
+ * 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.graphics.common;
+
+/**
+ * HDR static metadata extension as specified by CTA-861.3.
+ *
+ * This is an AIDL counterpart of the NDK struct `AHdrMetadata_cta861_3`.
+ */
+@VintfStability
+parcelable Cta861_3 {
+ /**
+ * Maximum content light level.
+ */
+ float maxContentLightLevel;
+ /**
+ * Maximum frame average light level.
+ */
+ float maxFrameAverageLightLevel;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
index 81a21ab..42cdd81 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
@@ -208,8 +208,6 @@
*/
STANDARD_ADOBE_RGB = 11 << 16, // 11 << STANDARD_SHIFT
-
-
TRANSFER_SHIFT = 22,
/**
@@ -396,9 +394,7 @@
* The values are encoded using the full range ([0,255] for 8-bit) for all
* components.
*/
- SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // deprecated, use V0_SRGB_LINEAR
-
- V0_SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
+ SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
/**
@@ -413,7 +409,7 @@
* Values beyond the range [0.0 - 1.0] would correspond to other colors
* spaces and/or HDR content.
*/
- V0_SCRGB_LINEAR = 1 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
+ SCRGB_LINEAR = 1 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
/**
@@ -429,9 +425,7 @@
*
* Use full range and BT.709 standard.
*/
- SRGB = 1 << 16 | 2 << 22 | 1 << 27, // deprecated, use V0_SRGB
-
- V0_SRGB = 1 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
+ SRGB = 1 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
/**
@@ -446,7 +440,7 @@
* Values beyond the range [0.0 - 1.0] would correspond to other colors
* spaces and/or HDR content.
*/
- V0_SCRGB = 1 << 16 | 2 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
+ SCRGB = 1 << 16 | 2 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
/**
* YCbCr Colorspaces
@@ -464,22 +458,18 @@
*
* Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
*
- * Use full range, BT.601 transfer and BT.601_625 standard.
+ * Use full range, SMPTE 170M transfer and BT.601_625 standard.
*/
- JFIF = 2 << 16 | 3 << 22 | 1 << 27, // deprecated, use V0_JFIF
-
- V0_JFIF = 2 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
+ JFIF = 2 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
/**
* ITU-R Recommendation 601 (BT.601) - 625-line
*
* Standard-definition television, 625 Lines (PAL)
*
- * Use limited range, BT.601 transfer and BT.601_625 standard.
+ * Use limited range, SMPTE 170M transfer and BT.601_625 standard.
*/
- BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_625
-
- V0_BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+ BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
/**
@@ -487,22 +477,18 @@
*
* Standard-definition television, 525 Lines (NTSC)
*
- * Use limited range, BT.601 transfer and BT.601_525 standard.
+ * Use limited range, SMPTE 170M transfer and BT.601_525 standard.
*/
- BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_525
-
- V0_BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+ BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
/**
* ITU-R Recommendation 709 (BT.709)
*
* High-definition television
*
- * Use limited range, BT.709 transfer and BT.709 standard.
+ * Use limited range, SMPTE 170M transfer and BT.709 standard.
*/
- BT709 = 1 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT709
-
- V0_BT709 = 1 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+ BT709 = 1 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
/**
@@ -570,7 +556,7 @@
*
* Ultra High-definition television
*
- * Use full range, BT.709 transfer and BT2020 standard
+ * Use full range, SMPTE 170M transfer and BT2020 standard
*/
BT2020 = 6 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL
@@ -622,7 +608,7 @@
*
* Ultra High-definition television
*
- * Use limited range, BT.709 transfer and BT2020 standard
+ * Use limited range, SMPTE 170M transfer and BT2020 standard
*/
BT2020_ITU = 6 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_LIMITED
@@ -679,4 +665,13 @@
* according to ISO/IEC 23008-12.
*/
HEIF = 0x1004,
+
+ /**
+ * ITU-R Recommendation 709 (BT.709)
+ *
+ * High-definition television
+ *
+ * Use full range, SMPTE 170M transfer and BT.709 standard.
+ */
+ BT709_FULL_RANGE = 1 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_FULL
}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl b/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl
new file mode 100644
index 0000000..5a22c0f
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.common;
+
+import android.hardware.common.NativeHandle;
+import android.hardware.graphics.common.HardwareBufferDescription;
+
+/**
+ * Stable AIDL counterpart of AHardwareBuffer.
+ *
+ * @note This is different from the public HardwareBuffer.
+ * @sa +ndk libnativewindow#AHardwareBuffer
+ */
+@VintfStability
+parcelable HardwareBuffer {
+ HardwareBufferDescription description;
+ NativeHandle handle;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl b/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl
new file mode 100644
index 0000000..e1e3492
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.common;
+
+import android.hardware.graphics.common.BufferUsage;
+import android.hardware.graphics.common.PixelFormat;
+
+/**
+ * Stable AIDL counterpart of AHardwareBuffer_Desc.
+ *
+ * @sa +ndk libnativewindow#AHardwareBuffer_Desc
+ */
+@VintfStability
+parcelable HardwareBufferDescription {
+ int width;
+ int height;
+ int layers;
+ PixelFormat format;
+ BufferUsage usage;
+ int stride;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
new file mode 100644
index 0000000..4942462
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
@@ -0,0 +1,516 @@
+/*
+ * 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.common;
+
+/**
+ * Pixel formats for graphics buffers.
+ */
+@VintfStability
+@Backing(type="int")
+enum PixelFormat {
+ /**
+ * This value may be used in an operation where the format is optional.
+ */
+ UNSPECIFIED = 0,
+ /**
+ * 32-bit format that has 8-bit R, G, B, and A components, in that order,
+ * from the lowest memory address to the highest memory address.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ RGBA_8888 = 0x1,
+
+ /**
+ * 32-bit format that has 8-bit R, G, B, and unused components, in that
+ * order, from the lowest memory address to the highest memory address.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ RGBX_8888 = 0x2,
+
+ /**
+ * 24-bit format that has 8-bit R, G, and B components, in that order,
+ * from the lowest memory address to the highest memory address.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ RGB_888 = 0x3,
+
+ /**
+ * 16-bit packed format that has 5-bit R, 6-bit G, and 5-bit B components,
+ * in that order, from the most-sigfinicant bits to the least-significant
+ * bits.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ RGB_565 = 0x4,
+
+ /**
+ * 32-bit format that has 8-bit B, G, R, and A components, in that order,
+ * from the lowest memory address to the highest memory address.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ BGRA_8888 = 0x5,
+
+ /**
+ * Legacy formats deprecated in favor of YCBCR_420_888.
+ */
+ YCBCR_422_SP = 0x10, // NV16
+ YCRCB_420_SP = 0x11, // NV21
+ YCBCR_422_I = 0x14, // YUY2
+
+ /**
+ * 64-bit format that has 16-bit R, G, B, and A components, in that order,
+ * from the lowest memory address to the highest memory address.
+ *
+ * The component values are signed floats, whose interpretation is defined
+ * by the dataspace.
+ */
+ RGBA_FP16 = 0x16,
+
+ /**
+ * RAW16 is a single-channel, 16-bit, little endian format, typically
+ * representing raw Bayer-pattern images from an image sensor, with minimal
+ * processing.
+ *
+ * The exact pixel layout of the data in the buffer is sensor-dependent, and
+ * needs to be queried from the camera device.
+ *
+ * Generally, not all 16 bits are used; more common values are 10 or 12
+ * bits. If not all bits are used, the lower-order bits are filled first.
+ * All parameters to interpret the raw data (black and white points,
+ * color space, etc) must be queried from the camera device.
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ * - strides are specified in pixels, not in bytes
+ *
+ * size = stride * height * 2
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ * - BufferUsage::RENDERSCRIPT
+ *
+ * The mapping of the dataspace to buffer contents for RAW16 is as
+ * follows:
+ *
+ * Dataspace value | Buffer contents
+ * -------------------------------+-----------------------------------------
+ * Dataspace::ARBITRARY | Raw image sensor data, layout is as
+ * | defined above.
+ * Dataspace::DEPTH | Unprocessed implementation-dependent raw
+ * | depth measurements, opaque with 16 bit
+ * | samples.
+ * Other | Unsupported
+ */
+ RAW16 = 0x20,
+
+ /**
+ * BLOB is used to carry task-specific data which does not have a standard
+ * image structure. The details of the format are left to the two
+ * endpoints.
+ *
+ * A typical use case is for transporting JPEG-compressed images from the
+ * Camera HAL to the framework or to applications.
+ *
+ * Buffers of this format must have a height of 1, and width equal to their
+ * size in bytes.
+ *
+ * The mapping of the dataspace to buffer contents for BLOB is as
+ * follows:
+ *
+ * Dataspace value | Buffer contents
+ * -------------------------------+-----------------------------------------
+ * Dataspace::JFIF | An encoded JPEG image
+ * Dataspace::DEPTH | An android_depth_points buffer
+ * Dataspace::SENSOR | Sensor event data.
+ * Other | Unsupported
+ */
+ BLOB = 0x21,
+
+ /**
+ * A format indicating that the choice of format is entirely up to the
+ * allocator.
+ *
+ * The allocator should examine the usage bits passed in when allocating a
+ * buffer with this format, and it should derive the pixel format from
+ * those usage flags. This format must never be used with any of the
+ * BufferUsage::CPU_* usage flags.
+ *
+ * Even when the internally chosen format has an alpha component, the
+ * clients must assume the alpha vlaue to be 1.0.
+ *
+ * The interpretation of the component values is defined by the dataspace.
+ */
+ IMPLEMENTATION_DEFINED = 0x22,
+
+ /**
+ * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:0
+ * buffer layout, while still describing the general format in a
+ * layout-independent manner. While called YCbCr, it can be used to
+ * describe formats with either chromatic ordering, as well as
+ * whole planar or semiplanar layouts.
+ *
+ * This format must be accepted by the allocator when BufferUsage::CPU_*
+ * are set.
+ *
+ * Buffers with this format must be locked with IMapper::lockYCbCr.
+ * Locking with IMapper::lock must return an error.
+ *
+ * The interpretation of the component values is defined by the dataspace.
+ */
+ YCBCR_420_888 = 0x23,
+
+ /**
+ * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an
+ * image sensor. The actual structure of buffers of this format is
+ * implementation-dependent.
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ * - BufferUsage::RENDERSCRIPT
+ *
+ * The mapping of the dataspace to buffer contents for RAW_OPAQUE is as
+ * follows:
+ *
+ * Dataspace value | Buffer contents
+ * -------------------------------+-----------------------------------------
+ * Dataspace::ARBITRARY | Raw image sensor data.
+ * Other | Unsupported
+ */
+ RAW_OPAQUE = 0x24,
+
+ /**
+ * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row,
+ * unprocessed format, usually representing raw Bayer-pattern images coming from
+ * an image sensor.
+ *
+ * In an image buffer with this format, starting from the first pixel of each
+ * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one
+ * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte
+ * contains the 2 least significant bits of the 4 pixels, the exact layout data
+ * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth
+ * bit of the ith pixel):
+ *
+ * bit 7 bit 0
+ * =====|=====|=====|=====|=====|=====|=====|=====|
+ * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]|
+ * ===============================================
+ *
+ * This format assumes
+ * - a width multiple of 4 pixels
+ * - an even height
+ * - a vertical stride equal to the height
+ * - strides are specified in bytes, not in pixels
+ *
+ * size = stride * height
+ *
+ * When stride is equal to width * (10 / 8), there will be no padding bytes at
+ * the end of each row, the entire image data is densely packed. When stride is
+ * larger than width * (10 / 8), padding bytes will be present at the end of each
+ * row (including the last row).
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ * - BufferUsage::RENDERSCRIPT
+ *
+ * The mapping of the dataspace to buffer contents for RAW10 is as
+ * follows:
+ *
+ * Dataspace value | Buffer contents
+ * -------------------------------+-----------------------------------------
+ * Dataspace::ARBITRARY | Raw image sensor data.
+ * Other | Unsupported
+ */
+ RAW10 = 0x25,
+
+ /**
+ * RAW12 is a single-channel, 12-bit per pixel, densely packed in each row,
+ * unprocessed format, usually representing raw Bayer-pattern images coming from
+ * an image sensor.
+ *
+ * In an image buffer with this format, starting from the first pixel of each
+ * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first
+ * and second byte contains the top 8 bits of first and second pixel. The third
+ * byte contains the 4 least significant bits of the two pixels, the exact layout
+ * data for each two consecutive pixels is illustrated below (Pi[j] stands for
+ * the jth bit of the ith pixel):
+ *
+ * bit 7 bit 0
+ * ======|======|======|======|======|======|======|======|
+ * Byte 0: |P0[11]|P0[10]|P0[ 9]|P0[ 8]|P0[ 7]|P0[ 6]|P0[ 5]|P0[ 4]|
+ * |------|------|------|------|------|------|------|------|
+ * Byte 1: |P1[11]|P1[10]|P1[ 9]|P1[ 8]|P1[ 7]|P1[ 6]|P1[ 5]|P1[ 4]|
+ * |------|------|------|------|------|------|------|------|
+ * Byte 2: |P1[ 3]|P1[ 2]|P1[ 1]|P1[ 0]|P0[ 3]|P0[ 2]|P0[ 1]|P0[ 0]|
+ * =======================================================
+ *
+ * This format assumes:
+ * - a width multiple of 4 pixels
+ * - an even height
+ * - a vertical stride equal to the height
+ * - strides are specified in bytes, not in pixels
+ *
+ * size = stride * height
+ *
+ * When stride is equal to width * (12 / 8), there will be no padding bytes at
+ * the end of each row, the entire image data is densely packed. When stride is
+ * larger than width * (12 / 8), padding bytes will be present at the end of
+ * each row (including the last row).
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ * - BufferUsage::RENDERSCRIPT
+ *
+ * The mapping of the dataspace to buffer contents for RAW12 is as
+ * follows:
+ *
+ * Dataspace value | Buffer contents
+ * -------------------------------+-----------------------------------------
+ * Dataspace::ARBITRARY | Raw image sensor data.
+ * Other | Unsupported
+ */
+ RAW12 = 0x26,
+
+ /** 0x27 to 0x2A are reserved for flexible formats */
+
+ /**
+ * 32-bit packed format that has 2-bit A, 10-bit B, G, and R components,
+ * in that order, from the most-sigfinicant bits to the least-significant
+ * bits.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ RGBA_1010102 = 0x2B,
+
+ /**
+ * 0x100 - 0x1FF
+ *
+ * This range is reserved for vendor extensions. Formats in this range
+ * must support BufferUsage::GPU_TEXTURE. Clients must assume they do not
+ * have an alpha component.
+ */
+
+ /**
+ * Y8 is a YUV planar format comprised of a WxH Y plane, with each pixel
+ * being represented by 8 bits. It is equivalent to just the Y plane from
+ * YV12.
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ *
+ * size = stride * height
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ Y8 = 0x20203859,
+
+ /**
+ * Y16 is a YUV planar format comprised of a WxH Y plane, with each pixel
+ * being represented by 16 bits. It is just like Y8, but has double the
+ * bits per pixel (little endian).
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ * - strides are specified in pixels, not in bytes
+ *
+ * size = stride * height * 2
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace. When the dataspace is
+ * Dataspace::DEPTH, each pixel is a distance value measured by a depth
+ * camera, plus an associated confidence value.
+ */
+ Y16 = 0x20363159,
+
+ /**
+ * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed
+ * by (W/2) x (H/2) Cr and Cb planes.
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ *
+ * y_size = stride * height
+ * c_stride = ALIGN(stride/2, 16)
+ * c_size = c_stride * height/2
+ * size = y_size + c_size * 2
+ * cr_offset = y_size
+ * cb_offset = y_size + c_size
+ *
+ * This range is reserved for vendor extensions. Formats in this range
+ * must support BufferUsage::GPU_TEXTURE. Clients must assume they do not
+ * have an alpha component.
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::CAMERA_*
+ * - BufferUsage::CPU_*
+ * - BufferUsage::GPU_TEXTURE
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ YV12 = 0x32315659, // YCrCb 4:2:0 Planar
+
+ /**
+ * 16-bit format that has a single 16-bit depth component.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ DEPTH_16 = 0x30,
+
+ /**
+ * 32-bit format that has a single 24-bit depth component and, optionally,
+ * 8 bits that are unused.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ DEPTH_24 = 0x31,
+
+ /**
+ * 32-bit format that has a 24-bit depth component and an 8-bit stencil
+ * component packed into 32-bits.
+ *
+ * The depth component values are unsigned normalized to the range [0, 1],
+ * whose interpretation is defined by the dataspace. The stencil values are
+ * unsigned integers, whose interpretation is defined by the dataspace.
+ */
+ DEPTH_24_STENCIL_8 = 0x32,
+
+ /**
+ * 32-bit format that has a single 32-bit depth component.
+ *
+ * The component values are signed floats, whose interpretation is defined
+ * by the dataspace.
+ */
+ DEPTH_32F = 0x33,
+
+ /**
+ * Two-component format that has a 32-bit depth component, an 8-bit stencil
+ * component, and optionally 24-bits unused.
+ *
+ * The depth component values are signed floats, whose interpretation is
+ * defined by the dataspace. The stencil bits are unsigned integers, whose
+ * interpretation is defined by the dataspace.
+ */
+ DEPTH_32F_STENCIL_8 = 0x34,
+
+ /**
+ * 8-bit format that has a single 8-bit stencil component.
+ *
+ * The component values are unsigned integers, whose interpretation is
+ * defined by the dataspace.
+ */
+ STENCIL_8 = 0x35,
+
+ /**
+ * P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
+ * followed immediately by a Wx(H/2) CbCr plane. Each sample is
+ * represented by a 16-bit little-endian value, with the lower 6 bits set
+ * to zero.
+ *
+ * This format assumes
+ * - an even height
+ * - a vertical stride equal to the height
+ *
+ * stride_in_bytes = stride * 2
+ * y_size = stride_in_bytes * height
+ * cbcr_size = stride_in_bytes * (height / 2)
+ * cb_offset = y_size
+ * cr_offset = cb_offset + 2
+ *
+ * This format must be accepted by the allocator when used with the
+ * following usage flags:
+ *
+ * - BufferUsage::VIDEO_*
+ * - BufferUsage::CPU_*
+ * - BufferUsage::GPU_TEXTURE
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ *
+ * This format is appropriate for 10bit video content.
+ *
+ * Buffers with this format must be locked with IMapper::lockYCbCr
+ * or with IMapper::lock.
+ */
+ YCBCR_P010 = 0x36,
+
+ /**
+ * 24-bit format that has 8-bit H, S, and V components, in that order,
+ * from the lowest memory address to the highest memory address.
+ *
+ * The component values are unsigned normalized to the range [0, 1], whose
+ * interpretation is defined by the dataspace.
+ */
+ HSV_888 = 0x37,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl
new file mode 100644
index 0000000..60614cd
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl
@@ -0,0 +1,51 @@
+/**
+ * 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.graphics.common;
+import android.hardware.graphics.common.XyColor;
+
+/**
+ * Mastering display metadata as specified by SMPTE ST 2086.
+ *
+ * This is an AIDL counterpart of the NDK struct `AHdrMetadata_smpte2086`.
+ */
+@VintfStability
+parcelable Smpte2086 {
+ /**
+ * CIE XYZ chromaticity for red in the RGB primaries.
+ */
+ XyColor primaryRed;
+ /**
+ * CIE XYZ chromaticity for green in the RGB primaries.
+ */
+ XyColor primaryGreen;
+ /**
+ * CIE XYZ chromaticity for blue in the RGB primaries.
+ */
+ XyColor primaryBlue;
+ /**
+ * CIE XYZ chromaticity for the white point.
+ */
+ XyColor whitePoint;
+ /**
+ * Maximum luminance in candelas per square meter.
+ */
+ float maxLuminance;
+ /**
+ * Minimum luminance in candelas per square meter.
+ */
+ float minLuminance;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
index 060d12c..43cf672 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -24,6 +24,15 @@
*
* IMapper@4.x must support getting the following standard buffer metadata types. IMapper@4.x may
* support setting these standard buffer metadata types as well.
+ *
+ * When encoding these StandardMetadataTypes into a byte stream, the associated MetadataType is
+ * is first encoded followed by the StandardMetadataType value. The MetadataType is encoded by
+ * writing the length of MetadataType.name using 8 bytes in little endian, followed by a char
+ * array of MetadataType.name's characters. The char array is not null terminated. Finally,
+ * MetadataType.value is represented by 8 bytes written in little endian.
+ *
+ * The StandardMetadataType encode/decode support library can be found in:
+ * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h.
*/
@VintfStability
@Backing(type="long")
@@ -279,4 +288,43 @@
* 4 bytes written in little endian.
*/
BLEND_MODE = 17,
+
+ /**
+ * Can be used to get or set static HDR metadata specified by SMPTE ST 2086.
+ *
+ * This metadata is a stable aidl android.hardware.graphics.common.Smpte2086.
+ *
+ * This is not used in tone mapping until it has been set for the first time.
+ *
+ * When it is encoded into a byte stream, each float member is represented by 4 bytes written in
+ * little endian. The ordering of float values follows the definition of Smpte2086 and XyColor.
+ * If this is unset when encoded into a byte stream, the byte stream is empty.
+ */
+ SMPTE2086 = 18,
+
+ /**
+ * Can be used to get or set static HDR metadata specified by CTA 861.3.
+ *
+ * This metadata is a stable aidl android.hardware.graphics.common.Cta861_3.
+ *
+ * This is not used in tone mapping until it has been set for the first time.
+ *
+ * When it is encoded into a byte stream, each float member is represented by 4 bytes written in
+ * little endian. The ordering of float values follows the definition of Cta861_3.
+ * If this is unset when encoded into a byte stream, the byte stream is empty.
+ */
+ CTA861_3 = 19,
+
+ /**
+ * Can be used to get or set dynamic HDR metadata specified by SMPTE ST 2094-40:2016.
+ *
+ * This metadata is uint8_t byte array.
+ *
+ * This is not used in tone mapping until it has been set for the first time.
+ *
+ * When it is encoded into a byte stream, the length of the HDR metadata byte array is written
+ * using 8 bytes in little endian. It is followed by the uint8_t byte array.
+ * If this is unset when encoded into a byte stream, the byte stream is empty.
+ */
+ SMPTE2094_40 = 20,
}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl
new file mode 100644
index 0000000..9571273
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl
@@ -0,0 +1,30 @@
+/**
+ * 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.graphics.common;
+
+/**
+ * Chromaticity based on 2 parameters.
+ *
+ * This is an AIDL counterpart of the NDK struct `AColor_xy`.
+ *
+ * @note This can be used to represent any 2-dimensional chromaticity.
+ */
+@VintfStability
+parcelable XyColor {
+ float x;
+ float y;
+}
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp b/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
index 5a75ae1..3702171 100644
--- a/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -2590,13 +2590,6 @@
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
- // If the HWC2-side callback hasn't been registered yet, buffer this until
- // it is registered
- if (mCallbacks.count(Callback::Hotplug) == 0) {
- mPendingHotplugs.emplace_back(hwc1DisplayId, connected);
- return;
- }
-
hwc2_display_t displayId = UINT64_MAX;
if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
if (connected == 0) {
@@ -2625,6 +2618,13 @@
mDisplays.erase(displayId);
}
+ // If the HWC2-side callback hasn't been registered yet, buffer this until
+ // it is registered
+ if (mCallbacks.count(Callback::Hotplug) == 0) {
+ mPendingHotplugs.emplace_back(hwc1DisplayId, connected);
+ return;
+ }
+
const auto& callbackInfo = mCallbacks[Callback::Hotplug];
// Call back without the state lock held
diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
index 0d4e5b8..e5ac842 100644
--- a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
+++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
@@ -49,12 +49,10 @@
public:
Composer();
explicit Composer(const std::string& name);
+ explicit Composer(const sp<IComposer>& composer);
std::unique_ptr<ComposerClient> createClient();
- protected:
- explicit Composer(const sp<IComposer>& composer);
-
private:
const sp<IComposer> mComposer;
};
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index b729062..fa4823e 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -49,4 +49,6 @@
"android.hardware.graphics.composer@2.2-command-buffer",
"android.hardware.graphics.composer@2.3-command-buffer",
],
+ disable_framework: true,
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index dafe587..94766af 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -18,13 +18,15 @@
#include <algorithm>
-#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
#include <composer-vts/2.1/TestCommandReader.h>
#include <composer-vts/2.3/ComposerVts.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <mapper-vts/2.0/MapperVts.h>
namespace android {
@@ -43,29 +45,11 @@
using mapper::V2_0::IMapper;
using V2_2::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:
+class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
+ protected:
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(
- mComposer = std::make_unique<Composer>(
- GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+ mComposer = std::make_unique<Composer>(IComposer::getService(GetParam())));
ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
@@ -175,7 +159,7 @@
*
* TODO: Check that ports are unique for multiple displays.
*/
-TEST_F(GraphicsComposerHidlTest, GetDisplayIdentificationData) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayIdentificationData) {
uint8_t port0;
std::vector<uint8_t> data0;
if (mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port0, &data0)) {
@@ -193,7 +177,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -244,7 +228,7 @@
/**
* Test IComposerClient::getHdrCapabilities_2_3
*/
-TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities_2_3) {
+TEST_P(GraphicsComposerHidlTest, GetHdrCapabilities_2_3) {
float maxLuminance;
float maxAverageLuminance;
float minLuminance;
@@ -256,7 +240,7 @@
/**
* Test IComposerClient::getPerFrameMetadataKeys_2_3
*/
-TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys_2_3) {
+TEST_P(GraphicsComposerHidlTest, GetPerFrameMetadataKeys_2_3) {
std::vector<IComposerClient::PerFrameMetadataKey> keys;
mComposerClient->getRaw()->getPerFrameMetadataKeys_2_3(
mPrimaryDisplay, [&](const auto tmpError, const auto outKeys) {
@@ -270,7 +254,7 @@
/**
* TestIComposerClient::getReadbackBufferAttributes_2_3
*/
-TEST_F(GraphicsComposerHidlTest, GetReadbackBufferAttributes_2_3) {
+TEST_P(GraphicsComposerHidlTest, GetReadbackBufferAttributes_2_3) {
Dataspace dataspace;
PixelFormat pixelFormat;
@@ -288,7 +272,7 @@
/**
* Test IComposerClient::getClientTargetSupport_2_3
*/
-TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_3) {
+TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_3) {
std::vector<V2_1::Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
for (auto config : configs) {
int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -311,7 +295,7 @@
* Error::BAD_DISPLAY when passed in an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_3BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_3BadDisplay) {
std::vector<V2_1::Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
for (auto config : configs) {
int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -333,7 +317,7 @@
/**
* Test IComposerClient::getRenderIntents_2_3
*/
-TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3) {
+TEST_P(GraphicsComposerHidlTest, GetRenderIntents_2_3) {
std::vector<ColorMode> modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
for (auto mode : modes) {
std::vector<RenderIntent> intents =
@@ -363,7 +347,7 @@
* Test that IComposerClient::getRenderIntents_2_3 returns Error::BAD_DISPLAY when
* passed an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetRenderIntents_2_3BadDisplay) {
std::vector<ColorMode> modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
for (auto mode : modes) {
mComposerClient->getRaw()->getRenderIntents_2_3(
@@ -378,7 +362,7 @@
* Test that IComposerClient::getRenderIntents_2_3 returns Error::BAD_PARAMETER when
* pased either an invalid Color mode or an invalid Render Intent
*/
-TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3BadParameter) {
+TEST_P(GraphicsComposerHidlTest, GetRenderIntents_2_3BadParameter) {
mComposerClient->getRaw()->getRenderIntents_2_3(
mPrimaryDisplay, static_cast<ColorMode>(-1),
[&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_PARAMETER, tmpError); });
@@ -387,7 +371,7 @@
/**
* IComposerClient::getColorModes_2_3
*/
-TEST_F(GraphicsComposerHidlTest, GetColorModes_2_3) {
+TEST_P(GraphicsComposerHidlTest, GetColorModes_2_3) {
std::vector<ColorMode> colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
auto native = std::find(colorModes.cbegin(), colorModes.cend(), ColorMode::NATIVE);
@@ -400,7 +384,7 @@
* Test that IComposerClient::getColorModes_2_3 returns Error::BAD_DISPLAY when
* passed an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, GetColorMode_2_3BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetColorMode_2_3BadDisplay) {
mComposerClient->getRaw()->getColorModes_2_3(
mInvalidDisplayId,
[&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_DISPLAY, tmpError); });
@@ -409,7 +393,7 @@
/**
* IComposerClient::setColorMode_2_3
*/
-TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode_2_3) {
std::vector<ColorMode> colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
for (auto mode : colorModes) {
std::vector<RenderIntent> intents =
@@ -430,7 +414,7 @@
* Test that IComposerClient::setColorMode_2_3 returns an Error::BAD_DISPLAY
* when passed an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode_2_3BadDisplay) {
Error error = mComposerClient->getRaw()->setColorMode_2_3(mInvalidDisplayId, ColorMode::NATIVE,
RenderIntent::COLORIMETRIC);
@@ -443,7 +427,7 @@
* Test that IComposerClient::setColorMode_2_3 returns Error::BAD_PARAMETER when
* passed an invalid Color mode or an invalid render intent
*/
-TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3BadParameter) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode_2_3BadParameter) {
Error colorModeError = mComposerClient->getRaw()->setColorMode_2_3(
mPrimaryDisplay, static_cast<ColorMode>(-1), RenderIntent::COLORIMETRIC);
EXPECT_EQ(Error::BAD_PARAMETER, colorModeError);
@@ -458,7 +442,7 @@
* TODO Add color to the layer, use matrix to keep only red component,
* and check.
*/
-TEST_F(GraphicsComposerHidlTest, SetLayerColorTransform) {
+TEST_P(GraphicsComposerHidlTest, SetLayerColorTransform) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -485,7 +469,7 @@
}
}
-TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) {
int constexpr invalid = -1;
auto format = static_cast<PixelFormat>(invalid);
auto dataspace = static_cast<Dataspace>(invalid);
@@ -505,7 +489,7 @@
static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid));
};
-TEST_F(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) {
+TEST_P(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) {
auto const maxFrames = 10;
auto const enableAllComponents = 0;
auto error = mComposerClient->setDisplayedContentSamplingEnabled(
@@ -523,7 +507,7 @@
EXPECT_EQ(error, Error::NONE);
}
-TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSample) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayedContentSample) {
int constexpr invalid = -1;
auto format = static_cast<PixelFormat>(invalid);
auto dataspace = static_cast<Dataspace>(invalid);
@@ -558,7 +542,7 @@
* getDisplayCapabilities is required in composer 2.3
* Test some constraints.
*/
-TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBasic) {
+TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBasic) {
std::vector<IComposerClient::DisplayCapability> capabilities;
const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
ASSERT_EQ(Error::NONE, error);
@@ -572,13 +556,13 @@
EXPECT_EQ(mComposerClient->getDisplayBrightnessSupport(mPrimaryDisplay), hasBrightnessSupport);
}
-TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) {
std::vector<IComposerClient::DisplayCapability> capabilities;
const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities);
EXPECT_EQ(Error::BAD_DISPLAY, error);
}
-TEST_F(GraphicsComposerHidlTest, SetLayerPerFrameMetadataBlobs) {
+TEST_P(GraphicsComposerHidlTest, SetLayerPerFrameMetadataBlobs) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -604,7 +588,7 @@
/*
* Test that if brightness operations are supported, setDisplayBrightness works as expected.
*/
-TEST_F(GraphicsComposerHidlTest, setDisplayBrightness) {
+TEST_P(GraphicsComposerHidlTest, setDisplayBrightness) {
std::vector<IComposerClient::DisplayCapability> capabilities;
const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
ASSERT_EQ(Error::NONE, error);
@@ -627,6 +611,16 @@
EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, -2.0f), Error::BAD_PARAMETER);
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GraphicsComposerHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GraphicsComposerHidlCommandTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
} // namespace
} // namespace vts
} // namespace V2_3
@@ -634,12 +628,3 @@
} // namespace graphics
} // namespace hardware
} // namespace android
-
-int main(int argc, char** argv) {
- using android::hardware::graphics::composer::V2_3::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/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
index f23536c..06b4c5e 100644
--- a/graphics/composer/2.4/IComposerClient.hal
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -48,6 +48,12 @@
* with protected buffers.
*/
PROTECTED_CONTENTS = 4,
+
+ /**
+ * Indicates that both the composer HAL implementation and the given display
+ * support a low latency mode, such as HDMI 2.1 Auto Low Latency Mode.
+ */
+ AUTO_LOW_LATENCY_MODE = 5,
};
/**
@@ -64,6 +70,18 @@
EXTERNAL = 1,
};
+ enum ContentType : uint32_t {
+ NONE = 0,
+
+ /**
+ * These modes correspond to those found in the HDMI 1.4 specification.
+ */
+ GRAPHICS = 1,
+ PHOTO = 2,
+ CINEMA = 3,
+ GAME = 4,
+ };
+
/**
* Constraints for changing vsync period.
*/
@@ -172,4 +190,60 @@
setActiveConfigWithConstraints(Display display, Config config,
VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints)
generates (Error error, VsyncPeriodChangeTimeline timeline);
+
+ /**
+ * Requests the display to enable/disable its low latency mode.
+ *
+ * If the display is connected via HDMI 2.1, then Auto Low Latency Mode should be triggered. If
+ * the display is internally connected and a custom low latency mode is available, that should
+ * be triggered.
+ *
+ * This function should only be called if the display reports support for
+ * DisplayCapability::AUTO_LOW_LATENCY_MODE from getDisplayCapabilities_2_4.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * UNSUPPORTED when AUTO_LOW_LATENCY_MODE is not supported by the composer
+ * implementation or the given display
+ */
+ setAutoLowLatencyMode(Display display, bool on)
+ generates (Error error);
+
+ /**
+ * Provides a list of all the content types supported by this display (any of
+ * ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}). This list must not change after
+ * initialization.
+ *
+ * Content types are introduced in HDMI 1.4 and supporting them is optional. The
+ * ContentType::NONE is always supported and will not be returned by this method..
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * @return supportedContentTypes is a list of supported content types.
+ */
+ getSupportedContentTypes(Display display)
+ generates(Error error, vec<ContentType> supportedContentTypes);
+
+ /**
+ * Instructs the connected display that the content being shown is of the given type - one of
+ * GRAPHICS, PHOTO, CINEMA, GAME.
+ *
+ * Content types are introduced in HDMI 1.4 and supporting them is optional. If they are
+ * supported, this signal should switch the display to a mode that is optimal for the given
+ * type of content. See HDMI 1.4 specification for more information.
+ *
+ * If the display is internally connected (not through HDMI), and such modes are available,
+ * this method should trigger them.
+ *
+ * This function should only be called if the display reports support for the corresponding
+ * content type (ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}) from getSupportedContentTypes.
+ * ContentType::NONE is supported by default and can always be set.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * UNSUPPORTED when the given content type is not supported by the composer
+ * implementation or the given display
+ */
+ setContentType(Display display, ContentType type)
+ generates (Error error);
};
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
index 4160ed9..dcd959d 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -139,6 +139,24 @@
return Void();
}
+ Return<Error> setAutoLowLatencyMode(Display display, bool on) override {
+ return mHal->setAutoLowLatencyMode(display, on);
+ }
+
+ Return<void> getSupportedContentTypes(
+ Display display, IComposerClient::getSupportedContentTypes_cb hidl_cb) override {
+ std::vector<IComposerClient::ContentType> supportedContentTypes;
+ Error error = mHal->getSupportedContentTypes(display, &supportedContentTypes);
+
+ hidl_cb(error, supportedContentTypes);
+ return Void();
+ }
+
+ Return<Error> setContentType(Display display,
+ IComposerClient::ContentType contentType) override {
+ return mHal->setContentType(display, contentType);
+ }
+
static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
auto client = std::make_unique<ComposerClientImpl>(hal);
return client->init() ? std::move(client) : nullptr;
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
index 89dbe66..a1e56ae 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
@@ -67,6 +67,11 @@
Display display, Config config,
const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
VsyncPeriodChangeTimeline* timeline) = 0;
+ virtual Error setAutoLowLatencyMode(Display display, bool on) = 0;
+ virtual Error getSupportedContentTypes(
+ Display display,
+ std::vector<IComposerClient::ContentType>* outSupportedContentTypes) = 0;
+ virtual Error setContentType(Display display, IComposerClient::ContentType contentType) = 0;
};
} // namespace hal
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
index d59d0d5..a34572d 100644
--- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -59,9 +59,6 @@
mDevice, HWC2_CALLBACK_REFRESH, this,
reinterpret_cast<hwc2_function_pointer_t>(refreshHook));
BaseType2_1::mDispatch.registerCallback(
- mDevice, HWC2_CALLBACK_VSYNC, this,
- reinterpret_cast<hwc2_function_pointer_t>(vsyncHook));
- BaseType2_1::mDispatch.registerCallback(
mDevice, HWC2_CALLBACK_VSYNC_2_4, this,
reinterpret_cast<hwc2_function_pointer_t>(vsync_2_4_Hook));
@@ -80,7 +77,6 @@
// which is likely incorrect
BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, nullptr);
BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, nullptr);
- BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, nullptr);
BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this, nullptr);
BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED,
this, nullptr);
@@ -167,6 +163,57 @@
return Error::NONE;
}
+ Error setAutoLowLatencyMode(Display display, bool on) override {
+ if (!mDispatch.setAutoLowLatencyMode) {
+ return Error::UNSUPPORTED;
+ }
+
+ int32_t error = mDispatch.setAutoLowLatencyMode(mDevice, display, on);
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+ return Error::NONE;
+ }
+
+ Error getSupportedContentTypes(
+ Display display,
+ std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override {
+ if (!mDispatch.getSupportedContentTypes) {
+ return Error::UNSUPPORTED;
+ }
+
+ uint32_t count = 0;
+ int32_t error = mDispatch.getSupportedContentTypes(mDevice, display, &count, nullptr);
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+
+ outSupportedContentTypes->resize(count);
+
+ error = mDispatch.getSupportedContentTypes(
+ mDevice, display, &count,
+ reinterpret_cast<std::underlying_type<IComposerClient::ContentType>::type*>(
+ outSupportedContentTypes->data()));
+ if (error != HWC2_ERROR_NONE) {
+ *outSupportedContentTypes = std::vector<IComposerClient::ContentType>();
+ return static_cast<Error>(error);
+ }
+ return Error::NONE;
+ }
+
+ Error setContentType(Display display, IComposerClient::ContentType contentType) override {
+ if (!mDispatch.setContentType) {
+ return Error::UNSUPPORTED;
+ }
+
+ int32_t error =
+ mDispatch.setContentType(mDevice, display, static_cast<int32_t>(contentType));
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+ return Error::NONE;
+ }
+
protected:
bool initDispatch() override {
if (!BaseType2_3::initDispatch()) {
@@ -179,6 +226,11 @@
&mDispatch.getDisplayVsyncPeriod);
this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS,
&mDispatch.setActiveConfigWithConstraints);
+ this->initOptionalDispatch(HWC2_FUNCTION_SET_AUTO_LOW_LATENCY_MODE,
+ &mDispatch.setAutoLowLatencyMode);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_CONTENT_TYPES,
+ &mDispatch.getSupportedContentTypes);
+ this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType);
return true;
}
@@ -222,6 +274,9 @@
HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType;
HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD getDisplayVsyncPeriod;
HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS setActiveConfigWithConstraints;
+ HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE setAutoLowLatencyMode;
+ HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes;
+ HWC2_PFN_SET_CONTENT_TYPE setContentType;
} mDispatch = {};
hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr;
diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
index 35ac23f..5b06d6d 100644
--- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -106,6 +106,25 @@
return error;
}
+Error ComposerClient::setAutoLowLatencyMode(Display display, bool on) {
+ return mClient->setAutoLowLatencyMode(display, on);
+}
+
+Error ComposerClient::getSupportedContentTypes(
+ Display display, std::vector<IComposerClient::ContentType>* outSupportedContentTypes) {
+ Error error = Error::NONE;
+ mClient->getSupportedContentTypes(
+ display, [&](const auto& tmpError, const auto& tmpSupportedContentTypes) {
+ error = tmpError;
+ *outSupportedContentTypes = tmpSupportedContentTypes;
+ });
+ return error;
+}
+
+Error ComposerClient::setContentType(Display display, IComposerClient::ContentType contentType) {
+ return mClient->setContentType(display, contentType);
+}
+
} // namespace vts
} // namespace V2_4
} // namespace composer
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
index 83e74ed..b094bc8 100644
--- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
@@ -84,6 +84,13 @@
const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
VsyncPeriodChangeTimeline* timeline);
+ Error setAutoLowLatencyMode(Display display, bool on);
+
+ Error getSupportedContentTypes(
+ Display display, std::vector<IComposerClient::ContentType>* outSupportedContentTypes);
+
+ Error setContentType(Display display, IComposerClient::ContentType contentType);
+
private:
const sp<IComposerClient> mClient;
};
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index f038f55..5a96d77 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -47,6 +47,9 @@
using mapper::V2_0::IMapper;
using mapper::V2_0::vts::Gralloc;
+using ContentType = IComposerClient::ContentType;
+using DisplayCapability = IComposerClient::DisplayCapability;
+
class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
protected:
void SetUp() override {
@@ -117,6 +120,11 @@
void Test_setActiveConfigWithConstraints(
const IComposerClient::VsyncPeriodChangeConstraints& constraints);
+ void Test_setContentType(const ContentType& contentType, const char* contentTypeStr);
+ void Test_setContentTypeForDisplay(const Display& display,
+ const std::vector<ContentType>& capabilities,
+ const ContentType& contentType, const char* contentTypeStr);
+
std::unique_ptr<Composer> mComposer;
std::unique_ptr<ComposerClient> mComposerClient;
sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
@@ -184,6 +192,13 @@
EXPECT_EQ(Error::BAD_DISPLAY, error);
}
+TEST_P(GraphicsComposerHidlTest, getDisplayCapabilities) {
+ for (Display display : mComposerCallback->getDisplays()) {
+ std::vector<IComposerClient::DisplayCapability> capabilities;
+ EXPECT_EQ(Error::NONE, mComposerClient->getDisplayCapabilities(display, &capabilities));
+ }
+}
+
TEST_P(GraphicsComposerHidlTest, getDisplayConnectionType) {
IComposerClient::DisplayConnectionType type;
EXPECT_EQ(Error::BAD_DISPLAY,
@@ -377,6 +392,117 @@
Test_setActiveConfigWithConstraints(constraints);
}
+TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyModeBadDisplay) {
+ EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, true));
+ EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, false));
+}
+
+TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyMode) {
+ for (Display display : mComposerCallback->getDisplays()) {
+ std::vector<DisplayCapability> capabilities;
+ const auto error = mComposerClient->getDisplayCapabilities(display, &capabilities);
+ EXPECT_EQ(Error::NONE, error);
+
+ const bool allmSupport =
+ std::find(capabilities.begin(), capabilities.end(),
+ DisplayCapability::AUTO_LOW_LATENCY_MODE) != capabilities.end();
+
+ if (!allmSupport) {
+ EXPECT_EQ(Error::UNSUPPORTED,
+ mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true));
+ EXPECT_EQ(Error::UNSUPPORTED,
+ mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false));
+ GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display "
+ << to_string(display) << ", skipping test";
+ return;
+ }
+
+ EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true));
+ EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false));
+ }
+}
+
+TEST_P(GraphicsComposerHidlTest, getSupportedContentTypesBadDisplay) {
+ std::vector<ContentType> supportedContentTypes;
+ const auto error =
+ mComposerClient->getSupportedContentTypes(mInvalidDisplayId, &supportedContentTypes);
+ EXPECT_EQ(Error::BAD_DISPLAY, error);
+}
+
+TEST_P(GraphicsComposerHidlTest, getSupportedContentTypes) {
+ std::vector<ContentType> supportedContentTypes;
+ for (Display display : mComposerCallback->getDisplays()) {
+ supportedContentTypes.clear();
+ const auto error =
+ mComposerClient->getSupportedContentTypes(display, &supportedContentTypes);
+ const bool noneSupported =
+ std::find(supportedContentTypes.begin(), supportedContentTypes.end(),
+ ContentType::NONE) != supportedContentTypes.end();
+ EXPECT_EQ(Error::NONE, error);
+ EXPECT_FALSE(noneSupported);
+ }
+}
+
+TEST_P(GraphicsComposerHidlTest, setContentTypeNoneAlwaysAccepted) {
+ for (Display display : mComposerCallback->getDisplays()) {
+ const auto error = mComposerClient->setContentType(display, ContentType::NONE);
+ EXPECT_NE(Error::UNSUPPORTED, error);
+ }
+}
+
+TEST_P(GraphicsComposerHidlTest, setContentTypeBadDisplay) {
+ const auto types = {ContentType::NONE, ContentType::GRAPHICS, ContentType::PHOTO,
+ ContentType::CINEMA, ContentType::GAME};
+ for (auto type : types) {
+ EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setContentType(mInvalidDisplayId, type));
+ }
+}
+
+void GraphicsComposerHidlTest::Test_setContentTypeForDisplay(
+ const Display& display, const std::vector<ContentType>& capabilities,
+ const ContentType& contentType, const char* contentTypeStr) {
+ const bool contentTypeSupport =
+ std::find(capabilities.begin(), capabilities.end(), contentType) != capabilities.end();
+
+ if (!contentTypeSupport) {
+ EXPECT_EQ(Error::UNSUPPORTED, mComposerClient->setContentType(display, contentType));
+ GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display "
+ << to_string(display) << ", skipping test";
+ return;
+ }
+
+ EXPECT_EQ(Error::NONE, mComposerClient->setContentType(display, contentType));
+ EXPECT_EQ(Error::NONE, mComposerClient->setContentType(display, ContentType::NONE));
+}
+
+void GraphicsComposerHidlTest::Test_setContentType(const ContentType& contentType,
+ const char* contentTypeStr) {
+ for (Display display : mComposerCallback->getDisplays()) {
+ std::vector<ContentType> supportedContentTypes;
+ const auto error =
+ mComposerClient->getSupportedContentTypes(display, &supportedContentTypes);
+ EXPECT_EQ(Error::NONE, error);
+
+ Test_setContentTypeForDisplay(display, supportedContentTypes, contentType, contentTypeStr);
+ }
+}
+
+TEST_P(GraphicsComposerHidlTest, setGraphicsContentType) {
+ Test_setContentType(ContentType::GRAPHICS, "GRAPHICS");
+}
+
+TEST_P(GraphicsComposerHidlTest, setPhotoContentType) {
+ Test_setContentType(ContentType::PHOTO, "PHOTO");
+}
+
+TEST_P(GraphicsComposerHidlTest, setCinemaContentType) {
+ Test_setContentType(ContentType::CINEMA, "CINEMA");
+}
+
+TEST_P(GraphicsComposerHidlTest, setGameContentType) {
+ Test_setContentType(ContentType::GAME, "GAME");
+}
+
INSTANTIATE_TEST_SUITE_P(
PerInstance, GraphicsComposerHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
diff --git a/graphics/mapper/2.0/utils/vts/MapperVts.cpp b/graphics/mapper/2.0/utils/vts/MapperVts.cpp
index d08ac56..d4e4dde 100644
--- a/graphics/mapper/2.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/2.0/utils/vts/MapperVts.cpp
@@ -16,8 +16,6 @@
#include <mapper-vts/2.0/MapperVts.h>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace android {
namespace hardware {
namespace graphics {
@@ -30,10 +28,10 @@
}
void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
- mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+ mAllocator = IAllocator::getService(allocatorServiceName);
ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
- mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName);
+ mMapper = IMapper::getService(mapperServiceName);
ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
}
diff --git a/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h b/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h
index 6c2c9a6..fc8a102 100644
--- a/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h
+++ b/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h
@@ -22,6 +22,7 @@
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <gtest/gtest.h>
#include <utils/StrongPointer.h>
namespace android {
diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp
index 853c2a3..a055b61 100644
--- a/graphics/mapper/2.0/vts/functional/Android.bp
+++ b/graphics/mapper/2.0/vts/functional/Android.bp
@@ -24,5 +24,5 @@
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.0-vts",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
index 5ec0af2..b079a4b 100644
--- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
@@ -20,8 +20,10 @@
#include <thread>
#include <vector>
-#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <mapper-vts/2.0/MapperVts.h>
namespace android {
@@ -35,28 +37,12 @@
using android::hardware::graphics::common::V1_0::BufferUsage;
using android::hardware::graphics::common::V1_0::PixelFormat;
-// Test environment for graphics.mapper.
-class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static GraphicsMapperHidlEnvironment* Instance() {
- static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override {
- registerTestService<IAllocator>();
- registerTestService<IMapper>();
- }
-};
-
-class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- protected:
+class GraphicsMapperHidlTest
+ : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+ protected:
void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(
- mGralloc = std::make_unique<Gralloc>(
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+ ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+ std::get<1>(GetParam())));
mDummyDescriptorInfo.width = 64;
mDummyDescriptorInfo.height = 64;
@@ -75,14 +61,14 @@
/**
* Test IAllocator::dumpDebugInfo by calling it.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
+TEST_P(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
mGralloc->dumpDebugInfo();
}
/**
* Test IAllocator::allocate with valid buffer descriptors.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocate) {
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
@@ -105,7 +91,7 @@
/**
* Test IAllocator::allocate with invalid buffer descriptors.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
// this assumes any valid descriptor is non-empty
BufferDescriptor descriptor;
mGralloc->getAllocator()->allocate(descriptor, 1,
@@ -117,7 +103,7 @@
/**
* Test IAllocator::allocate does not leak.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
auto info = mDummyDescriptorInfo;
info.width = 1024;
info.height = 1024;
@@ -131,7 +117,7 @@
/**
* Test that IAllocator::allocate is thread-safe.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
@@ -161,14 +147,14 @@
/**
* Test IMapper::createDescriptor with valid descriptor info.
*/
-TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorBasic) {
ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
}
/**
* Test IMapper::createDescriptor with invalid descriptor info.
*/
-TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorNegative) {
auto info = mDummyDescriptorInfo;
info.width = 0;
mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) {
@@ -179,7 +165,7 @@
/**
* Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
*/
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
const native_handle_t* bufferHandle;
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
@@ -188,7 +174,7 @@
/**
* Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
*/
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferClone) {
const native_handle_t* clonedBufferHandle;
ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
@@ -206,7 +192,7 @@
/**
* Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
*/
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
const native_handle_t* rawHandle;
ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
@@ -218,10 +204,8 @@
// free the imported handle with another mapper
std::unique_ptr<Gralloc> anotherGralloc;
- ASSERT_NO_FATAL_FAILURE(
- anotherGralloc = std::make_unique<Gralloc>(
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+ ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+ std::get<1>(GetParam())));
Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
ASSERT_EQ(Error::NONE, error);
@@ -231,7 +215,7 @@
/**
* Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
*/
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
auto info = mDummyDescriptorInfo;
info.width = 1024;
info.height = 1024;
@@ -245,7 +229,7 @@
/**
* Test IMapper::importBuffer with invalid buffers.
*/
-TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) {
+TEST_P(GraphicsMapperHidlTest, ImportBufferNegative) {
native_handle_t* invalidHandle = nullptr;
mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
@@ -263,7 +247,7 @@
/**
* Test IMapper::freeBuffer with invalid buffers.
*/
-TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) {
+TEST_P(GraphicsMapperHidlTest, FreeBufferNegative) {
native_handle_t* invalidHandle = nullptr;
Error error = mGralloc->getMapper()->freeBuffer(invalidHandle);
EXPECT_EQ(Error::BAD_BUFFER, error) << "freeBuffer with nullptr did not fail with BAD_BUFFER";
@@ -286,7 +270,7 @@
/**
* Test IMapper::lock and IMapper::unlock.
*/
-TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) {
+TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) {
const auto& info = mDummyDescriptorInfo;
const native_handle_t* bufferHandle;
@@ -332,7 +316,7 @@
* Test IMapper::lockYCbCr. This locks a YV12 buffer, and makes sure we can
* write to and read from it.
*/
-TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) {
+TEST_P(GraphicsMapperHidlTest, LockYCbCrBasic) {
auto info = mDummyDescriptorInfo;
info.format = PixelFormat::YV12;
@@ -391,7 +375,7 @@
/**
* Test IMapper::unlock with invalid buffers.
*/
-TEST_F(GraphicsMapperHidlTest, UnlockNegative) {
+TEST_P(GraphicsMapperHidlTest, UnlockNegative) {
native_handle_t* invalidHandle = nullptr;
mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
@@ -426,6 +410,14 @@
#endif
}
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, GraphicsMapperHidlTest,
+ testing::Combine(
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
+
} // namespace
} // namespace vts
} // namespace V2_0
@@ -433,13 +425,3 @@
} // namespace graphics
} // namespace hardware
} // namespace android
-
-int main(int argc, char** argv) {
- using android::hardware::graphics::mapper::V2_0::vts::GraphicsMapperHidlEnvironment;
- ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
diff --git a/graphics/mapper/2.1/utils/vts/Android.bp b/graphics/mapper/2.1/utils/vts/Android.bp
index ca02aad..abbe50a 100644
--- a/graphics/mapper/2.1/utils/vts/Android.bp
+++ b/graphics/mapper/2.1/utils/vts/Android.bp
@@ -16,14 +16,13 @@
cc_library_static {
name: "android.hardware.graphics.mapper@2.1-vts",
- defaults: ["hidl_defaults"],
+ defaults: ["hidl_defaults", "VtsHalTargetTestDefaults"],
srcs: ["MapperVts.cpp"],
cflags: [
"-O0",
"-g",
],
static_libs: [
- "VtsHalHidlTargetTestBase",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.0-vts",
diff --git a/graphics/mapper/2.1/utils/vts/MapperVts.cpp b/graphics/mapper/2.1/utils/vts/MapperVts.cpp
index 36f9cbb..239de74 100644
--- a/graphics/mapper/2.1/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/2.1/utils/vts/MapperVts.cpp
@@ -16,8 +16,6 @@
#include <mapper-vts/2.1/MapperVts.h>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace android {
namespace hardware {
namespace graphics {
diff --git a/graphics/mapper/2.1/vts/functional/Android.bp b/graphics/mapper/2.1/vts/functional/Android.bp
index afd8e7f..bb76c74 100644
--- a/graphics/mapper/2.1/vts/functional/Android.bp
+++ b/graphics/mapper/2.1/vts/functional/Android.bp
@@ -26,5 +26,5 @@
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@2.1-vts",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
index 5e7cf93..1185945 100644
--- a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
+++ b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
@@ -16,9 +16,11 @@
#define LOG_TAG "VtsHalGraphicsMapperV2_1TargetTest"
-#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <mapper-vts/2.1/MapperVts.h>
namespace android {
@@ -34,28 +36,12 @@
using android::hardware::graphics::common::V1_1::PixelFormat;
using V2_0::Error;
-// Test environment for graphics.mapper.
-class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static GraphicsMapperHidlEnvironment* Instance() {
- static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override {
- registerTestService<IAllocator>();
- registerTestService<IMapper>();
- }
-};
-
-class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- protected:
+class GraphicsMapperHidlTest
+ : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+ protected:
void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(
- mGralloc = std::make_unique<Gralloc>(
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+ ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+ std::get<1>(GetParam())));
mDummyDescriptorInfo.width = 64;
mDummyDescriptorInfo.height = 64;
@@ -74,7 +60,7 @@
/**
* Test that IMapper::validateBufferSize works.
*/
-TEST_F(GraphicsMapperHidlTest, ValidateBufferSizeBasic) {
+TEST_P(GraphicsMapperHidlTest, ValidateBufferSizeBasic) {
const native_handle_t* bufferHandle;
uint32_t stride;
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true, &stride));
@@ -87,7 +73,7 @@
/**
* Test IMapper::validateBufferSize with invalid buffers.
*/
-TEST_F(GraphicsMapperHidlTest, ValidateBufferSizeBadBuffer) {
+TEST_P(GraphicsMapperHidlTest, ValidateBufferSizeBadBuffer) {
native_handle_t* invalidHandle = nullptr;
Error ret = mGralloc->getMapper()->validateBufferSize(invalidHandle, mDummyDescriptorInfo,
mDummyDescriptorInfo.width);
@@ -114,7 +100,7 @@
/**
* Test IMapper::validateBufferSize with invalid descriptor and/or stride.
*/
-TEST_F(GraphicsMapperHidlTest, ValidateBufferSizeBadValue) {
+TEST_P(GraphicsMapperHidlTest, ValidateBufferSizeBadValue) {
auto info = mDummyDescriptorInfo;
info.width = 1024;
info.height = 1024;
@@ -161,7 +147,7 @@
/**
* Test IMapper::getTransportSize.
*/
-TEST_F(GraphicsMapperHidlTest, GetTransportSizeBasic) {
+TEST_P(GraphicsMapperHidlTest, GetTransportSizeBasic) {
const native_handle_t* bufferHandle;
uint32_t numFds;
uint32_t numInts;
@@ -173,7 +159,7 @@
/**
* Test IMapper::getTransportSize with invalid buffers.
*/
-TEST_F(GraphicsMapperHidlTest, GetTransportSizeBadBuffer) {
+TEST_P(GraphicsMapperHidlTest, GetTransportSizeBadBuffer) {
native_handle_t* invalidHandle = nullptr;
mGralloc->getMapper()->getTransportSize(
invalidHandle, [&](const auto& tmpError, const auto&, const auto&) {
@@ -203,14 +189,14 @@
/**
* Test IMapper::createDescriptor with valid descriptor info.
*/
-TEST_F(GraphicsMapperHidlTest, CreateDescriptor_2_1Basic) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptor_2_1Basic) {
ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
}
/**
* Test IMapper::createDescriptor with invalid descriptor info.
*/
-TEST_F(GraphicsMapperHidlTest, CreateDescriptor_2_1Negative) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptor_2_1Negative) {
auto info = mDummyDescriptorInfo;
info.width = 0;
mGralloc->getMapper()->createDescriptor_2_1(info, [&](const auto& tmpError, const auto&) {
@@ -218,22 +204,18 @@
});
}
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, GraphicsMapperHidlTest,
+ testing::Combine(
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
+
} // namespace
} // namespace vts
} // namespace V2_1
} // namespace mapper
} // namespace graphics
} // namespace hardware
-} // namespace android
-
-int main(int argc, char** argv) {
- using android::hardware::graphics::mapper::V2_1::vts::GraphicsMapperHidlEnvironment;
- ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv);
-
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
-
- return status;
-}
+} // namespace android
\ No newline at end of file
diff --git a/graphics/mapper/3.0/utils/vts/MapperVts.cpp b/graphics/mapper/3.0/utils/vts/MapperVts.cpp
index c94e8db..de886a9 100644
--- a/graphics/mapper/3.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/3.0/utils/vts/MapperVts.cpp
@@ -16,8 +16,6 @@
#include <mapper-vts/3.0/MapperVts.h>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace android {
namespace hardware {
namespace graphics {
@@ -35,19 +33,19 @@
}
void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
- mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+ mAllocator = IAllocator::getService(allocatorServiceName);
ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
- mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName);
+ mMapper = IMapper::getService(mapperServiceName);
ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
}
void Gralloc::initNoErr(const std::string& allocatorServiceName,
const std::string& mapperServiceName) {
- mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+ mAllocator = IAllocator::getService(allocatorServiceName);
- mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName);
+ mMapper = IMapper::getService(mapperServiceName);
if (mMapper.get()) {
ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
}
diff --git a/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h
index 1141a88..b2fbebb1 100644
--- a/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h
+++ b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h
@@ -22,6 +22,7 @@
#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <gtest/gtest.h>
#include <utils/StrongPointer.h>
namespace android {
diff --git a/graphics/mapper/3.0/vts/functional/Android.bp b/graphics/mapper/3.0/vts/functional/Android.bp
index 77075a5..f01670e 100644
--- a/graphics/mapper/3.0/vts/functional/Android.bp
+++ b/graphics/mapper/3.0/vts/functional/Android.bp
@@ -26,5 +26,5 @@
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@3.0-vts",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp b/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp
index ff73ecf..92b5994 100644
--- a/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp
+++ b/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp
@@ -20,8 +20,10 @@
#include <thread>
#include <vector>
-#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <mapper-vts/3.0/MapperVts.h>
namespace android {
@@ -35,28 +37,12 @@
using android::hardware::graphics::common::V1_2::BufferUsage;
using android::hardware::graphics::common::V1_2::PixelFormat;
-// Test environment for graphics.mapper.
-class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static GraphicsMapperHidlEnvironment* Instance() {
- static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override {
- registerTestService<IAllocator>();
- registerTestService<IMapper>();
- }
-};
-
-class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- protected:
+class GraphicsMapperHidlTest
+ : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+ protected:
void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(
- mGralloc = std::make_unique<Gralloc>(
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+ ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+ std::get<1>(GetParam())));
mDummyDescriptorInfo.width = 64;
mDummyDescriptorInfo.height = 64;
@@ -75,14 +61,14 @@
/**
* Test IAllocator::dumpDebugInfo by calling it.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
+TEST_P(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
mGralloc->dumpDebugInfo();
}
/**
* Test IAllocator::allocate with valid buffer descriptors.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocate) {
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
@@ -105,7 +91,7 @@
/**
* Test IAllocator::allocate with invalid buffer descriptors.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
// this assumes any valid descriptor is non-empty
BufferDescriptor descriptor;
mGralloc->getAllocator()->allocate(descriptor, 1,
@@ -117,7 +103,7 @@
/**
* Test IAllocator::allocate does not leak.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
auto info = mDummyDescriptorInfo;
info.width = 1024;
info.height = 1024;
@@ -131,7 +117,7 @@
/**
* Test that IAllocator::allocate is thread-safe.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
@@ -161,14 +147,14 @@
/**
* Test IMapper::createDescriptor with valid descriptor info.
*/
-TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorBasic) {
ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
}
/**
* Test IMapper::createDescriptor with invalid descriptor info.
*/
-TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorNegative) {
auto info = mDummyDescriptorInfo;
info.width = 0;
mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) {
@@ -179,7 +165,7 @@
/**
* Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
*/
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
const native_handle_t* bufferHandle;
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
@@ -188,7 +174,7 @@
/**
* Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
*/
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferClone) {
const native_handle_t* clonedBufferHandle;
ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
@@ -206,7 +192,7 @@
/**
* Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
*/
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
const native_handle_t* rawHandle;
ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
@@ -218,10 +204,8 @@
// free the imported handle with another mapper
std::unique_ptr<Gralloc> anotherGralloc;
- ASSERT_NO_FATAL_FAILURE(
- anotherGralloc = std::make_unique<Gralloc>(
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+ ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+ std::get<1>(GetParam())));
Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
ASSERT_EQ(Error::NONE, error);
@@ -231,7 +215,7 @@
/**
* Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
*/
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
auto info = mDummyDescriptorInfo;
info.width = 1024;
info.height = 1024;
@@ -245,7 +229,7 @@
/**
* Test IMapper::importBuffer with invalid buffers.
*/
-TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) {
+TEST_P(GraphicsMapperHidlTest, ImportBufferNegative) {
native_handle_t* invalidHandle = nullptr;
mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
@@ -263,7 +247,7 @@
/**
* Test IMapper::freeBuffer with invalid buffers.
*/
-TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) {
+TEST_P(GraphicsMapperHidlTest, FreeBufferNegative) {
native_handle_t* invalidHandle = nullptr;
Error error = mGralloc->getMapper()->freeBuffer(invalidHandle);
EXPECT_EQ(Error::BAD_BUFFER, error) << "freeBuffer with nullptr did not fail with BAD_BUFFER";
@@ -286,7 +270,7 @@
/**
* Test IMapper::lock and IMapper::unlock.
*/
-TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) {
+TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) {
const auto& info = mDummyDescriptorInfo;
const native_handle_t* bufferHandle;
@@ -346,7 +330,7 @@
* Test IMapper::lockYCbCr. This locks a YV12 buffer, and makes sure we can
* write to and read from it.
*/
-TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) {
+TEST_P(GraphicsMapperHidlTest, LockYCbCrBasic) {
auto info = mDummyDescriptorInfo;
info.format = PixelFormat::YV12;
@@ -405,7 +389,7 @@
/**
* Test IMapper::unlock with invalid buffers.
*/
-TEST_F(GraphicsMapperHidlTest, UnlockNegative) {
+TEST_P(GraphicsMapperHidlTest, UnlockNegative) {
native_handle_t* invalidHandle = nullptr;
mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
@@ -443,7 +427,7 @@
/**
* Test IMapper::isSupported with required format RGBA_8888
*/
-TEST_F(GraphicsMapperHidlTest, IsSupportedRGBA8888) {
+TEST_P(GraphicsMapperHidlTest, IsSupportedRGBA8888) {
const auto& info = mDummyDescriptorInfo;
bool supported = false;
@@ -454,7 +438,7 @@
/**
* Test IMapper::isSupported with required format YV12
*/
-TEST_F(GraphicsMapperHidlTest, IsSupportedYV12) {
+TEST_P(GraphicsMapperHidlTest, IsSupportedYV12) {
auto info = mDummyDescriptorInfo;
info.format = PixelFormat::YV12;
bool supported = false;
@@ -466,7 +450,7 @@
/**
* Test IMapper::isSupported with optional format Y16
*/
-TEST_F(GraphicsMapperHidlTest, IsSupportedY16) {
+TEST_P(GraphicsMapperHidlTest, IsSupportedY16) {
auto info = mDummyDescriptorInfo;
info.format = PixelFormat::Y16;
bool supported = false;
@@ -474,6 +458,14 @@
ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
}
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, GraphicsMapperHidlTest,
+ testing::Combine(
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
+
} // namespace
} // namespace vts
} // namespace V3_0
@@ -481,13 +473,3 @@
} // namespace graphics
} // namespace hardware
} // namespace android
-
-int main(int argc, char** argv) {
- using android::hardware::graphics::mapper::V3_0::vts::GraphicsMapperHidlEnvironment;
- ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal
index 298f31e..93c85bd 100644
--- a/graphics/mapper/4.0/IMapper.hal
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -56,6 +56,12 @@
* BufferUsage.
*/
bitfield<BufferUsage> usage;
+
+ /**
+ * The size in bytes of the reserved region associated with the buffer.
+ * See getReservedRegion for more information.
+ */
+ uint64_t reservedSize;
};
struct Rect {
@@ -71,9 +77,10 @@
*
* Since the buffer descriptor fully describes a buffer, any device
* dependent or device independent checks must be performed here whenever
- * possible. Specifically, when layered buffers are not supported, this
- * function must return `UNSUPPORTED` if `description.layers` is great than
- * 1.
+ * possible. When layered buffers are not supported, this function must
+ * return `UNSUPPORTED` if `description.layers` is great than 1. This
+ * function may return `UNSUPPORTED` if `description.reservedSize` is
+ * larger than a page.
*
* @param description Attributes of the descriptor.
* @return error Error status of the call, which may be
@@ -199,6 +206,9 @@
* outside of @p accessRegion is undefined, except that it must not cause
* process termination.
*
+ * An accessRegion of all-zeros means the entire buffer. That is, it is
+ * equivalent to '(0,0)-(buffer width, buffer height)'.
+ *
* This function can lock both single-planar and multi-planar formats. The caller
* should use get() to get information about the buffer they are locking.
* get() can be used to get information about the planes, offsets, stride,
@@ -259,6 +269,50 @@
unlock(pointer buffer) generates (Error error, handle releaseFence);
/**
+ * Flushes the contents of a locked buffer.
+ *
+ * This function flushes the CPUs caches for the range of all the buffer's
+ * planes and metadata. This should behave similarly to unlock() except the
+ * buffer should remain mapped to the CPU.
+ *
+ * The client is still responsible for calling unlock() when it is done
+ * with all CPU accesses to the buffer.
+ *
+ * If non-CPU blocks are simultaneously writing the buffer, the locked
+ * copy should still be flushed but what happens is undefined except that
+ * it should not cause any crashes.
+ *
+ * @param buffer Buffer to flush.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or not locked.
+ * @return releaseFence Handle containing a file descriptor referring to a
+ * sync fence object. The sync fence object will be signaled when the
+ * mapper has completed any pending work. @p releaseFence may be an
+ * empty fence.
+ */
+ flushLockedBuffer(pointer buffer) generates (Error error, handle releaseFence);
+
+ /**
+ * Rereads the contents of a locked buffer.
+ *
+ * This should fetch the most recent copy of the locked buffer.
+ *
+ * It may reread locked copies of the buffer in other processes.
+ *
+ * The client is still responsible for calling unlock() when it is done
+ * with all CPU accesses to the buffer.
+ *
+ * @param buffer Buffer to reread.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or not locked.
+ * - `NO_RESOURCES` if the buffer cannot be reread at this time. Note
+ * that rereading may succeed at a later time.
+ */
+ rereadLockedBuffer(pointer buffer) generates(Error error);
+
+ /**
* Test whether the given BufferDescriptorInfo is allocatable.
*
* If this function returns true, it means that a buffer with the given
@@ -427,7 +481,7 @@
* particular Metadata field.
*
* The framework may attempt to set the following StandardMetadataType
- * values: DATASPACE, PER_FRAME_METADATA, PER_FRAME_METADATA_BLOB and BLEND_MODE.
+ * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
* We strongly encourage everyone to support setting as many of those fields as
* possible. If a device's Composer implementation supports a field, it should be
* supported here. Over time these metadata fields will be moved out of
@@ -560,5 +614,35 @@
*/
dumpBuffers()
generates (Error error, vec<BufferDump> bufferDumps);
+
+ /**
+ * Returns the region of shared memory associated with the buffer that is
+ * reserved for client use.
+ *
+ * The shared memory may be allocated from any shared memory allocator.
+ * The shared memory must be CPU-accessible and virtually contiguous. The
+ * starting address must be word-aligned.
+ *
+ * This function may only be called after importBuffer() has been called by the
+ * client. The reserved region must remain accessible until freeBuffer() has
+ * been called. After freeBuffer() has been called, the client must not access
+ * the reserved region.
+ *
+ * This reserved memory may be used in future versions of Android to
+ * help clients implement backwards compatible features without requiring
+ * IAllocator/IMapper updates.
+ *
+ * @param buffer Imported buffer handle.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid.
+ * @return reservedRegion CPU-accessible pointer to the reserved region
+ * @return reservedSize the size of the reservedRegion that was requested
+ * in the BufferDescriptorInfo.
+ */
+ getReservedRegion(pointer buffer)
+ generates (Error error,
+ pointer reservedRegion,
+ uint64_t reservedSize);
};
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
index 8073e69..cb90fa0 100644
--- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -17,8 +17,6 @@
#include <gralloctypes/Gralloc4.h>
#include <mapper-vts/4.0/MapperVts.h>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace android {
namespace hardware {
namespace graphics {
@@ -36,19 +34,19 @@
}
void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
- mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+ mAllocator = IAllocator::getService(allocatorServiceName);
ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
- mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName);
+ mMapper = IMapper::getService(mapperServiceName);
ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
}
void Gralloc::initNoErr(const std::string& allocatorServiceName,
const std::string& mapperServiceName) {
- mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+ mAllocator = IAllocator::getService(allocatorServiceName);
- mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName);
+ mMapper = IMapper::getService(mapperServiceName);
if (mMapper.get()) {
ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
}
@@ -73,13 +71,6 @@
return mAllocator;
}
-std::string Gralloc::dumpDebugInfo() {
- std::string debugInfo;
- mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
-
- return debugInfo;
-}
-
const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) {
const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
EXPECT_NE(nullptr, bufferHandle);
@@ -246,6 +237,34 @@
return releaseFence;
}
+int Gralloc::flushLockedBuffer(const native_handle_t* bufferHandle) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ int releaseFence = -1;
+ mMapper->flushLockedBuffer(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to flush locked buffer " << buffer;
+
+ auto fenceHandle = tmpReleaseFence.getNativeHandle();
+ if (fenceHandle) {
+ ASSERT_EQ(0, fenceHandle->numInts) << "invalid fence handle " << fenceHandle;
+ if (fenceHandle->numFds == 1) {
+ releaseFence = dup(fenceHandle->data[0]);
+ ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
+ } else {
+ ASSERT_EQ(0, fenceHandle->numFds) << " invalid fence handle " << fenceHandle;
+ }
+ }
+ });
+
+ return releaseFence;
+}
+
+void Gralloc::rereadLockedBuffer(const native_handle_t* bufferHandle) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ ASSERT_EQ(Error::NONE, mMapper->rereadLockedBuffer(buffer));
+}
+
bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle,
const IMapper::BufferDescriptorInfo& descriptorInfo,
uint32_t stride) {
@@ -310,6 +329,19 @@
return err;
}
+Error Gralloc::getReservedRegion(const native_handle_t* bufferHandle, void** outReservedRegion,
+ uint64_t* outReservedSize) {
+ Error err;
+ mMapper->getReservedRegion(
+ const_cast<native_handle_t*>(bufferHandle),
+ [&](const auto& tmpError, const auto& tmpReservedRegion, const auto& tmpReservedSize) {
+ err = tmpError;
+ *outReservedRegion = tmpReservedRegion;
+ *outReservedSize = tmpReservedSize;
+ });
+ return err;
+}
+
} // namespace vts
} // namespace V4_0
} // namespace mapper
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
index 6251e66..cd40aa4 100644
--- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -22,6 +22,7 @@
#include <android/hardware/graphics/allocator/4.0/IAllocator.h>
#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <gtest/gtest.h>
#include <utils/StrongPointer.h>
namespace android {
@@ -44,8 +45,6 @@
sp<IAllocator> getAllocator() const;
- std::string dumpDebugInfo();
-
// When import is false, this simply calls IAllocator::allocate. When import
// is true, the returned buffers are also imported into the mapper.
//
@@ -73,6 +72,9 @@
const IMapper::Rect& accessRegion, int acquireFence);
int unlock(const native_handle_t* bufferHandle);
+ int flushLockedBuffer(const native_handle_t* bufferHandle);
+ void rereadLockedBuffer(const native_handle_t* bufferHandle);
+
bool validateBufferSize(const native_handle_t* bufferHandle,
const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride);
void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
@@ -90,6 +92,9 @@
const IMapper::MetadataType& metadataType,
hidl_vec<uint8_t>* outVec);
+ Error getReservedRegion(const native_handle_t* bufferHandle, void** outReservedRegion,
+ uint64_t* outReservedSize);
+
private:
void init(const std::string& allocatorServiceName, const std::string& mapperServiceName);
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
index a8030ab..3542a6e 100644
--- a/graphics/mapper/4.0/vts/functional/Android.bp
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -19,7 +19,10 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
static_libs: [
+ "android.hardware.graphics.common-ndk_platform",
"android.hardware.graphics.mapper@4.0-vts",
+ "libgralloctypes",
+ "libsync",
],
shared_libs: [
"android.hardware.graphics.allocator@4.0",
@@ -27,11 +30,12 @@
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@4.0",
- "libgralloctypes",
- "vintf-graphics-common-ndk_platform",
],
header_libs: [
"libsystem_headers",
],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index d63b078..2aad242 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -16,15 +16,19 @@
#define LOG_TAG "VtsHalGraphicsMapperV4_0TargetTest"
+#include <unistd.h>
#include <chrono>
#include <thread>
#include <vector>
#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
-#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
+#include <android/sync.h>
#include <gralloctypes/Gralloc4.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <mapper-vts/4.0/MapperVts.h>
#include <system/graphics.h>
@@ -40,38 +44,24 @@
using android::hardware::graphics::common::V1_2::PixelFormat;
using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
using aidl::android::hardware::graphics::common::BlendMode;
+using aidl::android::hardware::graphics::common::Cta861_3;
using aidl::android::hardware::graphics::common::Dataspace;
using aidl::android::hardware::graphics::common::ExtendableType;
using aidl::android::hardware::graphics::common::PlaneLayout;
using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+using aidl::android::hardware::graphics::common::Smpte2086;
using aidl::android::hardware::graphics::common::StandardMetadataType;
using DecodeFunction = std::function<void(const IMapper::BufferDescriptorInfo& descriptorInfo,
const hidl_vec<uint8_t>& vec)>;
-// Test environment for graphics.mapper.
-class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static GraphicsMapperHidlEnvironment* Instance() {
- static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override {
- registerTestService<IAllocator>();
- registerTestService<IMapper>();
- }
-};
-
-class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class GraphicsMapperHidlTest
+ : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
protected:
void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(
- mGralloc = std::make_unique<Gralloc>(
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+ ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+ std::get<1>(GetParam())));
ASSERT_NE(nullptr, mGralloc->getAllocator().get());
ASSERT_NE(nullptr, mGralloc->getMapper().get());
@@ -82,6 +72,7 @@
mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
mDummyDescriptorInfo.usage =
static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+ mDummyDescriptorInfo.reservedSize = 0;
}
void TearDown() override {}
@@ -128,7 +119,9 @@
int64_t offsetInBitsA = -1;
for (const auto& component : planeLayout.components) {
- EXPECT_EQ(GRALLOC4_PLANE_LAYOUT_COMPONENT_TYPE, component.type.name);
+ if (!gralloc4::isStandardPlaneLayoutComponentType(component.type)) {
+ continue;
+ }
EXPECT_EQ(8, component.sizeInBits);
if (component.type.value == gralloc4::PlaneLayoutComponentType_R.value) {
offsetInBitsR = component.offsetInBits;
@@ -218,9 +211,7 @@
for (const auto& planeLayout : planeLayouts) {
for (const auto& planeLayoutComponent : planeLayout.components) {
- std::string componentTypeName = planeLayoutComponent.type.name;
- if (!std::strncmp(componentTypeName.c_str(), GRALLOC4_PLANE_LAYOUT_COMPONENT_TYPE,
- componentTypeName.size())) {
+ if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
continue;
}
ASSERT_EQ(0, planeLayoutComponent.offsetInBits % 8);
@@ -273,6 +264,24 @@
ASSERT_NE(nullptr, outYCbCr->cr);
}
+ void fillRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes,
+ uint32_t seed = 0) {
+ for (uint32_t y = 0; y < height; y++) {
+ memset(data, y + seed, widthInBytes);
+ data += strideInBytes;
+ }
+ }
+
+ void verifyRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes,
+ uint32_t seed = 0) {
+ for (uint32_t y = 0; y < height; y++) {
+ for (size_t i = 0; i < widthInBytes; i++) {
+ EXPECT_EQ(static_cast<uint8_t>(y + seed), data[i]);
+ }
+ data += strideInBytes;
+ }
+ }
+
std::unique_ptr<Gralloc> mGralloc;
IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
static const std::set<StandardMetadataType> sRequiredMetadataTypes;
@@ -299,16 +308,9 @@
};
/**
- * Test IAllocator::dumpDebugInfo by calling it.
- */
-TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
- mGralloc->dumpDebugInfo();
-}
-
-/**
* Test IAllocator::allocate with valid buffer descriptors.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocate) {
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
@@ -331,7 +333,7 @@
/**
* Test IAllocator::allocate with invalid buffer descriptors.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
// this assumes any valid descriptor is non-empty
BufferDescriptor descriptor;
mGralloc->getAllocator()->allocate(descriptor, 1,
@@ -343,7 +345,7 @@
/**
* Test IAllocator::allocate does not leak.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
auto info = mDummyDescriptorInfo;
info.width = 1024;
info.height = 1024;
@@ -357,7 +359,7 @@
/**
* Test that IAllocator::allocate is thread-safe.
*/
-TEST_F(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
@@ -388,14 +390,14 @@
/**
* Test IMapper::createDescriptor with valid descriptor info.
*/
-TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorBasic) {
ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
}
/**
* Test IMapper::createDescriptor with invalid descriptor info.
*/
-TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) {
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorNegative) {
auto info = mDummyDescriptorInfo;
info.width = 0;
mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) {
@@ -406,7 +408,7 @@
/**
* Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
*/
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
const native_handle_t* bufferHandle;
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
@@ -415,7 +417,7 @@
/**
* Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
*/
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferClone) {
const native_handle_t* clonedBufferHandle;
ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
@@ -433,7 +435,7 @@
/**
* Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
*/
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
const native_handle_t* rawHandle;
ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
@@ -445,10 +447,8 @@
// free the imported handle with another mapper
std::unique_ptr<Gralloc> anotherGralloc;
- ASSERT_NO_FATAL_FAILURE(
- anotherGralloc = std::make_unique<Gralloc>(
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
- GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+ ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+ std::get<1>(GetParam())));
Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
ASSERT_EQ(Error::NONE, error);
@@ -458,7 +458,7 @@
/**
* Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
*/
-TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
auto info = mDummyDescriptorInfo;
info.width = 1024;
info.height = 1024;
@@ -472,7 +472,7 @@
/**
* Test IMapper::importBuffer with invalid buffers.
*/
-TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) {
+TEST_P(GraphicsMapperHidlTest, ImportBufferNegative) {
native_handle_t* invalidHandle = nullptr;
mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
@@ -490,7 +490,7 @@
/**
* Test IMapper::freeBuffer with invalid buffers.
*/
-TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) {
+TEST_P(GraphicsMapperHidlTest, FreeBufferNegative) {
native_handle_t* invalidHandle = nullptr;
Error error = mGralloc->getMapper()->freeBuffer(invalidHandle);
EXPECT_EQ(Error::BAD_BUFFER, error) << "freeBuffer with nullptr did not fail with BAD_BUFFER";
@@ -513,7 +513,7 @@
/**
* Test IMapper::lock and IMapper::unlock.
*/
-TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) {
+TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) {
const auto& info = mDummyDescriptorInfo;
const native_handle_t* bufferHandle;
@@ -529,25 +529,14 @@
data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
// RGBA_8888
- size_t strideInBytes = stride * 4;
- size_t writeInBytes = info.width * 4;
-
- for (uint32_t y = 0; y < info.height; y++) {
- memset(data, y, writeInBytes);
- data += strideInBytes;
- }
+ fillRGBA8888(data, info.height, stride * 4, info.width * 4);
ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
// lock again for reading
ASSERT_NO_FATAL_FAILURE(
data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
- for (uint32_t y = 0; y < info.height; y++) {
- for (size_t i = 0; i < writeInBytes; i++) {
- EXPECT_EQ(static_cast<uint8_t>(y), data[i]);
- }
- data += strideInBytes;
- }
+ ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(data, info.height, stride * 4, info.width * 4));
ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
if (fence >= 0) {
@@ -555,7 +544,7 @@
}
}
-TEST_F(GraphicsMapperHidlTest, Lock_YCBCR_420_888) {
+TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) {
auto info = mDummyDescriptorInfo;
info.format = PixelFormat::YCBCR_420_888;
@@ -628,7 +617,7 @@
/**
* Test IMapper::unlock with bad access region
*/
-TEST_F(GraphicsMapperHidlTest, LockBadAccessRegion) {
+TEST_P(GraphicsMapperHidlTest, LockBadAccessRegion) {
const auto& info = mDummyDescriptorInfo;
const native_handle_t* bufferHandle;
@@ -670,7 +659,7 @@
/**
* Test IMapper::unlock with invalid buffers.
*/
-TEST_F(GraphicsMapperHidlTest, UnlockNegative) {
+TEST_P(GraphicsMapperHidlTest, UnlockNegative) {
native_handle_t* invalidHandle = nullptr;
mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
@@ -706,9 +695,78 @@
}
/**
+ * Test IMapper::flush and IMapper::reread.
+ */
+TEST_P(GraphicsMapperHidlTest, FlushRereadBasic) {
+ const auto& info = mDummyDescriptorInfo;
+
+ const native_handle_t* rawHandle;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(
+ rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false, false, &stride));
+
+ const native_handle_t* writeBufferHandle;
+ const native_handle_t* readBufferHandle;
+ ASSERT_NO_FATAL_FAILURE(writeBufferHandle = mGralloc->importBuffer(rawHandle));
+ ASSERT_NO_FATAL_FAILURE(readBufferHandle = mGralloc->importBuffer(rawHandle));
+
+ // lock buffer for writing
+ const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+ static_cast<int32_t>(info.height)};
+ uint8_t* writeData;
+ ASSERT_NO_FATAL_FAILURE(
+ writeData = static_cast<uint8_t*>(mGralloc->lock(
+ writeBufferHandle, static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN), region,
+ -1)));
+
+ uint8_t* readData;
+ ASSERT_NO_FATAL_FAILURE(
+ readData = static_cast<uint8_t*>(mGralloc->lock(
+ readBufferHandle, static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN), region,
+ -1)));
+
+ fillRGBA8888(writeData, info.height, stride * 4, info.width * 4);
+
+ int fence;
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->flushLockedBuffer(writeBufferHandle));
+ ASSERT_EQ(0, sync_wait(fence, 3500));
+ close(fence);
+
+ ASSERT_NO_FATAL_FAILURE(mGralloc->rereadLockedBuffer(readBufferHandle));
+
+ ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(readData, info.height, stride * 4, info.width * 4));
+
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(readBufferHandle));
+ if (fence >= 0) {
+ close(fence);
+ }
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(writeBufferHandle));
+ if (fence >= 0) {
+ close(fence);
+ }
+}
+
+/**
+ * Test IMapper::flushLockedBuffer with bad buffer
+ */
+TEST_P(GraphicsMapperHidlTest, FlushLockedBufferBadBuffer) {
+ ASSERT_NO_FATAL_FAILURE(mGralloc->getMapper()->flushLockedBuffer(
+ nullptr, [&](const auto& tmpError, const auto& /*tmpReleaseFence*/) {
+ ASSERT_EQ(Error::BAD_BUFFER, tmpError);
+ }));
+}
+
+/**
+ * Test IMapper::rereadLockedBuffer with bad buffer
+ */
+TEST_P(GraphicsMapperHidlTest, RereadLockedBufferBadBuffer) {
+ ASSERT_EQ(Error::BAD_BUFFER, mGralloc->getMapper()->rereadLockedBuffer(nullptr));
+}
+
+/**
* Test IMapper::isSupported with required format RGBA_8888
*/
-TEST_F(GraphicsMapperHidlTest, IsSupportedRGBA8888) {
+TEST_P(GraphicsMapperHidlTest, IsSupportedRGBA8888) {
const auto& info = mDummyDescriptorInfo;
bool supported = false;
@@ -719,7 +777,7 @@
/**
* Test IMapper::isSupported with required format YV12
*/
-TEST_F(GraphicsMapperHidlTest, IsSupportedYV12) {
+TEST_P(GraphicsMapperHidlTest, IsSupportedYV12) {
auto info = mDummyDescriptorInfo;
info.format = PixelFormat::YV12;
bool supported = false;
@@ -731,7 +789,7 @@
/**
* Test IMapper::isSupported with optional format Y16
*/
-TEST_F(GraphicsMapperHidlTest, IsSupportedY16) {
+TEST_P(GraphicsMapperHidlTest, IsSupportedY16) {
auto info = mDummyDescriptorInfo;
info.format = PixelFormat::Y16;
bool supported = false;
@@ -742,7 +800,7 @@
/**
* Test IMapper::get(BufferId)
*/
-TEST_F(GraphicsMapperHidlTest, GetBufferId) {
+TEST_P(GraphicsMapperHidlTest, GetBufferId) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_BufferId,
[](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
uint64_t bufferId = 0;
@@ -753,7 +811,7 @@
/**
* Test IMapper::get(Name)
*/
-TEST_F(GraphicsMapperHidlTest, GetName) {
+TEST_P(GraphicsMapperHidlTest, GetName) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Name,
[](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
std::string name;
@@ -765,7 +823,7 @@
/**
* Test IMapper::get(Width)
*/
-TEST_F(GraphicsMapperHidlTest, GetWidth) {
+TEST_P(GraphicsMapperHidlTest, GetWidth) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Width,
[](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
uint64_t width = 0;
@@ -777,7 +835,7 @@
/**
* Test IMapper::get(Height)
*/
-TEST_F(GraphicsMapperHidlTest, GetHeight) {
+TEST_P(GraphicsMapperHidlTest, GetHeight) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Height,
[](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
uint64_t height = 0;
@@ -789,7 +847,7 @@
/**
* Test IMapper::get(LayerCount)
*/
-TEST_F(GraphicsMapperHidlTest, GetLayerCount) {
+TEST_P(GraphicsMapperHidlTest, GetLayerCount) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_LayerCount,
[](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
uint64_t layerCount = 0;
@@ -801,7 +859,7 @@
/**
* Test IMapper::get(PixelFormatRequested)
*/
-TEST_F(GraphicsMapperHidlTest, GetPixelFormatRequested) {
+TEST_P(GraphicsMapperHidlTest, GetPixelFormatRequested) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatRequested,
[](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
PixelFormat pixelFormatRequested = PixelFormat::BLOB;
@@ -814,7 +872,7 @@
/**
* Test IMapper::get(PixelFormatFourCC)
*/
-TEST_F(GraphicsMapperHidlTest, GetPixelFormatFourCC) {
+TEST_P(GraphicsMapperHidlTest, GetPixelFormatFourCC) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC,
[](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
uint32_t pixelFormatFourCC = 0;
@@ -825,7 +883,7 @@
/**
* Test IMapper::get(PixelFormatModifier)
*/
-TEST_F(GraphicsMapperHidlTest, GetPixelFormatModifier) {
+TEST_P(GraphicsMapperHidlTest, GetPixelFormatModifier) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier,
[](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
uint64_t pixelFormatModifier = 0;
@@ -836,7 +894,7 @@
/**
* Test IMapper::get(Usage)
*/
-TEST_F(GraphicsMapperHidlTest, GetUsage) {
+TEST_P(GraphicsMapperHidlTest, GetUsage) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage,
[](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
uint64_t usage = 0;
@@ -848,7 +906,7 @@
/**
* Test IMapper::get(AllocationSize)
*/
-TEST_F(GraphicsMapperHidlTest, GetAllocationSize) {
+TEST_P(GraphicsMapperHidlTest, GetAllocationSize) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_AllocationSize,
[](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
uint64_t allocationSize = 0;
@@ -859,7 +917,7 @@
/**
* Test IMapper::get(ProtectedContent)
*/
-TEST_F(GraphicsMapperHidlTest, GetProtectedContent) {
+TEST_P(GraphicsMapperHidlTest, GetProtectedContent) {
auto info = mDummyDescriptorInfo;
info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
@@ -881,7 +939,7 @@
/**
* Test IMapper::get(Compression)
*/
-TEST_F(GraphicsMapperHidlTest, GetCompression) {
+TEST_P(GraphicsMapperHidlTest, GetCompression) {
auto info = mDummyDescriptorInfo;
info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
@@ -898,7 +956,7 @@
/**
* Test IMapper::get(Interlaced)
*/
-TEST_F(GraphicsMapperHidlTest, GetInterlaced) {
+TEST_P(GraphicsMapperHidlTest, GetInterlaced) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced,
[](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
ExtendableType interlaced = gralloc4::Interlaced_TopBottom;
@@ -912,7 +970,7 @@
/**
* Test IMapper::get(ChromaSiting)
*/
-TEST_F(GraphicsMapperHidlTest, GetChromaSiting) {
+TEST_P(GraphicsMapperHidlTest, GetChromaSiting) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_ChromaSiting,
[](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
ExtendableType chromaSiting = gralloc4::ChromaSiting_Unknown;
@@ -926,7 +984,7 @@
/**
* Test IMapper::get(PlaneLayouts)
*/
-TEST_F(GraphicsMapperHidlTest, GetPlaneLayouts) {
+TEST_P(GraphicsMapperHidlTest, GetPlaneLayouts) {
const native_handle_t* bufferHandle = nullptr;
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
@@ -942,7 +1000,7 @@
/**
* Test IMapper::get(Dataspace)
*/
-TEST_F(GraphicsMapperHidlTest, GetDataspace) {
+TEST_P(GraphicsMapperHidlTest, GetDataspace) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace,
[](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
Dataspace dataspace = Dataspace::DISPLAY_P3;
@@ -954,7 +1012,7 @@
/**
* Test IMapper::get(BlendMode)
*/
-TEST_F(GraphicsMapperHidlTest, GetBlendMode) {
+TEST_P(GraphicsMapperHidlTest, GetBlendMode) {
testGet(mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode,
[](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
BlendMode blendMode = BlendMode::NONE;
@@ -964,9 +1022,45 @@
}
/**
+ * Test IMapper::get(Smpte2086)
+ */
+TEST_P(GraphicsMapperHidlTest, GetSmpte2086) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ std::optional<Smpte2086> smpte2086;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086));
+ EXPECT_FALSE(smpte2086.has_value());
+ });
+}
+
+/**
+ * Test IMapper::get(Cta861_3)
+ */
+TEST_P(GraphicsMapperHidlTest, GetCta861_3) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ std::optional<Cta861_3> cta861_3;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3));
+ EXPECT_FALSE(cta861_3.has_value());
+ });
+}
+
+/**
+ * Test IMapper::get(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, GetSmpte2094_40) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ std::optional<std::vector<uint8_t>> smpte2094_40;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40));
+ EXPECT_FALSE(smpte2094_40.has_value());
+ });
+}
+
+/**
* Test IMapper::get(metadata) with a bad buffer
*/
-TEST_F(GraphicsMapperHidlTest, GetMetadataBadValue) {
+TEST_P(GraphicsMapperHidlTest, GetMetadataBadValue) {
const native_handle_t* bufferHandle = nullptr;
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::BAD_BUFFER,
@@ -1016,12 +1110,21 @@
ASSERT_EQ(Error::BAD_BUFFER,
mGralloc->get(bufferHandle, gralloc4::MetadataType_BlendMode, &vec));
ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2086, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_Cta861_3, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, &vec));
+ ASSERT_EQ(0, vec.size());
}
/**
* Test IMapper::get(metadata) for unsupported metadata
*/
-TEST_F(GraphicsMapperHidlTest, GetUnsupportedMetadata) {
+TEST_P(GraphicsMapperHidlTest, GetUnsupportedMetadata) {
const native_handle_t* bufferHandle = nullptr;
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
@@ -1035,7 +1138,7 @@
/**
* Test IMapper::get(metadata) for unsupported standard metadata
*/
-TEST_F(GraphicsMapperHidlTest, GetUnsupportedStandardMetadata) {
+TEST_P(GraphicsMapperHidlTest, GetUnsupportedStandardMetadata) {
const native_handle_t* bufferHandle = nullptr;
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
@@ -1049,7 +1152,7 @@
/**
* Test IMapper::set(PixelFormatFourCC)
*/
-TEST_F(GraphicsMapperHidlTest, SetPixelFormatFourCC) {
+TEST_P(GraphicsMapperHidlTest, SetPixelFormatFourCC) {
uint32_t pixelFormatFourCC = 0x34324142; // DRM_FORMAT_BGRA8888
hidl_vec<uint8_t> vec;
ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatFourCC(pixelFormatFourCC, &vec));
@@ -1065,7 +1168,7 @@
/**
* Test IMapper::set(PixelFormatModifier)
*/
-TEST_F(GraphicsMapperHidlTest, SetPixelFormatModifier) {
+TEST_P(GraphicsMapperHidlTest, SetPixelFormatModifier) {
uint64_t pixelFormatModifier = 10;
hidl_vec<uint8_t> vec;
ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatModifier(pixelFormatModifier, &vec));
@@ -1082,7 +1185,7 @@
/**
* Test IMapper::set(Usage) remove flag
*/
-TEST_F(GraphicsMapperHidlTest, SetUsageRemoveBit) {
+TEST_P(GraphicsMapperHidlTest, SetUsageRemoveBit) {
uint64_t usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN);
hidl_vec<uint8_t> vec;
ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec));
@@ -1097,7 +1200,7 @@
/**
* Test IMapper::set(Usage) add flag
*/
-TEST_F(GraphicsMapperHidlTest, SetUsageAddBit) {
+TEST_P(GraphicsMapperHidlTest, SetUsageAddBit) {
uint64_t usage = mDummyDescriptorInfo.usage | static_cast<uint64_t>(BufferUsage::GPU_TEXTURE);
hidl_vec<uint8_t> vec;
ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec));
@@ -1113,7 +1216,7 @@
/**
* Test IMapper::set(Usage) to test protected content
*/
-TEST_F(GraphicsMapperHidlTest, SetUsageProtected) {
+TEST_P(GraphicsMapperHidlTest, SetUsageProtected) {
const native_handle_t* bufferHandle = nullptr;
auto info = mDummyDescriptorInfo;
info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
@@ -1140,7 +1243,7 @@
/**
* Test IMapper::set(AllocationSize)
*/
-TEST_F(GraphicsMapperHidlTest, SetAllocationSize) {
+TEST_P(GraphicsMapperHidlTest, SetAllocationSize) {
uint64_t allocationSize = 1000000;
hidl_vec<uint8_t> vec;
ASSERT_EQ(NO_ERROR, gralloc4::encodeAllocationSize(allocationSize, &vec));
@@ -1156,7 +1259,7 @@
/**
* Test IMapper::set(ProtectedContent)
*/
-TEST_F(GraphicsMapperHidlTest, SetProtectedContent) {
+TEST_P(GraphicsMapperHidlTest, SetProtectedContent) {
const native_handle_t* bufferHandle = nullptr;
auto info = mDummyDescriptorInfo;
info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
@@ -1184,7 +1287,7 @@
/**
* Test IMapper::set(Compression)
*/
-TEST_F(GraphicsMapperHidlTest, SetCompression) {
+TEST_P(GraphicsMapperHidlTest, SetCompression) {
auto info = mDummyDescriptorInfo;
info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
@@ -1205,7 +1308,7 @@
/**
* Test IMapper::set(Interlaced)
*/
-TEST_F(GraphicsMapperHidlTest, SetInterlaced) {
+TEST_P(GraphicsMapperHidlTest, SetInterlaced) {
ExtendableType interlaced = gralloc4::Interlaced_RightLeft;
hidl_vec<uint8_t> vec;
ASSERT_EQ(NO_ERROR, gralloc4::encodeInterlaced(interlaced, &vec));
@@ -1223,7 +1326,7 @@
/**
* Test IMapper::set(ChromaSiting)
*/
-TEST_F(GraphicsMapperHidlTest, SetChromaSiting) {
+TEST_P(GraphicsMapperHidlTest, SetChromaSiting) {
ExtendableType chromaSiting = gralloc4::ChromaSiting_SitedInterstitial;
hidl_vec<uint8_t> vec;
ASSERT_EQ(NO_ERROR, gralloc4::encodeChromaSiting(chromaSiting, &vec));
@@ -1241,7 +1344,7 @@
/**
* Test IMapper::set(PlaneLayouts)
*/
-TEST_F(GraphicsMapperHidlTest, SetPlaneLayouts) {
+TEST_P(GraphicsMapperHidlTest, SetPlaneLayouts) {
const native_handle_t* bufferHandle = nullptr;
auto info = mDummyDescriptorInfo;
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));
@@ -1342,8 +1445,8 @@
/**
* Test IMapper::set(Dataspace)
*/
-TEST_F(GraphicsMapperHidlTest, SetDataspace) {
- Dataspace dataspace = Dataspace::V0_SRGB_LINEAR;
+TEST_P(GraphicsMapperHidlTest, SetDataspace) {
+ Dataspace dataspace = Dataspace::SRGB_LINEAR;
hidl_vec<uint8_t> vec;
ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &vec));
@@ -1358,7 +1461,7 @@
/**
* Test IMapper::set(BlendMode)
*/
-TEST_F(GraphicsMapperHidlTest, SetBlendMode) {
+TEST_P(GraphicsMapperHidlTest, SetBlendMode) {
BlendMode blendMode = BlendMode::PREMULTIPLIED;
hidl_vec<uint8_t> vec;
ASSERT_EQ(NO_ERROR, gralloc4::encodeBlendMode(blendMode, &vec));
@@ -1372,9 +1475,93 @@
}
/**
+ * Test IMapper::set(Smpte2086)
+ */
+TEST_P(GraphicsMapperHidlTest, SetSmpte2086) {
+ /**
+ * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,
+ * the D65 white point and the SRGB transfer functions.
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.265 0.690
+ * blue 0.150 0.060
+ * red 0.680 0.320
+ * white (D65) 0.3127 0.3290
+ */
+ std::optional<Smpte2086> smpte2086;
+ smpte2086->primaryRed.x = 0.680;
+ smpte2086->primaryRed.y = 0.320;
+ smpte2086->primaryGreen.x = 0.265;
+ smpte2086->primaryGreen.y = 0.690;
+ smpte2086->primaryBlue.x = 0.150;
+ smpte2086->primaryBlue.y = 0.060;
+ smpte2086->whitePoint.x = 0.3127;
+ smpte2086->whitePoint.y = 0.3290;
+ smpte2086->maxLuminance = 100.0;
+ smpte2086->minLuminance = 0.1;
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2086(smpte2086, &vec));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ std::optional<Smpte2086> realSmpte2086;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &realSmpte2086));
+ ASSERT_TRUE(realSmpte2086.has_value());
+ EXPECT_EQ(smpte2086->primaryRed.x, realSmpte2086->primaryRed.x);
+ EXPECT_EQ(smpte2086->primaryRed.y, realSmpte2086->primaryRed.y);
+ EXPECT_EQ(smpte2086->primaryGreen.x, realSmpte2086->primaryGreen.x);
+ EXPECT_EQ(smpte2086->primaryGreen.y, realSmpte2086->primaryGreen.y);
+ EXPECT_EQ(smpte2086->primaryBlue.x, realSmpte2086->primaryBlue.x);
+ EXPECT_EQ(smpte2086->primaryBlue.y, realSmpte2086->primaryBlue.y);
+ EXPECT_EQ(smpte2086->whitePoint.x, realSmpte2086->whitePoint.x);
+ EXPECT_EQ(smpte2086->whitePoint.y, realSmpte2086->whitePoint.y);
+ EXPECT_EQ(smpte2086->maxLuminance, realSmpte2086->maxLuminance);
+ EXPECT_EQ(smpte2086->minLuminance, realSmpte2086->minLuminance);
+ });
+}
+
+/**
+ * Test IMapper::set(Cta8613)
+ */
+TEST_P(GraphicsMapperHidlTest, SetCta861_3) {
+ std::optional<Cta861_3> cta861_3;
+ cta861_3->maxContentLightLevel = 78.0;
+ cta861_3->maxFrameAverageLightLevel = 62.0;
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeCta861_3(cta861_3, &vec));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ std::optional<Cta861_3> realCta861_3;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &realCta861_3));
+ ASSERT_TRUE(realCta861_3.has_value());
+ EXPECT_EQ(cta861_3->maxContentLightLevel, realCta861_3->maxContentLightLevel);
+ EXPECT_EQ(cta861_3->maxFrameAverageLightLevel,
+ realCta861_3->maxFrameAverageLightLevel);
+ });
+}
+
+/**
+ * Test IMapper::set(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, SetSmpte2094_40) {
+ hidl_vec<uint8_t> vec;
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ std::optional<std::vector<uint8_t>> realSmpte2094_40;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40));
+ EXPECT_FALSE(realSmpte2094_40.has_value());
+ });
+}
+
+/**
* Test IMapper::set(metadata) with a bad buffer
*/
-TEST_F(GraphicsMapperHidlTest, SetMetadataNullBuffer) {
+TEST_P(GraphicsMapperHidlTest, SetMetadataNullBuffer) {
const native_handle_t* bufferHandle = nullptr;
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec));
@@ -1406,12 +1593,17 @@
mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec));
ASSERT_EQ(Error::BAD_BUFFER,
mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
+ ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2094_40, vec));
}
/**
* Test IMapper::set(metadata) for constant metadata
*/
-TEST_F(GraphicsMapperHidlTest, SetConstantMetadata) {
+TEST_P(GraphicsMapperHidlTest, SetConstantMetadata) {
const native_handle_t* bufferHandle = nullptr;
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
@@ -1430,7 +1622,7 @@
/**
* Test IMapper::set(metadata) for bad metadata
*/
-TEST_F(GraphicsMapperHidlTest, SetBadMetadata) {
+TEST_P(GraphicsMapperHidlTest, SetBadMetadata) {
const native_handle_t* bufferHandle = nullptr;
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
@@ -1465,12 +1657,16 @@
mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec));
ASSERT_EQ(Error::UNSUPPORTED,
mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec));
}
/**
* Test IMapper::getFromBufferDescriptorInfo(BufferId)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBufferId) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBufferId) {
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::UNSUPPORTED,
mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
@@ -1480,7 +1676,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(Name)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoName) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoName) {
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
mDummyDescriptorInfo, gralloc4::MetadataType_Name, &vec));
@@ -1493,7 +1689,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(Width)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoWidth) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoWidth) {
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
mDummyDescriptorInfo, gralloc4::MetadataType_Width, &vec));
@@ -1506,7 +1702,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(Height)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoHeight) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoHeight) {
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
mDummyDescriptorInfo, gralloc4::MetadataType_Height, &vec));
@@ -1519,7 +1715,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(PixelFormatRequested)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatRequested) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatRequested) {
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::NONE,
mGralloc->getFromBufferDescriptorInfo(
@@ -1533,7 +1729,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(PixelFormatFourCC)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatFourCC) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatFourCC) {
hidl_vec<uint8_t> vec;
Error err = mGralloc->getFromBufferDescriptorInfo(
mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, &vec);
@@ -1549,7 +1745,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(PixelFormatModifier)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatModifier) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatModifier) {
hidl_vec<uint8_t> vec;
Error err = mGralloc->getFromBufferDescriptorInfo(
mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, &vec);
@@ -1565,7 +1761,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(Usage)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUsage) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUsage) {
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
mDummyDescriptorInfo, gralloc4::MetadataType_Usage, &vec));
@@ -1578,7 +1774,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(AllocationSize)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoAllocationSize) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoAllocationSize) {
hidl_vec<uint8_t> vec;
Error err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
gralloc4::MetadataType_AllocationSize, &vec);
@@ -1594,7 +1790,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(ProtectedContent)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoProtectedContent) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoProtectedContent) {
auto info = mDummyDescriptorInfo;
info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
@@ -1610,7 +1806,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(Compression)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCompression) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCompression) {
auto info = mDummyDescriptorInfo;
info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
@@ -1628,7 +1824,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(Interlaced)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoInterlaced) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoInterlaced) {
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced, &vec));
@@ -1643,7 +1839,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(ChromaSiting)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoChromaSiting) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoChromaSiting) {
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::NONE,
mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
@@ -1659,7 +1855,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(PlaneLayouts)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) {
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::NONE,
mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
@@ -1673,7 +1869,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(Dataspace)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoDataspace) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoDataspace) {
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace, &vec));
@@ -1686,7 +1882,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(BlendMode)
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) {
hidl_vec<uint8_t> vec;
ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode, &vec));
@@ -1697,9 +1893,48 @@
}
/**
+ * Test IMapper::getFromBufferDescriptorInfo(Smpte2086)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2086) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, &vec));
+
+ std::optional<Smpte2086> smpte2086;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086));
+ EXPECT_FALSE(smpte2086.has_value());
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Cta861_3)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCta861_3) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, &vec));
+
+ std::optional<Cta861_3> cta861_3;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3));
+ EXPECT_FALSE(cta861_3.has_value());
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2094_40) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE,
+ mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+ gralloc4::MetadataType_Smpte2094_40, &vec));
+ std::optional<std::vector<uint8_t>> smpte2094_40;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40));
+ EXPECT_FALSE(smpte2094_40.has_value());
+}
+
+/**
* Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported metadata
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedMetadata) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedMetadata) {
MetadataType metadataTypeFake = {"FAKE", 1};
hidl_vec<uint8_t> vec;
@@ -1711,7 +1946,7 @@
/**
* Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported standard metadata
*/
-TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedStandardMetadata) {
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedStandardMetadata) {
MetadataType metadataTypeFake = {GRALLOC4_STANDARD_METADATA_TYPE, 9999};
hidl_vec<uint8_t> vec;
@@ -1723,7 +1958,7 @@
/**
* Test IMapper::listSupportedMetadataTypes()
*/
-TEST_F(GraphicsMapperHidlTest, ListSupportedMetadataTypes) {
+TEST_P(GraphicsMapperHidlTest, ListSupportedMetadataTypes) {
hidl_vec<IMapper::MetadataTypeDescription> descriptions;
mGralloc->getMapper()->listSupportedMetadataTypes(
[&](const auto& tmpError, const auto& tmpDescriptions) {
@@ -1771,7 +2006,7 @@
/**
* Test IMapper::dumpBuffer()
*/
-TEST_F(GraphicsMapperHidlTest, DumpBuffer) {
+TEST_P(GraphicsMapperHidlTest, DumpBuffer) {
const native_handle_t* bufferHandle = nullptr;
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
auto buffer = const_cast<native_handle_t*>(bufferHandle);
@@ -1788,7 +2023,7 @@
/**
* Test IMapper::dumpBuffer() with an invalid buffer
*/
-TEST_F(GraphicsMapperHidlTest, DumpBufferNullBuffer) {
+TEST_P(GraphicsMapperHidlTest, DumpBufferNullBuffer) {
native_handle_t* bufferHandle = nullptr;
auto buffer = const_cast<native_handle_t*>(bufferHandle);
@@ -1801,7 +2036,7 @@
/**
* Test IMapper::dumpBuffer() multiple
*/
-TEST_F(GraphicsMapperHidlTest, DumpBuffers) {
+TEST_P(GraphicsMapperHidlTest, DumpBuffers) {
size_t bufferCount = 10;
for (int i = 0; i < bufferCount; i++) {
@@ -1821,6 +2056,130 @@
}
}
+/**
+ * Test IMapper::getReservedRegion()
+ */
+TEST_P(GraphicsMapperHidlTest, GetReservedRegion) {
+ const native_handle_t* bufferHandle = nullptr;
+ auto info = mDummyDescriptorInfo;
+
+ const int pageSize = getpagesize();
+ ASSERT_GE(0, pageSize);
+ std::vector<uint64_t> requestedReservedSizes{1, 10, 333, static_cast<uint64_t>(pageSize) / 2,
+ static_cast<uint64_t>(pageSize)};
+
+ for (auto requestedReservedSize : requestedReservedSizes) {
+ info.reservedSize = requestedReservedSize;
+
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));
+
+ void* reservedRegion = nullptr;
+ uint64_t reservedSize = 0;
+ ASSERT_EQ(Error::NONE,
+ mGralloc->getReservedRegion(bufferHandle, &reservedRegion, &reservedSize));
+ ASSERT_NE(nullptr, reservedRegion);
+ ASSERT_EQ(requestedReservedSize, reservedSize);
+
+ uint8_t testValue = 1;
+ memset(reservedRegion, testValue, reservedSize);
+ for (uint64_t i = 0; i < reservedSize; i++) {
+ ASSERT_EQ(testValue, static_cast<uint8_t*>(reservedRegion)[i]);
+ }
+ }
+}
+
+/**
+ * Test IMapper::getReservedRegion() request over a page
+ */
+TEST_P(GraphicsMapperHidlTest, GetLargeReservedRegion) {
+ const native_handle_t* bufferHandle = nullptr;
+ auto info = mDummyDescriptorInfo;
+
+ const int pageSize = getpagesize();
+ ASSERT_GE(0, pageSize);
+ std::vector<uint64_t> requestedReservedSizes{static_cast<uint64_t>(pageSize) * 2,
+ static_cast<uint64_t>(pageSize) * 10,
+ static_cast<uint64_t>(pageSize) * 1000};
+
+ for (auto requestedReservedSize : requestedReservedSizes) {
+ info.reservedSize = requestedReservedSize;
+
+ BufferDescriptor descriptor;
+ ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(info));
+
+ Error err;
+ mGralloc->getAllocator()->allocate(
+ descriptor, 1,
+ [&](const auto& tmpError, const auto&, const auto&) { err = tmpError; });
+ if (err == Error::UNSUPPORTED) {
+ continue;
+ }
+ ASSERT_EQ(Error::NONE, err);
+
+ void* reservedRegion = nullptr;
+ uint64_t reservedSize = 0;
+ err = mGralloc->getReservedRegion(bufferHandle, &reservedRegion, &reservedSize);
+
+ ASSERT_EQ(Error::NONE, err);
+ ASSERT_NE(nullptr, reservedRegion);
+ ASSERT_EQ(requestedReservedSize, reservedSize);
+ }
+}
+
+/**
+ * Test IMapper::getReservedRegion() across multiple mappers
+ */
+TEST_P(GraphicsMapperHidlTest, GetReservedRegionMultiple) {
+ const native_handle_t* bufferHandle = nullptr;
+ auto info = mDummyDescriptorInfo;
+
+ const int pageSize = getpagesize();
+ ASSERT_GE(0, pageSize);
+ info.reservedSize = pageSize;
+
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));
+
+ void* reservedRegion1 = nullptr;
+ uint64_t reservedSize1 = 0;
+ ASSERT_EQ(Error::NONE,
+ mGralloc->getReservedRegion(bufferHandle, &reservedRegion1, &reservedSize1));
+ ASSERT_NE(nullptr, reservedRegion1);
+ ASSERT_EQ(info.reservedSize, reservedSize1);
+
+ std::unique_ptr<Gralloc> anotherGralloc;
+ ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+ std::get<1>(GetParam())));
+
+ void* reservedRegion2 = nullptr;
+ uint64_t reservedSize2 = 0;
+ ASSERT_EQ(Error::NONE,
+ mGralloc->getReservedRegion(bufferHandle, &reservedRegion2, &reservedSize2));
+ ASSERT_EQ(reservedRegion1, reservedRegion2);
+ ASSERT_EQ(reservedSize1, reservedSize2);
+}
+
+/**
+ * Test IMapper::getReservedRegion() with a bad buffer
+ */
+TEST_P(GraphicsMapperHidlTest, GetReservedRegionBadBuffer) {
+ const native_handle_t* bufferHandle = nullptr;
+
+ void* reservedRegion = nullptr;
+ uint64_t reservedSize = 0;
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->getReservedRegion(bufferHandle, &reservedRegion, &reservedSize));
+ ASSERT_EQ(nullptr, reservedRegion);
+ ASSERT_EQ(0, reservedSize);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, GraphicsMapperHidlTest,
+ testing::Combine(
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
+
} // namespace
} // namespace vts
} // namespace V4_0
@@ -1828,13 +2187,3 @@
} // namespace graphics
} // namespace hardware
} // namespace android
-
-int main(int argc, char** argv) {
- using android::hardware::graphics::mapper::V4_0::vts::GraphicsMapperHidlEnvironment;
- ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
diff --git a/health/1.0/default/Android.bp b/health/1.0/default/Android.bp
index 049e393..7581335 100644
--- a/health/1.0/default/Android.bp
+++ b/health/1.0/default/Android.bp
@@ -18,3 +18,55 @@
}
+cc_library_static {
+ name: "android.hardware.health@1.0-impl-helper",
+ vendor: true,
+ srcs: ["Health.cpp"],
+
+ header_libs: [
+ "libbase_headers",
+ "libhealthd_headers",
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "android.hardware.health@1.0",
+ ],
+
+ static_libs: [
+ "android.hardware.health@1.0-convert",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.health@1.0-impl",
+ vendor: true,
+ relative_install_path: "hw",
+
+ static_libs: [
+ "android.hardware.health@1.0-impl-helper",
+ "android.hardware.health@1.0-convert",
+ "libhealthd.default",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.health@1.0-service",
+ vendor: true,
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.health@1.0-service.rc"],
+ srcs: ["HealthService.cpp"],
+
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libdl",
+ "libbase",
+ "libutils",
+ "libhidlbase",
+ "android.hardware.health@1.0",
+ ],
+}
diff --git a/health/1.0/default/Android.mk b/health/1.0/default/Android.mk
deleted file mode 100644
index bbf37af..0000000
--- a/health/1.0/default/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.health@1.0-impl
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_C_INCLUDES := system/core/base/include
-LOCAL_SRC_FILES := \
- Health.cpp \
-
-LOCAL_HEADER_LIBRARIES := libhealthd_headers
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libhidlbase \
- liblog \
- libutils \
- android.hardware.health@1.0 \
-
-LOCAL_STATIC_LIBRARIES := android.hardware.health@1.0-convert
-
-LOCAL_HAL_STATIC_LIBRARIES := libhealthd
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_MODULE := android.hardware.health@1.0-service
-LOCAL_INIT_RC := android.hardware.health@1.0-service.rc
-LOCAL_SRC_FILES := \
- HealthService.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libcutils \
- libdl \
- libbase \
- libutils \
- libhidlbase \
- android.hardware.health@1.0 \
-
-include $(BUILD_EXECUTABLE)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/health/1.0/default/README.md b/health/1.0/default/README.md
new file mode 100644
index 0000000..1ded7de
--- /dev/null
+++ b/health/1.0/default/README.md
@@ -0,0 +1,66 @@
+# Implement the 2.1 HAL instead!
+
+It is strongly recommended that you implement the 2.1 HAL directly. See
+`hardware/interfaces/health/2.1/README.md` for more details.
+
+# Implement Health 1.0 HAL
+
+1. Install common binderized service. The binderized service `dlopen()`s
+ passthrough implementations on the device, so there is no need to write
+ your own.
+
+ ```mk
+ # Install default binderized implementation to vendor.
+ PRODUCT_PACKAGES += android.hardware.health@1.0-service
+ ```
+
+1. Add proper VINTF manifest entry to your device manifest. Example:
+
+ ```xml
+ <hal format="hidl">
+ <name>android.hardware.health</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IHealth</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ ```
+
+1. Install the proper passthrough implemetation.
+
+ 1. If you want to use the default implementation (with default `libhealthd`),
+ add the following to `device.mk`:
+
+ ```mk
+ PRODUCT_PACKAGES += \
+ android.hardware.health@1.0-impl
+ ```
+
+ 1. Otherwise, if you have a customized `libhealthd.<board>`:
+
+ 1. Define your passthrough implementation. Example (replace `<device>`
+ and `<board>` accordingly):
+
+ ```bp
+ cc_library_shared {
+ name: "android.hardware.health@1.0-impl-<device>",
+ vendor: true,
+ relative_install_path: "hw",
+
+ static_libs: [
+ "android.hardware.health@1.0-impl-helper",
+ "android.hardware.health@1.0-convert",
+ "libhealthd.<board>",
+ ],
+ }
+ ```
+
+ 1. Add to `device.mk`.
+
+ ```
+ PRODUCT_PACKAGES += android.hardware.health@1.0-impl-<device>
+ ```
+
+ 1. Define appropriate SELinux permissions.
diff --git a/health/2.0/vts/functional/Android.bp b/health/2.0/vts/functional/Android.bp
index b090548..43571ef 100644
--- a/health/2.0/vts/functional/Android.bp
+++ b/health/2.0/vts/functional/Android.bp
@@ -23,5 +23,5 @@
"android.hardware.health@1.0",
"android.hardware.health@2.0",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
index 6e13a98..49891b7 100644
--- a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
+++ b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
@@ -20,17 +20,18 @@
#include <set>
#include <string>
-#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
#include <android/hardware/health/2.0/IHealth.h>
#include <android/hardware/health/2.0/types.h>
#include <gflags/gflags.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
using ::testing::AssertionFailure;
using ::testing::AssertionResult;
using ::testing::AssertionSuccess;
-using ::testing::VtsHalHidlTargetTestBase;
-using ::testing::VtsHalHidlTargetTestEnvBase;
DEFINE_bool(force, false, "Force test healthd even when the default instance is present.");
@@ -74,30 +75,13 @@
using V1_0::BatteryStatus;
-// Test environment for graphics.composer
-class HealthHidlEnvironment : public VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static HealthHidlEnvironment* Instance() {
- static HealthHidlEnvironment* instance = new HealthHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IHealth>(); }
-
- private:
- HealthHidlEnvironment() {}
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(HealthHidlEnvironment);
-};
-
-class HealthHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class HealthHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- std::string serviceName = HealthHidlEnvironment::Instance()->getServiceName<IHealth>();
+ std::string serviceName = GetParam();
if (serviceName == "backup" && !FLAGS_force &&
- ::testing::VtsHalHidlTargetTestBase::getService<IHealth>() != nullptr) {
+ IHealth::getService() != nullptr) {
LOG(INFO) << "Skipping tests on healthd because the default instance is present. "
<< "Use --force if you really want to test healthd.";
GTEST_SKIP();
@@ -105,7 +89,7 @@
LOG(INFO) << "get service with name:" << serviceName;
ASSERT_FALSE(serviceName.empty());
- mHealth = ::testing::VtsHalHidlTargetTestBase::getService<IHealth>(serviceName);
+ mHealth = IHealth::getService(serviceName);
ASSERT_NE(mHealth, nullptr);
}
@@ -156,7 +140,7 @@
* Test whether callbacks work. Tested functions are IHealth::registerCallback,
* unregisterCallback, and update.
*/
-TEST_F(HealthHidlTest, Callbacks) {
+TEST_P(HealthHidlTest, Callbacks) {
SKIP_IF_SKIPPED();
using namespace std::chrono_literals;
sp<Callback> firstCallback = new Callback();
@@ -193,7 +177,7 @@
ASSERT_ALL_OK(mHealth->unregisterCallback(secondCallback));
}
-TEST_F(HealthHidlTest, UnregisterNonExistentCallback) {
+TEST_P(HealthHidlTest, UnregisterNonExistentCallback) {
SKIP_IF_SKIPPED();
sp<Callback> callback = new Callback();
auto ret = mHealth->unregisterCallback(callback);
@@ -278,7 +262,7 @@
/*
* Tests the values returned by getChargeCounter() from interface IHealth.
*/
-TEST_F(HealthHidlTest, getChargeCounter) {
+TEST_P(HealthHidlTest, getChargeCounter) {
SKIP_IF_SKIPPED();
EXPECT_OK(mHealth->getChargeCounter([](auto result, auto value) {
EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value > 0);
@@ -288,7 +272,7 @@
/*
* Tests the values returned by getCurrentNow() from interface IHealth.
*/
-TEST_F(HealthHidlTest, getCurrentNow) {
+TEST_P(HealthHidlTest, getCurrentNow) {
SKIP_IF_SKIPPED();
EXPECT_OK(mHealth->getCurrentNow([](auto result, auto value) {
EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT32_MIN);
@@ -298,7 +282,7 @@
/*
* Tests the values returned by getCurrentAverage() from interface IHealth.
*/
-TEST_F(HealthHidlTest, getCurrentAverage) {
+TEST_P(HealthHidlTest, getCurrentAverage) {
SKIP_IF_SKIPPED();
EXPECT_OK(mHealth->getCurrentAverage([](auto result, auto value) {
EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT32_MIN);
@@ -308,7 +292,7 @@
/*
* Tests the values returned by getCapacity() from interface IHealth.
*/
-TEST_F(HealthHidlTest, getCapacity) {
+TEST_P(HealthHidlTest, getCapacity) {
SKIP_IF_SKIPPED();
EXPECT_OK(mHealth->getCapacity([](auto result, auto value) {
EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), 0 <= value && value <= 100);
@@ -318,7 +302,7 @@
/*
* Tests the values returned by getEnergyCounter() from interface IHealth.
*/
-TEST_F(HealthHidlTest, getEnergyCounter) {
+TEST_P(HealthHidlTest, getEnergyCounter) {
SKIP_IF_SKIPPED();
EXPECT_OK(mHealth->getEnergyCounter([](auto result, auto value) {
EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT64_MIN);
@@ -328,7 +312,7 @@
/*
* Tests the values returned by getChargeStatus() from interface IHealth.
*/
-TEST_F(HealthHidlTest, getChargeStatus) {
+TEST_P(HealthHidlTest, getChargeStatus) {
SKIP_IF_SKIPPED();
EXPECT_OK(mHealth->getChargeStatus([](auto result, auto value) {
EXPECT_VALID_OR_UNSUPPORTED_PROP(
@@ -340,7 +324,7 @@
/*
* Tests the values returned by getStorageInfo() from interface IHealth.
*/
-TEST_F(HealthHidlTest, getStorageInfo) {
+TEST_P(HealthHidlTest, getStorageInfo) {
SKIP_IF_SKIPPED();
EXPECT_OK(mHealth->getStorageInfo([](auto result, auto& value) {
EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyStorageInfo(value));
@@ -350,7 +334,7 @@
/*
* Tests the values returned by getDiskStats() from interface IHealth.
*/
-TEST_F(HealthHidlTest, getDiskStats) {
+TEST_P(HealthHidlTest, getDiskStats) {
SKIP_IF_SKIPPED();
EXPECT_OK(mHealth->getDiskStats([](auto result, auto& value) {
EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), true);
@@ -360,25 +344,24 @@
/*
* Tests the values returned by getHealthInfo() from interface IHealth.
*/
-TEST_F(HealthHidlTest, getHealthInfo) {
+TEST_P(HealthHidlTest, getHealthInfo) {
SKIP_IF_SKIPPED();
EXPECT_OK(mHealth->getHealthInfo([](auto result, auto& value) {
EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyHealthInfo(value));
}));
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, HealthHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)),
+ android::hardware::PrintInstanceNameToString);
} // namespace V2_0
} // namespace health
} // namespace hardware
} // namespace android
int main(int argc, char** argv) {
- using ::android::hardware::health::V2_0::HealthHidlEnvironment;
- ::testing::AddGlobalTestEnvironment(HealthHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
- HealthHidlEnvironment::Instance()->init(&argc, argv);
gflags::ParseCommandLineFlags(&argc, &argv, true /* remove flags */);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
+ return RUN_ALL_TESTS();
}
diff --git a/keymaster/3.0/vts/functional/Android.bp b/keymaster/3.0/vts/functional/Android.bp
index 69aa56d..36a6861 100644
--- a/keymaster/3.0/vts/functional/Android.bp
+++ b/keymaster/3.0/vts/functional/Android.bp
@@ -29,5 +29,5 @@
"libcrypto_static",
"libsoftkeymasterdevice",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/keymaster/3.0/vts/functional/AndroidTest.xml b/keymaster/3.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..71e41fc
--- /dev/null
+++ b/keymaster/3.0/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalKeymasterV3_0TargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsHalKeymasterV3_0TargetTest->/data/local/tmp/VtsHalKeymasterV3_0TargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalKeymasterV3_0TargetTest" />
+ <option name="native-test-timeout" value="900000"/>
+ </test>
+</configuration>
diff --git a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
index ccb5622..ae32764 100644
--- a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -25,17 +25,15 @@
#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
#include <android/hardware/keymaster/3.0/types.h>
-
#include <cutils/properties.h>
-
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <keymaster/keymaster_configuration.h>
#include "authorization_set.h"
#include "key_param_output.h"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
#include "attestation_record.h"
#include "openssl_utils.h"
@@ -413,33 +411,19 @@
} // namespace
-// Test environment for Keymaster HIDL HAL.
-class KeymasterHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static KeymasterHidlEnvironment* Instance() {
- static KeymasterHidlEnvironment* instance = new KeymasterHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IKeymasterDevice>(); }
- private:
- KeymasterHidlEnvironment() {}
-};
-
-class KeymasterHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class KeymasterHidlTest : public ::testing::TestWithParam<std::string> {
public:
void TearDown() override {
if (key_blob_.size()) {
CheckedDeleteKey();
}
AbortIfNeeded();
+
+ keymaster_.clear();
}
- // SetUpTestCase runs only once per test case, not once per test.
- static void SetUpTestCase() {
- keymaster_ = ::testing::VtsHalHidlTargetTestBase::getService<IKeymasterDevice>(
- KeymasterHidlEnvironment::Instance()->getServiceName<IKeymasterDevice>());
+ void SetUp() override {
+ keymaster_ = IKeymasterDevice::getService(GetParam());
ASSERT_NE(keymaster_, nullptr);
ASSERT_TRUE(
@@ -461,11 +445,9 @@
os_patch_level_ = ::keymaster::GetOsPatchlevel();
}
- static void TearDownTestCase() { keymaster_.clear(); }
-
- static IKeymasterDevice& keymaster() { return *keymaster_; }
- static uint32_t os_version() { return os_version_; }
- static uint32_t os_patch_level() { return os_patch_level_; }
+ IKeymasterDevice& keymaster() { return *keymaster_; }
+ uint32_t os_version() { return os_version_; }
+ uint32_t os_patch_level() { return os_patch_level_; }
AuthorizationSet UserAuths() { return AuthorizationSetBuilder().Authorization(TAG_USER_ID, 7); }
@@ -929,134 +911,121 @@
}
}
- static bool IsSecure() { return is_secure_; }
- static bool SupportsEc() { return supports_ec_; }
- static bool SupportsSymmetric() { return supports_symmetric_; }
- static bool SupportsAllDigests() { return supports_all_digests_; }
- static bool SupportsAttestation() { return supports_attestation_; }
+ bool IsSecure() { return is_secure_; }
+ bool SupportsEc() { return supports_ec_; }
+ bool SupportsSymmetric() { return supports_symmetric_; }
+ bool SupportsAllDigests() { return supports_all_digests_; }
+ bool SupportsAttestation() { return supports_attestation_; }
- static bool Km2Profile() {
+ bool Km2Profile() {
return SupportsAttestation() && SupportsAllDigests() && SupportsSymmetric() &&
SupportsEc() && IsSecure();
}
- static bool Km1Profile() {
+ bool Km1Profile() {
return !SupportsAttestation() && SupportsSymmetric() && SupportsEc() && IsSecure();
}
- static bool Km0Profile() {
+ bool Km0Profile() {
return !SupportsAttestation() && !SupportsAllDigests() && !SupportsSymmetric() &&
IsSecure();
}
- static bool SwOnlyProfile() {
+ bool SwOnlyProfile() {
return !SupportsAttestation() && !SupportsAllDigests() && !SupportsSymmetric() &&
!SupportsEc() && !IsSecure();
}
+ bool verify_attestation_record(const string& challenge, const string& app_id,
+ AuthorizationSet expected_sw_enforced,
+ AuthorizationSet expected_tee_enforced,
+ const hidl_vec<uint8_t>& attestation_cert) {
+ X509_Ptr cert(parse_cert_blob(attestation_cert));
+ EXPECT_TRUE(!!cert.get());
+ if (!cert.get()) return false;
+
+ ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+ EXPECT_TRUE(!!attest_rec);
+ if (!attest_rec) return false;
+
+ AuthorizationSet att_sw_enforced;
+ AuthorizationSet att_tee_enforced;
+ uint32_t att_attestation_version;
+ uint32_t att_keymaster_version;
+ SecurityLevel att_attestation_security_level;
+ SecurityLevel att_keymaster_security_level;
+ HidlBuf att_challenge;
+ HidlBuf att_unique_id;
+ HidlBuf att_app_id;
+ EXPECT_EQ(ErrorCode::OK,
+ parse_attestation_record(attest_rec->data, //
+ attest_rec->length, //
+ &att_attestation_version, //
+ &att_attestation_security_level, //
+ &att_keymaster_version, //
+ &att_keymaster_security_level, //
+ &att_challenge, //
+ &att_sw_enforced, //
+ &att_tee_enforced, //
+ &att_unique_id));
+
+ EXPECT_TRUE(att_attestation_version == 1 || att_attestation_version == 2);
+
+ expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id));
+
+ if (!IsSecure()) {
+ // SW is KM3
+ EXPECT_EQ(att_keymaster_version, 3U);
+ }
+
+ if (SupportsSymmetric()) {
+ EXPECT_GE(att_keymaster_version, 1U);
+ }
+
+ if (SupportsAttestation()) {
+ EXPECT_GE(att_keymaster_version, 2U);
+ }
+
+ EXPECT_EQ(IsSecure() ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
+ att_keymaster_security_level);
+ EXPECT_EQ(SupportsAttestation() ? SecurityLevel::TRUSTED_ENVIRONMENT
+ : SecurityLevel::SOFTWARE,
+ att_attestation_security_level);
+
+ EXPECT_EQ(challenge.length(), att_challenge.size());
+ EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
+
+ att_sw_enforced.Sort();
+ expected_sw_enforced.Sort();
+ EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(att_sw_enforced))
+ << "(Possibly b/38394619)";
+
+ att_tee_enforced.Sort();
+ expected_tee_enforced.Sort();
+ EXPECT_EQ(filter_tags(expected_tee_enforced), filter_tags(att_tee_enforced))
+ << "(Possibly b/38394619)";
+
+ return true;
+ }
+
HidlBuf key_blob_;
KeyCharacteristics key_characteristics_;
OperationHandle op_handle_ = kOpHandleSentinel;
private:
- static sp<IKeymasterDevice> keymaster_;
- static uint32_t os_version_;
- static uint32_t os_patch_level_;
+ sp<IKeymasterDevice> keymaster_;
+ uint32_t os_version_;
+ uint32_t os_patch_level_;
- static bool is_secure_;
- static bool supports_ec_;
- static bool supports_symmetric_;
- static bool supports_attestation_;
- static bool supports_all_digests_;
- static hidl_string name_;
- static hidl_string author_;
+ bool is_secure_;
+ bool supports_ec_;
+ bool supports_symmetric_;
+ bool supports_attestation_;
+ bool supports_all_digests_;
+ hidl_string name_;
+ hidl_string author_;
};
-bool verify_attestation_record(const string& challenge, const string& app_id,
- AuthorizationSet expected_sw_enforced,
- AuthorizationSet expected_tee_enforced,
- const hidl_vec<uint8_t>& attestation_cert) {
- X509_Ptr cert(parse_cert_blob(attestation_cert));
- EXPECT_TRUE(!!cert.get());
- if (!cert.get()) return false;
-
- ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
- EXPECT_TRUE(!!attest_rec);
- if (!attest_rec) return false;
-
- AuthorizationSet att_sw_enforced;
- AuthorizationSet att_tee_enforced;
- uint32_t att_attestation_version;
- uint32_t att_keymaster_version;
- SecurityLevel att_attestation_security_level;
- SecurityLevel att_keymaster_security_level;
- HidlBuf att_challenge;
- HidlBuf att_unique_id;
- HidlBuf att_app_id;
- EXPECT_EQ(ErrorCode::OK,
- parse_attestation_record(attest_rec->data, //
- attest_rec->length, //
- &att_attestation_version, //
- &att_attestation_security_level, //
- &att_keymaster_version, //
- &att_keymaster_security_level, //
- &att_challenge, //
- &att_sw_enforced, //
- &att_tee_enforced, //
- &att_unique_id));
-
- EXPECT_TRUE(att_attestation_version == 1 || att_attestation_version == 2);
-
- expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID,
- HidlBuf(app_id));
-
- if (!KeymasterHidlTest::IsSecure()) {
- // SW is KM3
- EXPECT_EQ(att_keymaster_version, 3U);
- }
-
- if (KeymasterHidlTest::SupportsSymmetric()) {
- EXPECT_GE(att_keymaster_version, 1U);
- }
-
- if (KeymasterHidlTest::SupportsAttestation()) {
- EXPECT_GE(att_keymaster_version, 2U);
- }
-
- EXPECT_EQ(KeymasterHidlTest::IsSecure() ? SecurityLevel::TRUSTED_ENVIRONMENT
- : SecurityLevel::SOFTWARE,
- att_keymaster_security_level);
- EXPECT_EQ(KeymasterHidlTest::SupportsAttestation() ? SecurityLevel::TRUSTED_ENVIRONMENT
- : SecurityLevel::SOFTWARE,
- att_attestation_security_level);
-
- EXPECT_EQ(challenge.length(), att_challenge.size());
- EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
-
- att_sw_enforced.Sort();
- expected_sw_enforced.Sort();
- EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(att_sw_enforced))
- << "(Possibly b/38394619)";
-
- att_tee_enforced.Sort();
- expected_tee_enforced.Sort();
- EXPECT_EQ(filter_tags(expected_tee_enforced), filter_tags(att_tee_enforced))
- << "(Possibly b/38394619)";
-
- return true;
-}
-
-sp<IKeymasterDevice> KeymasterHidlTest::keymaster_;
-uint32_t KeymasterHidlTest::os_version_;
-uint32_t KeymasterHidlTest::os_patch_level_;
-bool KeymasterHidlTest::is_secure_;
-bool KeymasterHidlTest::supports_ec_;
-bool KeymasterHidlTest::supports_symmetric_;
-bool KeymasterHidlTest::supports_all_digests_;
-bool KeymasterHidlTest::supports_attestation_;
-hidl_string KeymasterHidlTest::name_;
-hidl_string KeymasterHidlTest::author_;
-
typedef KeymasterHidlTest KeymasterVersionTest;
/*
@@ -1065,7 +1034,7 @@
* Queries keymaster to find the set of features it supports. Fails if the combination doesn't
* correspond to any well-defined keymaster version.
*/
-TEST_F(KeymasterVersionTest, SensibleFeatures) {
+TEST_P(KeymasterVersionTest, SensibleFeatures) {
EXPECT_TRUE(Km2Profile() || Km1Profile() || Km0Profile() || SwOnlyProfile())
<< "Keymaster feature set doesn't fit any reasonable profile. Reported features:"
<< "SupportsAttestation [" << SupportsAttestation() << "], "
@@ -1124,7 +1093,7 @@
* Verifies that keymaster can generate all required RSA key sizes, and that the resulting keys have
* correct characteristics.
*/
-TEST_F(NewKeyGenerationTest, Rsa) {
+TEST_P(NewKeyGenerationTest, Rsa) {
for (auto key_size : {1024, 2048, 3072, 4096}) {
HidlBuf key_blob;
KeyCharacteristics key_characteristics;
@@ -1158,7 +1127,7 @@
*
* Verifies that failing to specify a key size for RSA key generation returns UNSUPPORTED_KEY_SIZE.
*/
-TEST_F(NewKeyGenerationTest, RsaNoDefaultSize) {
+TEST_P(NewKeyGenerationTest, RsaNoDefaultSize) {
ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_ALGORITHM, Algorithm::RSA)
@@ -1172,7 +1141,7 @@
* Verifies that keymaster can generate all required EC key sizes, and that the resulting keys have
* correct characteristics.
*/
-TEST_F(NewKeyGenerationTest, Ecdsa) {
+TEST_P(NewKeyGenerationTest, Ecdsa) {
for (auto key_size : {224, 256, 384, 521}) {
HidlBuf key_blob;
KeyCharacteristics key_characteristics;
@@ -1203,7 +1172,7 @@
*
* Verifies that failing to specify a key size for EC key generation returns UNSUPPORTED_KEY_SIZE.
*/
-TEST_F(NewKeyGenerationTest, EcdsaDefaultSize) {
+TEST_P(NewKeyGenerationTest, EcdsaDefaultSize) {
ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_ALGORITHM, Algorithm::EC)
@@ -1217,7 +1186,7 @@
* Verifies that failing to specify an invalid key size for EC key generation returns
* UNSUPPORTED_KEY_SIZE.
*/
-TEST_F(NewKeyGenerationTest, EcdsaInvalidSize) {
+TEST_P(NewKeyGenerationTest, EcdsaInvalidSize) {
ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(Digest::NONE)));
}
@@ -1228,7 +1197,7 @@
* Verifies that specifying mismatched key size and curve for EC key generation returns
* INVALID_ARGUMENT.
*/
-TEST_F(NewKeyGenerationTest, EcdsaMismatchKeySize) {
+TEST_P(NewKeyGenerationTest, EcdsaMismatchKeySize) {
ASSERT_EQ(ErrorCode::INVALID_ARGUMENT,
GenerateKey(AuthorizationSetBuilder()
.EcdsaSigningKey(224)
@@ -1237,7 +1206,7 @@
<< "(Possibly b/36233343)";
}
-TEST_F(NewKeyGenerationTest, EcdsaAllValidSizes) {
+TEST_P(NewKeyGenerationTest, EcdsaAllValidSizes) {
size_t valid_sizes[] = {224, 256, 384, 521};
for (size_t size : valid_sizes) {
EXPECT_EQ(ErrorCode::OK,
@@ -1252,7 +1221,7 @@
*
* Verifies that keymaster supports all required EC curves.
*/
-TEST_F(NewKeyGenerationTest, EcdsaAllValidCurves) {
+TEST_P(NewKeyGenerationTest, EcdsaAllValidCurves) {
EcCurve curves[] = {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521};
for (auto curve : curves) {
EXPECT_EQ(
@@ -1269,7 +1238,7 @@
* Verifies that keymaster supports all required digests, and that the resulting keys have correct
* characteristics.
*/
-TEST_F(NewKeyGenerationTest, Hmac) {
+TEST_P(NewKeyGenerationTest, Hmac) {
for (auto digest : {Digest::MD5, Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256,
Digest::SHA_2_384, Digest::SHA_2_512}) {
HidlBuf key_blob;
@@ -1318,7 +1287,7 @@
*
* Verifies that keymaster supports all key sizes, and rejects all invalid key sizes.
*/
-TEST_F(NewKeyGenerationTest, HmacCheckKeySizes) {
+TEST_P(NewKeyGenerationTest, HmacCheckKeySizes) {
for (size_t key_size = 0; key_size <= 512; ++key_size) {
if (key_size < 64 || key_size % 8 != 0) {
// To keep this test from being very slow, we only test a random fraction of non-byte
@@ -1349,7 +1318,7 @@
* test is probabilistic in order to keep the runtime down, but any failure prints out the specific
* MAC length that failed, so reproducing a failed run will be easy.
*/
-TEST_F(NewKeyGenerationTest, HmacCheckMinMacLengths) {
+TEST_P(NewKeyGenerationTest, HmacCheckMinMacLengths) {
for (size_t min_mac_length = 0; min_mac_length <= 256; ++min_mac_length) {
if (min_mac_length < 64 || min_mac_length % 8 != 0) {
// To keep this test from being very long, we only test a random fraction of non-byte
@@ -1379,7 +1348,7 @@
*
* Verifies that keymaster rejects HMAC key generation with multiple specified digest algorithms.
*/
-TEST_F(NewKeyGenerationTest, HmacMultipleDigests) {
+TEST_P(NewKeyGenerationTest, HmacMultipleDigests) {
ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
GenerateKey(AuthorizationSetBuilder()
.HmacKey(128)
@@ -1393,7 +1362,7 @@
*
* Verifies that keymaster rejects HMAC key generation with no digest or Digest::NONE
*/
-TEST_F(NewKeyGenerationTest, HmacDigestNone) {
+TEST_P(NewKeyGenerationTest, HmacDigestNone) {
ASSERT_EQ(
ErrorCode::UNSUPPORTED_DIGEST,
GenerateKey(AuthorizationSetBuilder().HmacKey(128).Authorization(TAG_MIN_MAC_LENGTH, 128)));
@@ -1413,7 +1382,7 @@
* Verifies that getKeyCharacteristics functions, and that generated and retrieved key
* characteristics match.
*/
-TEST_F(GetKeyCharacteristicsTest, SimpleRsa) {
+TEST_P(GetKeyCharacteristicsTest, SimpleRsa) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Digest(Digest::NONE)
@@ -1438,7 +1407,7 @@
*
* Verifies that raw RSA signature operations succeed.
*/
-TEST_F(SigningOperationsTest, RsaSuccess) {
+TEST_P(SigningOperationsTest, RsaSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Digest(Digest::NONE)
@@ -1454,7 +1423,7 @@
*
* Verifies that RSA-PSS signature operations succeed.
*/
-TEST_F(SigningOperationsTest, RsaPssSha256Success) {
+TEST_P(SigningOperationsTest, RsaPssSha256Success) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Digest(Digest::SHA_2_256)
@@ -1472,7 +1441,7 @@
* Verifies that keymaster rejects signature operations that specify a padding mode when the key
* supports only unpadded operations.
*/
-TEST_F(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
+TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Digest(Digest::NONE)
@@ -1492,7 +1461,7 @@
*
* Verifies that digested RSA-PKCS1 signature operations succeed.
*/
-TEST_F(SigningOperationsTest, RsaPkcs1Sha256Success) {
+TEST_P(SigningOperationsTest, RsaPkcs1Sha256Success) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Digest(Digest::SHA_2_256)
@@ -1509,7 +1478,7 @@
*
* Verifies that undigested RSA-PKCS1 signature operations succeed.
*/
-TEST_F(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Digest(Digest::NONE)
@@ -1527,7 +1496,7 @@
* Verifies that undigested RSA-PKCS1 signature operations fail with the correct error code when
* given a too-long message.
*/
-TEST_F(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Digest(Digest::NONE)
@@ -1555,7 +1524,7 @@
* uses SHA512, which has a digest_size == 512, so the message size is 1040 bits, too large for a
* 1024-bit key.
*/
-TEST_F(SigningOperationsTest, RsaPssSha512TooSmallKey) {
+TEST_P(SigningOperationsTest, RsaPssSha512TooSmallKey) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Digest(Digest::SHA_2_512)
@@ -1574,7 +1543,7 @@
* Verifies that raw RSA signature operations fail with the correct error code when
* given a too-long message.
*/
-TEST_F(SigningOperationsTest, RsaNoPaddingTooLong) {
+TEST_P(SigningOperationsTest, RsaNoPaddingTooLong) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Digest(Digest::NONE)
@@ -1608,7 +1577,7 @@
* Verifies that operations can be aborted correctly. Uses an RSA signing operation for the test,
* but the behavior should be algorithm and purpose-independent.
*/
-TEST_F(SigningOperationsTest, RsaAbort) {
+TEST_P(SigningOperationsTest, RsaAbort) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Digest(Digest::NONE)
@@ -1633,7 +1602,7 @@
* Verifies that RSA operations fail with the correct error (but key gen succeeds) when used with a
* padding mode inappropriate for RSA.
*/
-TEST_F(SigningOperationsTest, RsaUnsupportedPadding) {
+TEST_P(SigningOperationsTest, RsaUnsupportedPadding) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1650,7 +1619,7 @@
*
* Verifies that RSA PSS operations fail when no digest is used. PSS requires a digest.
*/
-TEST_F(SigningOperationsTest, RsaNoDigest) {
+TEST_P(SigningOperationsTest, RsaNoDigest) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1670,7 +1639,7 @@
* Verifies that RSA operations fail when no padding mode is specified. PaddingMode::NONE is
* supported in some cases (as validated in other tests), but a mode must be specified.
*/
-TEST_F(SigningOperationsTest, RsaNoPadding) {
+TEST_P(SigningOperationsTest, RsaNoPadding) {
// Padding must be specified
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaKey(1024, 3)
@@ -1686,7 +1655,7 @@
*
* Verifies that raw RSA signatures succeed with a message shorter than the key size.
*/
-TEST_F(SigningOperationsTest, RsaTooShortMessage) {
+TEST_P(SigningOperationsTest, RsaTooShortMessage) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(1024, 3)
@@ -1707,7 +1676,7 @@
*
* Verifies that RSA encryption keys cannot be used to sign.
*/
-TEST_F(SigningOperationsTest, RsaSignWithEncryptionKey) {
+TEST_P(SigningOperationsTest, RsaSignWithEncryptionKey) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(1024, 3)
@@ -1724,7 +1693,7 @@
* Verifies that attempting a raw signature of a message which is the same length as the key, but
* numerically larger than the public modulus, fails with the correct error.
*/
-TEST_F(SigningOperationsTest, RsaSignTooLargeMessage) {
+TEST_P(SigningOperationsTest, RsaSignTooLargeMessage) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(1024, 3)
@@ -1746,7 +1715,7 @@
*
* Verifies that ECDSA operations succeed with all possible key sizes and hashes.
*/
-TEST_F(SigningOperationsTest, EcdsaAllSizesAndHashes) {
+TEST_P(SigningOperationsTest, EcdsaAllSizesAndHashes) {
for (auto key_size : {224, 256, 384, 521}) {
for (auto digest : {
Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
@@ -1773,7 +1742,7 @@
*
* Verifies that ECDSA operations succeed with all possible curves.
*/
-TEST_F(SigningOperationsTest, EcdsaAllCurves) {
+TEST_P(SigningOperationsTest, EcdsaAllCurves) {
for (auto curve : {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521}) {
ErrorCode error = GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1795,7 +1764,7 @@
* work because ECDSA actually only signs the leftmost L_n bits of the message, however large it may
* be. Not using digesting is a bad idea, but in some cases digesting is done by the framework.
*/
-TEST_F(SigningOperationsTest, EcdsaNoDigestHugeData) {
+TEST_P(SigningOperationsTest, EcdsaNoDigestHugeData) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(224)
@@ -1809,7 +1778,7 @@
*
* Verifies that attempts to use AES keys to sign fail in the correct way.
*/
-TEST_F(SigningOperationsTest, AesEcbSign) {
+TEST_P(SigningOperationsTest, AesEcbSign) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.SigningKey()
@@ -1832,7 +1801,7 @@
*
* Verifies that HMAC works with all digests.
*/
-TEST_F(SigningOperationsTest, HmacAllDigests) {
+TEST_P(SigningOperationsTest, HmacAllDigests) {
for (auto digest : {Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
Digest::SHA_2_512}) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -1855,7 +1824,7 @@
* Verifies that HMAC fails in the correct way when asked to generate a MAC larger than the digest
* size.
*/
-TEST_F(SigningOperationsTest, HmacSha256TooLargeMacLength) {
+TEST_P(SigningOperationsTest, HmacSha256TooLargeMacLength) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.HmacKey(128)
@@ -1876,7 +1845,7 @@
* Verifies that HMAC fails in the correct way when asked to generate a MAC smaller than the
* specified minimum MAC length.
*/
-TEST_F(SigningOperationsTest, HmacSha256TooSmallMacLength) {
+TEST_P(SigningOperationsTest, HmacSha256TooSmallMacLength) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.HmacKey(128)
@@ -1896,7 +1865,7 @@
*
* Validates against the test vectors from RFC 4231 test case 3.
*/
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase3) {
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase3) {
string key(20, 0xaa);
string message(50, 0xdd);
uint8_t sha_224_expected[] = {
@@ -1933,7 +1902,7 @@
*
* Validates against the test vectors from RFC 4231 test case 5.
*/
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase5) {
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase5) {
string key(20, 0x0c);
string message = "Test With Truncation";
@@ -1965,7 +1934,7 @@
*
* Validates against the test vectors from RFC 4231 test case 6.
*/
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase6) {
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase6) {
string key(131, 0xaa);
string message = "Test Using Larger Than Block-Size Key - Hash Key First";
@@ -2003,7 +1972,7 @@
*
* Validates against the test vectors from RFC 4231 test case 7.
*/
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase7) {
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase7) {
string key(131, 0xaa);
string message = "This is a test using a larger than block-size key and a larger than "
"block-size data. The key needs to be hashed before being used by the HMAC "
@@ -2045,7 +2014,7 @@
*
* Verifies that a simple RSA signature/verification sequence succeeds.
*/
-TEST_F(VerificationOperationsTest, RsaSuccess) {
+TEST_P(VerificationOperationsTest, RsaSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(1024, 3)
@@ -2063,7 +2032,7 @@
*
* Verifies RSA signature/verification for all padding modes and digests.
*/
-TEST_F(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
+TEST_P(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
ASSERT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -2159,7 +2128,7 @@
*
* Verifies ECDSA signature/verification for all digests and curves.
*/
-TEST_F(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
+TEST_P(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
auto digests = {
Digest::NONE, Digest::SHA1, Digest::SHA_2_224,
Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512,
@@ -2242,7 +2211,7 @@
*
* Verifies HMAC signing and verification, but that a signing key cannot be used to verify.
*/
-TEST_F(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
+TEST_P(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
string key_material = "HelloThisIsAKey";
HidlBuf signing_key, verification_key;
@@ -2290,7 +2259,7 @@
*
* Verifies that attempting to export RSA keys in PKCS#8 format fails with the correct error.
*/
-TEST_F(ExportKeyTest, RsaUnsupportedKeyFormat) {
+TEST_P(ExportKeyTest, RsaUnsupportedKeyFormat) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Digest(Digest::NONE)
@@ -2305,7 +2274,7 @@
* Verifies that attempting to export RSA keys from corrupted key blobs fails. This is essentially
* a poor-man's key blob fuzzer.
*/
-TEST_F(ExportKeyTest, RsaCorruptedKeyBlob) {
+TEST_P(ExportKeyTest, RsaCorruptedKeyBlob) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(1024, 3)
@@ -2328,7 +2297,7 @@
* Verifies that attempting to export ECDSA keys from corrupted key blobs fails. This is
* essentially a poor-man's key blob fuzzer.
*/
-TEST_F(ExportKeyTest, EcCorruptedKeyBlob) {
+TEST_P(ExportKeyTest, EcCorruptedKeyBlob) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(EcCurve::P_256)
@@ -2349,7 +2318,7 @@
*
* Verifies that attempting to export AES keys fails in the expected way.
*/
-TEST_F(ExportKeyTest, AesKeyUnexportable) {
+TEST_P(ExportKeyTest, AesKeyUnexportable) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2368,7 +2337,7 @@
*
* Verifies that importing and using an RSA key pair works correctly.
*/
-TEST_F(ImportKeyTest, RsaSuccess) {
+TEST_P(ImportKeyTest, RsaSuccess) {
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(1024, 65537)
@@ -2395,7 +2364,7 @@
* Verifies that importing an RSA key pair with a size that doesn't match the key fails in the
* correct way.
*/
-TEST_F(ImportKeyTest, RsaKeySizeMismatch) {
+TEST_P(ImportKeyTest, RsaKeySizeMismatch) {
ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
ImportKey(AuthorizationSetBuilder()
.RsaSigningKey(2048 /* Doesn't match key */, 65537)
@@ -2410,7 +2379,7 @@
* Verifies that importing an RSA key pair with a public exponent that doesn't match the key fails
* in the correct way.
*/
-TEST_F(ImportKeyTest, RsaPublicExponentMismatch) {
+TEST_P(ImportKeyTest, RsaPublicExponentMismatch) {
ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
ImportKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3 /* Doesn't match key */)
@@ -2424,7 +2393,7 @@
*
* Verifies that importing and using an ECDSA P-256 key pair works correctly.
*/
-TEST_F(ImportKeyTest, EcdsaSuccess) {
+TEST_P(ImportKeyTest, EcdsaSuccess) {
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(256)
@@ -2450,7 +2419,7 @@
*
* Verifies that importing and using an ECDSA P-521 key pair works correctly.
*/
-TEST_F(ImportKeyTest, Ecdsa521Success) {
+TEST_P(ImportKeyTest, Ecdsa521Success) {
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(521)
@@ -2477,7 +2446,7 @@
* Verifies that importing an ECDSA key pair with a size that doesn't match the key fails in the
* correct way.
*/
-TEST_F(ImportKeyTest, EcdsaSizeMismatch) {
+TEST_P(ImportKeyTest, EcdsaSizeMismatch) {
ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
ImportKey(AuthorizationSetBuilder()
.EcdsaSigningKey(224 /* Doesn't match key */)
@@ -2491,7 +2460,7 @@
* Verifies that importing an ECDSA key pair with a curve that doesn't match the key fails in the
* correct way.
*/
-TEST_F(ImportKeyTest, EcdsaCurveMismatch) {
+TEST_P(ImportKeyTest, EcdsaCurveMismatch) {
if (SupportsSymmetric() && !SupportsAttestation()) {
// KM1 hardware doesn't know about curves
return;
@@ -2510,7 +2479,7 @@
*
* Verifies that importing and using an AES key works.
*/
-TEST_F(ImportKeyTest, AesSuccess) {
+TEST_P(ImportKeyTest, AesSuccess) {
string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -2537,7 +2506,7 @@
*
* Verifies that importing and using an HMAC key works.
*/
-TEST_F(ImportKeyTest, HmacKeySuccess) {
+TEST_P(ImportKeyTest, HmacKeySuccess) {
string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -2563,7 +2532,7 @@
*
* Verifies that raw RSA encryption works.
*/
-TEST_F(EncryptionOperationsTest, RsaNoPaddingSuccess) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(1024, 3)
@@ -2586,7 +2555,7 @@
*
* Verifies that raw RSA encryption of short messages works.
*/
-TEST_F(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(1024, 3)
@@ -2615,7 +2584,7 @@
*
* Verifies that raw RSA encryption of too-long messages fails in the expected way.
*/
-TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLong) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLong) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(1024, 3)
@@ -2635,7 +2604,7 @@
*
* Verifies that raw RSA encryption of too-large (numerically) messages fails in the expected way.
*/
-TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLarge) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLarge) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(1024, 3)
@@ -2677,7 +2646,7 @@
*
* Verifies that RSA-OAEP encryption operations work, with all digests.
*/
-TEST_F(EncryptionOperationsTest, RsaOaepSuccess) {
+TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
auto digests = {Digest::MD5, Digest::SHA1, Digest::SHA_2_224,
Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512};
@@ -2729,7 +2698,7 @@
* Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate
* without a digest.
*/
-TEST_F(EncryptionOperationsTest, RsaOaepInvalidDigest) {
+TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(1024, 3)
@@ -2747,7 +2716,7 @@
* Verifies that RSA-OAEP encryption operations fail in the correct way when asked to decrypt with a
* different digest than was used to encrypt.
*/
-TEST_F(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
+TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(1024, 3)
@@ -2773,7 +2742,7 @@
* Verifies that RSA-OAEP encryption operations fail in the correct way when asked to encrypt a
* too-large message.
*/
-TEST_F(EncryptionOperationsTest, RsaOaepTooLarge) {
+TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(1024, 3)
@@ -2796,7 +2765,7 @@
*
* Verifies that RSA PKCS encryption/decrypts works.
*/
-TEST_F(EncryptionOperationsTest, RsaPkcs1Success) {
+TEST_P(EncryptionOperationsTest, RsaPkcs1Success) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(1024, 3)
@@ -2835,7 +2804,7 @@
*
* Verifies that RSA PKCS encryption fails in the correct way when the mssage is too large.
*/
-TEST_F(EncryptionOperationsTest, RsaPkcs1TooLarge) {
+TEST_P(EncryptionOperationsTest, RsaPkcs1TooLarge) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(1024, 3)
@@ -2855,7 +2824,7 @@
*
* Verifies that attempting to use ECDSA keys to encrypt fails in the correct way.
*/
-TEST_F(EncryptionOperationsTest, EcdsaEncrypt) {
+TEST_P(EncryptionOperationsTest, EcdsaEncrypt) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(224)
@@ -2872,7 +2841,7 @@
*
* Verifies that attempting to use HMAC keys to encrypt fails in the correct way.
*/
-TEST_F(EncryptionOperationsTest, HmacEncrypt) {
+TEST_P(EncryptionOperationsTest, HmacEncrypt) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.HmacKey(128)
@@ -2894,7 +2863,7 @@
*
* Verifies that AES ECB mode works.
*/
-TEST_F(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2923,7 +2892,7 @@
*
* Verifies that AES encryption fails in the correct way when an unauthorized mode is specified.
*/
-TEST_F(EncryptionOperationsTest, AesWrongMode) {
+TEST_P(EncryptionOperationsTest, AesWrongMode) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2943,7 +2912,7 @@
* Verifies that AES encryption fails in the correct way when provided an input that is not a
* multiple of the block size and no padding is specified.
*/
-TEST_F(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
+TEST_P(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2964,7 +2933,7 @@
*
* Verifies that AES PKCS7 padding works for any message length.
*/
-TEST_F(EncryptionOperationsTest, AesEcbPkcs7Padding) {
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7Padding) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2989,7 +2958,7 @@
* Verifies that AES enryption fails in the correct way when an unauthorized padding mode is
* specified.
*/
-TEST_F(EncryptionOperationsTest, AesEcbWrongPadding) {
+TEST_P(EncryptionOperationsTest, AesEcbWrongPadding) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3010,7 +2979,7 @@
*
* Verifies that AES decryption fails in the correct way when the padding is corrupted.
*/
-TEST_F(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3041,7 +3010,7 @@
*
* Verifies that AES CTR mode works.
*/
-TEST_F(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3088,7 +3057,7 @@
*
* Verifies that AES works, all modes, when provided data in various size increments.
*/
-TEST_F(EncryptionOperationsTest, AesIncremental) {
+TEST_P(EncryptionOperationsTest, AesIncremental) {
auto block_modes = {
BlockMode::ECB, BlockMode::CBC, BlockMode::CTR, BlockMode::GCM,
};
@@ -3226,7 +3195,7 @@
*
* Verifies AES CTR implementation against SP800-38A test vectors.
*/
-TEST_F(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
+TEST_P(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
for (size_t i = 0; i < 3; i++) {
const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]);
const string key = hex2str(test.key);
@@ -3242,7 +3211,7 @@
*
* Verifies that keymaster rejects use of CTR mode with PKCS7 padding in the correct way.
*/
-TEST_F(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
+TEST_P(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3257,7 +3226,7 @@
*
* Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
*/
-TEST_F(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
+TEST_P(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3289,7 +3258,7 @@
*
* Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
*/
-TEST_F(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3322,7 +3291,7 @@
*
* Verifies that AES caller-provided nonces work correctly.
*/
-TEST_F(EncryptionOperationsTest, AesCallerNonce) {
+TEST_P(EncryptionOperationsTest, AesCallerNonce) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3371,7 +3340,7 @@
* Verifies that caller-provided nonces are not permitted when not specified in the key
* authorizations.
*/
-TEST_F(EncryptionOperationsTest, AesCallerNonceProhibited) {
+TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3406,7 +3375,7 @@
*
* Verifies that AES GCM mode works.
*/
-TEST_F(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3454,7 +3423,7 @@
*
* Verifies that AES GCM mode fails correctly when a too-short tag length is specified.
*/
-TEST_F(EncryptionOperationsTest, AesGcmTooShortTag) {
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3475,7 +3444,7 @@
*
* Verifies that AES GCM mode fails correctly when a too-short tag is provided to decryption.
*/
-TEST_F(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3518,7 +3487,7 @@
*
* Verifies that AES GCM mode fails correctly when the decryption key is incorrect.
*/
-TEST_F(EncryptionOperationsTest, AesGcmCorruptKey) {
+TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) {
const uint8_t nonce_bytes[] = {
0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f,
};
@@ -3570,7 +3539,7 @@
* Verifies that AES GCM mode works when provided additional authenticated data, but no data to
* encrypt.
*/
-TEST_F(EncryptionOperationsTest, AesGcmAadNoData) {
+TEST_P(EncryptionOperationsTest, AesGcmAadNoData) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3616,7 +3585,7 @@
*
* Verifies that AES GCM mode works when provided additional authenticated data in multiple chunks.
*/
-TEST_F(EncryptionOperationsTest, AesGcmMultiPartAad) {
+TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3675,7 +3644,7 @@
*
* Verifies that AES GCM mode fails correctly when given AAD after data to encipher.
*/
-TEST_F(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
+TEST_P(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3724,7 +3693,7 @@
*
* Verifies that AES GCM decryption fails correctly when additional authenticated date is wrong.
*/
-TEST_F(EncryptionOperationsTest, AesGcmBadAad) {
+TEST_P(EncryptionOperationsTest, AesGcmBadAad) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3768,7 +3737,7 @@
*
* Verifies that AES GCM decryption fails correctly when the nonce is incorrect.
*/
-TEST_F(EncryptionOperationsTest, AesGcmWrongNonce) {
+TEST_P(EncryptionOperationsTest, AesGcmWrongNonce) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3812,7 +3781,7 @@
*
* Verifies that AES GCM decryption fails correctly when the tag is wrong.
*/
-TEST_F(EncryptionOperationsTest, AesGcmCorruptTag) {
+TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3862,7 +3831,7 @@
*
* Verifies that the max uses per boot tag works correctly with AES keys.
*/
-TEST_F(MaxOperationsTest, TestLimitAes) {
+TEST_P(MaxOperationsTest, TestLimitAes) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3887,7 +3856,7 @@
*
* Verifies that the max uses per boot tag works correctly with RSA keys.
*/
-TEST_F(MaxOperationsTest, TestLimitRsa) {
+TEST_P(MaxOperationsTest, TestLimitRsa) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(1024, 3)
@@ -3914,7 +3883,7 @@
* Verifies that the addRngEntropy method doesn't blow up. There's no way to test that entropy is
* actually added.
*/
-TEST_F(AddEntropyTest, AddEntropy) {
+TEST_P(AddEntropyTest, AddEntropy) {
EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf("foo")));
}
@@ -3923,7 +3892,7 @@
*
* Verifies that the addRngEntropy method doesn't blow up when given an empty buffer.
*/
-TEST_F(AddEntropyTest, AddEmptyEntropy) {
+TEST_P(AddEntropyTest, AddEmptyEntropy) {
EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf()));
}
@@ -3932,7 +3901,7 @@
*
* Verifies that the addRngEntropy method doesn't blow up when given a largish amount of data.
*/
-TEST_F(AddEntropyTest, AddLargeEntropy) {
+TEST_P(AddEntropyTest, AddLargeEntropy) {
EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(2 * 1024, 'a'))));
}
@@ -3943,7 +3912,7 @@
*
* Verifies that attesting to RSA keys works and generates the expected output.
*/
-TEST_F(AttestationTest, RsaAttestation) {
+TEST_P(AttestationTest, RsaAttestation) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(1024, 3)
@@ -3971,7 +3940,7 @@
*
* Verifies that attesting to RSA requires app ID.
*/
-TEST_F(AttestationTest, RsaAttestationRequiresAppId) {
+TEST_P(AttestationTest, RsaAttestationRequiresAppId) {
ASSERT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -3992,7 +3961,7 @@
*
* Verifies that attesting to EC keys works and generates the expected output.
*/
-TEST_F(AttestationTest, EcAttestation) {
+TEST_P(AttestationTest, EcAttestation) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(EcCurve::P_256)
@@ -4020,7 +3989,7 @@
*
* Verifies that attesting to EC keys requires app ID
*/
-TEST_F(AttestationTest, EcAttestationRequiresAttestationAppId) {
+TEST_P(AttestationTest, EcAttestationRequiresAttestationAppId) {
ASSERT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -4040,7 +4009,7 @@
*
* Verifies that attesting to AES keys fails in the expected way.
*/
-TEST_F(AttestationTest, AesAttestation) {
+TEST_P(AttestationTest, AesAttestation) {
ASSERT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -4063,7 +4032,7 @@
*
* Verifies that attesting to HMAC keys fails in the expected way.
*/
-TEST_F(AttestationTest, HmacAttestation) {
+TEST_P(AttestationTest, HmacAttestation) {
ASSERT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -4090,7 +4059,7 @@
* This test checks that if rollback protection is implemented, DeleteKey invalidates a formerly
* valid key blob.
*/
-TEST_F(KeyDeletionTest, DeleteKey) {
+TEST_P(KeyDeletionTest, DeleteKey) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
.Digest(Digest::NONE)
@@ -4135,7 +4104,7 @@
*
* This test checks that the HAL excepts invalid key blobs.
*/
-TEST_F(KeyDeletionTest, DeleteInvalidKey) {
+TEST_P(KeyDeletionTest, DeleteInvalidKey) {
// Generate key just to check if rollback protection is implemented
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
@@ -4172,7 +4141,7 @@
* been provisioned. Use this test only on dedicated testing devices that have no valuable
* credentials stored in Keystore/Keymaster.
*/
-TEST_F(KeyDeletionTest, DeleteAllKeys) {
+TEST_P(KeyDeletionTest, DeleteAllKeys) {
if (!arm_deleteAllKeys) return;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3)
@@ -4207,6 +4176,45 @@
key_blob_ = HidlBuf();
}
+static const auto kKeymasterDeviceChoices =
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor));
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, NewKeyGenerationTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, KeymasterVersionTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, GetKeyCharacteristicsTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, SigningOperationsTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, VerificationOperationsTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, ExportKeyTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, ImportKeyTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, EncryptionOperationsTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, MaxOperationsTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, AddEntropyTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, AttestationTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, KeyDeletionTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
} // namespace test
} // namespace V3_0
} // namespace keymaster
@@ -4214,10 +4222,7 @@
} // namespace android
int main(int argc, char** argv) {
- using android::hardware::keymaster::V3_0::test::KeymasterHidlEnvironment;
- ::testing::AddGlobalTestEnvironment(KeymasterHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
- KeymasterHidlEnvironment::Instance()->init(&argc, argv);
for (int i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
if (std::string(argv[i]) == "--arm_deleteAllKeys") {
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index 0401362..5649f20 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -29,5 +29,5 @@
"libkeymaster4support",
"libsoftkeymasterdevice",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/keymaster/4.0/vts/functional/AndroidTest.xml b/keymaster/4.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..dcf7129
--- /dev/null
+++ b/keymaster/4.0/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalKeymasterV4_0TargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsHalKeymasterV4_0TargetTest->/data/local/tmp/VtsHalKeymasterV4_0TargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalKeymasterV4_0TargetTest" />
+ <option name="native-test-timeout" value="900000"/>
+ </test>
+</configuration>
diff --git a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
index f159796..c228ef7 100644
--- a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
+++ b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
@@ -101,7 +101,7 @@
}
};
-TEST_F(HmacKeySharingTest, GetParameters) {
+TEST_P(HmacKeySharingTest, GetParameters) {
auto result1 = getHmacSharingParameters(keymaster());
EXPECT_EQ(ErrorCode::OK, result1.error);
@@ -114,7 +114,7 @@
<< "A given keymaster should always return the same nonce until restart.";
}
-TEST_F(HmacKeySharingTest, ComputeSharedHmac) {
+TEST_P(HmacKeySharingTest, ComputeSharedHmac) {
auto params = getHmacSharingParameters(all_keymasters());
ASSERT_EQ(all_keymasters().size(), params.size())
<< "One or more keymasters failed to provide parameters.";
@@ -143,8 +143,8 @@
template <class F>
class final_action {
public:
- explicit final_action(F f) : f_(move(f)) {}
- ~final_action() { f_(); }
+ explicit final_action(F f) : f_(std::move(f)) {}
+ ~final_action() { f_(); }
private:
F f_;
@@ -155,7 +155,7 @@
return final_action<F>(f);
}
-TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptNonce) {
+TEST_P(HmacKeySharingTest, ComputeSharedHmacCorruptNonce) {
// Important: The execution of this test gets the keymaster implementations on the device out of
// sync with respect to the HMAC key. Granted that VTS tests aren't run on in-use production
// devices, this still has the potential to cause confusion. To mitigate that, we always
@@ -194,7 +194,7 @@
}
}
-TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptSeed) {
+TEST_P(HmacKeySharingTest, ComputeSharedHmacCorruptSeed) {
// Important: The execution of this test gets the keymaster implementations on the device out of
// sync with respect to the HMAC key. Granted that VTS tests aren't run on in-use production
// devices, this still has the potential to cause confusion. To mitigate that, we always
@@ -236,6 +236,11 @@
}
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, HmacKeySharingTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
} // namespace test
} // namespace V4_0
} // namespace keymaster
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index 4838e7e..7241984 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -41,18 +41,9 @@
namespace test {
-sp<IKeymasterDevice> KeymasterHidlTest::keymaster_;
-std::vector<sp<IKeymasterDevice>> KeymasterHidlTest::all_keymasters_;
-uint32_t KeymasterHidlTest::os_version_;
-uint32_t KeymasterHidlTest::os_patch_level_;
-SecurityLevel KeymasterHidlTest::securityLevel_;
-hidl_string KeymasterHidlTest::name_;
-hidl_string KeymasterHidlTest::author_;
-string KeymasterHidlTest::service_name_;
-
void KeymasterHidlTest::InitializeKeymaster() {
- service_name_ = KeymasterHidlEnvironment::Instance()->getServiceName<IKeymasterDevice>();
- keymaster_ = ::testing::VtsHalHidlTargetTestBase::getService<IKeymasterDevice>(service_name_);
+ service_name_ = GetParam();
+ keymaster_ = IKeymasterDevice::getService(service_name_);
ASSERT_NE(keymaster_, nullptr);
ASSERT_TRUE(keymaster_
@@ -65,8 +56,7 @@
.isOk());
}
-void KeymasterHidlTest::SetUpTestCase() {
-
+void KeymasterHidlTest::SetUp() {
InitializeKeymaster();
os_version_ = ::keymaster::GetOsVersion();
@@ -79,8 +69,7 @@
IKeymasterDevice::descriptor, [&](const hidl_vec<hidl_string>& names) {
for (auto& name : names) {
if (name == service_name_) continue;
- auto keymaster =
- ::testing::VtsHalHidlTargetTestBase::getService<IKeymasterDevice>(name);
+ auto keymaster = IKeymasterDevice::getService(name);
ASSERT_NE(keymaster, nullptr);
all_keymasters_.push_back(keymaster);
}
@@ -212,22 +201,6 @@
CheckedDeleteKey(&key_blob_);
}
-void KeymasterHidlTest::CheckCreationDateTime(
- const AuthorizationSet& sw_enforced,
- std::chrono::time_point<std::chrono::system_clock> creation) {
- for (int i = 0; i < sw_enforced.size(); i++) {
- if (sw_enforced[i].tag == TAG_CREATION_DATETIME) {
- std::chrono::time_point<std::chrono::system_clock> now =
- std::chrono::system_clock::now();
- std::chrono::time_point<std::chrono::system_clock> reported_time{
- std::chrono::milliseconds(sw_enforced[i].f.dateTime)};
- // The test is flaky for EC keys, so a buffer time of 120 seconds will be added.
- EXPECT_LE(creation - 120s, reported_time);
- EXPECT_LE(reported_time, now + 1s);
- }
- }
-}
-
void KeymasterHidlTest::CheckGetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
const HidlBuf& app_data,
KeyCharacteristics* key_characteristics) {
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index b09da45..4bd8b26 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#ifndef HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
-#define HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
+#pragma once
#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
#include <android/hardware/keymaster/4.0/types.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <keymaster/keymaster_configuration.h>
#include <keymasterV4_0/authorization_set.h>
@@ -69,43 +68,24 @@
constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF;
-class KeymasterHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static KeymasterHidlEnvironment* Instance() {
- static KeymasterHidlEnvironment* instance = new KeymasterHidlEnvironment;
- return instance;
- }
-
- void registerTestServices() override { registerTestService<IKeymasterDevice>(); }
-
- private:
- KeymasterHidlEnvironment(){};
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(KeymasterHidlEnvironment);
-};
-
-class KeymasterHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class KeymasterHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void SetUp();
void TearDown() override {
if (key_blob_.size()) {
CheckedDeleteKey();
}
AbortIfNeeded();
- }
-
- // SetUpTestCase runs only once per test case, not once per test.
- static void SetUpTestCase();
- static void InitializeKeymaster();
- static void TearDownTestCase() {
keymaster_.clear();
all_keymasters_.clear();
}
- static IKeymasterDevice& keymaster() { return *keymaster_; }
- static const std::vector<sp<IKeymasterDevice>>& all_keymasters() { return all_keymasters_; }
- static uint32_t os_version() { return os_version_; }
- static uint32_t os_patch_level() { return os_patch_level_; }
+ void InitializeKeymaster();
+
+ IKeymasterDevice& keymaster() { return *keymaster_; }
+ const std::vector<sp<IKeymasterDevice>>& all_keymasters() { return all_keymasters_; }
+ uint32_t os_version() { return os_version_; }
+ uint32_t os_patch_level() { return os_patch_level_; }
ErrorCode GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
KeyCharacteristics* key_characteristics);
@@ -133,9 +113,6 @@
void CheckedDeleteKey(HidlBuf* key_blob, bool keep_key_blob = false);
void CheckedDeleteKey();
- static void CheckCreationDateTime(const AuthorizationSet& sw_enforced,
- std::chrono::time_point<std::chrono::system_clock> creation);
-
void CheckGetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
const HidlBuf& app_data, KeyCharacteristics* key_characteristics);
ErrorCode GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
@@ -216,8 +193,8 @@
std::pair<ErrorCode, HidlBuf> UpgradeKey(const HidlBuf& key_blob);
- static bool IsSecure() { return securityLevel_ != SecurityLevel::SOFTWARE; }
- static SecurityLevel SecLevel() { return securityLevel_; }
+ bool IsSecure() { return securityLevel_ != SecurityLevel::SOFTWARE; }
+ SecurityLevel SecLevel() { return securityLevel_; }
std::vector<uint32_t> ValidKeySizes(Algorithm algorithm);
std::vector<uint32_t> InvalidKeySizes(Algorithm algorithm);
@@ -233,15 +210,15 @@
OperationHandle op_handle_ = kOpHandleSentinel;
private:
- static sp<IKeymasterDevice> keymaster_;
- static std::vector<sp<IKeymasterDevice>> all_keymasters_;
- static uint32_t os_version_;
- static uint32_t os_patch_level_;
+ sp<IKeymasterDevice> keymaster_;
+ std::vector<sp<IKeymasterDevice>> all_keymasters_;
+ uint32_t os_version_;
+ uint32_t os_patch_level_;
- static SecurityLevel securityLevel_;
- static hidl_string name_;
- static hidl_string author_;
- static string service_name_;
+ SecurityLevel securityLevel_;
+ hidl_string name_;
+ hidl_string author_;
+ string service_name_;
};
} // namespace test
@@ -249,5 +226,3 @@
} // namespace keymaster
} // namespace hardware
} // namespace android
-
-#endif // HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
diff --git a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
index de28683..693f4ae 100644
--- a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
+++ b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
@@ -75,7 +75,7 @@
* thing we really can test is that tokens can be created by TEE keymasters, and that the
* timestamps increase as expected.
*/
-TEST_F(VerificationTokenTest, TestCreation) {
+TEST_P(VerificationTokenTest, TestCreation) {
auto result1 = verifyAuthorization(
1 /* operation handle */, AuthorizationSet() /* paramtersToVerify */, HardwareAuthToken());
ASSERT_TRUE(result1.callSuccessful);
@@ -134,7 +134,7 @@
* stamp is included in the mac but on failure we know that it is not. Other than in the test
* case above we call verifyAuthorization with the exact same set of parameters.
*/
-TEST_F(VerificationTokenTest, MacChangesOnChangingTimestamp) {
+TEST_P(VerificationTokenTest, MacChangesOnChangingTimestamp) {
auto result1 =
verifyAuthorization(0 /* operation handle */,
AuthorizationSet() /* paramtersToVerify */, HardwareAuthToken());
@@ -185,6 +185,11 @@
memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, VerificationTokenTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
} // namespace test
} // namespace V4_0
} // namespace keymaster
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 4409bde..66132ad 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -320,8 +320,7 @@
bool verify_attestation_record(const string& challenge, const string& app_id,
AuthorizationSet expected_sw_enforced,
AuthorizationSet expected_hw_enforced, SecurityLevel security_level,
- const hidl_vec<uint8_t>& attestation_cert,
- std::chrono::time_point<std::chrono::system_clock> creation_time) {
+ const hidl_vec<uint8_t>& attestation_cert) {
X509_Ptr cert(parse_cert_blob(attestation_cert));
EXPECT_TRUE(!!cert.get());
if (!cert.get()) return false;
@@ -405,8 +404,6 @@
EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
- KeymasterHidlTest::CheckCreationDateTime(att_sw_enforced, creation_time);
-
if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) {
// For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be.
EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) ||
@@ -423,27 +420,33 @@
EXPECT_EQ(ErrorCode::OK, error);
if (avb_verification_enabled()) {
- property_get("ro.boot.vbmeta.digest", property_value, "nogood");
- EXPECT_NE(strcmp(property_value, "nogood"), 0);
+ EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 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(strcmp(property_value, "nogood"), 0);
+ EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
if (!strcmp(property_value, "unlocked")) {
EXPECT_FALSE(device_locked);
} else {
EXPECT_TRUE(device_locked);
}
+
+ // Check that the expected result from VBMeta matches the build type. Only a user build
+ // should have AVB reporting the device is locked.
+ EXPECT_NE(property_get("ro.build.type", property_value, ""), 0);
+ if (!strcmp(property_value, "user")) {
+ EXPECT_TRUE(device_locked);
+ } else {
+ EXPECT_FALSE(device_locked);
+ }
}
// Verified boot key should be all 0's if the boot state is not verified or self signed
std::string empty_boot_key(32, '\0');
std::string verified_boot_key_str((const char*)verified_boot_key.data(),
verified_boot_key.size());
- property_get("ro.boot.verifiedbootstate", property_value, "nogood");
- EXPECT_NE(property_value, "nogood");
+ EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
if (!strcmp(property_value, "green")) {
EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_VERIFIED);
EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
@@ -522,7 +525,7 @@
* Verifies that keymaster can generate all required RSA key sizes, and that the resulting keys have
* correct characteristics.
*/
-TEST_F(NewKeyGenerationTest, Rsa) {
+TEST_P(NewKeyGenerationTest, Rsa) {
for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
HidlBuf key_blob;
KeyCharacteristics key_characteristics;
@@ -546,36 +549,18 @@
EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
<< "Key size " << key_size << "missing";
- EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 3U));
+ EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
CheckedDeleteKey(&key_blob);
}
}
/*
- * NewKeyGenerationTest.RsaCheckCreationDateTime
- *
- * Verifies that creation date time is correct.
- */
-TEST_F(NewKeyGenerationTest, RsaCheckCreationDateTime) {
- KeyCharacteristics key_characteristics;
- auto creation_time = std::chrono::system_clock::now();
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .RsaSigningKey(2048, 3)
- .Digest(Digest::NONE)
- .Padding(PaddingMode::NONE)));
- GetCharacteristics(key_blob_, &key_characteristics);
- AuthorizationSet sw_enforced = key_characteristics.softwareEnforced;
- CheckCreationDateTime(sw_enforced, creation_time);
-}
-
-/*
* NewKeyGenerationTest.NoInvalidRsaSizes
*
* Verifies that keymaster cannot generate any RSA key sizes that are designated as invalid.
*/
-TEST_F(NewKeyGenerationTest, NoInvalidRsaSizes) {
+TEST_P(NewKeyGenerationTest, NoInvalidRsaSizes) {
for (auto key_size : InvalidKeySizes(Algorithm::RSA)) {
HidlBuf key_blob;
KeyCharacteristics key_characteristics;
@@ -593,7 +578,7 @@
*
* Verifies that failing to specify a key size for RSA key generation returns UNSUPPORTED_KEY_SIZE.
*/
-TEST_F(NewKeyGenerationTest, RsaNoDefaultSize) {
+TEST_P(NewKeyGenerationTest, RsaNoDefaultSize) {
ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_ALGORITHM, Algorithm::RSA)
@@ -607,7 +592,7 @@
* Verifies that keymaster can generate all required EC key sizes, and that the resulting keys have
* correct characteristics.
*/
-TEST_F(NewKeyGenerationTest, Ecdsa) {
+TEST_P(NewKeyGenerationTest, Ecdsa) {
for (auto key_size : ValidKeySizes(Algorithm::EC)) {
HidlBuf key_blob;
KeyCharacteristics key_characteristics;
@@ -635,28 +620,11 @@
}
/*
- * NewKeyGenerationTest.EcCheckCreationDateTime
- *
- * Verifies that creation date time is correct.
- */
-TEST_F(NewKeyGenerationTest, EcCheckCreationDateTime) {
- KeyCharacteristics key_characteristics;
- auto creation_time = std::chrono::system_clock::now();
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(256)
- .Digest(Digest::NONE)));
- GetCharacteristics(key_blob_, &key_characteristics);
- AuthorizationSet sw_enforced = key_characteristics.softwareEnforced;
- CheckCreationDateTime(sw_enforced, creation_time);
-}
-
-/*
* NewKeyGenerationTest.EcdsaDefaultSize
*
* Verifies that failing to specify a key size for EC key generation returns UNSUPPORTED_KEY_SIZE.
*/
-TEST_F(NewKeyGenerationTest, EcdsaDefaultSize) {
+TEST_P(NewKeyGenerationTest, EcdsaDefaultSize) {
ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_ALGORITHM, Algorithm::EC)
@@ -669,7 +637,7 @@
*
* Verifies that specifying an invalid key size for EC key generation returns UNSUPPORTED_KEY_SIZE.
*/
-TEST_F(NewKeyGenerationTest, EcdsaInvalidSize) {
+TEST_P(NewKeyGenerationTest, EcdsaInvalidSize) {
for (auto key_size : InvalidKeySizes(Algorithm::EC)) {
HidlBuf key_blob;
KeyCharacteristics key_characteristics;
@@ -689,7 +657,7 @@
* Verifies that specifying mismatched key size and curve for EC key generation returns
* INVALID_ARGUMENT.
*/
-TEST_F(NewKeyGenerationTest, EcdsaMismatchKeySize) {
+TEST_P(NewKeyGenerationTest, EcdsaMismatchKeySize) {
if (SecLevel() == SecurityLevel::STRONGBOX) return;
ASSERT_EQ(ErrorCode::INVALID_ARGUMENT,
@@ -704,7 +672,7 @@
*
* Verifies that keymaster supports all required EC key sizes.
*/
-TEST_F(NewKeyGenerationTest, EcdsaAllValidSizes) {
+TEST_P(NewKeyGenerationTest, EcdsaAllValidSizes) {
auto valid_sizes = ValidKeySizes(Algorithm::EC);
for (size_t size : valid_sizes) {
EXPECT_EQ(ErrorCode::OK,
@@ -720,7 +688,7 @@
*
* Verifies that keymaster does not support any curve designated as unsupported.
*/
-TEST_F(NewKeyGenerationTest, EcdsaAllValidCurves) {
+TEST_P(NewKeyGenerationTest, EcdsaAllValidCurves) {
Digest digest;
if (SecLevel() == SecurityLevel::STRONGBOX) {
digest = Digest::SHA_2_256;
@@ -743,7 +711,7 @@
* Verifies that keymaster supports all required digests, and that the resulting keys have correct
* characteristics.
*/
-TEST_F(NewKeyGenerationTest, Hmac) {
+TEST_P(NewKeyGenerationTest, Hmac) {
for (auto digest : ValidDigests(false /* withNone */, true /* withMD5 */)) {
HidlBuf key_blob;
KeyCharacteristics key_characteristics;
@@ -779,7 +747,7 @@
*
* Verifies that keymaster supports all key sizes, and rejects all invalid key sizes.
*/
-TEST_F(NewKeyGenerationTest, HmacCheckKeySizes) {
+TEST_P(NewKeyGenerationTest, HmacCheckKeySizes) {
for (size_t key_size = 0; key_size <= 512; ++key_size) {
if (key_size < 64 || key_size % 8 != 0) {
// To keep this test from being very slow, we only test a random fraction of non-byte
@@ -812,7 +780,7 @@
* test is probabilistic in order to keep the runtime down, but any failure prints out the specific
* MAC length that failed, so reproducing a failed run will be easy.
*/
-TEST_F(NewKeyGenerationTest, HmacCheckMinMacLengths) {
+TEST_P(NewKeyGenerationTest, HmacCheckMinMacLengths) {
for (size_t min_mac_length = 0; min_mac_length <= 256; ++min_mac_length) {
if (min_mac_length < 64 || min_mac_length % 8 != 0) {
// To keep this test from being very long, we only test a random fraction of non-byte
@@ -844,7 +812,7 @@
*
* Verifies that keymaster rejects HMAC key generation with multiple specified digest algorithms.
*/
-TEST_F(NewKeyGenerationTest, HmacMultipleDigests) {
+TEST_P(NewKeyGenerationTest, HmacMultipleDigests) {
if (SecLevel() == SecurityLevel::STRONGBOX) return;
ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
@@ -860,7 +828,7 @@
*
* Verifies that keymaster rejects HMAC key generation with no digest or Digest::NONE
*/
-TEST_F(NewKeyGenerationTest, HmacDigestNone) {
+TEST_P(NewKeyGenerationTest, HmacDigestNone) {
ASSERT_EQ(
ErrorCode::UNSUPPORTED_DIGEST,
GenerateKey(AuthorizationSetBuilder().HmacKey(128).Authorization(TAG_MIN_MAC_LENGTH, 128)));
@@ -879,7 +847,7 @@
*
* Verifies that raw RSA signature operations succeed.
*/
-TEST_F(SigningOperationsTest, RsaSuccess) {
+TEST_P(SigningOperationsTest, RsaSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Digest(Digest::NONE)
@@ -895,7 +863,7 @@
*
* Verifies that getting RSA key characteristics requires the correct app ID/data.
*/
-TEST_F(SigningOperationsTest, RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData) {
+TEST_P(SigningOperationsTest, RsaGetKeyCharacteristicsRequiresCorrectAppIdAppData) {
HidlBuf key_blob;
KeyCharacteristics key_characteristics;
ASSERT_EQ(ErrorCode::OK,
@@ -916,7 +884,7 @@
*
* Verifies that using an RSA key requires the correct app ID/data.
*/
-TEST_F(SigningOperationsTest, RsaUseRequiresCorrectAppIdAppData) {
+TEST_P(SigningOperationsTest, RsaUseRequiresCorrectAppIdAppData) {
ASSERT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -958,7 +926,7 @@
*
* Verifies that RSA-PSS signature operations succeed.
*/
-TEST_F(SigningOperationsTest, RsaPssSha256Success) {
+TEST_P(SigningOperationsTest, RsaPssSha256Success) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Digest(Digest::SHA_2_256)
@@ -976,7 +944,7 @@
* Verifies that keymaster rejects signature operations that specify a padding mode when the key
* supports only unpadded operations.
*/
-TEST_F(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
+TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Digest(Digest::NONE)
@@ -998,7 +966,7 @@
* TRUSTED_CONFIRMATION_REQUIRED and no valid confirmation token
* presented.
*/
-TEST_F(SigningOperationsTest, NoUserConfirmation) {
+TEST_P(SigningOperationsTest, NoUserConfirmation) {
if (SecLevel() == SecurityLevel::STRONGBOX) return;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 65537)
@@ -1020,7 +988,7 @@
*
* Verifies that digested RSA-PKCS1 signature operations succeed.
*/
-TEST_F(SigningOperationsTest, RsaPkcs1Sha256Success) {
+TEST_P(SigningOperationsTest, RsaPkcs1Sha256Success) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Digest(Digest::SHA_2_256)
@@ -1037,7 +1005,7 @@
*
* Verifies that undigested RSA-PKCS1 signature operations succeed.
*/
-TEST_F(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Digest(Digest::NONE)
@@ -1055,7 +1023,7 @@
* Verifies that undigested RSA-PKCS1 signature operations fail with the correct error code when
* given a too-long message.
*/
-TEST_F(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Digest(Digest::NONE)
@@ -1083,7 +1051,7 @@
* uses SHA512, which has a digest_size == 512, so the message size is 1040 bits, too large for a
* 1024-bit key.
*/
-TEST_F(SigningOperationsTest, RsaPssSha512TooSmallKey) {
+TEST_P(SigningOperationsTest, RsaPssSha512TooSmallKey) {
if (SecLevel() == SecurityLevel::STRONGBOX) return;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 65537)
@@ -1102,7 +1070,7 @@
* Verifies that raw RSA signature operations fail with the correct error code when
* given a too-long message.
*/
-TEST_F(SigningOperationsTest, RsaNoPaddingTooLong) {
+TEST_P(SigningOperationsTest, RsaNoPaddingTooLong) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Digest(Digest::NONE)
@@ -1136,7 +1104,7 @@
* Verifies that operations can be aborted correctly. Uses an RSA signing operation for the test,
* but the behavior should be algorithm and purpose-independent.
*/
-TEST_F(SigningOperationsTest, RsaAbort) {
+TEST_P(SigningOperationsTest, RsaAbort) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Digest(Digest::NONE)
@@ -1161,7 +1129,7 @@
* Verifies that RSA operations fail with the correct error (but key gen succeeds) when used with a
* padding mode inappropriate for RSA.
*/
-TEST_F(SigningOperationsTest, RsaUnsupportedPadding) {
+TEST_P(SigningOperationsTest, RsaUnsupportedPadding) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1178,7 +1146,7 @@
*
* Verifies that RSA PSS operations fail when no digest is used. PSS requires a digest.
*/
-TEST_F(SigningOperationsTest, RsaNoDigest) {
+TEST_P(SigningOperationsTest, RsaNoDigest) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1198,7 +1166,7 @@
* Verifies that RSA operations fail when no padding mode is specified. PaddingMode::NONE is
* supported in some cases (as validated in other tests), but a mode must be specified.
*/
-TEST_F(SigningOperationsTest, RsaNoPadding) {
+TEST_P(SigningOperationsTest, RsaNoPadding) {
// Padding must be specified
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaKey(2048, 65537)
@@ -1214,7 +1182,7 @@
*
* Verifies that raw RSA signatures succeed with a message shorter than the key size.
*/
-TEST_F(SigningOperationsTest, RsaTooShortMessage) {
+TEST_P(SigningOperationsTest, RsaTooShortMessage) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(2048, 65537)
@@ -1235,7 +1203,7 @@
*
* Verifies that RSA encryption keys cannot be used to sign.
*/
-TEST_F(SigningOperationsTest, RsaSignWithEncryptionKey) {
+TEST_P(SigningOperationsTest, RsaSignWithEncryptionKey) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
@@ -1252,7 +1220,7 @@
* Verifies that attempting a raw signature of a message which is the same length as the key, but
* numerically larger than the public modulus, fails with the correct error.
*/
-TEST_F(SigningOperationsTest, RsaSignTooLargeMessage) {
+TEST_P(SigningOperationsTest, RsaSignTooLargeMessage) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(2048, 65537)
@@ -1274,7 +1242,7 @@
*
* Verifies that ECDSA operations succeed with all possible key sizes and hashes.
*/
-TEST_F(SigningOperationsTest, EcdsaAllSizesAndHashes) {
+TEST_P(SigningOperationsTest, EcdsaAllSizesAndHashes) {
for (auto key_size : ValidKeySizes(Algorithm::EC)) {
for (auto digest : ValidDigests(false /* withNone */, false /* withMD5 */)) {
ErrorCode error = GenerateKey(AuthorizationSetBuilder()
@@ -1298,7 +1266,7 @@
*
* Verifies that ECDSA operations succeed with all possible curves.
*/
-TEST_F(SigningOperationsTest, EcdsaAllCurves) {
+TEST_P(SigningOperationsTest, EcdsaAllCurves) {
for (auto curve : ValidCurves()) {
ErrorCode error = GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1320,7 +1288,7 @@
* work because ECDSA actually only signs the leftmost L_n bits of the message, however large it may
* be. Not using digesting is a bad idea, but in some cases digesting is done by the framework.
*/
-TEST_F(SigningOperationsTest, EcdsaNoDigestHugeData) {
+TEST_P(SigningOperationsTest, EcdsaNoDigestHugeData) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(256)
@@ -1334,7 +1302,7 @@
*
* Verifies that getting EC key characteristics requires the correct app ID/data.
*/
-TEST_F(SigningOperationsTest, EcGetKeyCharacteristicsRequiresCorrectAppIdAppData) {
+TEST_P(SigningOperationsTest, EcGetKeyCharacteristicsRequiresCorrectAppIdAppData) {
HidlBuf key_blob;
KeyCharacteristics key_characteristics;
ASSERT_EQ(ErrorCode::OK,
@@ -1354,7 +1322,7 @@
*
* Verifies that using an EC key requires the correct app ID/data.
*/
-TEST_F(SigningOperationsTest, EcUseRequiresCorrectAppIdAppData) {
+TEST_P(SigningOperationsTest, EcUseRequiresCorrectAppIdAppData) {
ASSERT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1391,7 +1359,7 @@
*
* Verifies that attempts to use AES keys to sign fail in the correct way.
*/
-TEST_F(SigningOperationsTest, AesEcbSign) {
+TEST_P(SigningOperationsTest, AesEcbSign) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.SigningKey()
@@ -1410,7 +1378,7 @@
*
* Verifies that HMAC works with all digests.
*/
-TEST_F(SigningOperationsTest, HmacAllDigests) {
+TEST_P(SigningOperationsTest, HmacAllDigests) {
for (auto digest : ValidDigests(false /* withNone */, false /* withMD5 */)) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -1432,7 +1400,7 @@
* Verifies that HMAC fails in the correct way when asked to generate a MAC larger than the digest
* size.
*/
-TEST_F(SigningOperationsTest, HmacSha256TooLargeMacLength) {
+TEST_P(SigningOperationsTest, HmacSha256TooLargeMacLength) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.HmacKey(128)
@@ -1453,7 +1421,7 @@
* Verifies that HMAC fails in the correct way when asked to generate a MAC smaller than the
* specified minimum MAC length.
*/
-TEST_F(SigningOperationsTest, HmacSha256TooSmallMacLength) {
+TEST_P(SigningOperationsTest, HmacSha256TooSmallMacLength) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.HmacKey(128)
@@ -1473,7 +1441,7 @@
*
* Validates against the test vectors from RFC 4231 test case 3.
*/
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase3) {
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase3) {
string key(20, 0xaa);
string message(50, 0xdd);
uint8_t sha_224_expected[] = {
@@ -1512,7 +1480,7 @@
*
* Validates against the test vectors from RFC 4231 test case 5.
*/
-TEST_F(SigningOperationsTest, HmacRfc4231TestCase5) {
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase5) {
string key(20, 0x0c);
string message = "Test With Truncation";
@@ -1548,7 +1516,7 @@
*
* Verifies that a simple RSA signature/verification sequence succeeds.
*/
-TEST_F(VerificationOperationsTest, RsaSuccess) {
+TEST_P(VerificationOperationsTest, RsaSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(2048, 65537)
@@ -1566,7 +1534,7 @@
*
* Verifies RSA signature/verification for all padding modes and digests.
*/
-TEST_F(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
+TEST_P(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
auto authorizations = AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(2048, 65537)
@@ -1660,7 +1628,7 @@
*
* Verifies ECDSA signature/verification for all digests and curves.
*/
-TEST_F(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
+TEST_P(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
auto digests = ValidDigests(true /* withNone */, false /* withMD5 */);
string message = "1234567890";
@@ -1740,7 +1708,7 @@
*
* Verifies HMAC signing and verification, but that a signing key cannot be used to verify.
*/
-TEST_F(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
+TEST_P(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
string key_material = "HelloThisIsAKey";
HidlBuf signing_key, verification_key;
@@ -1788,7 +1756,7 @@
*
* Verifies that attempting to export RSA keys in PKCS#8 format fails with the correct error.
*/
-TEST_F(ExportKeyTest, RsaUnsupportedKeyFormat) {
+TEST_P(ExportKeyTest, RsaUnsupportedKeyFormat) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Digest(Digest::NONE)
@@ -1803,7 +1771,7 @@
* Verifies that attempting to export RSA keys from corrupted key blobs fails. This is essentially
* a poor-man's key blob fuzzer.
*/
-TEST_F(ExportKeyTest, RsaCorruptedKeyBlob) {
+TEST_P(ExportKeyTest, RsaCorruptedKeyBlob) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(2048, 65537)
@@ -1826,7 +1794,7 @@
* Verifies that attempting to export ECDSA keys from corrupted key blobs fails. This is
* essentially a poor-man's key blob fuzzer.
*/
-TEST_F(ExportKeyTest, EcCorruptedKeyBlob) {
+TEST_P(ExportKeyTest, EcCorruptedKeyBlob) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(EcCurve::P_256)
@@ -1847,7 +1815,7 @@
*
* Verifies that attempting to export AES keys fails in the expected way.
*/
-TEST_F(ExportKeyTest, AesKeyUnexportable) {
+TEST_P(ExportKeyTest, AesKeyUnexportable) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -1895,7 +1863,7 @@
*
* Verifies that importing and using an RSA key pair works correctly.
*/
-TEST_F(ImportKeyTest, RsaSuccess) {
+TEST_P(ImportKeyTest, RsaSuccess) {
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(1024, 65537)
@@ -1922,7 +1890,7 @@
* Verifies that importing an RSA key pair with a size that doesn't match the key fails in the
* correct way.
*/
-TEST_F(ImportKeyTest, RsaKeySizeMismatch) {
+TEST_P(ImportKeyTest, RsaKeySizeMismatch) {
ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
ImportKey(AuthorizationSetBuilder()
.RsaSigningKey(2048 /* Doesn't match key */, 65537)
@@ -1937,7 +1905,7 @@
* Verifies that importing an RSA key pair with a public exponent that doesn't match the key fails
* in the correct way.
*/
-TEST_F(ImportKeyTest, RsaPublicExponentMismatch) {
+TEST_P(ImportKeyTest, RsaPublicExponentMismatch) {
ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
ImportKey(AuthorizationSetBuilder()
.RsaSigningKey(1024, 3 /* Doesn't match key */)
@@ -1951,7 +1919,7 @@
*
* Verifies that importing and using an ECDSA P-256 key pair works correctly.
*/
-TEST_F(ImportKeyTest, EcdsaSuccess) {
+TEST_P(ImportKeyTest, EcdsaSuccess) {
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(256)
@@ -1976,7 +1944,7 @@
*
* Verifies that importing and using an ECDSA P-256 key pair encoded using RFC5915 works correctly.
*/
-TEST_F(ImportKeyTest, EcdsaP256RFC5915Success) {
+TEST_P(ImportKeyTest, EcdsaP256RFC5915Success) {
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(256)
@@ -2001,7 +1969,7 @@
*
* Verifies that importing and using an ECDSA P-256 key pair encoded using SEC1 works correctly.
*/
-TEST_F(ImportKeyTest, EcdsaP256SEC1Success) {
+TEST_P(ImportKeyTest, EcdsaP256SEC1Success) {
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(256)
@@ -2026,7 +1994,7 @@
*
* Verifies that importing and using an ECDSA P-521 key pair works correctly.
*/
-TEST_F(ImportKeyTest, Ecdsa521Success) {
+TEST_P(ImportKeyTest, Ecdsa521Success) {
if (SecLevel() == SecurityLevel::STRONGBOX) return;
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -2052,7 +2020,7 @@
* Verifies that importing an ECDSA key pair with a size that doesn't match the key fails in the
* correct way.
*/
-TEST_F(ImportKeyTest, EcdsaSizeMismatch) {
+TEST_P(ImportKeyTest, EcdsaSizeMismatch) {
ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
ImportKey(AuthorizationSetBuilder()
.EcdsaSigningKey(224 /* Doesn't match key */)
@@ -2066,7 +2034,7 @@
* Verifies that importing an ECDSA key pair with a curve that doesn't match the key fails in the
* correct way.
*/
-TEST_F(ImportKeyTest, EcdsaCurveMismatch) {
+TEST_P(ImportKeyTest, EcdsaCurveMismatch) {
ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
ImportKey(AuthorizationSetBuilder()
.EcdsaSigningKey(EcCurve::P_224 /* Doesn't match key */)
@@ -2079,7 +2047,7 @@
*
* Verifies that importing and using an AES key works.
*/
-TEST_F(ImportKeyTest, AesSuccess) {
+TEST_P(ImportKeyTest, AesSuccess) {
string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -2106,7 +2074,7 @@
*
* Verifies that importing and using an HMAC key works.
*/
-TEST_F(ImportKeyTest, HmacKeySuccess) {
+TEST_P(ImportKeyTest, HmacKeySuccess) {
string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -2181,7 +2149,7 @@
class ImportWrappedKeyTest : public KeymasterHidlTest {};
-TEST_F(ImportWrappedKeyTest, Success) {
+TEST_P(ImportWrappedKeyTest, Success) {
auto wrapping_key_desc = AuthorizationSetBuilder()
.RsaEncryptionKey(2048, 65537)
.Digest(Digest::SHA_2_256)
@@ -2202,7 +2170,7 @@
EXPECT_EQ(message, plaintext);
}
-TEST_F(ImportWrappedKeyTest, SuccessMasked) {
+TEST_P(ImportWrappedKeyTest, SuccessMasked) {
auto wrapping_key_desc = AuthorizationSetBuilder()
.RsaEncryptionKey(2048, 65537)
.Digest(Digest::SHA_2_256)
@@ -2217,7 +2185,7 @@
.Padding(PaddingMode::RSA_OAEP)));
}
-TEST_F(ImportWrappedKeyTest, WrongMask) {
+TEST_P(ImportWrappedKeyTest, WrongMask) {
auto wrapping_key_desc = AuthorizationSetBuilder()
.RsaEncryptionKey(2048, 65537)
.Digest(Digest::SHA_2_256)
@@ -2232,7 +2200,7 @@
.Padding(PaddingMode::RSA_OAEP)));
}
-TEST_F(ImportWrappedKeyTest, WrongPurpose) {
+TEST_P(ImportWrappedKeyTest, WrongPurpose) {
auto wrapping_key_desc = AuthorizationSetBuilder()
.RsaEncryptionKey(2048, 65537)
.Digest(Digest::SHA_2_256)
@@ -2253,7 +2221,7 @@
*
* Verifies that raw RSA encryption works.
*/
-TEST_F(EncryptionOperationsTest, RsaNoPaddingSuccess) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
@@ -2276,7 +2244,7 @@
*
* Verifies that raw RSA encryption of short messages works.
*/
-TEST_F(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
@@ -2305,7 +2273,7 @@
*
* Verifies that raw RSA encryption of too-long messages fails in the expected way.
*/
-TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLong) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLong) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
@@ -2325,7 +2293,7 @@
*
* Verifies that raw RSA encryption of too-large (numerically) messages fails in the expected way.
*/
-TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLarge) {
+TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLarge) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
@@ -2367,7 +2335,7 @@
*
* Verifies that RSA-OAEP encryption operations work, with all digests.
*/
-TEST_F(EncryptionOperationsTest, RsaOaepSuccess) {
+TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
auto digests = ValidDigests(false /* withNone */, true /* withMD5 */);
size_t key_size = 2048; // Need largish key for SHA-512 test.
@@ -2418,7 +2386,7 @@
* Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate
* without a digest.
*/
-TEST_F(EncryptionOperationsTest, RsaOaepInvalidDigest) {
+TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
@@ -2436,7 +2404,7 @@
* Verifies that RSA-OAEP encryption operations fail in the correct way when asked to decrypt with a
* different digest than was used to encrypt.
*/
-TEST_F(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
+TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
if (SecLevel() == SecurityLevel::STRONGBOX) return;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -2464,7 +2432,7 @@
* Verifies that RSA-OAEP encryption operations fail in the correct way when asked to encrypt a
* too-large message.
*/
-TEST_F(EncryptionOperationsTest, RsaOaepTooLarge) {
+TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
@@ -2487,7 +2455,7 @@
*
* Verifies that RSA PKCS encryption/decrypts works.
*/
-TEST_F(EncryptionOperationsTest, RsaPkcs1Success) {
+TEST_P(EncryptionOperationsTest, RsaPkcs1Success) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
@@ -2526,7 +2494,7 @@
*
* Verifies that RSA PKCS encryption fails in the correct way when the mssage is too large.
*/
-TEST_F(EncryptionOperationsTest, RsaPkcs1TooLarge) {
+TEST_P(EncryptionOperationsTest, RsaPkcs1TooLarge) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
@@ -2546,7 +2514,7 @@
*
* Verifies that attempting to use ECDSA keys to encrypt fails in the correct way.
*/
-TEST_F(EncryptionOperationsTest, EcdsaEncrypt) {
+TEST_P(EncryptionOperationsTest, EcdsaEncrypt) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(256)
@@ -2561,7 +2529,7 @@
*
* Verifies that attempting to use HMAC keys to encrypt fails in the correct way.
*/
-TEST_F(EncryptionOperationsTest, HmacEncrypt) {
+TEST_P(EncryptionOperationsTest, HmacEncrypt) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.HmacKey(128)
@@ -2581,7 +2549,7 @@
*
* Verifies that AES ECB mode works.
*/
-TEST_F(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2610,7 +2578,7 @@
*
* Verifies that AES encryption fails in the correct way when an unauthorized mode is specified.
*/
-TEST_F(EncryptionOperationsTest, AesWrongMode) {
+TEST_P(EncryptionOperationsTest, AesWrongMode) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2629,7 +2597,7 @@
*
* Verifies that AES encryption fails in the correct way when an unauthorized purpose is specified.
*/
-TEST_F(EncryptionOperationsTest, AesWrongPurpose) {
+TEST_P(EncryptionOperationsTest, AesWrongPurpose) {
auto err = GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesKey(128)
@@ -2639,8 +2607,10 @@
.Padding(PaddingMode::NONE));
ASSERT_EQ(ErrorCode::OK, err) << "Got " << err;
- err = Begin(KeyPurpose::DECRYPT,
- AuthorizationSetBuilder().BlockMode(BlockMode::GCM).Padding(PaddingMode::NONE));
+ err = Begin(KeyPurpose::DECRYPT, AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128));
EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err;
CheckedDeleteKey();
@@ -2653,8 +2623,10 @@
.Authorization(TAG_MIN_MAC_LENGTH, 128)
.Padding(PaddingMode::NONE)));
- err = Begin(KeyPurpose::ENCRYPT,
- AuthorizationSetBuilder().BlockMode(BlockMode::GCM).Padding(PaddingMode::NONE));
+ err = Begin(KeyPurpose::ENCRYPT, AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128));
EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err;
}
@@ -2664,7 +2636,7 @@
* Verifies that AES encryption fails in the correct way when provided an input that is not a
* multiple of the block size and no padding is specified.
*/
-TEST_F(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
+TEST_P(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2685,7 +2657,7 @@
*
* Verifies that AES PKCS7 padding works for any message length.
*/
-TEST_F(EncryptionOperationsTest, AesEcbPkcs7Padding) {
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7Padding) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2710,7 +2682,7 @@
* Verifies that AES enryption fails in the correct way when an unauthorized padding mode is
* specified.
*/
-TEST_F(EncryptionOperationsTest, AesEcbWrongPadding) {
+TEST_P(EncryptionOperationsTest, AesEcbWrongPadding) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2731,7 +2703,7 @@
*
* Verifies that AES decryption fails in the correct way when the padding is corrupted.
*/
-TEST_F(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2762,7 +2734,7 @@
*
* Verifies that AES CTR mode works.
*/
-TEST_F(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2809,7 +2781,7 @@
*
* Verifies that AES works, all modes, when provided data in various size increments.
*/
-TEST_F(EncryptionOperationsTest, AesIncremental) {
+TEST_P(EncryptionOperationsTest, AesIncremental) {
auto block_modes = {
BlockMode::ECB, BlockMode::CBC, BlockMode::CTR, BlockMode::GCM,
};
@@ -2948,7 +2920,7 @@
*
* Verifies AES CTR implementation against SP800-38A test vectors.
*/
-TEST_F(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
+TEST_P(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
std::vector<uint32_t> InvalidSizes = InvalidKeySizes(Algorithm::AES);
for (size_t i = 0; i < 3; i++) {
const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]);
@@ -2968,7 +2940,7 @@
*
* Verifies that keymaster rejects use of CTR mode with PKCS7 padding in the correct way.
*/
-TEST_F(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
+TEST_P(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -2983,7 +2955,7 @@
*
* Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
*/
-TEST_F(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
+TEST_P(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3015,7 +2987,7 @@
*
* Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
*/
-TEST_F(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3048,7 +3020,7 @@
*
* Verifies that AES caller-provided nonces work correctly.
*/
-TEST_F(EncryptionOperationsTest, AesCallerNonce) {
+TEST_P(EncryptionOperationsTest, AesCallerNonce) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3097,7 +3069,7 @@
* Verifies that caller-provided nonces are not permitted when not specified in the key
* authorizations.
*/
-TEST_F(EncryptionOperationsTest, AesCallerNonceProhibited) {
+TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3132,7 +3104,7 @@
*
* Verifies that AES GCM mode works.
*/
-TEST_F(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3183,7 +3155,7 @@
* Verifies that AES GCM mode works, even when there's a long delay
* between operations.
*/
-TEST_F(EncryptionOperationsTest, AesGcmRoundTripWithDelaySuccess) {
+TEST_P(EncryptionOperationsTest, AesGcmRoundTripWithDelaySuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3236,7 +3208,7 @@
*
* Verifies that encrypting the same data with different nonces produces different outputs.
*/
-TEST_F(EncryptionOperationsTest, AesGcmDifferentNonces) {
+TEST_P(EncryptionOperationsTest, AesGcmDifferentNonces) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3268,7 +3240,7 @@
*
* Verifies that AES GCM mode fails correctly when a too-short tag length is specified.
*/
-TEST_F(EncryptionOperationsTest, AesGcmTooShortTag) {
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3289,7 +3261,7 @@
*
* Verifies that AES GCM mode fails correctly when a too-short tag is provided to decryption.
*/
-TEST_F(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3332,7 +3304,7 @@
*
* Verifies that AES GCM mode fails correctly when the decryption key is incorrect.
*/
-TEST_F(EncryptionOperationsTest, AesGcmCorruptKey) {
+TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) {
const uint8_t nonce_bytes[] = {
0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f,
};
@@ -3384,7 +3356,7 @@
* Verifies that AES GCM mode works when provided additional authenticated data, but no data to
* encrypt.
*/
-TEST_F(EncryptionOperationsTest, AesGcmAadNoData) {
+TEST_P(EncryptionOperationsTest, AesGcmAadNoData) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3429,7 +3401,7 @@
*
* Verifies that AES GCM mode works when provided additional authenticated data in multiple chunks.
*/
-TEST_F(EncryptionOperationsTest, AesGcmMultiPartAad) {
+TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) {
const size_t tag_bits = 128;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -3490,7 +3462,7 @@
*
* Verifies that AES GCM mode fails correctly when given AAD after data to encipher.
*/
-TEST_F(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
+TEST_P(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3538,7 +3510,7 @@
*
* Verifies that AES GCM decryption fails correctly when additional authenticated date is wrong.
*/
-TEST_F(EncryptionOperationsTest, AesGcmBadAad) {
+TEST_P(EncryptionOperationsTest, AesGcmBadAad) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3582,7 +3554,7 @@
*
* Verifies that AES GCM decryption fails correctly when the nonce is incorrect.
*/
-TEST_F(EncryptionOperationsTest, AesGcmWrongNonce) {
+TEST_P(EncryptionOperationsTest, AesGcmWrongNonce) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3626,7 +3598,7 @@
*
* Verifies that AES GCM decryption fails correctly when the tag is wrong.
*/
-TEST_F(EncryptionOperationsTest, AesGcmCorruptTag) {
+TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -3674,7 +3646,7 @@
*
* Verifies that 3DES is basically functional.
*/
-TEST_F(EncryptionOperationsTest, TripleDesEcbRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, TripleDesEcbRoundTripSuccess) {
auto auths = AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::ECB)
@@ -3703,7 +3675,7 @@
*
* Verifies that CBC keys reject ECB usage.
*/
-TEST_F(EncryptionOperationsTest, TripleDesEcbNotAuthorized) {
+TEST_P(EncryptionOperationsTest, TripleDesEcbNotAuthorized) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::CBC)
@@ -3719,7 +3691,7 @@
*
* Tests ECB mode with PKCS#7 padding, various message sizes.
*/
-TEST_F(EncryptionOperationsTest, TripleDesEcbPkcs7Padding) {
+TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7Padding) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::ECB)
@@ -3742,7 +3714,7 @@
*
* Verifies that keys configured for no padding reject PKCS7 padding
*/
-TEST_F(EncryptionOperationsTest, TripleDesEcbNoPaddingKeyWithPkcs7Padding) {
+TEST_P(EncryptionOperationsTest, TripleDesEcbNoPaddingKeyWithPkcs7Padding) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::ECB)
@@ -3760,7 +3732,7 @@
*
* Verifies that corrupted padding is detected.
*/
-TEST_F(EncryptionOperationsTest, TripleDesEcbPkcs7PaddingCorrupted) {
+TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7PaddingCorrupted) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::ECB)
@@ -3876,7 +3848,7 @@
*
* Verifies that NIST (plus a few extra) test vectors produce the correct results.
*/
-TEST_F(EncryptionOperationsTest, TripleDesTestVector) {
+TEST_P(EncryptionOperationsTest, TripleDesTestVector) {
constexpr size_t num_tests = sizeof(kTripleDesTestVectors) / sizeof(TripleDesTestVector);
for (auto* test = kTripleDesTestVectors; test < kTripleDesTestVectors + num_tests; ++test) {
SCOPED_TRACE(test->name);
@@ -3891,7 +3863,7 @@
*
* Validates CBC mode functionality.
*/
-TEST_F(EncryptionOperationsTest, TripleDesCbcRoundTripSuccess) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcRoundTripSuccess) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::CBC)
@@ -3920,7 +3892,7 @@
*
* Validates that 3DES keys can allow caller-specified IVs, and use them correctly.
*/
-TEST_F(EncryptionOperationsTest, TripleDesCallerIv) {
+TEST_P(EncryptionOperationsTest, TripleDesCallerIv) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::CBC)
@@ -3955,7 +3927,7 @@
*
* Verifies that 3DES keys without TAG_CALLER_NONCE do not allow caller-specified IVS.
*/
-TEST_F(EncryptionOperationsTest, TripleDesCallerNonceProhibited) {
+TEST_P(EncryptionOperationsTest, TripleDesCallerNonceProhibited) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::CBC)
@@ -3987,7 +3959,7 @@
*
* Verifies that 3DES ECB-only keys do not allow CBC usage.
*/
-TEST_F(EncryptionOperationsTest, TripleDesCbcNotAuthorized) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcNotAuthorized) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::ECB)
@@ -4005,7 +3977,7 @@
*
* Verifies that unpadded CBC operations reject inputs that are not a multiple of block size.
*/
-TEST_F(EncryptionOperationsTest, TripleDesCbcNoPaddingWrongInputSize) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcNoPaddingWrongInputSize) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::CBC)
@@ -4027,7 +3999,7 @@
*
* Verifies that PKCS7 padding works correctly in CBC mode.
*/
-TEST_F(EncryptionOperationsTest, TripleDesCbcPkcs7Padding) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7Padding) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::CBC)
@@ -4050,7 +4022,7 @@
*
* Verifies that a key that requires PKCS7 padding cannot be used in unpadded mode.
*/
-TEST_F(EncryptionOperationsTest, TripleDesCbcNoPaddingKeyWithPkcs7Padding) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcNoPaddingKeyWithPkcs7Padding) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::CBC)
@@ -4070,7 +4042,7 @@
*
* Verifies that corrupted PKCS7 padding is rejected during decryption.
*/
-TEST_F(EncryptionOperationsTest, TripleDesCbcPkcs7PaddingCorrupted) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7PaddingCorrupted) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::CBC)
@@ -4101,7 +4073,7 @@
*
* Verifies that 3DES CBC works with many different input sizes.
*/
-TEST_F(EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding) {
+TEST_P(EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(BlockMode::CBC)
@@ -4146,7 +4118,7 @@
*
* Verifies that the max uses per boot tag works correctly with AES keys.
*/
-TEST_F(MaxOperationsTest, TestLimitAes) {
+TEST_P(MaxOperationsTest, TestLimitAes) {
if (SecLevel() == SecurityLevel::STRONGBOX) return;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -4173,7 +4145,7 @@
*
* Verifies that the max uses per boot tag works correctly with RSA keys.
*/
-TEST_F(MaxOperationsTest, TestLimitRsa) {
+TEST_P(MaxOperationsTest, TestLimitRsa) {
if (SecLevel() == SecurityLevel::STRONGBOX) return;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -4202,7 +4174,7 @@
* Verifies that the addRngEntropy method doesn't blow up. There's no way to test that entropy is
* actually added.
*/
-TEST_F(AddEntropyTest, AddEntropy) {
+TEST_P(AddEntropyTest, AddEntropy) {
EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf("foo")));
}
@@ -4211,7 +4183,7 @@
*
* Verifies that the addRngEntropy method doesn't blow up when given an empty buffer.
*/
-TEST_F(AddEntropyTest, AddEmptyEntropy) {
+TEST_P(AddEntropyTest, AddEmptyEntropy) {
EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf()));
}
@@ -4220,7 +4192,7 @@
*
* Verifies that the addRngEntropy method doesn't blow up when given a largish amount of data.
*/
-TEST_F(AddEntropyTest, AddLargeEntropy) {
+TEST_P(AddEntropyTest, AddLargeEntropy) {
EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(2 * 1024, 'a'))));
}
@@ -4231,8 +4203,7 @@
*
* Verifies that attesting to RSA keys works and generates the expected output.
*/
-TEST_F(AttestationTest, RsaAttestation) {
- auto creation_time = std::chrono::system_clock::now();
+TEST_P(AttestationTest, RsaAttestation) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(2048, 65537)
@@ -4257,7 +4228,7 @@
EXPECT_TRUE(verify_attestation_record("challenge", "foo", //
key_characteristics_.softwareEnforced, //
key_characteristics_.hardwareEnforced, //
- SecLevel(), cert_chain[0], creation_time));
+ SecLevel(), cert_chain[0]));
}
/*
@@ -4265,7 +4236,7 @@
*
* Verifies that attesting to RSA requires app ID.
*/
-TEST_F(AttestationTest, RsaAttestationRequiresAppId) {
+TEST_P(AttestationTest, RsaAttestationRequiresAppId) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaSigningKey(2048, 65537)
@@ -4285,8 +4256,7 @@
*
* Verifies that attesting to EC keys works and generates the expected output.
*/
-TEST_F(AttestationTest, EcAttestation) {
- auto creation_time = std::chrono::system_clock::now();
+TEST_P(AttestationTest, EcAttestation) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(EcCurve::P_256)
@@ -4308,7 +4278,7 @@
EXPECT_TRUE(verify_attestation_record("challenge", "foo", //
key_characteristics_.softwareEnforced, //
key_characteristics_.hardwareEnforced, //
- SecLevel(), cert_chain[0], creation_time));
+ SecLevel(), cert_chain[0]));
}
/*
@@ -4316,7 +4286,7 @@
*
* Verifies that attesting to EC keys requires app ID
*/
-TEST_F(AttestationTest, EcAttestationRequiresAttestationAppId) {
+TEST_P(AttestationTest, EcAttestationRequiresAttestationAppId) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(EcCurve::P_256)
@@ -4338,10 +4308,9 @@
* byte. Proper DER encoding specifies that for lengths greather than 127, one byte should be used
* to specify how many following bytes will be used to encode the length.
*/
-TEST_F(AttestationTest, AttestationApplicationIDLengthProperlyEncoded) {
+TEST_P(AttestationTest, AttestationApplicationIDLengthProperlyEncoded) {
std::vector<uint32_t> app_id_lengths{143, 258};
for (uint32_t length : app_id_lengths) {
- auto creation_time = std::chrono::system_clock::now();
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.EcdsaSigningKey(EcCurve::P_256)
@@ -4359,7 +4328,7 @@
EXPECT_TRUE(verify_attestation_record("challenge", app_id, //
key_characteristics_.softwareEnforced, //
key_characteristics_.hardwareEnforced, //
- SecLevel(), cert_chain[0], creation_time));
+ SecLevel(), cert_chain[0]));
CheckedDeleteKey();
}
}
@@ -4368,7 +4337,7 @@
*
* Verifies that attesting to AES keys fails in the expected way.
*/
-TEST_F(AttestationTest, AesAttestation) {
+TEST_P(AttestationTest, AesAttestation) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -4388,7 +4357,7 @@
*
* Verifies that attesting to HMAC keys fails in the expected way.
*/
-TEST_F(AttestationTest, HmacAttestation) {
+TEST_P(AttestationTest, HmacAttestation) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.HmacKey(128)
@@ -4412,7 +4381,7 @@
* This test checks that if rollback protection is implemented, DeleteKey invalidates a formerly
* valid key blob.
*/
-TEST_F(KeyDeletionTest, DeleteKey) {
+TEST_P(KeyDeletionTest, DeleteKey) {
auto error = GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
.Digest(Digest::NONE)
@@ -4444,7 +4413,7 @@
*
* This test checks that the HAL excepts invalid key blobs..
*/
-TEST_F(KeyDeletionTest, DeleteInvalidKey) {
+TEST_P(KeyDeletionTest, DeleteInvalidKey) {
// Generate key just to check if rollback protection is implemented
auto error = GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
@@ -4480,7 +4449,7 @@
* been provisioned. Use this test only on dedicated testing devices that have no valuable
* credentials stored in Keystore/Keymaster.
*/
-TEST_F(KeyDeletionTest, DeleteAllKeys) {
+TEST_P(KeyDeletionTest, DeleteAllKeys) {
if (!arm_deleteAllKeys) return;
auto error = GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(2048, 65537)
@@ -4516,7 +4485,7 @@
*
* Verifies that calling upgrade key on an up-to-date key works (i.e. does nothing).
*/
-TEST_F(UpgradeKeyTest, UpgradeKey) {
+TEST_P(UpgradeKeyTest, UpgradeKey) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.AesEncryptionKey(128)
.Padding(PaddingMode::NONE)
@@ -4528,7 +4497,6 @@
EXPECT_EQ(result, std::make_pair(ErrorCode::OK, HidlBuf()));
}
-
using ClearOperationsTest = KeymasterHidlTest;
/*
@@ -4539,7 +4507,7 @@
* that aborting the operations clears the operations.
*
*/
-TEST_F(ClearOperationsTest, TooManyOperations) {
+TEST_P(ClearOperationsTest, TooManyOperations) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
@@ -4571,8 +4539,7 @@
* Verifies that the service is restarted after death and the ongoing
* operations are cleared.
*/
-TEST_F(ClearOperationsTest, ServiceDeath) {
-
+TEST_P(ClearOperationsTest, ServiceDeath) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
@@ -4612,7 +4579,7 @@
*
* Verifies that passing large input data to finish either succeeds or fails as expected.
*/
-TEST_F(TransportLimitTest, LargeFinishInput) {
+TEST_P(TransportLimitTest, LargeFinishInput) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -4657,18 +4624,53 @@
CheckedDeleteKey();
}
+static const auto kKeymasterDeviceChoices =
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor));
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, NewKeyGenerationTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, ImportKeyTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, ImportWrappedKeyTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, SigningOperationsTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, VerificationOperationsTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, ExportKeyTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, EncryptionOperationsTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, MaxOperationsTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, AddEntropyTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, AttestationTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, KeyDeletionTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, TransportLimitTest, kKeymasterDeviceChoices,
+ android::hardware::PrintInstanceNameToString);
+
} // namespace test
} // namespace V4_0
} // namespace keymaster
} // namespace hardware
} // namespace android
-using android::hardware::keymaster::V4_0::test::KeymasterHidlEnvironment;
-
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(KeymasterHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
- KeymasterHidlEnvironment::Instance()->init(&argc, argv);
for (int i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
if (std::string(argv[i]) == "--arm_deleteAllKeys") {
diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal
index ba9d068..1175a30 100644
--- a/neuralnetworks/1.0/types.hal
+++ b/neuralnetworks/1.0/types.hal
@@ -261,8 +261,8 @@
* filter.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32}
- * the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale.
* * 3: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -290,7 +290,8 @@
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32}
* the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale.
* * 3: An {@link OperandType::INT32} scalar, specifying the implicit
@@ -355,8 +356,8 @@
* specifying the filter.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32}
- * the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale.
* * 3: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -384,8 +385,8 @@
* specifying the filter.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32}
- * the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale.
* * 3: An {@link OperandType::INT32} scalar, specifying the implicit
@@ -492,8 +493,6 @@
*
* Supported value tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT32}
- * * {@link OperandType::TENSOR_INT32}
- * * {@link OperandType::TENSOR_QUANT8_ASYMM}
*
* Supported value tensor rank: from 2
*
@@ -556,10 +555,10 @@
* of output nodes.
* * 2: A 1-D tensor, of shape [num_units], specifying the bias. For input
* tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should
- * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor
- * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
- * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
- * bias_scale == input_scale * filter_scale.
+ * also be of {@link OperandType::TENSOR_FLOAT32}.
+ * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * the bias should be of {@link OperandType::TENSOR_INT32},
+ * with zeroPoint of 0 and bias_scale == input_scale * filter_scale.
* * 3: An {@link OperandType::INT32} scalar, and has to be one of the
* {@link FusedActivationFunc} values. Specifies the activation to
* invoke on the result.
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index b111d96..e867120 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -375,8 +375,8 @@
* must be set to 0.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32}
- * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale.
* For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
@@ -425,7 +425,8 @@
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32}
* or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale.
* For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
@@ -523,8 +524,8 @@
* must be set to 3.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32}
- * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale.
* For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
@@ -569,8 +570,8 @@
* specifying the filter.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32}
- * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale.
* For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
@@ -705,8 +706,8 @@
*
* Supported value tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT32}
- * * {@link OperandType::TENSOR_INT32}
- * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_INT32} (since HAL version 1.2)
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
*
* Supported value tensor rank: from 2
*
@@ -772,10 +773,10 @@
* of output nodes.
* * 2: A 1-D tensor, of shape [num_units], specifying the bias. For input
* tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should
- * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor
- * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
- * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
- * bias_scale == input_scale * filter_scale.
+ * also be of {@link OperandType::TENSOR_FLOAT32}.
+ * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * the bias should be of {@link OperandType::TENSOR_INT32},
+ * with zeroPoint of 0 and bias_scale == input_scale * filter_scale.
* * 3: An {@link OperandType::INT32} scalar, and has to be one of the
* {@link FusedActivationFunc} values. Specifies the activation to
* invoke on the result.
@@ -2659,7 +2660,8 @@
* order of the boxes corresponds with input0. For input0 of type
* {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of
* {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint of 0 and
- * scale of 0.125. Zero num_rois is supported for this tensor.
+ * scale of 0.125.
+ * Zero num_rois is supported for this tensor.
* * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
* [num_rois], specifying the batch index of each box. Boxes with
* the same batch index are grouped together.
@@ -2686,6 +2688,7 @@
* [num_output_rois], specifying the score of each output box. The boxes
* are grouped by batches, but the sequential order in each batch is not
* guaranteed. For type of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * guaranteed. For type of {@link OperandType::TENSOR_QUANT8_ASYMM}
* the scale and zero point must be the same as input0.
* * 1: A 2-D Tensor of the same {@link OperandType} as input1, with shape
* [num_output_rois, 4], specifying the coordinates of each
@@ -2703,7 +2706,7 @@
BOX_WITH_NMS_LIMIT = 44,
/**
- * Casts a tensor to a new type.
+ * Casts a tensor to a type.
*
* This operation ignores the scale and zeroPoint of quanized tensors,
* e.g. it treats a {@link OperandType::TENSOR_QUANT8_ASYMM} input
@@ -3141,8 +3144,8 @@
* {@link SymmPerChannelQuantParams}) must be set to 0.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32} or
- * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale. For filter tensor
* of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
@@ -3181,7 +3184,8 @@
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32} or
* {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale. For filter tensor
* of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
@@ -3661,21 +3665,24 @@
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
* For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
- * the scale and zeroPoint can be diffent from the input0 scale and zeroPoint.
+ * the scales and zeroPoint can be different from input0 scale and zeroPoint.
*/
PRELU = 71,
/**
* Quantizes the input tensor.
*
- * The formula is:
+ * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM} output tensor is:
*
* output = max(0, min(255, round(input / scale) + zeroPoint)
*
- * Supported tensor {@link OperandType}:
+ * Supported input tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
*
+ * Supported output tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: from 1
*
* Inputs:
@@ -4325,15 +4332,15 @@
* dimension (SymmPerChannelQuantParams::channelDim) must be set to 0.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32} or
- * {@link OperandType::TENSOR_FLOAT16}, the bias should be of the
- * same type. For input tensor of type
- * {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
- * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
- * bias_scale == input_scale * filter_scale. For filter tensor of
- * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
- * must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
- * 0 and bias_scale of 0. The actual scale of each value 'i' is equal
- * to bias_scale[i] = input_scale * filter_scale[i].
+ * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the
+ * same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * the bias should be of {@link OperandType::TENSOR_INT32},
+ * with zeroPoint of 0 and bias_scale == input_scale * filter_scale.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+ * the bias must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+ * and bias_scale of 0. The actual scale of each value 'i' is equal to
+ * bias_scale[i] = input_scale * filter_scale[i].
* * 3: An {@link OperandType::INT32} scalar, specifying the padding on
* the left, in the ‘width’ dimension.
* * 4: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -4363,14 +4370,14 @@
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32} or
* {@link OperandType::TENSOR_FLOAT16}, the bias should be of the
- * same type. For input tensor of type
- * {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
- * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
- * bias_scale == input_scale * filter_scale. For filter tensor of
- * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
- * must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
- * 0 and bias_scale of 0. The actual scale of each value 'i' is equal
- * to bias_scale[i] = input_scale * filter_scale[i].
+ * same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * the bias should be of {@link OperandType::TENSOR_INT32},
+ * with zeroPoint of 0 and bias_scale == input_scale * filter_scale.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+ * the bias must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+ * and bias_scale of 0. The actual scale of each value 'i' is equal to
+ * bias_scale[i] = input_scale * filter_scale[i].
* * 3: An {@link OperandType::TENSOR_INT32} tensor, specifying the output
* tensor shape.
* * 4: An {@link OperandType::INT32} scalar, specifying the implicit
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
index c1bf494..4909214 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -29,13 +29,14 @@
#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 <gtest/gtest.h>
#include <hidlmemory/mapping.h>
-#include <gtest/gtest.h>
#include <algorithm>
#include <chrono>
#include <iostream>
#include <numeric>
+#include <vector>
#include "1.0/Utils.h"
#include "1.2/Callbacks.h"
@@ -333,9 +334,9 @@
void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
bool testDynamicOutputShape) {
- std::initializer_list<OutputType> outputTypesList;
- std::initializer_list<MeasureTiming> measureTimingList;
- std::initializer_list<Executor> executorList;
+ std::vector<OutputType> outputTypesList;
+ std::vector<MeasureTiming> measureTimingList;
+ std::vector<Executor> executorList;
if (testDynamicOutputShape) {
outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal
index c04809f..7aea416 100644
--- a/neuralnetworks/1.3/IPreparedModel.hal
+++ b/neuralnetworks/1.3/IPreparedModel.hal
@@ -18,9 +18,11 @@
import @1.0::ErrorStatus;
import @1.0::Request;
-import @1.2::MeasureTiming;
import @1.2::IExecutionCallback;
import @1.2::IPreparedModel;
+import @1.2::MeasureTiming;
+import @1.2::OutputShape;
+import @1.2::Timing;
/**
* IPreparedModel describes a model that has been prepared for execution and
@@ -62,8 +64,8 @@
* values, the execution should complete successfully (ErrorStatus::NONE):
* There must be no failure unless the device itself is in a bad state.
*
- * Any number of calls to the execute, execute_1_2, execute_1_3, and executeSynchronously
- * functions, in any combination, may be made concurrently, even on the same
+ * Any number of calls to the execute* and executeSynchronously* functions,
+ * in any combination, may be made concurrently, even on the same
* IPreparedModel object.
*
* @param request The input and output information on which the prepared
@@ -87,4 +89,60 @@
*/
execute_1_3(Request request, MeasureTiming measure, IExecutionCallback callback)
generates (ErrorStatus status);
+
+ /**
+ * Performs a synchronous execution on a prepared model.
+ *
+ * The execution is performed synchronously with respect to the caller.
+ * executeSynchronously_1_3 must verify the inputs to the function are
+ * correct. If there is an error, executeSynchronously_1_3 must immediately
+ * return with the appropriate ErrorStatus value. If the inputs to the
+ * function are valid and there is no error, executeSynchronously_1_3 must
+ * perform the execution, and must not return until the execution is
+ * complete.
+ *
+ * The caller must not change the content of any data object referenced by
+ * 'request' (described by the {@link @1.0::DataLocation} of a
+ * {@link @1.0::RequestArgument}) until executeSynchronously_1_3
+ * returns. executeSynchronously_1_3 must not change the content of any of the
+ * data objects corresponding to 'request' inputs.
+ *
+ * If the prepared model was prepared from a model wherein all tensor
+ * operands have fully specified dimensions, and the inputs to the function
+ * are valid, and at execution time every operation's input operands have
+ * legal values, then the execution should complete successfully
+ * (ErrorStatus::NONE): There must be no failure unless the device itself is
+ * in a bad state.
+ *
+ * Any number of calls to the execute* and executeSynchronously* functions,
+ * in any combination, may be made concurrently, even on the same
+ * IPreparedModel object.
+ *
+ * @param request The input and output information on which the prepared
+ * model is to be executed.
+ * @param measure Specifies whether or not to measure duration of the execution.
+ * The duration runs from the time the driver sees the call
+ * to the executeSynchronously_1_3 function to the time the driver
+ * returns from the function.
+ * @return status Error status of the execution, must be:
+ * - NONE if execution is performed successfully
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is 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 is
+ * invalid
+ * @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.
+ * @return Timing Duration of execution. Unless measure is YES 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
+ * measurement is not available.
+ */
+ executeSynchronously_1_3(Request request, MeasureTiming measure)
+ generates (ErrorStatus status, vec<OutputShape> outputShapes, Timing timing);
};
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index 84c4813..b70bd1b 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -110,6 +110,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
* * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+ * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
*
* Supported tensor rank: up to 4
*
@@ -123,11 +124,13 @@
* * 2: An {@link OperandType::INT32} scalar, and has to be one of the
* {@link FusedActivationFunc} values. Specifies the activation to
* invoke on the result.
+ * For a {@link OperandType::TENSOR_INT32} tensor,
+ * the {@link FusedActivationFunc} must be "NONE".
*
* Outputs:
* * 0: The sum, a tensor of the same {@link OperandType} as input0.
* For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
- * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint can be different from inputs' scale and zeroPoint.
*/
ADD = @1.2::OperationType:ADD,
@@ -293,6 +296,18 @@
* * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
* * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
*
+ * Available since HAL version 1.3:
+ * * Quantized signed (since HAL version 1.3):
+ * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output.
+ * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+ * * * input.scale * filter.scale).
+ *
+ * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3):
+ * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output.
+ * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+ * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
+ * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+ *
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
* With the default data layout NHWC, the data is stored in the order of:
* [batch, height, width, channels]. Alternatively, the data layout could
@@ -313,8 +328,9 @@
* must be set to 0.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32}
- * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale.
* For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
@@ -363,7 +379,9 @@
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32}
* or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale.
* For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
@@ -443,6 +461,18 @@
* * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
* * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
*
+ * Available since HAL version 1.3:
+ * * Quantized signed (since HAL version 1.3):
+ * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output.
+ * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+ * * * input.scale * filter.scale).
+ *
+ * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3):
+ * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output.
+ * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+ * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
+ * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+ *
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
* With the default data layout NHWC, the data is stored in the order of:
* [batch, height, width, channels]. Alternatively, the data layout could
@@ -461,8 +491,9 @@
* must be set to 3.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32}
- * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale.
* For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
@@ -507,8 +538,9 @@
* specifying the filter.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32}
- * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * or {@link OperandType::TENSOR_FLOAT16} the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale.
* For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
@@ -569,6 +601,7 @@
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
* With the default data layout NHWC, the data is stored in the order of:
@@ -589,7 +622,8 @@
* Outputs:
* * 0: The output 4-D tensor, of shape [batch, height*block_size,
* width*block_size, depth/(block_size*block_size)].
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
DEPTH_TO_SPACE = @1.2::OperationType:DEPTH_TO_SPACE,
@@ -605,6 +639,7 @@
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
* * {@link OperandType::TENSOR_QUANT8_SYMM} (since HAL version 1.2)
* * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} (since HAL version 1.2)
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported output tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
@@ -642,9 +677,11 @@
* and an error must be reported.
*
* Supported value tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.3)
* * {@link OperandType::TENSOR_FLOAT32}
- * * {@link OperandType::TENSOR_INT32}
- * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_INT32} (since HAL version 1.2)
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported value tensor rank: from 2
*
@@ -658,7 +695,8 @@
* * 0: A n-D tensor with the same rank and shape as the Values
* tensor, except for the first dimension which has the same size
* as Lookups' only dimension.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input1.
*/
EMBEDDING_LOOKUP = @1.2::OperationType:EMBEDDING_LOOKUP,
@@ -693,6 +731,7 @@
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: up to 4.
*
@@ -710,10 +749,11 @@
* of output nodes.
* * 2: A 1-D tensor, of shape [num_units], specifying the bias. For input
* tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should
- * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor
- * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
- * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
- * bias_scale == input_scale * filter_scale.
+ * also be of {@link OperandType::TENSOR_FLOAT32}.
+ * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+ * the bias should be of {@link OperandType::TENSOR_INT32},
+ * with zeroPoint of 0 and bias_scale == input_scale * filter_scale.
* * 3: An {@link OperandType::INT32} scalar, and has to be one of the
* {@link FusedActivationFunc} values. Specifies the activation to
* invoke on the result.
@@ -798,6 +838,7 @@
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: up to 4
* Tensors with rank less than 4 are only supported since HAL version 1.2.
@@ -814,6 +855,8 @@
* * 0: A tensor of the same {@link OperandType} and same shape as input0.
* For {@link OperandType::TENSOR_QUANT8_ASYMM},
* the scale must be 1.f / 128 and the zeroPoint must be 128.
+ * For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+ * the scale must be 1.f / 128 and the zeroPoint must be 0.
*/
L2_NORMALIZATION = @1.2::OperationType:L2_NORMALIZATION,
@@ -1507,6 +1550,7 @@
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
* With the default data layout NHWC, the data is stored in the order of:
@@ -1549,7 +1593,8 @@
* Outputs:
* * 0: The output 4-D tensor, of shape
* [batches, new_height, new_width, depth].
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
RESIZE_BILINEAR = @1.2::OperationType:RESIZE_BILINEAR,
@@ -1624,6 +1669,7 @@
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: up to 4.
* Tensors with rank other than 2 or 4 are only supported since HAL version 1.2.
@@ -1632,9 +1678,10 @@
* * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped.
* Since HAL version 1.2, this tensor may be zero-sized.
* * 1: A scalar, specifying the positive scaling factor for the exponent,
- * beta. If input0 is of {@link OperandType::TENSOR_FLOAT32} or
- * {@link OperandType::TENSOR_QUANT8_ASYMM}, the scalar must be of
- * {@link OperandType::FLOAT32}.
+ * beta. If input0 is of {@link OperandType::TENSOR_FLOAT32},
+ * {@link OperandType::TENSOR_QUANT8_ASYMM} or
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, the scalar
+ * must be of {@link OperandType::FLOAT32}.
* If input0 is of {@link OperandType::TENSOR_FLOAT16}, then the
* scalar must be of {@link OperandType::FLOAT16}.
* * 2: An optional {@link OperandType::INT32} scalar, default to -1,
@@ -1647,6 +1694,8 @@
* * 0: The output tensor of same shape as input0.
* For {@link OperandType::TENSOR_QUANT8_ASYMM},
* the scale must be 1.f / 256 and the zeroPoint must be 0.
+ * For {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+ * the scale must be 1.f / 256 and the zeroPoint must be -128.
*/
SOFTMAX = @1.2::OperationType:SOFTMAX,
@@ -1668,6 +1717,7 @@
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
* With the default data layout NHWC, the data is stored in the order of:
@@ -1688,7 +1738,8 @@
* Outputs:
* * 0: The output 4-D tensor, of shape [batches, height/block_size,
* width/block_size, depth_in*block_size*block_size].
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
SPACE_TO_DEPTH = @1.2::OperationType:SPACE_TO_DEPTH,
@@ -1812,6 +1863,7 @@
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
* With the default data layout NHWC, the data is stored in the order of:
@@ -1830,7 +1882,8 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
BATCH_TO_SPACE_ND = @1.2::OperationType:BATCH_TO_SPACE_ND,
@@ -1925,6 +1978,7 @@
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
* (full support since HAL version 1.2, see the output section)
*
* Supported tensor rank: up to 4
@@ -1947,7 +2001,8 @@
* of the padding:
* output0.dimension[i] =
* padding[i, 0] + input0.dimension[i] + padding[i, 1]
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*
* NOTE: Before HAL version 1.2, the pad value for
@@ -1971,6 +2026,7 @@
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
* (full support since HAL version 1.2, see the output section)
*
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
@@ -1998,7 +2054,8 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*
* NOTE: Before HAL version 1.2, the pad value for
@@ -2151,6 +2208,7 @@
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: up to 4
*
@@ -2162,7 +2220,8 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
TRANSPOSE = @1.2::OperationType:TRANSPOSE,
@@ -2192,6 +2251,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -2216,6 +2276,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -2257,7 +2318,8 @@
* and height, dw and dh is the log-scale relative correction factor
* for the width and height. For input0 of type
* {@link OperandType::TENSOR_QUANT16_ASYMM}, this tensor should be
- * of {@link OperandType::TENSOR_QUANT8_ASYMM}. Zero num_rois is
+ * of {@link OperandType::TENSOR_QUANT8_ASYMM} or
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}. Zero num_rois is
* supported for this tensor.
* * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
* [num_rois], specifying the batch index of each box. Boxes with
@@ -2612,6 +2674,7 @@
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Inputs:
* * 0: A 2-D Tensor of shape [num_rois, num_classes], specifying the score
@@ -2623,7 +2686,11 @@
* order of the boxes corresponds with input0. For input0 of type
* {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of
* {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint of 0 and
- * scale of 0.125. Zero num_rois is supported for this tensor.
+ * scale of 0.125.
+ * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+ * this tensor should be of {@link OperandType::TENSOR_QUANT16_ASYMM},
+ * with zeroPoint of -128 and scale of 0.125.
+ * Zero num_rois is supported for this tensor.
* * 2: A 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
* [num_rois], specifying the batch index of each box. Boxes with
* the same batch index are grouped together.
@@ -2650,6 +2717,8 @@
* [num_output_rois], specifying the score of each output box. The boxes
* are grouped by batches, but the sequential order in each batch is not
* guaranteed. For type of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * guaranteed. For type of {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * or {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
* the scale and zero point must be the same as input0.
* * 1: A 2-D Tensor of the same {@link OperandType} as input1, with shape
* [num_output_rois, 4], specifying the coordinates of each
@@ -2667,7 +2736,7 @@
BOX_WITH_NMS_LIMIT = @1.2::OperationType:BOX_WITH_NMS_LIMIT,
/**
- * Casts a tensor to a new type.
+ * Casts a tensor to a type.
*
* This operation ignores the scale and zeroPoint of quanized tensors,
* e.g. it treats a {@link OperandType::TENSOR_QUANT8_ASYMM} input
@@ -2678,6 +2747,14 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * Since HAL version 1.3, casting tensors of the following
+ * {@link OperandType} to the same {@link OperandType} is supported:
+ * * {@link OperandType::TENSOR_BOOL8}
+ * * {@link OperandType::TENSOR_INT32}
+ * * {@link OperandType::TENSOR_QUANT16_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT16_SYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+ * * {@link OperandType::TENSOR_QUANT8_SYMM}
*
* Supported tensor rank: from 1
*
@@ -2708,6 +2785,7 @@
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: up to 4
*
@@ -2722,7 +2800,8 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} and same shape as input0.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
CHANNEL_SHUFFLE = @1.2::OperationType:CHANNEL_SHUFFLE,
@@ -2816,6 +2895,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -2861,6 +2941,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -2872,7 +2953,8 @@
* Outputs:
* * 0: An (n + 1)-D tensor with the same {@link OperandType} and data as
* input0.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
EXPAND_DIMS = @1.2::OperationType:EXPAND_DIMS,
@@ -2896,6 +2978,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -2910,7 +2993,8 @@
*
* Outputs:
* * 0: An (n + k - 1)-D tensor with the same {@link OperandType} as input0.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
GATHER = @1.2::OperationType:GATHER,
@@ -2931,6 +3015,7 @@
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Inputs:
* * 0: A 4-D Tensor specifying the score of each anchor at each
@@ -2948,11 +3033,13 @@
* dimensions is the channel dimension.
* * 2: A 2-D Tensor of shape [num_anchors, 4], specifying the shape of each
* predefined anchor, with format [x1, y1, x2, y2]. For input0 of type
- * {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should be of
+ * {@link OperandType::TENSOR_QUANT8_ASYMM} or
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, this tensor should be of
* {@link OperandType::TENSOR_QUANT16_SYMM}, with scale of 0.125.
* * 3: A 2-D Tensor of shape [batches, 2], specifying the size of
* each image in the batch, with format [image_height, image_width].
- * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM}, this
+ * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM} or
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, this
* tensor should be of {@link OperandType::TENSOR_QUANT16_SYMM}, with
* scale of 0.125.
* * 4: An {@link OperandType::FLOAT32} scalar, specifying the ratio
@@ -2979,7 +3066,8 @@
* [num_output_rois], specifying the score of each output box.
* The boxes are grouped by batches, but the sequential order in
* each batch is not guaranteed. For type of
- * {@link OperandType::TENSOR_QUANT8_ASYMM}, the scale and zero
+ * {@link OperandType::TENSOR_QUANT8_ASYMM} or
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, the scale and zero
* point must be the same as input0.
* * 1: A tensor of the same {@link OperandType} as input3, of shape
* [num_output_rois, 4], specifying the coordinates of each output
@@ -3002,6 +3090,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -3025,6 +3114,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -3081,12 +3171,23 @@
* * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
* * * input.scale * filter.scale).
*
+ * * Quantized signed (since HAL version 1.3):
+ * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output.
+ * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+ * * * input.scale * filter.scale).
+ *
* * Quantized with symmetric per channel quantization for the filter:
* * * {@link OperandType::TENSOR_QUANT8_ASYMM} for input, and output.
* * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
* * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
* * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
*
+ * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3):
+ * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output.
+ * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+ * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
+ * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+ *
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
* With the default data layout NHWC, the data is stored in the order of:
* [batch, height, width, channels]. Alternatively, the data layout could
@@ -3105,8 +3206,9 @@
* {@link SymmPerChannelQuantParams}) must be set to 0.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32} or
- * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale. For filter tensor
* of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
@@ -3145,7 +3247,9 @@
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32} or
* {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same
- * type. For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
* the bias should be of {@link OperandType::TENSOR_INT32}, with zeroPoint
* of 0 and bias_scale == input_scale * filter_scale. For filter tensor
* of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
@@ -3170,7 +3274,8 @@
* Outputs:
* * 0: The output 4-D tensor, of shape
* [batches, out_height, out_width, depth_out].
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint can be different from inputs' scale and zeroPoint.
*/
GROUPED_CONV_2D = @1.2::OperationType:GROUPED_CONV_2D,
@@ -3190,6 +3295,7 @@
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
* With the default data layout NHWC, the data is stored in the order of:
@@ -3206,13 +3312,18 @@
* {@link OperandType::TENSOR_QUANT8_ASYMM}, this tensor should
* be of {@link OperandType::TENSOR_QUANT16_ASYMM}, with zeroPoint
* of 0 and scale of 0.125.
+ * For input0 of type
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}, this tensor
+ * should be of {@link OperandType::TENSOR_QUANT16_ASYMM}, with
+ * zeroPoint of -128 and scale of 0.125.
* * 2: An {@link OperandType::BOOL} scalar, set to true to specify
* NCHW data layout for input0. Set to false for NHWC.
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0, with shape
* [num_boxes, num_keypoints], specifying score of the keypoints.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} or
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint can be different from input0 scale and zeroPoint.
* * 1: A tensor of the same {@link OperandType} as input1, with shape
* [num_boxes, num_keypoints, 2], specifying the location of
@@ -3283,6 +3394,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -3307,6 +3419,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -3434,6 +3547,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1.
*
@@ -3446,7 +3560,8 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
* the scale and zeroPoint can be different from inputs' scale and zeroPoint.
*/
MAXIMUM = @1.2::OperationType:MAXIMUM,
@@ -3459,6 +3574,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1.
*
@@ -3471,7 +3587,8 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
* the scale and zeroPoint can be different from inputs' scale and zeroPoint.
*/
MINIMUM = @1.2::OperationType:MINIMUM,
@@ -3503,6 +3620,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -3526,6 +3644,7 @@
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: up to 4
*
@@ -3543,7 +3662,8 @@
* pad value must be of {@link OperandType::FLOAT16}.
* For input tensor of {@link OperandType::TENSOR_FLOAT32}, the
* pad value must be of {@link OperandType::FLOAT32}.
- * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
* the pad value must be of {@link OperandType::INT32}. The
* scale and zeroPoint are assumed to be the same as in input0.
*
@@ -3555,7 +3675,8 @@
* of the padding:
* output0.dimension[i] =
* padding[i, 0] + input0.dimension[i] + padding[i, 1]
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
PAD_V2 = @1.2::OperationType:PAD_V2,
@@ -3614,6 +3735,7 @@
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -3624,22 +3746,32 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
- * the scale and zeroPoint can be diffent from the input0 scale and zeroPoint.
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scales and zeroPoint can be different from input0 scale and zeroPoint.
*/
PRELU = @1.2::OperationType:PRELU,
/**
* Quantizes the input tensor.
*
- * The formula is:
+ * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM} output tensor is:
*
* output = max(0, min(255, round(input / scale) + zeroPoint)
*
- * Supported tensor {@link OperandType}:
+ * The formula for {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} output
+ * tensor is:
+ *
+ * output = max(-128, min(127, round(input / scale) + zeroPoint)
+ *
+ * Supported input tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
*
+ * Supported output tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+ *
* Supported tensor rank: from 1
*
* Inputs:
@@ -3647,7 +3779,8 @@
*
* Outputs:
* * 0: The output tensor of same shape as input0, but with
- * {@link OperandType::TENSOR_QUANT8_ASYMM}.
+ * {@link OperandType::TENSOR_QUANT8_ASYMM} or.
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}.
*/
QUANTIZE = @1.2::OperationType:QUANTIZE,
@@ -3955,6 +4088,7 @@
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
* With the default data layout NHWC, the data is stored in the order of:
@@ -3993,7 +4127,8 @@
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0. The output
* shape is [num_rois, out_height, out_width, depth].
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint can be different from the input0 scale and zeroPoint.
*/
ROI_ALIGN = @1.2::OperationType:ROI_ALIGN,
@@ -4014,6 +4149,7 @@
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
* With the default data layout NHWC, the data is stored in the order of:
@@ -4024,7 +4160,8 @@
* * 0: A 4-D tensor, specifying the feature map.
* * 1: A 2-D Tensor of shape [num_rois, 4], specifying the locations of
* the regions of interest, each line with format [x1, y1, x2, y2].
- * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* this tensor should be of {@link OperandType::TENSOR_QUANT16_ASYMM},
* with zeroPoint of 0 and scale of 0.125.
* * 2: An 1-D {@link OperandType::TENSOR_INT32} tensor, of shape
@@ -4044,7 +4181,8 @@
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0. The output
* shape is [num_rois, out_height, out_width, depth].
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For input0 of type {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
ROI_POOLING = @1.2::OperationType:ROI_POOLING,
@@ -4133,6 +4271,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -4145,7 +4284,8 @@
*
* Outputs:
* * 0: An n-D tensor of the same type as the input containing the slice.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* its scale and zeroPoint has to be same as the input0 scale and zeroPoint.
*/
SLICE = @1.2::OperationType:SLICE,
@@ -4158,6 +4298,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -4170,7 +4311,8 @@
*
* Outputs:
* * 0 ~ (num_splits - 1): Resulting subtensors.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
SPLIT = @1.2::OperationType:SPLIT,
@@ -4206,6 +4348,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -4216,7 +4359,8 @@
*
* Outputs:
* * 0: A tiled tensor of the same {@link OperandType} and rank as `input`.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
TILE = @1.2::OperationType:TILE,
@@ -4232,6 +4376,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: from 1
*
@@ -4243,7 +4388,8 @@
* Outputs:
* * 0: An n-D tensor of the same type as the input, containing the k
* largest elements along each last dimensional slice.
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
* * 1: An n-D tensor of type {@link OperandType::TENSOR_INT32}
* containing the indices of values within the last dimension of input.
@@ -4278,6 +4424,18 @@
* * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
* * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
*
+ * Available since HAL version 1.3:
+ * * Quantized signed (since HAL version 1.3):
+ * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output.
+ * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
+ * * * input.scale * filter.scale).
+ *
+ * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3):
+ * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output.
+ * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+ * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
+ * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+ *
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
* With the default data layout NHWC, the data is stored in the order of:
* [batch, height, width, channels]. Alternatively, the data layout could
@@ -4295,15 +4453,16 @@
* dimension (SymmPerChannelQuantParams::channelDim) must be set to 0.
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32} or
- * {@link OperandType::TENSOR_FLOAT16}, the bias should be of the
- * same type. For input tensor of type
- * {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
- * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
- * bias_scale == input_scale * filter_scale. For filter tensor of
- * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
- * must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
- * 0 and bias_scale of 0. The actual scale of each value 'i' is equal
- * to bias_scale[i] = input_scale * filter_scale[i].
+ * {@link OperandType::TENSOR_FLOAT16}, the bias must be of the
+ * same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+ * the bias should be of {@link OperandType::TENSOR_INT32},
+ * with zeroPoint of 0 and bias_scale == input_scale * filter_scale.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+ * the bias must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+ * and bias_scale of 0. The actual scale of each value 'i' is equal to
+ * bias_scale[i] = input_scale * filter_scale[i].
* * 3: An {@link OperandType::INT32} scalar, specifying the padding on
* the left, in the ‘width’ dimension.
* * 4: An {@link OperandType::INT32} scalar, specifying the padding on
@@ -4333,14 +4492,15 @@
* * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
* tensor of type {@link OperandType::TENSOR_FLOAT32} or
* {@link OperandType::TENSOR_FLOAT16}, the bias should be of the
- * same type. For input tensor of type
- * {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
- * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
- * bias_scale == input_scale * filter_scale. For filter tensor of
- * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
- * must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
- * 0 and bias_scale of 0. The actual scale of each value 'i' is equal
- * to bias_scale[i] = input_scale * filter_scale[i].
+ * same type.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+ * the bias should be of {@link OperandType::TENSOR_INT32},
+ * with zeroPoint of 0 and bias_scale == input_scale * filter_scale.
+ * For filter tensor of {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL},
+ * the bias must be of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0
+ * and bias_scale of 0. The actual scale of each value 'i' is equal to
+ * bias_scale[i] = input_scale * filter_scale[i].
* * 3: An {@link OperandType::TENSOR_INT32} tensor, specifying the output
* tensor shape.
* * 4: An {@link OperandType::INT32} scalar, specifying the implicit
@@ -4359,7 +4519,8 @@
* Outputs:
* * 0: The output 4-D tensor, of shape
* [batches, out_height, out_width, depth_out].
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint can be different from inputs' scale and zeroPoint.
*/
TRANSPOSE_CONV_2D = @1.2::OperationType:TRANSPOSE_CONV_2D,
@@ -4539,6 +4700,7 @@
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
*
* Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
* With the default data layout NHWC, the data is stored in the order of:
@@ -4578,7 +4740,8 @@
* Outputs:
* * 0: The output 4-D tensor, of shape
* [batches, new_height, new_width, depth].
- * For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+ * For a {@link OperandType::TENSOR_QUANT8_ASYMM} and
+ * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
* the scale and zeroPoint must be the same as input0.
*/
RESIZE_NEAREST_NEIGHBOR = @1.2::OperationType:RESIZE_NEAREST_NEIGHBOR,
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 3e947f5..e3c5376 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -34,13 +34,14 @@
#include <android/hardware/neuralnetworks/1.3/types.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
+#include <gtest/gtest.h>
#include <hidlmemory/mapping.h>
-#include <gtest/gtest.h>
#include <algorithm>
#include <chrono>
#include <iostream>
#include <numeric>
+#include <vector>
#include "1.0/Utils.h"
#include "1.2/Callbacks.h"
@@ -214,7 +215,7 @@
hidl_vec<OutputShape>* outputShapes,
Timing* timing) {
ErrorStatus result;
- Return<void> ret = preparedModel->executeSynchronously(
+ Return<void> ret = preparedModel->executeSynchronously_1_3(
request, measure,
[&result, outputShapes, timing](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
const Timing& time) {
@@ -368,9 +369,9 @@
void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
TestKind testKind) {
- std::initializer_list<OutputType> outputTypesList;
- std::initializer_list<MeasureTiming> measureTimingList;
- std::initializer_list<Executor> executorList;
+ std::vector<OutputType> outputTypesList;
+ std::vector<MeasureTiming> measureTimingList;
+ std::vector<Executor> executorList;
switch (testKind) {
case TestKind::GENERAL: {
@@ -403,11 +404,9 @@
const TestModel& testModel,
const sp<IPreparedModel>& preparedCoupledModel,
const TestModel& coupledModel) {
- std::initializer_list<OutputType> outputTypesList = {OutputType::FULLY_SPECIFIED};
- std::initializer_list<MeasureTiming> measureTimingList = {MeasureTiming::NO,
- MeasureTiming::YES};
- std::initializer_list<Executor> executorList = {Executor::ASYNC, Executor::SYNC,
- Executor::BURST};
+ const std::vector<OutputType> outputTypesList = {OutputType::FULLY_SPECIFIED};
+ const std::vector<MeasureTiming> measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+ const std::vector<Executor> executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
for (const OutputType outputType : outputTypesList) {
for (const MeasureTiming measureTiming : measureTimingList) {
@@ -453,7 +452,7 @@
EvaluatePreparedModel(preparedModel, testModel, TestKind::DYNAMIC_SHAPE);
} break;
case TestKind::QUANTIZATION_COUPLING: {
- ASSERT_TRUE(testModel.hasQuant8AsymmOperands());
+ ASSERT_TRUE(testModel.hasQuant8CoupledOperands());
createPreparedModel(device, model, &preparedModel, /*reportSkipping*/ false);
TestModel signedQuantizedModel = convertQuant8AsymmOperandsToSigned(testModel);
sp<IPreparedModel> preparedCoupledModel;
@@ -522,7 +521,7 @@
[](const TestModel& testModel) { return !testModel.expectFailure; });
INSTANTIATE_GENERATED_TEST(DISABLED_QuantizationCouplingTest, [](const TestModel& testModel) {
- return testModel.hasQuant8AsymmOperands() && testModel.operations.size() == 1;
+ return testModel.hasQuant8CoupledOperands() && testModel.operations.size() == 1;
});
} // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 242e12e..14ab897 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -323,13 +323,15 @@
// - CAST's argument can be any of TENSOR_(FLOAT16|FLOAT32|INT32|QUANT8_ASYMM).
// - RANDOM_MULTINOMIAL's argument can be either TENSOR_FLOAT16 or TENSOR_FLOAT32.
// - DEQUANTIZE input can be any of
- // TENSOR_(QUANT8_ASYMM|QUANT8_SYMM|QUANT8_SYMM_PER_CHANNEL), output can
- // be of either TENSOR_FLOAT16 or TENSOR_FLOAT32.
+ // TENSOR_(QUANT8_ASYMM|QUANT8_ASYMM_SIGNED|QUANT8_SYMM|QUANT8_SYMM_PER_CHANNEL),
+ // output can be of either TENSOR_FLOAT16 or TENSOR_FLOAT32.
// - QUANTIZE input can be either TENSOR_FLOAT16 or TENSOR_FLOAT32
// - CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
// - DEPTHWISE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
// - GROUPED_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
// - TRANSPOSE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
+ // - AXIS_ALIGNED_BBOX_TRANSFORM bounding boxes (arg 1) can be of
+ // TENSOR_QUANT8_ASYMM or TENSOR_QUANT8_ASYMM_SIGNED.
switch (operation.type) {
case OperationType::LSH_PROJECTION: {
if (operand == operation.inputs[1]) {
@@ -340,7 +342,8 @@
case OperationType::ARGMAX:
case OperationType::ARGMIN: {
if (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32 ||
- type == OperandType::TENSOR_INT32 || type == OperandType::TENSOR_QUANT8_ASYMM) {
+ type == OperandType::TENSOR_INT32 || type == OperandType::TENSOR_QUANT8_ASYMM ||
+ type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) {
return true;
}
} break;
@@ -364,6 +367,7 @@
case OperationType::DEQUANTIZE: {
if (operand == operation.inputs[0] &&
(type == OperandType::TENSOR_QUANT8_ASYMM ||
+ type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED ||
type == OperandType::TENSOR_QUANT8_SYMM ||
type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL)) {
return true;
@@ -383,6 +387,13 @@
return true;
}
} break;
+ case OperationType::AXIS_ALIGNED_BBOX_TRANSFORM: {
+ if (operand == operation.inputs[1] &&
+ (type == OperandType::TENSOR_QUANT8_ASYMM ||
+ type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED)) {
+ return true;
+ }
+ } break;
default:
break;
}
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index 2cf30d5..8092d04 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -79,9 +79,9 @@
// synchronous
{
- SCOPED_TRACE(message + " [executeSynchronously]");
+ SCOPED_TRACE(message + " [executeSynchronously_1_3]");
- Return<void> executeStatus = preparedModel->executeSynchronously(
+ Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
request, measure,
[](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes,
const Timing& timing) {
@@ -158,8 +158,8 @@
}
void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request) {
- SCOPED_TRACE("Expecting request to fail [executeSynchronously]");
- Return<void> executeStatus = preparedModel->executeSynchronously(
+ SCOPED_TRACE("Expecting request to fail [executeSynchronously_1_3]");
+ Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
request, MeasureTiming::NO,
[](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
ASSERT_NE(ErrorStatus::NONE, error);
diff --git a/oemlock/1.0/vts/functional/Android.bp b/oemlock/1.0/vts/functional/Android.bp
index 28d6bf6..90de347 100644
--- a/oemlock/1.0/vts/functional/Android.bp
+++ b/oemlock/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalOemLockV1_0TargetTest.cpp"],
static_libs: ["android.hardware.oemlock@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/oemlock/1.0/vts/functional/VtsHalOemLockV1_0TargetTest.cpp b/oemlock/1.0/vts/functional/VtsHalOemLockV1_0TargetTest.cpp
index 05462a8..bafe87d 100644
--- a/oemlock/1.0/vts/functional/VtsHalOemLockV1_0TargetTest.cpp
+++ b/oemlock/1.0/vts/functional/VtsHalOemLockV1_0TargetTest.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
#include <android/hardware/oemlock/1.0/IOemLock.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
using ::android::hardware::oemlock::V1_0::IOemLock;
using ::android::hardware::oemlock::V1_0::OemLockStatus;
@@ -25,22 +25,9 @@
using ::android::hardware::hidl_vec;
using ::android::sp;
-// Test environment for OemLock HIDL HAL.
-class OemLockHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static OemLockHidlEnvironment* Instance() {
- static OemLockHidlEnvironment* instance = new OemLockHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IOemLock>(); }
-};
-
-struct OemLockHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+struct OemLockHidlTest : public ::testing::TestWithParam<std::string> {
virtual void SetUp() override {
- oemlock = ::testing::VtsHalHidlTargetTestBase::getService<IOemLock>(
- OemLockHidlEnvironment::Instance()->getServiceName<IOemLock>());
+ oemlock = IOemLock::getService(GetParam());
ASSERT_NE(oemlock, nullptr);
}
@@ -52,7 +39,7 @@
/*
* Check the name can be retrieved
*/
-TEST_F(OemLockHidlTest, GetName) {
+TEST_P(OemLockHidlTest, GetName) {
std::string name;
OemLockStatus status;
@@ -72,7 +59,7 @@
/*
* Check the unlock allowed by device state can be queried
*/
-TEST_F(OemLockHidlTest, QueryUnlockAllowedByDevice) {
+TEST_P(OemLockHidlTest, QueryUnlockAllowedByDevice) {
bool allowed;
OemLockStatus status;
@@ -92,7 +79,7 @@
/*
* Check unlock allowed by device state can be toggled
*/
-TEST_F(OemLockHidlTest, AllowedByDeviceCanBeToggled) {
+TEST_P(OemLockHidlTest, AllowedByDeviceCanBeToggled) {
bool allowed;
OemLockStatus status;
@@ -129,7 +116,7 @@
/*
* Check the unlock allowed by device state can be queried
*/
-TEST_F(OemLockHidlTest, QueryUnlockAllowedByCarrier) {
+TEST_P(OemLockHidlTest, QueryUnlockAllowedByCarrier) {
bool allowed;
OemLockStatus status;
@@ -153,7 +140,7 @@
* is a valid implementation so the test will pass. If there is no signature
* required, the test will toggle the value.
*/
-TEST_F(OemLockHidlTest, CarrierUnlock) {
+TEST_P(OemLockHidlTest, CarrierUnlock) {
const hidl_vec<uint8_t> noSignature = {};
bool allowed;
OemLockStatus status;
@@ -201,11 +188,7 @@
ASSERT_EQ(allowed, originallyAllowed);
};
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(OemLockHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- OemLockHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, OemLockHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IOemLock::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
index 6d422be..fafc6e2 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -16,8 +16,12 @@
package android.hardware.radio@1.5;
+import @1.2::DataRequestReason;
import @1.4::IRadio;
+import @1.4::DataProfileInfo;
import @1.5::AccessNetwork;
+import @1.5::DataProfileInfo;
+import @1.5::LinkAddress;
import @1.5::NetworkScanRequest;
import @1.5::RadioAccessSpecifier;
import @1.5::SignalThresholdInfo;
@@ -42,16 +46,20 @@
* -EUTRAN - RSRP/RSRQ/RSSNR
* -NGRAN - SSRSRP/SSRSRQ/SSSINR
*
- * Note: Reporting criteria must be individually set for each RAN. For any unset reporting
- * criteria, the value is implementation-defined.
+ * Note: Reporting criteria must be individually set for each RAN. For each RAN, if none of
+ * reporting criteria of any measurement is set enabled
+ * (see @1.5::SignalThresholdInfo.isEnabled), the reporting criteria for this RAN is
+ * implementation-defined. For each RAN, if any of reporting criteria of any measure is set
+ * enabled, the reporting criteria of the other measures in this RAN are set disabled
+ * (see @1.5::SignalThresholdInfo.isEnabled) until they are set enabled.
*
* Response callback is
* IRadioResponse.setSignalStrengthReportingCriteriaResponse_1_5()
*
* @param serial Serial number of request.
* @param signalThresholdInfo Signal threshold info including the threshold values,
- * hysteresisDb, and hysteresisMs. See @1.5::SignalThresholdInfo
- * for details.
+ * hysteresisDb, hysteresisMs and isEnabled.
+ * See @1.5::SignalThresholdInfo for details.
* @param accessNetwork The type of network for which to apply these thresholds.
*/
oneway setSignalStrengthReportingCriteria_1_5(int32_t serial,
@@ -68,8 +76,8 @@
* The preference is per SIM, and must be remembered over power cycle, modem reboot, or SIM
* insertion / unplug.
*
- * @param serial: Serial number of request.
- * @param enable: true if to enable uiccApplications, false to disable.
+ * @param serial Serial number of request.
+ * @param enable true if to enable uiccApplications, false to disable.
* Response callback is IRadioResponse.enableUiccApplicationsResponse()
*/
@@ -88,17 +96,6 @@
oneway areUiccApplicationsEnabled(int32_t serial);
/**
- * Query whether disabling and enabling UiccApplications functionality is supported. If not,
- * calling enableUiccApplications with a different value will return
- * RadioError:REQUEST_NOT_SUPPORTED.
- *
- * @param serial Serial number of request.
- *
- * Response callback is IRadioResponse.canToggleUiccApplicationsEnablementResponse()
- */
- oneway canToggleUiccApplicationsEnablement(int32_t serial);
-
- /**
* Specify which bands modem's background scan must act on.
* If specifyChannels is true, it only scans bands specified in specifiers.
* If specifyChannels is false, it scans all bands.
@@ -125,4 +122,101 @@
* 1.5 version of NetworkScanRequest
*/
oneway startNetworkScan_1_5(int32_t serial, NetworkScanRequest request);
+
+ /**
+ * Setup a packet data connection. If DataCallResponse.status returns DataCallFailCause:NONE,
+ * the data connection must be added to data calls and a unsolDataCallListChanged() must be
+ * sent. The call remains until removed by subsequent unsolDataCallIstChanged(). It may be
+ * lost due to many factors, including deactivateDataCall() being issued, the radio powered
+ * off, reception lost or even transient factors like congestion. This data call list is
+ * returned by getDataCallList() and dataCallListChanged().
+ *
+ * The Radio is expected to:
+ * - Create one data call context.
+ * - Create and configure a dedicated interface for the context.
+ * - The interface must be point to point.
+ * - The interface is configured with one or more addresses and is capable of sending and
+ * receiving packets. The prefix length of the addresses must be /32 for IPv4 and /128
+ * for IPv6.
+ * - Must not modify routing configuration related to this interface; routing management is
+ * exclusively within the purview of the Android OS.
+ * - Support simultaneous data call contexts up to DataRegStateResult.maxDataCalls specified
+ * in the response of getDataRegistrationState.
+ *
+ * @param serial Serial number of request.
+ * @param accessNetwork The access network to setup the data call. If the data connection cannot
+ * be established on the specified access network, the setup request must be failed.
+ * @param dataProfileInfo Data profile info.
+ * @param roamingAllowed Indicates whether or not data roaming is allowed by the user.
+ * @param reason The request reason. Must be DataRequestReason.NORMAL or
+ * DataRequestReason.HANDOVER.
+ * @param addresses If the reason is DataRequestReason.HANDOVER, this indicates the list of link
+ * addresses of the existing data connection. This parameter must be ignored unless reason
+ * is DataRequestReason.HANDOVER.
+ * @param dnses If the reason is DataRequestReason.HANDOVER, this indicates the list of DNS
+ * addresses of the existing data connection. The format is defined in RFC-4291 section
+ * 2.2. For example, "192.0.1.3" or "2001:db8::1". This parameter must be ignored unless
+ * reason is DataRequestReason.HANDOVER.
+ *
+ * Response function is IRadioResponse.setupDataCallResponse_1_5()
+ *
+ * Note this API is the same as the 1.4 version except using the
+ * 1.5 AccessNetwork, DataProfileInto, and link addresses as the input param.
+ */
+ oneway setupDataCall_1_5(int32_t serial, AccessNetwork accessNetwork,
+ DataProfileInfo dataProfileInfo, bool roamingAllowed,
+ DataRequestReason reason, vec<LinkAddress> addresses, vec<string> dnses);
+
+ /**
+ * Set an apn to initial attach network
+ *
+ * @param serial Serial number of request.
+ * @param dataProfileInfo data profile containing APN settings
+ *
+ * Response callback is IRadioResponse.setInitialAttachApnResponse_1_5()
+ *
+ * Note this API is the same as the 1.4 version except using the 1.5 DataProfileInfo
+ * as the input param.
+ */
+ oneway setInitialAttachApn_1_5(int32_t serial, DataProfileInfo dataProfileInfo);
+
+ /**
+ * Send data profiles of the current carrier to the modem.
+ *
+ * @param serial Serial number of request.
+ * @param profiles Array of DataProfile to set.
+ *
+ * Response callback is IRadioResponse.setDataProfileResponse_1_5()
+ *
+ * Note this API is the same as the 1.4 version except using the 1.5 DataProfileInfo
+ * as the input param.
+ */
+ oneway setDataProfile_1_5(int32_t serial, vec<DataProfileInfo> profiles);
+
+ /**
+ * Toggle radio on and off (for "airplane" mode)
+ * If the radio is turned off/on the radio modem subsystem
+ * is expected return to an initialized state. For instance,
+ * any voice and data calls must be terminated and all associated
+ * lists emptied.
+ *
+ * When setting radio power on to exit from airplane mode to place an emergency call on this
+ * logical modem, powerOn, forEmergencyCall and preferredForEmergencyCall must be true. In
+ * this case, this modem is optimized to scan only emergency call bands, until:
+ * 1) Emergency call is completed; or
+ * 2) Another setRadioPower_1_5 is issued with forEmergencyCall being false or
+ * preferredForEmergencyCall being false; or
+ * 3) Timeout after a long period of time.
+ *
+ * @param serial Serial number of request.
+ * @param powerOn To turn on radio -> on = true, to turn off radio -> on = false.
+ * @param forEmergencyCall To indication to radio if this request is due to emergency call.
+ * No effect if powerOn is false.
+ * @param preferredForEmergencyCall indicate whether the following emergency call will be sent
+ * on this modem or not. No effect if forEmergencyCall is false, or powerOn is false.
+ *
+ * Response callback is IRadioConfigResponse. setRadioPowerResponse_1_5.
+ */
+ oneway setRadioPower_1_5(int32_t serial, bool powerOn, bool forEmergencyCall,
+ bool preferredForEmergencyCall);
};
diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal
index 81452ab..879e9ad 100644
--- a/radio/1.5/IRadioIndication.hal
+++ b/radio/1.5/IRadioIndication.hal
@@ -30,4 +30,33 @@
* @param enabled whether uiccApplications are enabled, or disabled
*/
oneway uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled);
+
+ /**
+ * Report that Registration or a Location/Routing/Tracking Area update has failed.
+ *
+ * <p>Indicate whenever a registration procedure, including a location, routing, or tracking
+ * area update fails. This includes procedures that do not necessarily result in a change of
+ * the modem's registration status. If the modem's registration status changes, that is
+ * reflected in the onNetworkStateChanged() and subsequent get{Voice/Data}RegistrationState().
+ *
+ * @param cellIdentity the CellIdentity, which must include the globally unique identifier for
+ * the cell (for example, all components of the CGI or ECGI).
+ * @param chosenPlmn a 5 or 6 digit alphanumeric PLMN (MCC|MNC) among those broadcast by the
+ * cell that was chosen for the failed registration attempt.
+ * @param domain Domain::CS, Domain::PS, or both in case of a combined procedure.
+ * @param causeCode the primary failure cause code of the procedure.
+ * For GSM/UMTS (MM), values are in TS 24.008 Sec 10.5.95
+ * For GSM/UMTS (GMM), values are in TS 24.008 Sec 10.5.147
+ * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9
+ * For NR (5GMM), cause codes are TS 24.501 Sec 9.11.3.2
+ * MAX_INT if this value is unused.
+ * @param additionalCauseCode the cause code of any secondary/combined procedure if appropriate.
+ * For UMTS, if a combined attach succeeds for PS only, then the GMM cause code shall be
+ * included as an additionalCauseCode.
+ * For LTE (ESM), cause codes are in TS 24.301 9.9.4.4
+ * MAX_INT if this value is unused.
+ */
+ oneway registrationFailed(
+ RadioIndicationType type, CellIdentity cellIdentity, string chosenPlmn,
+ bitfield<Domain> domain, int32_t causeCode, int32_t additionalCauseCode);
};
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index e7a3852..968948b 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -18,6 +18,7 @@
import @1.0::RadioResponseInfo;
import @1.4::IRadioResponse;
+import @1.5::SetupDataCallResult;
/**
* Interface declaring response functions to solicited radio requests.
@@ -42,7 +43,6 @@
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
* RadioError:BUSY
- * RadioError:REQUEST_NOT_SUPPORTED
*/
oneway enableUiccApplicationsResponse(RadioResponseInfo info);
@@ -55,23 +55,11 @@
* RadioError:SIM_ABSENT
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
*/
oneway areUiccApplicationsEnabledResponse(RadioResponseInfo info, bool enabled);
/**
* @param info Response info struct containing response type, serial no. and error
- * @param canToggle whether toggling UiccApplications functionality is supported.
- *
- * Valid errors returned:
- * RadioError:NONE
- * RadioError:RADIO_NOT_AVAILABLE
- * RadioError:INTERNAL_ERR
- */
- oneway canToggleUiccApplicationsEnablementResponse(RadioResponseInfo info, bool canToggle);
-
- /**
- * @param info Response info struct containing response type, serial no. and error
*
* Valid errors returned:
* RadioError:NONE
@@ -93,4 +81,68 @@
* RadioError:INVALID_ARGUMENTS
*/
oneway startNetworkScanResponse_1_5(RadioResponseInfo info);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param dcResponse SetupDataCallResult defined in types.hal
+ *
+ * Valid errors returned:
+ * RadioError:NONE must be returned on both success and failure of setup with the
+ * DataCallResponse.status containing the actual status
+ * For all other errors the DataCallResponse is ignored.
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:OP_NOT_ALLOWED_BEFORE_REG_TO_NW
+ * RadioError:OP_NOT_ALLOWED_DURING_VOICE_CALL
+ * RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:INVALID_ARGUMENTS
+ * RadioError:INTERNAL_ERR
+ * RadioError:NO_RESOURCES
+ * RadioError:SIM_ABSENT
+ */
+ oneway setupDataCallResponse_1_5(RadioResponseInfo info, SetupDataCallResult dcResponse);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:SUBSCRIPTION_NOT_AVAILABLE
+ * RadioError:NO_MEMORY
+ * RadioError:INTERNAL_ERR
+ * RadioError:SYSTEM_ERR
+ * RadioError:MODEM_ERR
+ * RadioError:INVALID_ARGUMENTS
+ * RadioError:NOT_PROVISIONED
+ * RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:NO_RESOURCES
+ * RadioError:CANCELLED
+ */
+ oneway setInitialAttachApnResponse_1_5(RadioResponseInfo info);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:SUBSCRIPTION_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ * RadioError:NO_MEMORY
+ * RadioError:NO_RESOURCES
+ * RadioError:CANCELLED
+ * RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:SIM_ABSENT
+ */
+ oneway setDataProfileResponse_1_5(RadioResponseInfo info);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:INTERNAL_ERR
+ * RadioError:INVALID_ARGUMENTS
+ */
+ oneway setRadioPowerResponse_1_5(RadioResponseInfo info);
};
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index 664ddc4..7d6ec41 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -22,8 +22,21 @@
import @1.1::RadioAccessSpecifier;
import @1.1::ScanType;
import @1.1::UtranBands;
+import @1.2::CellIdentityCdma;
+import @1.2::CellIdentityGsm;
+import @1.2::CellIdentityWcdma;
+import @1.2::CellIdentityTdscdma;
+import @1.2::CellIdentityLte;
import @1.2::NetworkScanRequest;
import @1.4::AccessNetwork;
+import @1.4::ApnTypes;
+import @1.4::CellIdentityNr;
+import @1.4::DataCallFailCause;
+import @1.4::DataConnActiveStatus;
+import @1.4::DataProfileInfo;
+import @1.4::PdpProtocolType;
+
+import android.hidl.safe_union@1.0::Monostate;
/**
* Defining signal strength type.
@@ -52,9 +65,9 @@
RSRP = 3,
/**
* Reference Signal Received Quality
- * Range: -20 dB to -3 dB;
+ * Range: -34 dB to 3 dB;
* Used RAN: EUTRAN
- * Reference: 3GPP TS 36.133 9.1.7
+ * Reference: 3GPP TS 36.133 v12.6.0 section 9.1.7
*/
RSRQ = 4,
/**
@@ -113,6 +126,15 @@
* A vector size of 0 disables the use of thresholds for reporting.
*/
vec<int32_t> thresholds;
+
+ /**
+ * Indicates whether the reporting criteria of the corresponding measurement is enabled
+ * (isEnabled==true) or disabled (isEnabled==false).
+ *
+ * If enabled, modem must trigger the report based on the criteria.
+ * If disabled, modem must not trigger the report based on the criteria.
+ */
+ bool isEnabled;
};
enum AccessNetwork : @1.4::AccessNetwork {
@@ -259,3 +281,146 @@
*/
vec<string> mccMncs;
};
+
+enum ApnTypes : @1.4::ApnTypes {
+ /**
+ * APN type for XCAP
+ * NOTE: Due to the addition of this new value, the value ALL defined in
+ * 1.0::ApnTypes is deprecated and should not be used.
+ */
+ XCAP = 1 << 11,
+};
+
+/**
+ * Extended from @1.4::DataProfileInfo to update ApnTypes to 1.5 version
+ */
+struct DataProfileInfo {
+ @1.4::DataProfileInfo base;
+
+ /** Supported APN types bitmap. See ApnTypes for the value of each bit. */
+ bitfield<ApnTypes> supportedApnTypesBitmap;
+};
+
+/**
+ * The properties of the link address. This enum reflects the definition in
+ * if_addr.h in Linux kernel.
+ */
+enum AddressProperty : int32_t {
+ NONE = 0,
+
+ /** Indicates this address is deprecated */
+ DEPRECATED = 0x20,
+};
+
+/**
+ * Describes a data link address for mobile data connection.
+ */
+struct LinkAddress {
+ /**
+ * The format is IP address with optional "/"
+ * prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3",
+ * "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If
+ * the prefix length is absent, then the addresses are assumed to be point to point with
+ * IPv4 with prefix length 32 or IPv6 with prefix length 128.
+ */
+ string address;
+
+ /**
+ * The properties of the link address
+ */
+ bitfield<AddressProperty> properties;
+
+ /**
+ * The UTC time that this link address will be deprecated. 0 indicates this information is not
+ * available.
+ */
+ uint64_t deprecatedTime;
+
+ /**
+ * The UTC time that this link address will expire and no longer valid. 0 indicates this
+ * information is not available.
+ */
+ uint64_t expiredTime;
+};
+
+/**
+ * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5
+ * version. In 1.5 the type of addresses changes to vector of LinkAddress.
+ */
+struct SetupDataCallResult {
+ /** Data call fail cause. DataCallFailCause.NONE if no error. */
+ DataCallFailCause cause;
+
+ /**
+ * If status != DataCallFailCause.NONE, this field indicates the suggested retry back-off timer
+ * value RIL wants to override the one pre-configured in FW. The unit is milliseconds.
+ * The value < 0 means no value is suggested.
+ * The value 0 means retry must be done ASAP.
+ * The value of INT_MAX(0x7fffffff) means no retry.
+ */
+ int32_t suggestedRetryTime;
+
+ /** Context ID, uniquely identifies this call. */
+ int32_t cid;
+
+ /** Data connection active status. */
+ DataConnActiveStatus active;
+
+ /**
+ * PDP_type values. If cause is DataCallFailCause.ONLY_SINGLE_BEARER_ALLOWED, this is the type
+ * supported such as "IP" or "IPV6".
+ */
+ PdpProtocolType type;
+
+ /** The network interface name. */
+ string ifname;
+
+ /**
+ * List of link address.
+ */
+ vec<LinkAddress> addresses;
+
+ /**
+ * List of DNS server addresses, e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1". Empty if no dns
+ * server addresses returned.
+ */
+ vec<string> dnses;
+
+ /**
+ * List of default gateway addresses, e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+ * When empty, the addresses represent point to point connections.
+ */
+ vec<string> gateways;
+
+ /**
+ * List of P-CSCF(Proxy Call State Control Function) addresses via PCO(Protocol Configuration
+ * Option), e.g., "2001:db8::1 2001:db8::2 2001:db8::3". Empty if not IMS client.
+ */
+ vec<string> pcscf;
+
+ /**
+ * MTU received from network. Value <= 0 means network has either not sent a value or sent an
+ * invalid value.
+ */
+ int32_t mtu;
+};
+
+enum Domain : int32_t {
+ /** Circuit-switched */
+ CS = 1 << 0,
+
+ /** Packet-switched */
+ PS = 1 << 1,
+};
+
+/** A union representing the CellIdentity of a single cell */
+safe_union CellIdentity {
+ Monostate noinit;
+
+ CellIdentityGsm gsm;
+ CellIdentityWcdma wcdma;
+ CellIdentityTdscdma tdscdma;
+ CellIdentityCdma cdma;
+ CellIdentityLte lte;
+ CellIdentityNr nr;
+};
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index 4df5b14..77d9a02 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -29,6 +29,7 @@
signalThresholdInfo.hysteresisMs = 5000;
signalThresholdInfo.hysteresisDb = 10; // hysteresisDb too large given threshold list deltas
signalThresholdInfo.thresholds = {-109, -103, -97, -89};
+ signalThresholdInfo.isEnabled = true;
Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
@@ -52,6 +53,7 @@
signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSI;
signalThresholdInfo.hysteresisMs = 0;
signalThresholdInfo.hysteresisDb = 0;
+ signalThresholdInfo.isEnabled = true;
Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
@@ -76,6 +78,7 @@
signalThresholdInfo.hysteresisMs = 5000;
signalThresholdInfo.hysteresisDb = 2;
signalThresholdInfo.thresholds = {-109, -103, -97, -89};
+ signalThresholdInfo.isEnabled = true;
Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
@@ -100,6 +103,7 @@
signalThresholdInfo.hysteresisMs = 5000;
signalThresholdInfo.hysteresisDb = 2;
signalThresholdInfo.thresholds = {-110, -97, -73, -49, -25};
+ signalThresholdInfo.isEnabled = true;
Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::UTRAN);
@@ -124,6 +128,7 @@
signalThresholdInfo.hysteresisMs = 5000;
signalThresholdInfo.hysteresisDb = 2;
signalThresholdInfo.thresholds = {-128, -108, -88, -68};
+ signalThresholdInfo.isEnabled = true;
Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN);
@@ -148,6 +153,7 @@
signalThresholdInfo.hysteresisMs = 5000;
signalThresholdInfo.hysteresisDb = 2;
signalThresholdInfo.thresholds = {-27, -20, -13, -6};
+ signalThresholdInfo.isEnabled = true;
Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN);
@@ -172,6 +178,7 @@
signalThresholdInfo.hysteresisMs = 5000;
signalThresholdInfo.hysteresisDb = 2;
signalThresholdInfo.thresholds = {-10, 0, 10, 20};
+ signalThresholdInfo.isEnabled = true;
Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN);
@@ -192,6 +199,7 @@
signalThresholdInfo.hysteresisMs = 5000;
signalThresholdInfo.hysteresisDb = 2;
signalThresholdInfo.thresholds = {-105, -90, -75, -65};
+ signalThresholdInfo.isEnabled = true;
Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::CDMA2000);
@@ -216,6 +224,7 @@
signalThresholdInfo.hysteresisMs = 5000;
signalThresholdInfo.hysteresisDb = 0;
signalThresholdInfo.thresholds = {-105, -90, -75, -65};
+ signalThresholdInfo.isEnabled = true;
Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN);
@@ -240,6 +249,7 @@
signalThresholdInfo.hysteresisMs = 5000;
signalThresholdInfo.hysteresisDb = 0;
signalThresholdInfo.thresholds = {-15, -10, -5, -4};
+ signalThresholdInfo.isEnabled = true;
Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN);
@@ -254,6 +264,27 @@
}
/*
+ * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN
+ */
+TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Disable_RSSNR) {
+ serial = GetRandomSerialNumber();
+
+ ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
+ signalThresholdInfo.signalMeasurement = SignalMeasurementType::RSSNR;
+ signalThresholdInfo.hysteresisMs = 5000;
+ signalThresholdInfo.hysteresisDb = 2;
+ signalThresholdInfo.thresholds = {-10, 0, 10, 20};
+ signalThresholdInfo.isEnabled = false;
+
+ Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
+ serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN);
+ ASSERT_OK(res);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+}
+
+/*
* Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSSINR
*/
TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) {
@@ -264,6 +295,7 @@
signalThresholdInfo.hysteresisMs = 5000;
signalThresholdInfo.hysteresisDb = 0;
signalThresholdInfo.thresholds = {-10, 3, 16, 18};
+ signalThresholdInfo.isEnabled = true;
Return<void> res = radio_v1_5->setSignalStrengthReportingCriteria_1_5(
serial, signalThresholdInfo, ::android::hardware::radio::V1_5::AccessNetwork::NGRAN);
@@ -279,62 +311,9 @@
/*
* Test IRadio.enableUiccApplications() for the response returned.
- */
-TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsNotSupported) {
- serial = GetRandomSerialNumber();
-
- radio_v1_5->canToggleUiccApplicationsEnablement(serial);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
- EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
- EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- // No error should happen.
- EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
-
- // Supported case will be tested by other test cases.
- if (radioRsp_v1_5->canToggleUiccApplicationsEnablement) return;
-
- // Enabling UiccApplications should still work as it should be enabled by default.
- serial = GetRandomSerialNumber();
- radio_v1_5->enableUiccApplications(serial, true);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
- EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
- EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
-
- // Disabling UiccApplications should return REQUEST_NOT_SUPPORTED error.
- serial = GetRandomSerialNumber();
- radio_v1_5->enableUiccApplications(serial, false);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
- EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
- EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- EXPECT_EQ(RadioError::REQUEST_NOT_SUPPORTED, radioRsp_v1_5->rspInfo.error);
-
- // Query areUiccApplicationsEnabled should return true.
- serial = GetRandomSerialNumber();
- radio_v1_5->areUiccApplicationsEnabled(serial);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
- EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
- EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
- ASSERT_TRUE(radioRsp_v1_5->areUiccApplicationsEnabled);
-}
-
-/*
- * Test IRadio.enableUiccApplications() for the response returned.
* For SIM ABSENT case.
*/
-TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSupportedSimAbsent) {
- serial = GetRandomSerialNumber();
-
- radio_v1_5->canToggleUiccApplicationsEnablement(serial);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
- EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
- EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- // No error should happen.
- EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
- // Not supported case will be tested by togglingUiccApplicationsNotSupported test case.
- if (!radioRsp_v1_5->canToggleUiccApplicationsEnablement) return;
-
+TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSimAbsent) {
// This test case only test SIM ABSENT case.
if (cardStatus.base.base.cardState != CardState::ABSENT) return;
@@ -361,18 +340,7 @@
* Test IRadio.enableUiccApplications() for the response returned.
* For SIM PRESENT case.
*/
-TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSupportedSimPresent) {
- serial = GetRandomSerialNumber();
-
- radio_v1_5->canToggleUiccApplicationsEnablement(serial);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
- EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
- EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- // No error should happen.
- EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
- // Not supported case will be tested by disablingUiccApplicationsNotSupported test case.
- if (!radioRsp_v1_5->canToggleUiccApplicationsEnablement) return;
-
+TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSimPresent) {
// This test case only test SIM ABSENT case.
if (cardStatus.base.base.cardState != CardState::PRESENT) return;
@@ -419,18 +387,6 @@
* Test IRadio.areUiccApplicationsEnabled() for the response returned.
*/
TEST_F(RadioHidlTest_v1_5, areUiccApplicationsEnabled) {
- serial = GetRandomSerialNumber();
-
- radio_v1_5->canToggleUiccApplicationsEnablement(serial);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
- EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
- EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- // No error should happen.
- EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
-
- // Not supported case will be tested by togglingUiccApplicationsNotSupported test case.
- if (!radioRsp_v1_5->canToggleUiccApplicationsEnablement) return;
-
// Disable Uicc applications.
serial = GetRandomSerialNumber();
radio_v1_5->areUiccApplicationsEnabled(serial);
@@ -865,3 +821,169 @@
RadioError::REQUEST_NOT_SUPPORTED}));
}
}
+
+/*
+ * Test IRadio.setupDataCall_1_5() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_5, setupDataCall_1_5) {
+ serial = GetRandomSerialNumber();
+
+ ::android::hardware::radio::V1_5::AccessNetwork accessNetwork =
+ ::android::hardware::radio::V1_5::AccessNetwork::EUTRAN;
+
+ android::hardware::radio::V1_5::DataProfileInfo dataProfileInfo;
+ memset(&dataProfileInfo, 0, sizeof(dataProfileInfo));
+ dataProfileInfo.base.profileId = DataProfileId::DEFAULT;
+ dataProfileInfo.base.apn = hidl_string("internet");
+ dataProfileInfo.base.protocol = PdpProtocolType::IP;
+ dataProfileInfo.base.roamingProtocol = PdpProtocolType::IP;
+ dataProfileInfo.base.authType = ApnAuthType::NO_PAP_NO_CHAP;
+ dataProfileInfo.base.user = hidl_string("username");
+ dataProfileInfo.base.password = hidl_string("password");
+ dataProfileInfo.base.type = DataProfileInfoType::THREE_GPP;
+ dataProfileInfo.base.maxConnsTime = 300;
+ dataProfileInfo.base.maxConns = 20;
+ dataProfileInfo.base.waitTime = 0;
+ dataProfileInfo.base.enabled = true;
+ dataProfileInfo.supportedApnTypesBitmap = 320;
+ dataProfileInfo.base.bearerBitmap = 161543;
+ dataProfileInfo.base.mtu = 0;
+ dataProfileInfo.base.preferred = true;
+ dataProfileInfo.base.persistent = false;
+
+ bool roamingAllowed = false;
+
+ std::vector<::android::hardware::radio::V1_5::LinkAddress> addresses = {};
+ std::vector<hidl_string> dnses = {};
+
+ ::android::hardware::radio::V1_2::DataRequestReason reason =
+ ::android::hardware::radio::V1_2::DataRequestReason::NORMAL;
+
+ Return<void> res = radio_v1_5->setupDataCall_1_5(serial, accessNetwork, dataProfileInfo,
+ roamingAllowed, reason, addresses, dnses);
+ ASSERT_OK(res);
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+ if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+ {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
+ } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
+ }
+}
+
+TEST_F(RadioHidlTest_v1_5, setInitialAttachApn_1_5) {
+ serial = GetRandomSerialNumber();
+
+ // Create a dataProfileInfo
+ android::hardware::radio::V1_5::DataProfileInfo dataProfileInfo;
+ memset(&dataProfileInfo, 0, sizeof(dataProfileInfo));
+ dataProfileInfo.base.profileId = DataProfileId::DEFAULT;
+ dataProfileInfo.base.apn = hidl_string("internet");
+ dataProfileInfo.base.protocol = PdpProtocolType::IPV4V6;
+ dataProfileInfo.base.roamingProtocol = PdpProtocolType::IPV4V6;
+ dataProfileInfo.base.authType = ApnAuthType::NO_PAP_NO_CHAP;
+ dataProfileInfo.base.user = hidl_string("username");
+ dataProfileInfo.base.password = hidl_string("password");
+ dataProfileInfo.base.type = DataProfileInfoType::THREE_GPP;
+ dataProfileInfo.base.maxConnsTime = 300;
+ dataProfileInfo.base.maxConns = 20;
+ dataProfileInfo.base.waitTime = 0;
+ dataProfileInfo.base.enabled = true;
+ dataProfileInfo.supportedApnTypesBitmap = 320;
+ dataProfileInfo.base.bearerBitmap = 161543;
+ dataProfileInfo.base.mtu = 0;
+ dataProfileInfo.base.preferred = true;
+ dataProfileInfo.base.persistent = false;
+
+ radio_v1_5->setInitialAttachApn_1_5(serial, dataProfileInfo);
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+ if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+ {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE}));
+ } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
+ }
+}
+
+TEST_F(RadioHidlTest_v1_5, setDataProfile_1_5) {
+ serial = GetRandomSerialNumber();
+
+ // Create a dataProfileInfo
+ android::hardware::radio::V1_5::DataProfileInfo dataProfileInfo;
+ memset(&dataProfileInfo, 0, sizeof(dataProfileInfo));
+ dataProfileInfo.base.profileId = DataProfileId::DEFAULT;
+ dataProfileInfo.base.apn = hidl_string("internet");
+ dataProfileInfo.base.protocol = PdpProtocolType::IPV4V6;
+ dataProfileInfo.base.roamingProtocol = PdpProtocolType::IPV4V6;
+ dataProfileInfo.base.authType = ApnAuthType::NO_PAP_NO_CHAP;
+ dataProfileInfo.base.user = hidl_string("username");
+ dataProfileInfo.base.password = hidl_string("password");
+ dataProfileInfo.base.type = DataProfileInfoType::THREE_GPP;
+ dataProfileInfo.base.maxConnsTime = 300;
+ dataProfileInfo.base.maxConns = 20;
+ dataProfileInfo.base.waitTime = 0;
+ dataProfileInfo.base.enabled = true;
+ dataProfileInfo.supportedApnTypesBitmap = 320;
+ dataProfileInfo.base.bearerBitmap = 161543;
+ dataProfileInfo.base.mtu = 0;
+ dataProfileInfo.base.preferred = true;
+ dataProfileInfo.base.persistent = true;
+
+ // Create a dataProfileInfoList
+ android::hardware::hidl_vec<android::hardware::radio::V1_5::DataProfileInfo>
+ dataProfileInfoList = {dataProfileInfo};
+
+ radio_v1_5->setDataProfile_1_5(serial, dataProfileInfoList);
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+ if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+ {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE}));
+ } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
+ }
+}
+
+TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancalled) {
+ // Set radio power to off.
+ serial = GetRandomSerialNumber();
+ radio_v1_5->setRadioPower_1_5(serial, false, false, false);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+ EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+ // Set radio power to on with forEmergencyCall being true. This should put modem to only scan
+ // emergency call bands.
+ serial = GetRandomSerialNumber();
+ radio_v1_5->setRadioPower_1_5(serial, true, true, true);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+ EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+ // Set radio power to on with forEmergencyCall being false. This should put modem in regular
+ // operation modem.
+ serial = GetRandomSerialNumber();
+ radio_v1_5->setRadioPower_1_5(serial, true, false, false);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+ EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+}
\ No newline at end of file
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index 01bda69..49a315d 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -541,6 +541,16 @@
Return<void> setSystemSelectionChannelsResponse_1_5(const RadioResponseInfo& info);
Return<void> startNetworkScanResponse_1_5(const RadioResponseInfo& info);
+
+ Return<void> setupDataCallResponse_1_5(
+ const RadioResponseInfo& info,
+ const android::hardware::radio::V1_5::SetupDataCallResult& dcResponse);
+
+ Return<void> setInitialAttachApnResponse_1_5(const RadioResponseInfo& info);
+
+ Return<void> setDataProfileResponse_1_5(const RadioResponseInfo& info);
+
+ Return<void> setRadioPowerResponse_1_5(const RadioResponseInfo& info);
};
/* Callback class for radio indication */
@@ -729,6 +739,13 @@
Return<void> modemReset(RadioIndicationType type,
const ::android::hardware::hidl_string& reason);
+
+ Return<void> registrationFailed(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_5::CellIdentity& cellIdentity,
+ const ::android::hardware::hidl_string& chosenPlmn,
+ ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_5::Domain> domain,
+ int32_t causeCode, int32_t additionalCauseCode);
};
// Test environment for Radio HIDL HAL.
diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp
index acffbbe..2416605 100644
--- a/radio/1.5/vts/functional/radio_indication.cpp
+++ b/radio/1.5/vts/functional/radio_indication.cpp
@@ -333,3 +333,12 @@
bool /*enabled*/) {
return Void();
}
+
+Return<void> RadioIndication_v1_5::registrationFailed(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
+ const ::android::hardware::hidl_string& /*chosenPlmn*/,
+ ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_5::Domain> /*domain*/,
+ int32_t /*causeCode*/, int32_t /*additionalCauseCode*/) {
+ return Void();
+}
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index 5964c96..a0b3d5f 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -928,3 +928,29 @@
parent_v1_5.notify(info.serial);
return Void();
}
+
+Return<void> RadioResponse_v1_5::setupDataCallResponse_1_5(
+ const RadioResponseInfo& info,
+ const android::hardware::radio::V1_5::SetupDataCallResult& /* dcResponse */) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setInitialAttachApnResponse_1_5(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setDataProfileResponse_1_5(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setRadioPowerResponse_1_5(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
\ No newline at end of file
diff --git a/rebootescrow/aidl/Android.bp b/rebootescrow/aidl/Android.bp
new file mode 100644
index 0000000..0742939
--- /dev/null
+++ b/rebootescrow/aidl/Android.bp
@@ -0,0 +1,18 @@
+aidl_interface {
+ name: "android.hardware.rebootescrow",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/rebootescrow/IRebootEscrow.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ },
+}
diff --git a/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl b/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl
new file mode 100644
index 0000000..edc695d
--- /dev/null
+++ b/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.rebootescrow;
+
+/**
+ * This HAL defines the interface to the device-specific implementation
+ * of retaining a secret to unlock the Synthetic Password stored during
+ * a reboot to perform an OTA update. The implementation of this interface
+ * should never store the key on any non-volatile medium. The key should be
+ * overwritten with zeroes when destroyKey() is called. All care should be given
+ * to provide the shortest lifetime for the storage of the key in volatile and
+ * erasable storage.
+ *
+ * This HAL is optional so does not require an implementation on device.
+ */
+@VintfStability
+interface IRebootEscrow {
+ /**
+ * Store the key for reboot.
+ */
+ void storeKey(in byte[] kek);
+
+ /**
+ * Retrieve the possible keys. If the implementation is probabalistic, it
+ * should return the keys in order from most-probable to least-probable.
+ * There is not a hard limit to the number of keys, but it is suggested to
+ * keep the number of key possibilities less than 32.
+ */
+ byte[] retrieveKey();
+}
diff --git a/rebootescrow/aidl/default/Android.bp b/rebootescrow/aidl/default/Android.bp
new file mode 100644
index 0000000..b77272f
--- /dev/null
+++ b/rebootescrow/aidl/default/Android.bp
@@ -0,0 +1,88 @@
+//
+// 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: "librebootescrowdefaultimpl",
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.rebootescrow-ndk_platform",
+ ],
+ export_include_dirs: ["include"],
+ srcs: [
+ "RebootEscrow.cpp",
+ ],
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.rebootescrow-service.default",
+ init_rc: ["rebootescrow-default.rc"],
+ relative_install_path: "hw",
+ vintf_fragments: ["rebootescrow-default.xml"],
+ vendor: true,
+ srcs: [
+ "service.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.rebootescrow-ndk_platform",
+ ],
+ static_libs: [
+ "libhadamardutils",
+ "librebootescrowdefaultimpl",
+ ],
+}
+
+cc_library_static {
+ name: "libhadamardutils",
+ vendor_available: true,
+ host_supported: true,
+ shared_libs: [
+ "libbase",
+ ],
+ srcs: [
+ "HadamardUtils.cpp",
+ ],
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
+cc_test {
+ name: "HadamardUtilsTest",
+ host_supported: true,
+ srcs: [
+ "HadamardUtilsTest.cpp",
+ ],
+ static_libs: [
+ "libhadamardutils",
+ "libgtest_prod",
+ ],
+ shared_libs: [
+ "liblog",
+ "libbase",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/rebootescrow/aidl/default/HadamardUtils.cpp b/rebootescrow/aidl/default/HadamardUtils.cpp
new file mode 100644
index 0000000..d2422b9
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtils.cpp
@@ -0,0 +1,163 @@
+/*
+ * 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 <HadamardUtils.h>
+
+#include <limits>
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+namespace hadamard {
+
+static inline uint8_t read_bit(const std::vector<uint8_t>& input, size_t bit) {
+ return (input[bit >> 3] >> (bit & 7)) & 1u;
+}
+
+// Use a simple LCG which is easy to run in reverse.
+// https://www.johndcook.com/blog/2017/07/05/simple-random-number-generator/
+constexpr uint64_t RNG_MODULUS = 0x7fffffff;
+constexpr uint64_t RNG_MUL = 742938285;
+constexpr uint64_t RNG_SEED = 20170705;
+constexpr uint64_t RNG_INV_MUL = 1413043504; // (mul * inv_mul) % modulus == 1
+constexpr uint64_t RNG_INV_SEED = 1173538311; // (seed * mul**65534) % modulus
+
+// Apply an error correcting encoding.
+//
+// The error correcting code used is an augmented Hadamard code with
+// k=15, so it takes a 16-bit input and produces a 2^15-bit output.
+// We break the 32-byte key into 16 16-bit codewords and encode
+// each codeword to a 2^15-bit output.
+//
+// To better defend against clustered errors, we stripe together the encoded
+// codewords. Thus if a single 512-byte DRAM line is lost, instead of losing
+// 2^11 bits from the encoding of a single code word, we lose 2^7 bits
+// from the encoding of each of the 16 codewords.
+// In addition we apply a Fisher-Yates shuffle to the bytes of the encoding;
+// Hadamard encoding recovers much better from random errors than systematic
+// ones, and this ensures that errors will be random.
+std::vector<uint8_t> EncodeKey(const std::vector<uint8_t>& input) {
+ CHECK_EQ(input.size(), KEY_SIZE_IN_BYTES);
+ std::vector<uint8_t> result(OUTPUT_SIZE_BYTES, 0);
+ static_assert(OUTPUT_SIZE_BYTES == 64 * 1024);
+ // Transpose the key so that each row contains one bit from each codeword
+ uint16_t wordmatrix[CODEWORD_BITS];
+ for (size_t i = 0; i < CODEWORD_BITS; i++) {
+ uint16_t word = 0;
+ for (size_t j = 0; j < KEY_CODEWORDS; j++) {
+ word |= read_bit(input, i + j * CODEWORD_BITS) << j;
+ }
+ wordmatrix[i] = word;
+ }
+ // Fill in the encodings in Gray code order for speed.
+ uint16_t val = wordmatrix[CODEWORD_BITS - 1];
+ size_t ix = 0;
+ for (size_t i = 0; i < ENCODE_LENGTH; i++) {
+ for (size_t b = 0; b < CODEWORD_BITS; b++) {
+ if (i & (1 << b)) {
+ ix ^= (1 << b);
+ val ^= wordmatrix[b];
+ break;
+ }
+ }
+ result[ix * KEY_CODEWORD_BYTES] = val & 0xffu;
+ result[ix * KEY_CODEWORD_BYTES + 1] = val >> 8u;
+ }
+ // Apply the inverse shuffle here; we apply the forward shuffle in decoding.
+ uint64_t rng_state = RNG_INV_SEED;
+ for (size_t i = OUTPUT_SIZE_BYTES - 1; i > 0; i--) {
+ auto j = rng_state % (i + 1);
+ auto t = result[i];
+ result[i] = result[j];
+ result[j] = t;
+ rng_state *= RNG_INV_MUL;
+ rng_state %= RNG_MODULUS;
+ }
+ return result;
+}
+
+// Decode a single codeword. Because of the way codewords are striped together
+// this takes the entire input, plus an offset telling it which word to decode.
+static uint16_t DecodeWord(size_t word, const std::vector<uint8_t>& encoded) {
+ std::vector<int32_t> scores;
+ scores.reserve(ENCODE_LENGTH);
+ // Convert x -> -1^x in the encoded bits. e.g [1, 0, 0, 1] -> [-1, 1, 1, -1]
+ for (uint32_t i = 0; i < ENCODE_LENGTH; i++) {
+ scores.push_back(1 - 2 * read_bit(encoded, i * KEY_CODEWORDS + word));
+ }
+
+ // Multiply the hadamard matrix by the transformed input.
+ // |1 1 1 1| |-1| | 0|
+ // |1 -1 1 -1| * | 1| = | 0|
+ // |1 1 -1 -1| | 1| | 0|
+ // |1 -1 -1 1| |-1| |-4|
+ for (uint32_t i = 0; i < CODE_K; i++) {
+ uint16_t step = 1u << i;
+ for (uint32_t j = 0; j < ENCODE_LENGTH; j += 2 * step) {
+ for (uint32_t k = j; k < j + step; k++) {
+ auto a0 = scores[k];
+ auto a1 = scores[k + step];
+ scores[k] = a0 + a1;
+ scores[k + step] = a0 - a1;
+ }
+ }
+ }
+ auto hiscore = std::numeric_limits<int32_t>::min();
+ uint16_t winner;
+ // TODO(b/146520538): this needs to be constant time
+ for (size_t i = 0; i < ENCODE_LENGTH; i++) {
+ if (scores[i] > hiscore) {
+ winner = i;
+ hiscore = scores[i];
+
+ } else if (-scores[i] > hiscore) {
+ winner = i | (1 << CODE_K);
+ hiscore = -scores[i];
+ }
+ }
+ return winner;
+}
+
+std::vector<uint8_t> DecodeKey(const std::vector<uint8_t>& shuffled) {
+ CHECK_EQ(OUTPUT_SIZE_BYTES, shuffled.size());
+ // Apply the forward Fisher-Yates shuffle.
+ std::vector<uint8_t> encoded(OUTPUT_SIZE_BYTES, 0);
+ encoded[0] = shuffled[0];
+ uint64_t rng_state = RNG_SEED;
+ for (size_t i = 1; i < OUTPUT_SIZE_BYTES; i++) {
+ auto j = rng_state % (i + 1);
+ encoded[i] = encoded[j];
+ encoded[j] = shuffled[i];
+ rng_state *= RNG_MUL;
+ rng_state %= RNG_MODULUS;
+ }
+ std::vector<uint8_t> result(KEY_SIZE_IN_BYTES, 0);
+ for (size_t i = 0; i < KEY_CODEWORDS; i++) {
+ uint16_t val = DecodeWord(i, encoded);
+ result[i * CODEWORD_BYTES] = val & 0xffu;
+ result[i * CODEWORD_BYTES + 1] = val >> 8u;
+ }
+ return result;
+}
+
+} // namespace hadamard
+} // namespace rebootescrow
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/rebootescrow/aidl/default/HadamardUtils.h b/rebootescrow/aidl/default/HadamardUtils.h
new file mode 100644
index 0000000..e04f7d5
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtils.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <vector>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+namespace hadamard {
+
+constexpr auto BYTE_LENGTH = 8u;
+constexpr auto CODEWORD_BYTES = 2u; // uint16_t
+constexpr auto CODEWORD_BITS = CODEWORD_BYTES * BYTE_LENGTH;
+constexpr uint32_t CODE_K = CODEWORD_BITS - 1;
+constexpr uint32_t ENCODE_LENGTH = 1u << CODE_K;
+constexpr auto KEY_CODEWORD_BYTES = 2u; // uint16_t (after transpose)
+constexpr auto KEY_CODEWORDS = KEY_CODEWORD_BYTES * BYTE_LENGTH;
+constexpr auto KEY_SIZE_IN_BYTES = KEY_CODEWORDS * CODEWORD_BYTES;
+constexpr auto OUTPUT_SIZE_BYTES = ENCODE_LENGTH * KEY_CODEWORD_BYTES;
+
+// Encodes a key that has a size of KEY_SIZE_IN_BYTES. Returns a byte array representation of the
+// encoded bitset. So a 32 bytes key will expand to 16*(2^15) bits = 64KiB.
+std::vector<uint8_t> EncodeKey(const std::vector<uint8_t>& input);
+
+// Given a byte array representation of the encoded keys, decodes it and return the result.
+std::vector<uint8_t> DecodeKey(const std::vector<uint8_t>& encoded);
+
+} // namespace hadamard
+} // namespace rebootescrow
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/rebootescrow/aidl/default/HadamardUtilsTest.cpp b/rebootescrow/aidl/default/HadamardUtilsTest.cpp
new file mode 100644
index 0000000..1c9a2fb
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtilsTest.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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 <stdint.h>
+#include <random>
+
+#include <gtest/gtest.h>
+
+#include <HadamardUtils.h>
+
+using namespace aidl::android::hardware::rebootescrow::hadamard;
+
+class HadamardTest : public testing::Test {};
+
+static void AddError(std::vector<uint8_t>* data) {
+ for (size_t i = 0; i < data->size(); i++) {
+ for (size_t j = 0; j < BYTE_LENGTH; j++) {
+ if (random() % 100 < 47) {
+ (*data)[i] ^= (1 << j);
+ }
+ }
+ }
+}
+
+TEST_F(HadamardTest, Decode_error_correction) {
+ constexpr auto iteration = 10;
+ for (int i = 0; i < iteration; i++) {
+ std::vector<uint8_t> key;
+ for (int j = 0; j < KEY_SIZE_IN_BYTES; j++) {
+ key.emplace_back(random() & 0xff);
+ }
+ auto encoded = EncodeKey(key);
+ ASSERT_EQ(64 * 1024, encoded.size());
+ AddError(&encoded);
+ auto decoded = DecodeKey(encoded);
+ ASSERT_EQ(key, std::vector<uint8_t>(decoded.begin(), decoded.begin() + key.size()));
+ }
+}
diff --git a/rebootescrow/aidl/default/OWNERS b/rebootescrow/aidl/default/OWNERS
new file mode 100644
index 0000000..c5288d6
--- /dev/null
+++ b/rebootescrow/aidl/default/OWNERS
@@ -0,0 +1,2 @@
+kroot@google.com
+paulcrowley@google.com
diff --git a/rebootescrow/aidl/default/RebootEscrow.cpp b/rebootescrow/aidl/default/RebootEscrow.cpp
new file mode 100644
index 0000000..94d0901
--- /dev/null
+++ b/rebootescrow/aidl/default/RebootEscrow.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+#include "HadamardUtils.h"
+#include "rebootescrow-impl/RebootEscrow.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+
+using ::android::base::unique_fd;
+
+ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector<int8_t>& kek) {
+ int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
+ unique_fd fd(rawFd);
+ if (fd.get() < 0) {
+ LOG(WARNING) << "Could not open reboot escrow device";
+ return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+ }
+
+ std::vector<uint8_t> ukek(kek.begin(), kek.end());
+ auto encoded = hadamard::EncodeKey(ukek);
+
+ if (!::android::base::WriteFully(fd, encoded.data(), encoded.size())) {
+ LOG(WARNING) << "Could not write data fully to character device";
+ return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RebootEscrow::retrieveKey(std::vector<int8_t>* _aidl_return) {
+ int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
+ unique_fd fd(rawFd);
+ if (fd.get() < 0) {
+ LOG(WARNING) << "Could not open reboot escrow device";
+ return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+ }
+
+ std::string encodedString;
+ if (!::android::base::ReadFdToString(fd, &encodedString)) {
+ LOG(WARNING) << "Could not read device to string";
+ return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+ }
+
+ std::vector<uint8_t> encodedBytes(encodedString.begin(), encodedString.end());
+ auto keyBytes = hadamard::DecodeKey(encodedBytes);
+
+ std::vector<int8_t> signedKeyBytes(keyBytes.begin(), keyBytes.end());
+ *_aidl_return = signedKeyBytes;
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace rebootescrow
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
new file mode 100644
index 0000000..1ed7397
--- /dev/null
+++ b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/rebootescrow/BnRebootEscrow.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+
+static const char* REBOOT_ESCROW_DEVICE = "/dev/access-kregistry";
+
+class RebootEscrow : public BnRebootEscrow {
+ ndk::ScopedAStatus storeKey(const std::vector<int8_t>& kek) override;
+ ndk::ScopedAStatus retrieveKey(std::vector<int8_t>* _aidl_return) override;
+};
+
+} // namespace rebootescrow
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/rebootescrow/aidl/default/rebootescrow-default.rc b/rebootescrow/aidl/default/rebootescrow-default.rc
new file mode 100644
index 0000000..e7a9cfc
--- /dev/null
+++ b/rebootescrow/aidl/default/rebootescrow-default.rc
@@ -0,0 +1,9 @@
+service vendor.rebootescrow-default /vendor/bin/hw/android.hardware.rebootescrow-service.default
+ interface aidl android.hardware.rebootescrow.IRebootEscrow/default
+ class hal
+ user system
+ group system
+
+on boot
+ chmod 770 /dev/access-kregistry
+ chown system system /dev/access-kregistry
diff --git a/rebootescrow/aidl/default/rebootescrow-default.xml b/rebootescrow/aidl/default/rebootescrow-default.xml
new file mode 100644
index 0000000..0499fcc
--- /dev/null
+++ b/rebootescrow/aidl/default/rebootescrow-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.rebootescrow</name>
+ <fqname>IRebootEscrow/default</fqname>
+ </hal>
+</manifest>
diff --git a/rebootescrow/aidl/default/service.cpp b/rebootescrow/aidl/default/service.cpp
new file mode 100644
index 0000000..bd2378e
--- /dev/null
+++ b/rebootescrow/aidl/default/service.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rebootescrow-impl/RebootEscrow.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::rebootescrow::RebootEscrow;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ auto re = ndk::SharedRefBase::make<RebootEscrow>();
+ const std::string instance = std::string() + RebootEscrow::descriptor + "/default";
+ binder_status_t status = AServiceManager_addService(re->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE;
+}
diff --git a/rebootescrow/aidl/vts/OWNERS b/rebootescrow/aidl/vts/OWNERS
new file mode 100644
index 0000000..c5288d6
--- /dev/null
+++ b/rebootescrow/aidl/vts/OWNERS
@@ -0,0 +1,2 @@
+kroot@google.com
+paulcrowley@google.com
diff --git a/rebootescrow/aidl/vts/functional/Android.bp b/rebootescrow/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..5d51a53
--- /dev/null
+++ b/rebootescrow/aidl/vts/functional/Android.bp
@@ -0,0 +1,34 @@
+//
+// 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: "VtsHalRebootEscrowTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalRebootEscrowTargetTest.cpp"],
+ shared_libs: [
+ "libbinder",
+ ],
+ static_libs: [
+ "android.hardware.rebootescrow-cpp",
+ ],
+ test_suites: [
+ "vts-core",
+ ],
+ require_root: true,
+}
diff --git a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
new file mode 100644
index 0000000..f69cf87
--- /dev/null
+++ b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android/hardware/rebootescrow/BnRebootEscrow.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+using android::sp;
+using android::String16;
+using android::hardware::rebootescrow::IRebootEscrow;
+
+/**
+ * This tests that the key can be written, read, and removed. It does not test
+ * that the key survives a reboot. That needs a host-based test.
+ *
+ * atest VtsHalRebootEscrowV1_0TargetTest
+ */
+class RebootEscrowAidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ rebootescrow = android::waitForDeclaredService<IRebootEscrow>(String16(GetParam().c_str()));
+ ASSERT_NE(rebootescrow, nullptr);
+ }
+
+ sp<IRebootEscrow> rebootescrow;
+
+ std::vector<uint8_t> KEY_1{
+ 0xA5, 0x00, 0xFF, 0x01, 0xA5, 0x5a, 0xAA, 0x55, 0x00, 0xD3, 0x2A,
+ 0x8C, 0x2E, 0x83, 0x0E, 0x65, 0x9E, 0x8D, 0xC6, 0xAC, 0x1E, 0x83,
+ 0x21, 0xB3, 0x95, 0x02, 0x89, 0x64, 0x64, 0x92, 0x12, 0x1F,
+ };
+ std::vector<uint8_t> KEY_2{
+ 0xFF, 0x00, 0x00, 0xAA, 0x5A, 0x19, 0x20, 0x71, 0x9F, 0xFB, 0xDA,
+ 0xB6, 0x2D, 0x06, 0xD5, 0x49, 0x7E, 0xEF, 0x63, 0xAC, 0x18, 0xFF,
+ 0x5A, 0xA3, 0x40, 0xBB, 0x64, 0xFA, 0x67, 0xC1, 0x10, 0x18,
+ };
+ std::vector<uint8_t> EMPTY_KEY{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+};
+
+TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_Success) {
+ ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
+
+ std::vector<uint8_t> actualKey;
+ ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+ EXPECT_EQ(actualKey, KEY_1);
+}
+
+TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_SecondRetrieveSucceeds) {
+ ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
+
+ std::vector<uint8_t> actualKey;
+ ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+ EXPECT_EQ(actualKey, KEY_1);
+
+ ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+ EXPECT_EQ(actualKey, KEY_1);
+}
+
+TEST_P(RebootEscrowAidlTest, StoreTwiceOverwrites_Success) {
+ ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
+ ASSERT_TRUE(rebootescrow->storeKey(KEY_2).isOk());
+
+ std::vector<uint8_t> actualKey;
+ ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+ EXPECT_EQ(actualKey, KEY_2);
+}
+
+TEST_P(RebootEscrowAidlTest, StoreEmpty_AfterGetEmptyKey_Success) {
+ rebootescrow->storeKey(KEY_1);
+ rebootescrow->storeKey(EMPTY_KEY);
+
+ std::vector<uint8_t> actualKey;
+ ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+ EXPECT_EQ(actualKey, EMPTY_KEY);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ RebootEscrow, RebootEscrowAidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IRebootEscrow::descriptor)),
+ android::PrintInstanceNameToString);
diff --git a/renderscript/1.0/vts/functional/Android.bp b/renderscript/1.0/vts/functional/Android.bp
index 87e62f1..e3716e0 100644
--- a/renderscript/1.0/vts/functional/Android.bp
+++ b/renderscript/1.0/vts/functional/Android.bp
@@ -28,5 +28,5 @@
"android.hardware.renderscript@1.0",
"libnativewindow",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/renderscript/1.0/vts/functional/VtsCopyTests.cpp b/renderscript/1.0/vts/functional/VtsCopyTests.cpp
index f47253f..3040cbf 100644
--- a/renderscript/1.0/vts/functional/VtsCopyTests.cpp
+++ b/renderscript/1.0/vts/functional/VtsCopyTests.cpp
@@ -27,7 +27,7 @@
*
* Expect: dataIn & dataOut are the same.
*/
-TEST_F(RenderscriptHidlTest, Simple1DCopyTest) {
+TEST_P(RenderscriptHidlTest, Simple1DCopyTest) {
// float1
Element element = context->elementCreate(DataType::FLOAT_32, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element);
@@ -63,7 +63,7 @@
*
* Expect: dataIn & dataOut are the same.
*/
-TEST_F(RenderscriptHidlTest, Simple2DCopyTest) {
+TEST_P(RenderscriptHidlTest, Simple2DCopyTest) {
// float1
Element element = context->elementCreate(DataType::FLOAT_32, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element);
@@ -100,7 +100,7 @@
*
* Expect: dataIn & dataOut are the same.
*/
-TEST_F(RenderscriptHidlTest, Simple3DCopyTest) {
+TEST_P(RenderscriptHidlTest, Simple3DCopyTest) {
// float1
Element element = context->elementCreate(DataType::FLOAT_32, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element);
@@ -137,7 +137,7 @@
*
* Expect: dataIn & dataOut are the same.
*/
-TEST_F(RenderscriptHidlTest, SimpleBitmapTest) {
+TEST_P(RenderscriptHidlTest, SimpleBitmapTest) {
// float1
Element element = context->elementCreate(DataType::FLOAT_32, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element);
@@ -177,7 +177,7 @@
*
* Expect: dataIn & dataOut are the same.
*/
-TEST_F(RenderscriptHidlTest, AllocationCopy2DRangeTest) {
+TEST_P(RenderscriptHidlTest, AllocationCopy2DRangeTest) {
// float1
Element element = context->elementCreate(DataType::FLOAT_32, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element);
@@ -229,7 +229,7 @@
*
* Expect: dataIn & dataOut are the same.
*/
-TEST_F(RenderscriptHidlTest, AllocationCopy3DRangeTest) {
+TEST_P(RenderscriptHidlTest, AllocationCopy3DRangeTest) {
// float1
Element element = context->elementCreate(DataType::FLOAT_32, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element);
@@ -282,7 +282,7 @@
*
* Expect: dataIn & dataOut are the same.
*/
-TEST_F(RenderscriptHidlTest, SimpleAdapterTest) {
+TEST_P(RenderscriptHidlTest, SimpleAdapterTest) {
// float1
Element element = context->elementCreate(DataType::FLOAT_32, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element);
@@ -339,7 +339,7 @@
*
* Expect: dataIn & dataOut are the same.
*/
-TEST_F(RenderscriptHidlTest, SimpleMipmapTest) {
+TEST_P(RenderscriptHidlTest, SimpleMipmapTest) {
// uint8_t
Element element = context->elementCreate(DataType::UNSIGNED_8, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element);
@@ -386,7 +386,7 @@
*
* Expect: dataIn & dataOut are the same.
*/
-TEST_F(RenderscriptHidlTest, SimpleCubemapTest) {
+TEST_P(RenderscriptHidlTest, SimpleCubemapTest) {
// float1
Element element = context->elementCreate(DataType::FLOAT_32, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element);
@@ -425,7 +425,7 @@
* typeCreate, allocationCreateTyped, allocationElementWrite,
* allocationElementRead
*/
-TEST_F(RenderscriptHidlTest, ComplexElementTest) {
+TEST_P(RenderscriptHidlTest, ComplexElementTest) {
Element element1 = context->elementCreate(DataType::UNSIGNED_8, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element1);
diff --git a/renderscript/1.0/vts/functional/VtsHalRenderscriptV1_0TargetTest.cpp b/renderscript/1.0/vts/functional/VtsHalRenderscriptV1_0TargetTest.cpp
index 0636cf9..5e5776c 100644
--- a/renderscript/1.0/vts/functional/VtsHalRenderscriptV1_0TargetTest.cpp
+++ b/renderscript/1.0/vts/functional/VtsHalRenderscriptV1_0TargetTest.cpp
@@ -18,8 +18,7 @@
// The main test class for RENDERSCRIPT HIDL HAL.
void RenderscriptHidlTest::SetUp() {
- device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
- RenderscriptHidlEnvironment::Instance()->getServiceName<IDevice>());
+ device = IDevice::getService(GetParam());
ASSERT_NE(nullptr, device.get());
uint32_t version = 0;
@@ -35,11 +34,7 @@
}
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(RenderscriptHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- RenderscriptHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, RenderscriptHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IDevice::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/renderscript/1.0/vts/functional/VtsHalRenderscriptV1_0TargetTest.h b/renderscript/1.0/vts/functional/VtsHalRenderscriptV1_0TargetTest.h
index e11ab92..b7dbed4 100644
--- a/renderscript/1.0/vts/functional/VtsHalRenderscriptV1_0TargetTest.h
+++ b/renderscript/1.0/vts/functional/VtsHalRenderscriptV1_0TargetTest.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef VTS_HAL_RENDERSCRIPT_V1_0_TARGET_TESTS_H
-#define VTS_HAL_RENDERSCRIPT_V1_0_TARGET_TESTS_H
+#pragma once
#define LOG_TAG "renderscript_hidl_hal_test"
#include <android-base/logging.h>
@@ -24,9 +23,9 @@
#include <android/hardware/renderscript/1.0/IDevice.h>
#include <android/hardware/renderscript/1.0/types.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
using ::android::hardware::renderscript::V1_0::Allocation;
using ::android::hardware::renderscript::V1_0::AllocationAdapter;
@@ -89,8 +88,8 @@
extern const int bitCodeLength;
// The main test class for RENDERSCRIPT HIDL HAL.
-class RenderscriptHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-public:
+class RenderscriptHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override;
virtual void TearDown() override;
@@ -99,17 +98,3 @@
private:
sp<IDevice> device;
};
-
-// Test environment for RENDERSCRIPT HIDL HAL.
-class RenderscriptHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static RenderscriptHidlEnvironment* Instance() {
- static RenderscriptHidlEnvironment* instance = new RenderscriptHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IDevice>(); }
-};
-
-#endif // VTS_HAL_RENDERSCRIPT_V1_0_TARGET_TESTS_H
diff --git a/renderscript/1.0/vts/functional/VtsMiscellaneousTests.cpp b/renderscript/1.0/vts/functional/VtsMiscellaneousTests.cpp
index 278dbf3..c66ddea 100644
--- a/renderscript/1.0/vts/functional/VtsMiscellaneousTests.cpp
+++ b/renderscript/1.0/vts/functional/VtsMiscellaneousTests.cpp
@@ -25,14 +25,14 @@
*
* Calls: getService<IDevice>, contextCreate, contextDestroy
*/
-TEST_F(RenderscriptHidlTest, ContextCreateAndDestroy) {}
+TEST_P(RenderscriptHidlTest, ContextCreateAndDestroy) {}
/*
* Create an Element and verify the return value is valid.
*
* Calls: elementCreate
*/
-TEST_F(RenderscriptHidlTest, ElementCreate) {
+TEST_P(RenderscriptHidlTest, ElementCreate) {
Element element = context->elementCreate(DataType::FLOAT_32, DataKind::USER, false, 1);
EXPECT_NE(Element(0), element);
}
@@ -43,7 +43,7 @@
*
* Calls: elementCreate, typeCreate, allocationCreateTyped, allocationGetType
*/
-TEST_F(RenderscriptHidlTest, ElementTypeAllocationCreate) {
+TEST_P(RenderscriptHidlTest, ElementTypeAllocationCreate) {
// Element create test
Element element = context->elementCreate(DataType::FLOAT_32, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element);
@@ -71,7 +71,7 @@
* Calls: elementCreate, typeCreate, elementGetNativeMetadata,
* typeGetNativeMetadata
*/
-TEST_F(RenderscriptHidlTest, MetadataTest) {
+TEST_P(RenderscriptHidlTest, MetadataTest) {
// float1
Element element = context->elementCreate(DataType::FLOAT_32, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element);
@@ -107,7 +107,7 @@
* Calls: elementCreate, typeCreate, allocationCreateTyped,
* allocationGetPointer, allocationResize1D
*/
-TEST_F(RenderscriptHidlTest, ResizeTest) {
+TEST_P(RenderscriptHidlTest, ResizeTest) {
// float1
Element element = context->elementCreate(DataType::FLOAT_32, DataKind::USER, false, 1);
ASSERT_NE(Element(0), element);
@@ -145,7 +145,7 @@
* allocationGetNativeWindow, allocationSetNativeWindow, allocationIoSend,
* allocationIoReceive, allocation2DRead
*/
-TEST_F(RenderscriptHidlTest, NativeWindowIoTest) {
+TEST_P(RenderscriptHidlTest, NativeWindowIoTest) {
// uint8x4
Element element = context->elementCreate(DataType::UNSIGNED_8, DataKind::USER, false, 4);
ASSERT_NE(Element(0), element);
@@ -198,7 +198,7 @@
* allocation2DWrite, allocation2DRead, allocationIoSend,
* allocationIoReceive
*/
-TEST_F(RenderscriptHidlTest, BufferQueueTest) {
+TEST_P(RenderscriptHidlTest, BufferQueueTest) {
// uint8x4
Element element = context->elementCreate(DataType::UNSIGNED_8, DataKind::USER, false, 4);
ASSERT_NE(Element(0), element);
@@ -269,7 +269,7 @@
* Calls: contextInitToClient, contextSendMessage, contextPeekMessage,
* contextGetMessage, contextDeinitToClient, contextLog
*/
-TEST_F(RenderscriptHidlTest, ContextMessageTest) {
+TEST_P(RenderscriptHidlTest, ContextMessageTest) {
context->contextInitToClient();
const char * message = "correct";
@@ -299,7 +299,7 @@
* Calls: contextSetPriority, contextSetCacheDir, elementCreate, assignName,
* contextFinish, getName, objDestroy, samplerCreate
*/
-TEST_F(RenderscriptHidlTest, MiscellaneousTests) {
+TEST_P(RenderscriptHidlTest, MiscellaneousTests) {
context->contextSetPriority(ThreadPriorities::NORMAL);
context->contextSetCacheDir("/data/local/tmp/temp/");
diff --git a/renderscript/1.0/vts/functional/VtsScriptTests.cpp b/renderscript/1.0/vts/functional/VtsScriptTests.cpp
index 8d24cfa..9607267 100644
--- a/renderscript/1.0/vts/functional/VtsScriptTests.cpp
+++ b/renderscript/1.0/vts/functional/VtsScriptTests.cpp
@@ -22,7 +22,7 @@
*
* Calls: elementCreate, scriptIntrinsicCreate, scriptSetTimeZone
*/
-TEST_F(RenderscriptHidlTest, IntrinsicTest) {
+TEST_P(RenderscriptHidlTest, IntrinsicTest) {
// uint8
Element element = context->elementCreate(DataType::UNSIGNED_8, DataKind::USER, false, 1);
EXPECT_NE(Element(0), element);
@@ -41,7 +41,7 @@
* scriptSetVarF, scriptSetVarD, elementCreate, typeCreate,
* allocationCreateTyped, scriptSetVarObj, scriptSetVarV, scriptSetVarVE
*/
-TEST_F(RenderscriptHidlTest, ScriptVarTest) {
+TEST_P(RenderscriptHidlTest, ScriptVarTest) {
hidl_vec<uint8_t> bitcode;
bitcode.setToExternal((uint8_t*)bitCode, bitCodeLength);
Script script = context->scriptCCreate("struct_test", "/data/local/tmp/", bitcode);
@@ -132,7 +132,7 @@
*
* Calls: scriptCCreate, scriptInvoke, scriptGetVarV, scriptInvokeV
*/
-TEST_F(RenderscriptHidlTest, ScriptInvokeTest) {
+TEST_P(RenderscriptHidlTest, ScriptInvokeTest) {
hidl_vec<uint8_t> bitcode;
bitcode.setToExternal((uint8_t*)bitCode, bitCodeLength);
Script script = context->scriptCCreate("struct_test", "/data/local/tmp/", bitcode);
@@ -191,7 +191,7 @@
* Calls: scriptCCreate, elementCreate, typeCreate, allocationCreateTyped,
* allocation1DWrite, scriptForEach, allocationRead
*/
-TEST_F(RenderscriptHidlTest, ScriptForEachTest) {
+TEST_P(RenderscriptHidlTest, ScriptForEachTest) {
hidl_vec<uint8_t> bitcode;
bitcode.setToExternal((uint8_t*)bitCode, bitCodeLength);
Script script = context->scriptCCreate("struct_test", "/data/local/tmp/", bitcode);
@@ -237,7 +237,7 @@
* Calls: scriptCCreate, elementCreate, typeCreate, allocationCreateTyped,
* allocation1DWrite, scriptReduce, contextFinish, allocationRead
*/
-TEST_F(RenderscriptHidlTest, ScriptReduceTest) {
+TEST_P(RenderscriptHidlTest, ScriptReduceTest) {
hidl_vec<uint8_t> bitcode;
bitcode.setToExternal((uint8_t*)bitCode, bitCodeLength);
Script script = context->scriptCCreate("struct_test", "/data/local/tmp/", bitcode);
@@ -288,7 +288,7 @@
* allocation1DWrite, scriptBindAllocation, scriptSetVarV, scriptBindAllocation,
* allocationRead, scriptInvokeV, allocationRead
*/
-TEST_F(RenderscriptHidlTest, ScriptBindTest) {
+TEST_P(RenderscriptHidlTest, ScriptBindTest) {
hidl_vec<uint8_t> bitcode;
bitcode.setToExternal((uint8_t*)bitCode, bitCodeLength);
Script script = context->scriptCCreate("struct_test", "/data/local/tmp/", bitcode);
@@ -333,7 +333,7 @@
* scriptGroupCreate, scriptGroupSetInput, scriptGroupSetOutput,
* scriptGroupExecute, contextFinish, allocation2DRead
*/
-TEST_F(RenderscriptHidlTest, ScriptGroupTest) {
+TEST_P(RenderscriptHidlTest, ScriptGroupTest) {
std::vector<uint8_t> dataIn(256 * 256 * 4, 128), dataOut(256 * 256 * 4, 0),
zeros(256 * 256 * 4, 0);
hidl_vec<uint8_t> _dataIn, _dataOut;
@@ -418,7 +418,7 @@
* invokeClosureCreate, closureCreate, closureSetGlobal, scriptGroup2Create,
* scriptGroupExecute, allocationRead
*/
-TEST_F(RenderscriptHidlTest, ScriptGroup2Test) {
+TEST_P(RenderscriptHidlTest, ScriptGroup2Test) {
hidl_vec<uint8_t> bitcode;
bitcode.setToExternal((uint8_t*)bitCode, bitCodeLength);
Script script = context->scriptCCreate("struct_test", "/data/local/tmp/", bitcode);
@@ -495,7 +495,7 @@
* allocation1DWrite, scriptKernelIDCreate, closureCreate, closureSetArg,
* scriptGroup2Create, scriptGroupExecute, allocationRead
*/
-TEST_F(RenderscriptHidlTest, ScriptGroup2KernelTest) {
+TEST_P(RenderscriptHidlTest, ScriptGroup2KernelTest) {
hidl_vec<uint8_t> bitcode;
bitcode.setToExternal((uint8_t*)bitCode, bitCodeLength);
Script script = context->scriptCCreate("struct_test", "/data/local/tmp/", bitcode);
diff --git a/secure_element/1.0/vts/functional/Android.bp b/secure_element/1.0/vts/functional/Android.bp
index 2b2b73e..6dbd027 100644
--- a/secure_element/1.0/vts/functional/Android.bp
+++ b/secure_element/1.0/vts/functional/Android.bp
@@ -21,5 +21,5 @@
static_libs: [
"android.hardware.secure_element@1.0",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
index 671923a..93ffd05 100644
--- a/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
+++ b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
@@ -20,10 +20,11 @@
#include <android/hardware/secure_element/1.0/ISecureElement.h>
#include <android/hardware/secure_element/1.0/ISecureElementHalCallback.h>
#include <android/hardware/secure_element/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
using ::android::hardware::secure_element::V1_0::ISecureElement;
using ::android::hardware::secure_element::V1_0::ISecureElementHalCallback;
@@ -32,7 +33,6 @@
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
-using ::testing::VtsHalHidlTargetTestEnvBase;
#define DATA_APDU \
{ 0x00, 0x08, 0x00, 0x00, 0x00 }
@@ -63,30 +63,11 @@
};
};
-class SecureElementHidlEnvironment : public VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static SecureElementHidlEnvironment* Instance() {
- static SecureElementHidlEnvironment* instance = new SecureElementHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<ISecureElement>(); }
-
- private:
- SecureElementHidlEnvironment() {}
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(SecureElementHidlEnvironment);
-};
-
-class SecureElementHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class SecureElementHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override {
- std::string serviceName =
- SecureElementHidlEnvironment::Instance()->getServiceName<ISecureElement>("eSE1");
- LOG(INFO) << "get service with name:" << serviceName;
- ASSERT_FALSE(serviceName.empty());
- se_ = ::testing::VtsHalHidlTargetTestBase::getService<ISecureElement>(serviceName);
+ LOG(INFO) << "get service with name:" << GetParam();
+ se_ = ISecureElement::getService(GetParam());
ASSERT_NE(se_, nullptr);
se_cb_ = new SecureElementHalCallback();
@@ -105,7 +86,7 @@
* isCardPresent:
* Expects the card to be present
*/
-TEST_F(SecureElementHidlTest, isCardPresent) {
+TEST_P(SecureElementHidlTest, isCardPresent) {
EXPECT_TRUE(se_->isCardPresent());
}
@@ -113,7 +94,7 @@
* transmit:
* Check status word in the response
*/
-TEST_F(SecureElementHidlTest, transmit) {
+TEST_P(SecureElementHidlTest, transmit) {
std::vector<uint8_t> aid = ANDROID_TEST_AID;
SecureElementStatus statusReturned;
LogicalChannelResponse response;
@@ -153,7 +134,7 @@
* If the secure element allows opening of basic channel:
* open channel, check the length of selectResponse and close the channel
*/
-TEST_F(SecureElementHidlTest, openBasicChannel) {
+TEST_P(SecureElementHidlTest, openBasicChannel) {
std::vector<uint8_t> aid = ANDROID_TEST_AID;
SecureElementStatus statusReturned;
std::vector<uint8_t> response;
@@ -179,7 +160,7 @@
/*
* GetATR
*/
-TEST_F(SecureElementHidlTest, getAtr) {
+TEST_P(SecureElementHidlTest, getAtr) {
std::vector<uint8_t> atr;
se_->getAtr([&atr](std::vector<uint8_t> atrReturned) {
atr.resize(atrReturned.size());
@@ -200,7 +181,7 @@
* Check status
* Close Channel
*/
-TEST_F(SecureElementHidlTest, openCloseLogicalChannel) {
+TEST_P(SecureElementHidlTest, openCloseLogicalChannel) {
std::vector<uint8_t> aid = ANDROID_TEST_AID;
SecureElementStatus statusReturned;
LogicalChannelResponse response;
@@ -223,10 +204,7 @@
EXPECT_EQ(SecureElementStatus::SUCCESS, se_->closeChannel(response.channelNumber));
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(SecureElementHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- SecureElementHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, SecureElementHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISecureElement::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/secure_element/1.1/vts/functional/Android.bp b/secure_element/1.1/vts/functional/Android.bp
index 51410bd..a2c39dc 100644
--- a/secure_element/1.1/vts/functional/Android.bp
+++ b/secure_element/1.1/vts/functional/Android.bp
@@ -22,5 +22,5 @@
"android.hardware.secure_element@1.0",
"android.hardware.secure_element@1.1",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp b/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp
index f8765ca..66fc47c 100644
--- a/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp
+++ b/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp
@@ -22,10 +22,11 @@
#include <android/hardware/secure_element/1.0/types.h>
#include <android/hardware/secure_element/1.1/ISecureElement.h>
#include <android/hardware/secure_element/1.1/ISecureElementHalCallback.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
using ::android::sp;
using ::android::hardware::hidl_string;
@@ -33,7 +34,6 @@
using ::android::hardware::Void;
using ::android::hardware::secure_element::V1_1::ISecureElement;
using ::android::hardware::secure_element::V1_1::ISecureElementHalCallback;
-using ::testing::VtsHalHidlTargetTestEnvBase;
constexpr char kCallbackNameOnStateChange[] = "onStateChange";
@@ -60,30 +60,11 @@
Return<void> onStateChange(__attribute__((unused)) bool state) override { return Void(); }
};
-class SecureElementHidlEnvironment : public VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static SecureElementHidlEnvironment* Instance() {
- static SecureElementHidlEnvironment* instance = new SecureElementHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<ISecureElement>(); }
-
- private:
- SecureElementHidlEnvironment() {}
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(SecureElementHidlEnvironment);
-};
-
-class SecureElementHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class SecureElementHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override {
- std::string serviceName =
- SecureElementHidlEnvironment::Instance()->getServiceName<ISecureElement>("eSE1");
- LOG(INFO) << "get service with name:" << serviceName;
- ASSERT_FALSE(serviceName.empty());
- se_ = ::testing::VtsHalHidlTargetTestBase::getService<ISecureElement>(serviceName);
+ LOG(INFO) << "get service with name:" << GetParam();
+ se_ = ISecureElement::getService(GetParam());
ASSERT_NE(se_, nullptr);
se_cb_ = new SecureElementHalCallback();
@@ -103,14 +84,11 @@
* isCardPresent:
* Expects the card to be present
*/
-TEST_F(SecureElementHidlTest, isCardPresent) {
+TEST_P(SecureElementHidlTest, isCardPresent) {
EXPECT_TRUE(se_->isCardPresent());
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(SecureElementHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- SecureElementHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, SecureElementHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISecureElement::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index 7bb992b..1167fd4 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -31,6 +31,6 @@
"android.hardware.sensors@1.0",
"VtsHalSensorsTargetTestUtils",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/sensors/1.0/vts/functional/AndroidTest.xml b/sensors/1.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..fb0d64c
--- /dev/null
+++ b/sensors/1.0/vts/functional/AndroidTest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalSensorsV1_0TargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="stop"/>
+ <option name="teardown-command" value="start"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsHalSensorsV1_0TargetTest->/data/local/tmp/VtsHalSensorsV1_0TargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-timeout" value="900000" />
+ <option name="runtime-hint" value="300000"/>
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalSensorsV1_0TargetTest" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
index 00207b1..1e5e886 100644
--- a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
+++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
@@ -35,8 +35,7 @@
// this do ... while is for easy error handling
do {
step = "getService()";
- sensors = ISensors::getService(
- SensorsHidlEnvironmentV1_0::Instance()->getServiceName<ISensors>());
+ sensors = ISensors::getService(mServiceName);
if (sensors == nullptr) {
break;
}
diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
index 0a9e59f..29bfa50 100644
--- a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
+++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
@@ -32,23 +32,14 @@
class SensorsHidlEnvironmentV1_0 : public SensorsHidlEnvironmentBase {
public:
using Event = ::android::hardware::sensors::V1_0::Event;
- // get the test environment singleton
- static SensorsHidlEnvironmentV1_0* Instance() {
- static SensorsHidlEnvironmentV1_0* instance = new SensorsHidlEnvironmentV1_0();
- return instance;
- }
+ SensorsHidlEnvironmentV1_0(const std::string& service_name)
+ : SensorsHidlEnvironmentBase(service_name) {}
- virtual void registerTestServices() override {
- registerTestService<android::hardware::sensors::V1_0::ISensors>();
- }
-
- private:
+ private:
friend SensorsHidlTest;
// sensors hidl service
sp<android::hardware::sensors::V1_0::ISensors> sensors;
- SensorsHidlEnvironmentV1_0() {}
-
bool resetHal() override;
void startPollingThread() override;
static void pollingThread(SensorsHidlEnvironmentV1_0* env, std::atomic_bool& stop);
diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
index 5453ef6..2cad54d 100644
--- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
+++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -19,6 +19,8 @@
#include <android/hardware/sensors/1.0/ISensors.h>
#include <android/hardware/sensors/1.0/types.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <log/log.h>
#include <utils/SystemClock.h>
@@ -33,7 +35,17 @@
// The main test class for SENSORS HIDL HAL.
class SensorsHidlTest : public SensorsHidlTestBase {
- protected:
+ public:
+ virtual void SetUp() override {
+ mEnvironment = new SensorsHidlEnvironmentV1_0(GetParam());
+ mEnvironment->HidlSetUp();
+ // Ensure that we have a valid environment before performing tests
+ ASSERT_NE(S(), nullptr);
+ }
+
+ virtual void TearDown() override { mEnvironment->HidlTearDown(); }
+
+ protected:
SensorInfo defaultSensorByType(SensorType type) override;
std::vector<SensorInfo> getSensorsList();
// implementation wrapper
@@ -66,11 +78,13 @@
return S()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
}
- inline sp<ISensors>& S() { return SensorsHidlEnvironmentV1_0::Instance()->sensors; }
+ inline sp<ISensors>& S() { return mEnvironment->sensors; }
- SensorsHidlEnvironmentBase* getEnvironment() override {
- return SensorsHidlEnvironmentV1_0::Instance();
- }
+ SensorsHidlEnvironmentBase* getEnvironment() override { return mEnvironment; }
+
+ private:
+ // Test environment for sensors HAL.
+ SensorsHidlEnvironmentV1_0* mEnvironment;
};
Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
@@ -133,55 +147,52 @@
}
// Test if sensor list returned is valid
-TEST_F(SensorsHidlTest, SensorListValid) {
- S()->getSensorsList(
- [&] (const auto &list) {
+TEST_P(SensorsHidlTest, SensorListValid) {
+ S()->getSensorsList([&](const auto& list) {
const size_t count = list.size();
for (size_t i = 0; i < count; ++i) {
- const auto &s = list[i];
- SCOPED_TRACE(::testing::Message() << i << "/" << count << ": "
- << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
- << s.sensorHandle << std::dec
- << " type=" << static_cast<int>(s.type)
- << " name=" << s.name);
+ const auto& s = list[i];
+ SCOPED_TRACE(::testing::Message()
+ << i << "/" << count << ": "
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << s.sensorHandle << std::dec << " type=" << static_cast<int>(s.type)
+ << " name=" << s.name);
- // Test non-empty type string
- EXPECT_FALSE(s.typeAsString.empty());
+ // Test non-empty type string
+ EXPECT_FALSE(s.typeAsString.empty());
- // Test defined type matches defined string type
- EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
+ // Test defined type matches defined string type
+ EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
- // Test if all sensor has name and vendor
- EXPECT_FALSE(s.name.empty());
- EXPECT_FALSE(s.vendor.empty());
+ // Test if all sensor has name and vendor
+ EXPECT_FALSE(s.name.empty());
+ EXPECT_FALSE(s.vendor.empty());
- // Test power > 0, maxRange > 0
- EXPECT_LE(0, s.power);
- EXPECT_LT(0, s.maxRange);
+ // Test power > 0, maxRange > 0
+ EXPECT_LE(0, s.power);
+ EXPECT_LT(0, s.maxRange);
- // Info type, should have no sensor
- EXPECT_FALSE(
- s.type == SensorType::ADDITIONAL_INFO
- || s.type == SensorType::META_DATA);
+ // Info type, should have no sensor
+ EXPECT_FALSE(s.type == SensorType::ADDITIONAL_INFO || s.type == SensorType::META_DATA);
- // Test fifoMax >= fifoReserved
- EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
- << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
+ // Test fifoMax >= fifoReserved
+ EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
+ << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
- // Test Reporting mode valid
- EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
+ // Test Reporting mode valid
+ EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
- // Test min max are in the right order
- EXPECT_LE(s.minDelay, s.maxDelay);
- // Test min/max delay matches reporting mode
- EXPECT_NO_FATAL_FAILURE(
- assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
+ // Test min max are in the right order
+ EXPECT_LE(s.minDelay, s.maxDelay);
+ // Test min/max delay matches reporting mode
+ EXPECT_NO_FATAL_FAILURE(
+ assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
}
- });
+ });
}
// Test if sensor list returned is valid
-TEST_F(SensorsHidlTest, SetOperationMode) {
+TEST_P(SensorsHidlTest, SetOperationMode) {
std::vector<SensorInfo> sensorList = getSensorsList();
bool needOperationModeSupport =
@@ -199,7 +210,7 @@
}
// Test if sensor list returned is valid
-TEST_F(SensorsHidlTest, InjectSensorEventData) {
+TEST_P(SensorsHidlTest, InjectSensorEventData) {
std::vector<SensorInfo> sensorList = getSensorsList();
std::vector<SensorInfo> sensorSupportInjection;
@@ -244,224 +255,202 @@
}
// Test if sensor hal can do UI speed accelerometer streaming properly
-TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
- testStreamingOperation(SensorType::ACCELEROMETER,
- std::chrono::milliseconds(200),
- std::chrono::seconds(5),
- sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
+ testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(200),
+ std::chrono::seconds(5), sAccelNormChecker);
}
// Test if sensor hal can do normal speed accelerometer streaming properly
-TEST_F(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
- testStreamingOperation(SensorType::ACCELEROMETER,
- std::chrono::milliseconds(20),
- std::chrono::seconds(5),
- sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
+ testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(20),
+ std::chrono::seconds(5), sAccelNormChecker);
}
// Test if sensor hal can do game speed accelerometer streaming properly
-TEST_F(SensorsHidlTest, AccelerometerStreamingOperationFast) {
- testStreamingOperation(SensorType::ACCELEROMETER,
- std::chrono::milliseconds(5),
- std::chrono::seconds(5),
- sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) {
+ testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(5),
+ std::chrono::seconds(5), sAccelNormChecker);
}
// Test if sensor hal can do UI speed gyroscope streaming properly
-TEST_F(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
- testStreamingOperation(SensorType::GYROSCOPE,
- std::chrono::milliseconds(200),
- std::chrono::seconds(5),
- sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
+ testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(200),
+ std::chrono::seconds(5), sGyroNormChecker);
}
// Test if sensor hal can do normal speed gyroscope streaming properly
-TEST_F(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
- testStreamingOperation(SensorType::GYROSCOPE,
- std::chrono::milliseconds(20),
- std::chrono::seconds(5),
- sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
+ testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(20),
+ std::chrono::seconds(5), sGyroNormChecker);
}
// Test if sensor hal can do game speed gyroscope streaming properly
-TEST_F(SensorsHidlTest, GyroscopeStreamingOperationFast) {
- testStreamingOperation(SensorType::GYROSCOPE,
- std::chrono::milliseconds(5),
- std::chrono::seconds(5),
- sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) {
+ testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(5),
+ std::chrono::seconds(5), sGyroNormChecker);
}
// Test if sensor hal can do UI speed magnetometer streaming properly
-TEST_F(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
- testStreamingOperation(SensorType::MAGNETIC_FIELD,
- std::chrono::milliseconds(200),
- std::chrono::seconds(5),
- NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200),
+ std::chrono::seconds(5), NullChecker());
}
// Test if sensor hal can do normal speed magnetometer streaming properly
-TEST_F(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
- testStreamingOperation(SensorType::MAGNETIC_FIELD,
- std::chrono::milliseconds(20),
- std::chrono::seconds(5),
- NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20),
+ std::chrono::seconds(5), NullChecker());
}
// Test if sensor hal can do game speed magnetometer streaming properly
-TEST_F(SensorsHidlTest, MagnetometerStreamingOperationFast) {
- testStreamingOperation(SensorType::MAGNETIC_FIELD,
- std::chrono::milliseconds(5),
- std::chrono::seconds(5),
- NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5),
+ std::chrono::seconds(5), NullChecker());
}
// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
- testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
- testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER, false /*fastToSlow*/);
+TEST_P(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
+ testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER, false /*fastToSlow*/);
}
// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
- testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE);
- testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE, false /*fastToSlow*/);
+TEST_P(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE);
+ testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE, false /*fastToSlow*/);
}
// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
- testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD);
- testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/);
+TEST_P(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD);
+ testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/);
}
// Test if sensor hal can do accelerometer batching properly
-TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
- testBatchingOperation(SensorType::ACCELEROMETER);
+TEST_P(SensorsHidlTest, AccelerometerBatchingOperation) {
+ testBatchingOperation(SensorType::ACCELEROMETER);
}
// Test if sensor hal can do gyroscope batching properly
-TEST_F(SensorsHidlTest, GyroscopeBatchingOperation) {
- testBatchingOperation(SensorType::GYROSCOPE);
+TEST_P(SensorsHidlTest, GyroscopeBatchingOperation) {
+ testBatchingOperation(SensorType::GYROSCOPE);
}
// Test if sensor hal can do magnetometer batching properly
-TEST_F(SensorsHidlTest, MagnetometerBatchingOperation) {
- testBatchingOperation(SensorType::MAGNETIC_FIELD);
+TEST_P(SensorsHidlTest, MagnetometerBatchingOperation) {
+ testBatchingOperation(SensorType::MAGNETIC_FIELD);
}
// Test sensor event direct report with ashmem for accel sensor at normal rate
-TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
- testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
- sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ sAccelNormChecker);
}
// Test sensor event direct report with ashmem for accel sensor at fast rate
-TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
- testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
- sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
+ sAccelNormChecker);
}
// Test sensor event direct report with ashmem for accel sensor at very fast rate
-TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
- testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
- sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM,
+ RateLevel::VERY_FAST, sAccelNormChecker);
}
// Test sensor event direct report with ashmem for gyro sensor at normal rate
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
- testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
- sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ sGyroNormChecker);
}
// Test sensor event direct report with ashmem for gyro sensor at fast rate
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
- testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
- sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
+ sGyroNormChecker);
}
// Test sensor event direct report with ashmem for gyro sensor at very fast rate
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
- testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
- sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
+ sGyroNormChecker);
}
// Test sensor event direct report with ashmem for mag sensor at normal rate
-TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
- testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
- NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ NullChecker());
}
// Test sensor event direct report with ashmem for mag sensor at fast rate
-TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
- testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
- NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
+ NullChecker());
}
// Test sensor event direct report with ashmem for mag sensor at very fast rate
-TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
- testDirectReportOperation(
- SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::VERY_FAST, NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM,
+ RateLevel::VERY_FAST, NullChecker());
}
// Test sensor event direct report with gralloc for accel sensor at normal rate
-TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
- testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL,
- sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL,
+ sAccelNormChecker);
}
// Test sensor event direct report with gralloc for accel sensor at fast rate
-TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
- testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST,
- sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST,
+ sAccelNormChecker);
}
// Test sensor event direct report with gralloc for accel sensor at very fast rate
-TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
- testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
- sAccelNormChecker);
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC,
+ RateLevel::VERY_FAST, sAccelNormChecker);
}
// Test sensor event direct report with gralloc for gyro sensor at normal rate
-TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
- testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL,
- sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL,
+ sGyroNormChecker);
}
// Test sensor event direct report with gralloc for gyro sensor at fast rate
-TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
- testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
- sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
+ sGyroNormChecker);
}
// Test sensor event direct report with gralloc for gyro sensor at very fast rate
-TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
- testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
- sGyroNormChecker);
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
+ sGyroNormChecker);
}
// Test sensor event direct report with gralloc for mag sensor at normal rate
-TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
- testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL,
- NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL,
+ NullChecker());
}
// Test sensor event direct report with gralloc for mag sensor at fast rate
-TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
- testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST,
- NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST,
+ NullChecker());
}
// Test sensor event direct report with gralloc for mag sensor at very fast rate
-TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
- testDirectReportOperation(
- SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::VERY_FAST, NullChecker());
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC,
+ RateLevel::VERY_FAST, NullChecker());
}
-int main(int argc, char **argv) {
- ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironmentV1_0::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- SensorsHidlEnvironmentV1_0::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, SensorsHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISensors::descriptor)),
+ android::hardware::PrintInstanceNameToString);
// vim: set ts=2 sw=2
diff --git a/sensors/2.0/vts/functional/AndroidTest.xml b/sensors/2.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..b710ed0
--- /dev/null
+++ b/sensors/2.0/vts/functional/AndroidTest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalSensorsV2_0TargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="stop"/>
+ <option name="teardown-command" value="start"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsHalSensorsV2_0TargetTest->/data/local/tmp/VtsHalSensorsV2_0TargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-timeout" value="900000" />
+ <option name="runtime-hint" value="300000"/>
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalSensorsV2_0TargetTest" />
+ </test>
+</configuration>
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
index dc54f27..81db5a0 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
@@ -58,8 +58,7 @@
bool SensorsHidlEnvironmentV2_0::resetHal() {
bool succeed = false;
do {
- mSensors = ISensors::getService(
- SensorsHidlEnvironmentV2_0::Instance()->getServiceName<ISensors>());
+ mSensors = ISensors::getService(mServiceName);
if (mSensors == nullptr) {
break;
}
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
index b0dbd90..819cdd4 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
@@ -42,22 +42,12 @@
class SensorsHidlEnvironmentV2_0 : public SensorsHidlEnvironmentBase {
public:
using Event = ::android::hardware::sensors::V1_0::Event;
- // get the test environment singleton
- static SensorsHidlEnvironmentV2_0* Instance() {
- static SensorsHidlEnvironmentV2_0* instance = new SensorsHidlEnvironmentV2_0();
- return instance;
- }
-
- virtual void registerTestServices() override {
- registerTestService<android::hardware::sensors::V2_0::ISensors>();
- }
-
virtual void HidlTearDown() override;
protected:
friend SensorsHidlTest;
-
- SensorsHidlEnvironmentV2_0() : mEventQueueFlag(nullptr) {}
+ SensorsHidlEnvironmentV2_0(const std::string& service_name)
+ : SensorsHidlEnvironmentBase(service_name), mEventQueueFlag(nullptr) {}
/**
* Resets the HAL with new FMQs and a new Event Flag
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index 8364ba9..c5eb442 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -20,6 +20,8 @@
#include <android/hardware/sensors/2.0/ISensors.h>
#include <android/hardware/sensors/2.0/types.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <log/log.h>
#include <utils/SystemClock.h>
@@ -120,10 +122,14 @@
class SensorsHidlTest : public SensorsHidlTestBase {
public:
virtual void SetUp() override {
+ mEnvironment = new SensorsHidlEnvironmentV2_0(GetParam());
+ mEnvironment->HidlSetUp();
// Ensure that we have a valid environment before performing tests
ASSERT_NE(getSensors(), nullptr);
}
+ virtual void TearDown() override { mEnvironment->HidlTearDown(); }
+
protected:
SensorInfo defaultSensorByType(SensorType type) override;
std::vector<SensorInfo> getSensorsList();
@@ -160,12 +166,10 @@
}
inline sp<::android::hardware::sensors::V2_0::ISensors>& getSensors() {
- return SensorsHidlEnvironmentV2_0::Instance()->mSensors;
+ return mEnvironment->mSensors;
}
- SensorsHidlEnvironmentBase* getEnvironment() override {
- return SensorsHidlEnvironmentV2_0::Instance();
- }
+ SensorsHidlEnvironmentBase* getEnvironment() override { return mEnvironment; }
// Test helpers
void runSingleFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
@@ -191,6 +195,10 @@
void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, RateLevel rateLevel);
void queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
bool* supportsAnyDirectChannel);
+
+ private:
+ // Test environment for sensors HAL.
+ SensorsHidlEnvironmentV2_0* mEnvironment;
};
Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
@@ -301,7 +309,7 @@
}
// Test if sensor list returned is valid
-TEST_F(SensorsHidlTest, SensorListValid) {
+TEST_P(SensorsHidlTest, SensorListValid) {
getSensors()->getSensorsList([&](const auto& list) {
const size_t count = list.size();
for (size_t i = 0; i < count; ++i) {
@@ -346,7 +354,7 @@
}
// Test that SetOperationMode returns the expected value
-TEST_F(SensorsHidlTest, SetOperationMode) {
+TEST_P(SensorsHidlTest, SetOperationMode) {
std::vector<SensorInfo> sensors = getInjectEventSensors();
if (getInjectEventSensors().size() > 0) {
ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
@@ -358,7 +366,7 @@
}
// Test that an injected event is written back to the Event FMQ
-TEST_F(SensorsHidlTest, InjectSensorEventData) {
+TEST_P(SensorsHidlTest, InjectSensorEventData) {
std::vector<SensorInfo> sensors = getInjectEventSensors();
if (sensors.size() == 0) {
return;
@@ -414,196 +422,196 @@
}
// Test if sensor hal can do UI speed accelerometer streaming properly
-TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(200),
std::chrono::seconds(5), sAccelNormChecker);
}
// Test if sensor hal can do normal speed accelerometer streaming properly
-TEST_F(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(20),
std::chrono::seconds(5), sAccelNormChecker);
}
// Test if sensor hal can do game speed accelerometer streaming properly
-TEST_F(SensorsHidlTest, AccelerometerStreamingOperationFast) {
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) {
testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(5),
std::chrono::seconds(5), sAccelNormChecker);
}
// Test if sensor hal can do UI speed gyroscope streaming properly
-TEST_F(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(200),
std::chrono::seconds(5), sGyroNormChecker);
}
// Test if sensor hal can do normal speed gyroscope streaming properly
-TEST_F(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(20),
std::chrono::seconds(5), sGyroNormChecker);
}
// Test if sensor hal can do game speed gyroscope streaming properly
-TEST_F(SensorsHidlTest, GyroscopeStreamingOperationFast) {
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) {
testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(5),
std::chrono::seconds(5), sGyroNormChecker);
}
// Test if sensor hal can do UI speed magnetometer streaming properly
-TEST_F(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200),
std::chrono::seconds(5), NullChecker());
}
// Test if sensor hal can do normal speed magnetometer streaming properly
-TEST_F(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20),
std::chrono::seconds(5), NullChecker());
}
// Test if sensor hal can do game speed magnetometer streaming properly
-TEST_F(SensorsHidlTest, MagnetometerStreamingOperationFast) {
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) {
testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5),
std::chrono::seconds(5), NullChecker());
}
// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
+TEST_P(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER, false /*fastToSlow*/);
}
// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
+TEST_P(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE);
testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE, false /*fastToSlow*/);
}
// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
+TEST_P(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD);
testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/);
}
// Test if sensor hal can do accelerometer batching properly
-TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
+TEST_P(SensorsHidlTest, AccelerometerBatchingOperation) {
testBatchingOperation(SensorType::ACCELEROMETER);
}
// Test if sensor hal can do gyroscope batching properly
-TEST_F(SensorsHidlTest, GyroscopeBatchingOperation) {
+TEST_P(SensorsHidlTest, GyroscopeBatchingOperation) {
testBatchingOperation(SensorType::GYROSCOPE);
}
// Test if sensor hal can do magnetometer batching properly
-TEST_F(SensorsHidlTest, MagnetometerBatchingOperation) {
+TEST_P(SensorsHidlTest, MagnetometerBatchingOperation) {
testBatchingOperation(SensorType::MAGNETIC_FIELD);
}
// Test sensor event direct report with ashmem for accel sensor at normal rate
-TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
sAccelNormChecker);
}
// Test sensor event direct report with ashmem for accel sensor at fast rate
-TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
sAccelNormChecker);
}
// Test sensor event direct report with ashmem for accel sensor at very fast rate
-TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM,
RateLevel::VERY_FAST, sAccelNormChecker);
}
// Test sensor event direct report with ashmem for gyro sensor at normal rate
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
sGyroNormChecker);
}
// Test sensor event direct report with ashmem for gyro sensor at fast rate
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
sGyroNormChecker);
}
// Test sensor event direct report with ashmem for gyro sensor at very fast rate
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
sGyroNormChecker);
}
// Test sensor event direct report with ashmem for mag sensor at normal rate
-TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
NullChecker());
}
// Test sensor event direct report with ashmem for mag sensor at fast rate
-TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
NullChecker());
}
// Test sensor event direct report with ashmem for mag sensor at very fast rate
-TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM,
RateLevel::VERY_FAST, NullChecker());
}
// Test sensor event direct report with gralloc for accel sensor at normal rate
-TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL,
sAccelNormChecker);
}
// Test sensor event direct report with gralloc for accel sensor at fast rate
-TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST,
sAccelNormChecker);
}
// Test sensor event direct report with gralloc for accel sensor at very fast rate
-TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC,
RateLevel::VERY_FAST, sAccelNormChecker);
}
// Test sensor event direct report with gralloc for gyro sensor at normal rate
-TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL,
sGyroNormChecker);
}
// Test sensor event direct report with gralloc for gyro sensor at fast rate
-TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
sGyroNormChecker);
}
// Test sensor event direct report with gralloc for gyro sensor at very fast rate
-TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
sGyroNormChecker);
}
// Test sensor event direct report with gralloc for mag sensor at normal rate
-TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL,
NullChecker());
}
// Test sensor event direct report with gralloc for mag sensor at fast rate
-TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST,
NullChecker());
}
// Test sensor event direct report with gralloc for mag sensor at very fast rate
-TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC,
RateLevel::VERY_FAST, NullChecker());
}
@@ -619,9 +627,13 @@
// Test that if initialize is called twice, then the HAL writes events to the FMQs from the second
// call to the function.
-TEST_F(SensorsHidlTest, CallInitializeTwice) {
+TEST_P(SensorsHidlTest, CallInitializeTwice) {
// Create a helper class so that a second environment is able to be instantiated
- class SensorsHidlEnvironmentTest : public SensorsHidlEnvironmentV2_0 {};
+ class SensorsHidlEnvironmentTest : public SensorsHidlEnvironmentV2_0 {
+ public:
+ SensorsHidlEnvironmentTest(const std::string& service_name)
+ : SensorsHidlEnvironmentV2_0(service_name) {}
+ };
if (getSensorsList().size() == 0) {
// No sensors
@@ -633,7 +645,7 @@
// Create a new environment that calls initialize()
std::unique_ptr<SensorsHidlEnvironmentTest> newEnv =
- std::make_unique<SensorsHidlEnvironmentTest>();
+ std::make_unique<SensorsHidlEnvironmentTest>(GetParam());
newEnv->HidlSetUp();
if (HasFatalFailure()) {
return; // Exit early if setting up the new environment failed
@@ -662,7 +674,7 @@
activateAllSensors(false);
}
-TEST_F(SensorsHidlTest, CleanupConnectionsOnInitialize) {
+TEST_P(SensorsHidlTest, CleanupConnectionsOnInitialize) {
activateAllSensors(true);
// Verify that events are received
@@ -731,7 +743,7 @@
}
}
-TEST_F(SensorsHidlTest, FlushSensor) {
+TEST_P(SensorsHidlTest, FlushSensor) {
// Find a sensor that is not a one-shot sensor
std::vector<SensorInfo> sensors = getNonOneShotSensors();
if (sensors.size() == 0) {
@@ -743,7 +755,7 @@
runFlushTest(sensors, true /* activateSensor */, kFlushes, kFlushes, Result::OK);
}
-TEST_F(SensorsHidlTest, FlushOneShotSensor) {
+TEST_P(SensorsHidlTest, FlushOneShotSensor) {
// Find a sensor that is a one-shot sensor
std::vector<SensorInfo> sensors = getOneShotSensors();
if (sensors.size() == 0) {
@@ -754,7 +766,7 @@
Result::BAD_VALUE);
}
-TEST_F(SensorsHidlTest, FlushInactiveSensor) {
+TEST_P(SensorsHidlTest, FlushInactiveSensor) {
// Attempt to find a non-one shot sensor, then a one-shot sensor if necessary
std::vector<SensorInfo> sensors = getNonOneShotSensors();
if (sensors.size() == 0) {
@@ -768,7 +780,7 @@
Result::BAD_VALUE);
}
-TEST_F(SensorsHidlTest, FlushNonexistentSensor) {
+TEST_P(SensorsHidlTest, FlushNonexistentSensor) {
SensorInfo sensor;
std::vector<SensorInfo> sensors = getNonOneShotSensors();
if (sensors.size() == 0) {
@@ -783,7 +795,7 @@
0 /* expectedFlushCount */, Result::BAD_VALUE);
}
-TEST_F(SensorsHidlTest, Batch) {
+TEST_P(SensorsHidlTest, Batch) {
if (getSensorsList().size() == 0) {
return;
}
@@ -815,7 +827,7 @@
Result::BAD_VALUE);
}
-TEST_F(SensorsHidlTest, Activate) {
+TEST_P(SensorsHidlTest, Activate) {
if (getSensorsList().size() == 0) {
return;
}
@@ -841,7 +853,7 @@
ASSERT_EQ(activate(invalidHandle, false), Result::BAD_VALUE);
}
-TEST_F(SensorsHidlTest, NoStaleEvents) {
+TEST_P(SensorsHidlTest, NoStaleEvents) {
constexpr milliseconds kFiveHundredMs(500);
constexpr milliseconds kOneSecond(1000);
@@ -1021,11 +1033,11 @@
}
}
-TEST_F(SensorsHidlTest, DirectChannelAshmem) {
+TEST_P(SensorsHidlTest, DirectChannelAshmem) {
verifyDirectChannel(SharedMemType::ASHMEM);
}
-TEST_F(SensorsHidlTest, DirectChannelGralloc) {
+TEST_P(SensorsHidlTest, DirectChannelGralloc) {
verifyDirectChannel(SharedMemType::GRALLOC);
}
@@ -1064,7 +1076,7 @@
return found;
}
-TEST_F(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) {
+TEST_P(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) {
SensorInfo sensor;
SharedMemType memType;
RateLevel rate;
@@ -1078,7 +1090,7 @@
});
}
-TEST_F(SensorsHidlTest, CleanupDirectConnectionOnInitialize) {
+TEST_P(SensorsHidlTest, CleanupDirectConnectionOnInitialize) {
constexpr size_t kNumEvents = 1;
constexpr size_t kMemSize = kNumEvents * kEventSize;
@@ -1124,12 +1136,8 @@
mDirectChannelHandles = handles;
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironmentV2_0::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- SensorsHidlEnvironmentV2_0::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(PerInstance, SensorsHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::sensors::V2_0::ISensors::descriptor)),
+ android::hardware::PrintInstanceNameToString);
// vim: set ts=2 sw=2
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp
index 02dc608..bb4d329 100644
--- a/sensors/common/vts/utils/Android.bp
+++ b/sensors/common/vts/utils/Android.bp
@@ -16,6 +16,7 @@
cc_library_static {
name: "VtsHalSensorsTargetTestUtils",
+ defaults: ["VtsHalTargetTestDefaults"],
cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
srcs: [
"GrallocWrapper.cpp",
@@ -36,6 +37,5 @@
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
"android.hardware.sensors@1.0",
- "VtsHalHidlTargetTestBase",
],
}
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
index 6499fba..dbc9392 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
@@ -17,9 +17,8 @@
#ifndef ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
#define ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
-#include <VtsHalHidlTargetTestEnvBase.h>
-
#include <android/hardware/sensors/1.0/types.h>
+#include <gtest/gtest.h>
#include <atomic>
#include <memory>
@@ -33,11 +32,11 @@
virtual void onEvent(const ::android::hardware::sensors::V1_0::Event& event) = 0;
};
-class SensorsHidlEnvironmentBase : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
+class SensorsHidlEnvironmentBase {
+ public:
using Event = ::android::hardware::sensors::V1_0::Event;
- virtual void HidlSetUp() override;
- virtual void HidlTearDown() override;
+ virtual void HidlSetUp();
+ virtual void HidlTearDown();
// Get and clear all events collected so far (like "cat" shell command).
// If output is nullptr, it clears all collected events.
@@ -50,22 +49,27 @@
void unregisterCallback();
protected:
- SensorsHidlEnvironmentBase() : mCollectionEnabled(false), mCallback(nullptr) {}
+ SensorsHidlEnvironmentBase(const std::string& service_name)
+ : mCollectionEnabled(false), mCallback(nullptr) {
+ mServiceName = service_name;
+ }
+ virtual ~SensorsHidlEnvironmentBase(){};
- void addEvent(const Event& ev);
+ void addEvent(const Event& ev);
- virtual void startPollingThread() = 0;
- virtual bool resetHal() = 0;
+ virtual void startPollingThread() = 0;
+ virtual bool resetHal() = 0;
- bool mCollectionEnabled;
- std::atomic_bool mStopThread;
- std::thread mPollThread;
- std::vector<Event> mEvents;
- std::mutex mEventsMutex;
+ std::string mServiceName;
+ bool mCollectionEnabled;
+ std::atomic_bool mStopThread;
+ std::thread mPollThread;
+ std::vector<Event> mEvents;
+ std::mutex mEventsMutex;
- IEventCallback* mCallback;
+ IEventCallback* mCallback;
- GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentBase);
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentBase);
};
#endif // ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
\ No newline at end of file
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
index 6fd9a2b..5fb6c5c 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
@@ -23,6 +23,7 @@
#include <VtsHalHidlTargetTestBase.h>
#include <android/hardware/sensors/1.0/ISensors.h>
#include <android/hardware/sensors/1.0/types.h>
+#include <gtest/gtest.h>
#include <unordered_set>
#include <vector>
@@ -44,8 +45,8 @@
using ::android::hardware::sensors::V1_0::SharedMemInfo;
using ::android::hardware::sensors::V1_0::SharedMemType;
-class SensorsHidlTestBase : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class SensorsHidlTestBase : public testing::TestWithParam<std::string> {
+ public:
virtual SensorsHidlEnvironmentBase* getEnvironment() = 0;
virtual void SetUp() override {}
diff --git a/soundtrigger/2.3/Android.bp b/soundtrigger/2.3/Android.bp
new file mode 100644
index 0000000..3253a86
--- /dev/null
+++ b/soundtrigger/2.3/Android.bp
@@ -0,0 +1,22 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.soundtrigger@2.3",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "ISoundTriggerHw.hal",
+ ],
+ interfaces: [
+ "android.hardware.audio.common@2.0",
+ "android.hardware.soundtrigger@2.0",
+ "android.hardware.soundtrigger@2.1",
+ "android.hardware.soundtrigger@2.2",
+ "android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/soundtrigger/2.3/ISoundTriggerHw.hal b/soundtrigger/2.3/ISoundTriggerHw.hal
new file mode 100644
index 0000000..207b9b7
--- /dev/null
+++ b/soundtrigger/2.3/ISoundTriggerHw.hal
@@ -0,0 +1,87 @@
+/*
+ * 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.soundtrigger@2.3;
+
+import @2.0::SoundModelHandle;
+import @2.2::ISoundTriggerHw;
+
+/**
+ * SoundTrigger HAL interface. Used for hardware recognition of hotwords
+ * and other sounds.
+ */
+interface ISoundTriggerHw extends @2.2::ISoundTriggerHw {
+
+ /**
+ * Set a model specific parameter with the given value. This parameter
+ * will keep its value for the duration the model is loaded regardless of starting and stopping
+ * recognition. Once the model is unloaded, the value will be lost.
+ * It is expected to check if the handle supports the parameter via the queryParameter
+ * API prior to calling this method.
+ *
+ * @param modelHandle The sound model handle indicating which model to modify parameters
+ * @param modelParam Parameter to set which will be validated against the
+ * ModelParameter type. Not putting ModelParameter type
+ * directly in the definition and validating internally
+ * allows for forward compatibility.
+ * @param value The value to set for the given model parameter
+ * @return status Operation completion status: 0 in case of success,
+ * -ENODEV if the native service cannot be reached
+ * -EINVAL invalid input parameter
+ */
+ setParameter(SoundModelHandle modelHandle, ModelParameter modelParam, int32_t value)
+ generates (int32_t status);
+
+ /**
+ * Get a model specific parameter. This parameter will keep its value
+ * for the duration the model is loaded regardless of starting and stopping recognition.
+ * Once the model is unloaded, the value will be lost. If the value is not set, a default
+ * value is returned. See ModelParameter for parameter default values.
+ * It is expected to check if the handle supports the parameter via the queryParameter
+ * API prior to calling this method.
+ *
+ * @param modelHandle The sound model associated with given modelParam
+ * @param modelParam Parameter to set which will be validated against the
+ * ModelParameter type. Not putting ModelParameter type
+ * directly in the definition and validating internally
+ * allows for forward compatibility.
+ * @return status Operation completion status: 0 in case of success,
+ * -ENODEV if the native service cannot be reached
+ * -EINVAL invalid input parameter
+ * @return value Value set to the requested parameter. Value is only set when status
+ * indicates success.
+ */
+ getParameter(SoundModelHandle modelHandle, ModelParameter modelParam)
+ generates (int32_t status, int32_t value);
+
+ /**
+ * Get supported parameter attributes with respect to the provided model
+ * handle. Along with determining the valid range, this API is also used
+ * to determine if a given parameter ID is supported at all by the
+ * modelHandle for use with getParameter and setParameter APIs.
+ *
+ * @param modelHandle The sound model handle indicating which model to query
+ * @param modelParam Parameter to set which will be validated against the
+ * ModelParameter type
+ * @return status Operation completion status: 0 in case of success
+ * -ENODEV if the native service cannot be reached
+ * -EINVAL invalid input parameter
+ * @return retval ModelParameter structure indicating supported attributes
+ * of the parameter for the given model handle
+ */
+ queryParameter(SoundModelHandle modelHandle, ModelParameter modelParam)
+ generates (int32_t status, OptionalModelParameterRange retval);
+};
diff --git a/soundtrigger/2.3/default/Android.bp b/soundtrigger/2.3/default/Android.bp
new file mode 100644
index 0000000..be2c8b0
--- /dev/null
+++ b/soundtrigger/2.3/default/Android.bp
@@ -0,0 +1,37 @@
+//
+// 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_shared {
+ name: "android.hardware.soundtrigger@2.3-impl",
+ relative_install_path: "hw",
+ vendor: true,
+ srcs: [
+ "SoundTriggerHw.cpp",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "liblog",
+ "libhidlmemory",
+ "libutils",
+ "libhardware",
+ "android.hardware.soundtrigger@2.0",
+ "android.hardware.soundtrigger@2.0-core",
+ "android.hardware.soundtrigger@2.1",
+ "android.hardware.soundtrigger@2.2",
+ "android.hardware.soundtrigger@2.3",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ ],
+}
diff --git a/soundtrigger/2.3/default/SoundTriggerHw.cpp b/soundtrigger/2.3/default/SoundTriggerHw.cpp
new file mode 100644
index 0000000..4a39ab5
--- /dev/null
+++ b/soundtrigger/2.3/default/SoundTriggerHw.cpp
@@ -0,0 +1,804 @@
+/*
+ * 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 "SoundTriggerHw"
+
+#include "SoundTriggerHw.h"
+
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/log.h>
+#include <hidlmemory/mapping.h>
+#include <utility>
+
+using android::hardware::hidl_memory;
+using android::hidl::allocator::V1_0::IAllocator;
+using android::hidl::memory::V1_0::IMemory;
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_3 {
+namespace implementation {
+
+/**
+ * According to the HIDL C++ Users Guide: client and server implementations
+ * should never directly refer to anything other than the interface header
+ * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so
+ * this V2_3 implementation copies the previous implementations and
+ * then adds the new implementation.
+ */
+
+// Begin V2_0 implementation, copied from
+// hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
+
+// static
+void soundModelCallback_(struct sound_trigger_model_event* halEvent, void* cookie) {
+ if (halEvent == NULL) {
+ ALOGW("soundModelCallback called with NULL event");
+ return;
+ }
+ sp<SoundTriggerHw::SoundModelClient> client =
+ wp<SoundTriggerHw::SoundModelClient>(
+ static_cast<SoundTriggerHw::SoundModelClient*>(cookie))
+ .promote();
+ if (client == 0) {
+ ALOGW("soundModelCallback called on stale client");
+ return;
+ }
+ if (halEvent->model != client->getHalHandle()) {
+ ALOGW("soundModelCallback call with wrong handle %d on client with handle %d",
+ (int)halEvent->model, (int)client->getHalHandle());
+ return;
+ }
+
+ client->soundModelCallback(halEvent);
+}
+
+// static
+void recognitionCallback_(struct sound_trigger_recognition_event* halEvent, void* cookie) {
+ if (halEvent == NULL) {
+ ALOGW("recognitionCallback call NULL event");
+ return;
+ }
+ sp<SoundTriggerHw::SoundModelClient> client =
+ wp<SoundTriggerHw::SoundModelClient>(
+ static_cast<SoundTriggerHw::SoundModelClient*>(cookie))
+ .promote();
+ if (client == 0) {
+ ALOGW("recognitionCallback called on stale client");
+ return;
+ }
+
+ client->recognitionCallback(halEvent);
+}
+
+Return<void> SoundTriggerHw::getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb) {
+ ALOGV("getProperties() mHwDevice %p", mHwDevice);
+ int ret;
+ struct sound_trigger_properties halProperties;
+ ISoundTriggerHw::Properties properties;
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ ret = mHwDevice->get_properties(mHwDevice, &halProperties);
+
+ convertPropertiesFromHal(&properties, &halProperties);
+
+ ALOGV("getProperties implementor %s recognitionModes %08x", properties.implementor.c_str(),
+ properties.recognitionModes);
+
+exit:
+ _hidl_cb(ret, properties);
+ return Void();
+}
+
+int SoundTriggerHw::doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+ sp<SoundTriggerHw::SoundModelClient> client) {
+ int32_t ret = 0;
+ struct sound_trigger_sound_model* halSoundModel;
+
+ ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size());
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ halSoundModel = convertSoundModelToHal(&soundModel);
+ if (halSoundModel == NULL) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ sound_model_handle_t halHandle;
+ ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback_, client.get(),
+ &halHandle);
+
+ free(halSoundModel);
+
+ if (ret != 0) {
+ goto exit;
+ }
+
+ client->setHalHandle(halHandle);
+ {
+ AutoMutex lock(mLock);
+ mClients.add(client->getId(), client);
+ }
+
+exit:
+ return ret;
+}
+
+Return<void> SoundTriggerHw::loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+ const sp<V2_0::ISoundTriggerHwCallback>& callback,
+ V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,
+ ISoundTriggerHw::loadSoundModel_cb _hidl_cb) {
+ sp<SoundTriggerHw::SoundModelClient> client =
+ new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
+ _hidl_cb(doLoadSoundModel(soundModel, client), client->getId());
+ return Void();
+}
+
+Return<void> SoundTriggerHw::loadPhraseSoundModel(
+ const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<V2_0::ISoundTriggerHwCallback>& callback,
+ V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,
+ ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb) {
+ sp<SoundTriggerHw::SoundModelClient> client =
+ new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
+ _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel, client),
+ client->getId());
+ return Void();
+}
+
+Return<int32_t> SoundTriggerHw::unloadSoundModel(int32_t modelHandle) {
+ int32_t ret;
+ sp<SoundTriggerHw::SoundModelClient> client;
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ ret = -ENOSYS;
+ goto exit;
+ }
+ }
+
+ ret = mHwDevice->unload_sound_model(mHwDevice, client->getHalHandle());
+
+ mClients.removeItem(modelHandle);
+
+exit:
+ return ret;
+}
+
+Return<int32_t> SoundTriggerHw::startRecognition(
+ int32_t modelHandle, const V2_0::ISoundTriggerHw::RecognitionConfig& config,
+ const sp<V2_0::ISoundTriggerHwCallback>& /* callback */, int32_t /* cookie */) {
+ int32_t ret;
+ sp<SoundTriggerHw::SoundModelClient> client;
+ struct sound_trigger_recognition_config* halConfig;
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ ret = -ENOSYS;
+ goto exit;
+ }
+ }
+
+ halConfig =
+ convertRecognitionConfigToHal((const V2_0::ISoundTriggerHw::RecognitionConfig*)&config);
+
+ if (halConfig == NULL) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ ret = mHwDevice->start_recognition(mHwDevice, client->getHalHandle(), halConfig,
+ recognitionCallback_, client.get());
+
+ free(halConfig);
+
+exit:
+ return ret;
+}
+
+Return<int32_t> SoundTriggerHw::stopRecognition(int32_t modelHandle) {
+ int32_t ret;
+ sp<SoundTriggerHw::SoundModelClient> client;
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ ret = -ENOSYS;
+ goto exit;
+ }
+ }
+
+ ret = mHwDevice->stop_recognition(mHwDevice, client->getHalHandle());
+
+exit:
+ return ret;
+}
+
+Return<int32_t> SoundTriggerHw::stopAllRecognitions() {
+ int32_t ret;
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ ret = mHwDevice->stop_all_recognitions(mHwDevice);
+
+exit:
+ return ret;
+}
+
+SoundTriggerHw::SoundTriggerHw() : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1) {}
+
+void SoundTriggerHw::onFirstRef() {
+ const hw_module_t* mod;
+ int rc;
+
+ rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod);
+ if (rc != 0) {
+ ALOGE("couldn't load sound trigger module %s.%s (%s)", SOUND_TRIGGER_HARDWARE_MODULE_ID,
+ mModuleName, strerror(-rc));
+ return;
+ }
+ rc = sound_trigger_hw_device_open(mod, &mHwDevice);
+ if (rc != 0) {
+ ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
+ SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
+ mHwDevice = NULL;
+ return;
+ }
+ if (mHwDevice->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_1_3) {
+ ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version);
+ sound_trigger_hw_device_close(mHwDevice);
+ mHwDevice = NULL;
+ return;
+ }
+
+ ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice);
+}
+
+SoundTriggerHw::~SoundTriggerHw() {
+ if (mHwDevice != NULL) {
+ sound_trigger_hw_device_close(mHwDevice);
+ }
+}
+
+uint32_t SoundTriggerHw::nextUniqueModelId() {
+ uint32_t modelId = 0;
+ {
+ AutoMutex lock(mLock);
+ do {
+ modelId = atomic_fetch_add_explicit(&mNextModelId, (uint_fast32_t)1,
+ memory_order_acq_rel);
+ } while (mClients.valueFor(modelId) != 0 && modelId != 0);
+ }
+ LOG_ALWAYS_FATAL_IF(modelId == 0, "wrap around in sound model IDs, num loaded models %zu",
+ mClients.size());
+ return modelId;
+}
+
+void SoundTriggerHw::convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid) {
+ uuid->timeLow = halUuid->timeLow;
+ uuid->timeMid = halUuid->timeMid;
+ uuid->versionAndTimeHigh = halUuid->timeHiAndVersion;
+ uuid->variantAndClockSeqHigh = halUuid->clockSeq;
+ memcpy(&uuid->node[0], &halUuid->node[0], 6);
+}
+
+void SoundTriggerHw::convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid) {
+ halUuid->timeLow = uuid->timeLow;
+ halUuid->timeMid = uuid->timeMid;
+ halUuid->timeHiAndVersion = uuid->versionAndTimeHigh;
+ halUuid->clockSeq = uuid->variantAndClockSeqHigh;
+ memcpy(&halUuid->node[0], &uuid->node[0], 6);
+}
+
+void SoundTriggerHw::convertPropertiesFromHal(
+ ISoundTriggerHw::Properties* properties,
+ const struct sound_trigger_properties* halProperties) {
+ properties->implementor = halProperties->implementor;
+ properties->description = halProperties->description;
+ properties->version = halProperties->version;
+ convertUuidFromHal(&properties->uuid, &halProperties->uuid);
+ properties->maxSoundModels = halProperties->max_sound_models;
+ properties->maxKeyPhrases = halProperties->max_key_phrases;
+ properties->maxUsers = halProperties->max_users;
+ properties->recognitionModes = halProperties->recognition_modes;
+ properties->captureTransition = halProperties->capture_transition;
+ properties->maxBufferMs = halProperties->max_buffer_ms;
+ properties->concurrentCapture = halProperties->concurrent_capture;
+ properties->triggerInEvent = halProperties->trigger_in_event;
+ properties->powerConsumptionMw = halProperties->power_consumption_mw;
+}
+
+void SoundTriggerHw::convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
+ const ISoundTriggerHw::Phrase* triggerPhrase) {
+ halTriggerPhrase->id = triggerPhrase->id;
+ halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes;
+ unsigned int i;
+
+ halTriggerPhrase->num_users =
+ std::min((int)triggerPhrase->users.size(), SOUND_TRIGGER_MAX_USERS);
+ for (i = 0; i < halTriggerPhrase->num_users; i++) {
+ halTriggerPhrase->users[i] = triggerPhrase->users[i];
+ }
+
+ strlcpy(halTriggerPhrase->locale, triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN);
+ strlcpy(halTriggerPhrase->text, triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
+}
+
+struct sound_trigger_sound_model* SoundTriggerHw::convertSoundModelToHal(
+ const V2_0::ISoundTriggerHw::SoundModel* soundModel) {
+ struct sound_trigger_sound_model* halModel = NULL;
+ if (soundModel->type == V2_0::SoundModelType::KEYPHRASE) {
+ size_t allocSize =
+ sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size();
+ struct sound_trigger_phrase_sound_model* halKeyPhraseModel =
+ static_cast<struct sound_trigger_phrase_sound_model*>(malloc(allocSize));
+ LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL,
+ "malloc failed for size %zu in convertSoundModelToHal PHRASE",
+ allocSize);
+
+ const V2_0::ISoundTriggerHw::PhraseSoundModel* keyPhraseModel =
+ reinterpret_cast<const V2_0::ISoundTriggerHw::PhraseSoundModel*>(soundModel);
+
+ size_t i;
+ for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
+ convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i], &keyPhraseModel->phrases[i]);
+ }
+ halKeyPhraseModel->num_phrases = (unsigned int)i;
+ halModel = reinterpret_cast<struct sound_trigger_sound_model*>(halKeyPhraseModel);
+ halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model);
+ } else {
+ size_t allocSize = sizeof(struct sound_trigger_sound_model) + soundModel->data.size();
+ halModel = static_cast<struct sound_trigger_sound_model*>(malloc(allocSize));
+ LOG_ALWAYS_FATAL_IF(halModel == NULL,
+ "malloc failed for size %zu in convertSoundModelToHal GENERIC",
+ allocSize);
+
+ halModel->data_offset = sizeof(struct sound_trigger_sound_model);
+ }
+ halModel->type = (sound_trigger_sound_model_type_t)soundModel->type;
+ convertUuidToHal(&halModel->uuid, &soundModel->uuid);
+ convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid);
+ halModel->data_size = soundModel->data.size();
+ uint8_t* dst = reinterpret_cast<uint8_t*>(halModel) + halModel->data_offset;
+ const uint8_t* src = reinterpret_cast<const uint8_t*>(&soundModel->data[0]);
+ memcpy(dst, src, soundModel->data.size());
+
+ return halModel;
+}
+
+void SoundTriggerHw::convertPhraseRecognitionExtraToHal(
+ struct sound_trigger_phrase_recognition_extra* halExtra,
+ const V2_0::PhraseRecognitionExtra* extra) {
+ halExtra->id = extra->id;
+ halExtra->recognition_modes = extra->recognitionModes;
+ halExtra->confidence_level = extra->confidenceLevel;
+
+ unsigned int i;
+ for (i = 0; i < extra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) {
+ halExtra->levels[i].user_id = extra->levels[i].userId;
+ halExtra->levels[i].level = extra->levels[i].levelPercent;
+ }
+ halExtra->num_levels = i;
+}
+
+struct sound_trigger_recognition_config* SoundTriggerHw::convertRecognitionConfigToHal(
+ const V2_0::ISoundTriggerHw::RecognitionConfig* config) {
+ size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size();
+ struct sound_trigger_recognition_config* halConfig =
+ static_cast<struct sound_trigger_recognition_config*>(malloc(allocSize));
+
+ LOG_ALWAYS_FATAL_IF(halConfig == NULL,
+ "malloc failed for size %zu in convertRecognitionConfigToHal", allocSize);
+
+ halConfig->capture_handle = (audio_io_handle_t)config->captureHandle;
+ halConfig->capture_device = (audio_devices_t)config->captureDevice;
+ halConfig->capture_requested = config->captureRequested;
+
+ unsigned int i;
+ for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
+ convertPhraseRecognitionExtraToHal(&halConfig->phrases[i], &config->phrases[i]);
+ }
+ halConfig->num_phrases = i;
+
+ halConfig->data_offset = sizeof(struct sound_trigger_recognition_config);
+ halConfig->data_size = config->data.size();
+ uint8_t* dst = reinterpret_cast<uint8_t*>(halConfig) + halConfig->data_offset;
+ const uint8_t* src = reinterpret_cast<const uint8_t*>(&config->data[0]);
+ memcpy(dst, src, config->data.size());
+ return halConfig;
+}
+
+// static
+void SoundTriggerHw::convertSoundModelEventFromHal(
+ V2_0::ISoundTriggerHwCallback::ModelEvent* event,
+ const struct sound_trigger_model_event* halEvent) {
+ event->status = (V2_0::ISoundTriggerHwCallback::SoundModelStatus)halEvent->status;
+ // event->model to be remapped by called
+ event->data.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) +
+ halEvent->data_offset,
+ halEvent->data_size);
+}
+
+// static
+void SoundTriggerHw::convertPhaseRecognitionEventFromHal(
+ V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
+ const struct sound_trigger_phrase_recognition_event* halEvent) {
+ event->phraseExtras.resize(halEvent->num_phrases);
+ for (unsigned int i = 0; i < halEvent->num_phrases; i++) {
+ convertPhraseRecognitionExtraFromHal(&event->phraseExtras[i], &halEvent->phrase_extras[i]);
+ }
+ convertRecognitionEventFromHal(&event->common, &halEvent->common);
+}
+
+// static
+void SoundTriggerHw::convertRecognitionEventFromHal(
+ V2_0::ISoundTriggerHwCallback::RecognitionEvent* event,
+ const struct sound_trigger_recognition_event* halEvent) {
+ event->status = static_cast<V2_0::ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status);
+ event->type = static_cast<V2_0::SoundModelType>(halEvent->type);
+ // event->model to be remapped by called
+ event->captureAvailable = halEvent->capture_available;
+ event->captureSession = halEvent->capture_session;
+ event->captureDelayMs = halEvent->capture_delay_ms;
+ event->capturePreambleMs = halEvent->capture_preamble_ms;
+ event->triggerInData = halEvent->trigger_in_data;
+ event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate;
+ event->audioConfig.channelMask =
+ (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask;
+ event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format;
+ event->data.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) +
+ halEvent->data_offset,
+ halEvent->data_size);
+}
+
+// static
+void SoundTriggerHw::convertPhraseRecognitionExtraFromHal(
+ V2_0::PhraseRecognitionExtra* extra,
+ const struct sound_trigger_phrase_recognition_extra* halExtra) {
+ extra->id = halExtra->id;
+ extra->recognitionModes = halExtra->recognition_modes;
+ extra->confidenceLevel = halExtra->confidence_level;
+
+ extra->levels.resize(halExtra->num_levels);
+ for (unsigned int i = 0; i < halExtra->num_levels; i++) {
+ extra->levels[i].userId = halExtra->levels[i].user_id;
+ extra->levels[i].levelPercent = halExtra->levels[i].level;
+ }
+}
+
+void SoundTriggerHw::SoundModelClient_2_0::recognitionCallback(
+ struct sound_trigger_recognition_event* halEvent) {
+ if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event;
+ convertPhaseRecognitionEventFromHal(
+ &event, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
+ event.common.model = mId;
+ mCallback->phraseRecognitionCallback(event, mCookie);
+ } else {
+ V2_0::ISoundTriggerHwCallback::RecognitionEvent event;
+ convertRecognitionEventFromHal(&event, halEvent);
+ event.model = mId;
+ mCallback->recognitionCallback(event, mCookie);
+ }
+}
+
+void SoundTriggerHw::SoundModelClient_2_0::soundModelCallback(
+ struct sound_trigger_model_event* halEvent) {
+ V2_0::ISoundTriggerHwCallback::ModelEvent event;
+ convertSoundModelEventFromHal(&event, halEvent);
+ event.model = mId;
+ mCallback->soundModelCallback(event, mCookie);
+}
+
+// Begin V2_1 implementation, copied from
+// hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.cpp
+
+namespace {
+
+// Backs up by the vector with the contents of shared memory.
+// It is assumed that the passed hidl_vector is empty, so it's
+// not cleared if the memory is a null object.
+// The caller needs to keep the returned sp<IMemory> as long as
+// the data is needed.
+std::pair<bool, sp<IMemory>> memoryAsVector(const hidl_memory& m, hidl_vec<uint8_t>* vec) {
+ sp<IMemory> memory;
+ if (m.size() == 0) {
+ return std::make_pair(true, memory);
+ }
+ memory = mapMemory(m);
+ if (memory != nullptr) {
+ memory->read();
+ vec->setToExternal(static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())),
+ memory->getSize());
+ return std::make_pair(true, memory);
+ }
+ ALOGE("%s: Could not map HIDL memory to IMemory", __func__);
+ return std::make_pair(false, memory);
+}
+
+// Moves the data from the vector into allocated shared memory,
+// emptying the vector.
+// It is assumed that the passed hidl_memory is a null object, so it's
+// not reset if the vector is empty.
+// The caller needs to keep the returned sp<IMemory> as long as
+// the data is needed.
+std::pair<bool, sp<IMemory>> moveVectorToMemory(hidl_vec<uint8_t>* v, hidl_memory* mem) {
+ sp<IMemory> memory;
+ if (v->size() == 0) {
+ return std::make_pair(true, memory);
+ }
+ sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+ if (ashmem == 0) {
+ ALOGE("Failed to retrieve ashmem allocator service");
+ return std::make_pair(false, memory);
+ }
+ bool success = false;
+ Return<void> r = ashmem->allocate(v->size(), [&](bool s, const hidl_memory& m) {
+ success = s;
+ if (success) *mem = m;
+ });
+ if (r.isOk() && success) {
+ memory = hardware::mapMemory(*mem);
+ if (memory != 0) {
+ memory->update();
+ memcpy(memory->getPointer(), v->data(), v->size());
+ memory->commit();
+ v->resize(0);
+ return std::make_pair(true, memory);
+ } else {
+ ALOGE("Failed to map allocated ashmem");
+ }
+ } else {
+ ALOGE("Failed to allocate %llu bytes from ashmem", (unsigned long long)v->size());
+ }
+ return std::make_pair(false, memory);
+}
+
+} // namespace
+
+Return<void> SoundTriggerHw::loadSoundModel_2_1(
+ const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+ V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb) {
+ // It is assumed that legacy data vector is empty, thus making copy is cheap.
+ V2_0::ISoundTriggerHw::SoundModel soundModel_2_0(soundModel.header);
+ auto result = memoryAsVector(soundModel.data, &soundModel_2_0.data);
+ if (result.first) {
+ sp<SoundModelClient> client =
+ new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
+ _hidl_cb(doLoadSoundModel(soundModel_2_0, client), client->getId());
+ return Void();
+ }
+ _hidl_cb(-ENOMEM, 0);
+ return Void();
+}
+
+Return<void> SoundTriggerHw::loadPhraseSoundModel_2_1(
+ const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+ V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb) {
+ V2_0::ISoundTriggerHw::PhraseSoundModel soundModel_2_0;
+ // It is assumed that legacy data vector is empty, thus making copy is cheap.
+ soundModel_2_0.common = soundModel.common.header;
+ // Avoid copying phrases data.
+ soundModel_2_0.phrases.setToExternal(
+ const_cast<V2_0::ISoundTriggerHw::Phrase*>(soundModel.phrases.data()),
+ soundModel.phrases.size());
+ auto result = memoryAsVector(soundModel.common.data, &soundModel_2_0.common.data);
+ if (result.first) {
+ sp<SoundModelClient> client =
+ new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
+ _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel_2_0, client),
+ client->getId());
+ return Void();
+ }
+ _hidl_cb(-ENOMEM, 0);
+ return Void();
+}
+
+Return<int32_t> SoundTriggerHw::startRecognition_2_1(
+ int32_t modelHandle, const V2_1::ISoundTriggerHw::RecognitionConfig& config,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie) {
+ // It is assumed that legacy data vector is empty, thus making copy is cheap.
+ V2_0::ISoundTriggerHw::RecognitionConfig config_2_0(config.header);
+ auto result = memoryAsVector(config.data, &config_2_0.data);
+ return result.first ? startRecognition(modelHandle, config_2_0, callback, cookie)
+ : Return<int32_t>(-ENOMEM);
+}
+
+void SoundTriggerHw::SoundModelClient_2_1::recognitionCallback(
+ struct sound_trigger_recognition_event* halEvent) {
+ if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event_2_0;
+ convertPhaseRecognitionEventFromHal(
+ &event_2_0, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
+ event_2_0.common.model = mId;
+ V2_1::ISoundTriggerHwCallback::PhraseRecognitionEvent event;
+ event.phraseExtras.setToExternal(event_2_0.phraseExtras.data(),
+ event_2_0.phraseExtras.size());
+ auto result = moveVectorToMemory(&event_2_0.common.data, &event.common.data);
+ if (result.first) {
+ // The data vector is now empty, thus copying is cheap.
+ event.common.header = event_2_0.common;
+ mCallback->phraseRecognitionCallback_2_1(event, mCookie);
+ }
+ } else {
+ V2_1::ISoundTriggerHwCallback::RecognitionEvent event;
+ convertRecognitionEventFromHal(&event.header, halEvent);
+ event.header.model = mId;
+ auto result = moveVectorToMemory(&event.header.data, &event.data);
+ if (result.first) {
+ mCallback->recognitionCallback_2_1(event, mCookie);
+ }
+ }
+}
+
+void SoundTriggerHw::SoundModelClient_2_1::soundModelCallback(
+ struct sound_trigger_model_event* halEvent) {
+ V2_1::ISoundTriggerHwCallback::ModelEvent event;
+ convertSoundModelEventFromHal(&event.header, halEvent);
+ event.header.model = mId;
+ auto result = moveVectorToMemory(&event.header.data, &event.data);
+ if (result.first) {
+ mCallback->soundModelCallback_2_1(event, mCookie);
+ }
+}
+
+// Begin V2_2 implementation, copied from
+// hardware/interfaces/soundtrigger/2.2/default/SoundTriggerHw.cpp
+
+Return<int32_t> SoundTriggerHw::getModelState(int32_t modelHandle) {
+ sp<SoundModelClient> client;
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ return -ENOSYS;
+ }
+ }
+
+ return mHwDevice->get_model_state(mHwDevice, client->getHalHandle());
+}
+
+// Begin V2_3 implementation
+
+Return<int32_t> SoundTriggerHw::setParameter(V2_0::SoundModelHandle modelHandle,
+ ModelParameter modelParam, int32_t value) {
+ sp<SoundModelClient> client;
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ return -EINVAL;
+ }
+ }
+
+ return mHwDevice->set_parameter(mHwDevice, client->getHalHandle(),
+ convertModelParameterToHal(modelParam), value);
+}
+
+Return<void> SoundTriggerHw::getParameter(V2_0::SoundModelHandle modelHandle,
+ ModelParameter modelParam, getParameter_cb _hidl_cb) {
+ sp<SoundModelClient> client;
+ if (mHwDevice == NULL) {
+ _hidl_cb(-ENODEV, 0);
+ return Void();
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ _hidl_cb(-EINVAL, 0);
+ return Void();
+ }
+ }
+
+ int32_t value;
+ int32_t status = mHwDevice->get_parameter(mHwDevice, client->getHalHandle(),
+ convertModelParameterToHal(modelParam), &value);
+ _hidl_cb(status, value);
+ return Void();
+}
+
+Return<void> SoundTriggerHw::queryParameter(V2_0::SoundModelHandle modelHandle,
+ ModelParameter modelParam, queryParameter_cb _hidl_cb) {
+ OptionalModelParameterRange optionalParamRange;
+ sp<SoundModelClient> client;
+ if (mHwDevice == NULL) {
+ _hidl_cb(-ENODEV, optionalParamRange);
+ return Void();
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ _hidl_cb(-EINVAL, optionalParamRange);
+ return Void();
+ }
+ }
+
+ sound_trigger_model_parameter_range_t paramRange;
+ int32_t status = mHwDevice->query_parameter(
+ mHwDevice, client->getHalHandle(), convertModelParameterToHal(modelParam), ¶mRange);
+
+ if (status == 0) {
+ optionalParamRange.range({.start = paramRange.start, .end = paramRange.end});
+ }
+ _hidl_cb(status, optionalParamRange);
+ return Void();
+}
+
+// static
+sound_trigger_model_parameter_t SoundTriggerHw::convertModelParameterToHal(ModelParameter param) {
+ switch (param) {
+ case ModelParameter::THRESHOLD_FACTOR:
+ return MODEL_PARAMETER_THRESHOLD_FACTOR;
+ case ModelParameter::INVALID:
+ default:
+ return MODEL_PARAMETER_INVALID;
+ }
+}
+
+// Methods from ::android::hidl::base::V1_0::IBase follow.
+
+ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* /* name */) {
+ return new SoundTriggerHw();
+}
+
+} // namespace implementation
+} // namespace V2_3
+} // namespace soundtrigger
+} // namespace hardware
+} // namespace android
diff --git a/soundtrigger/2.3/default/SoundTriggerHw.h b/soundtrigger/2.3/default/SoundTriggerHw.h
new file mode 100644
index 0000000..c82c9ea
--- /dev/null
+++ b/soundtrigger/2.3/default/SoundTriggerHw.h
@@ -0,0 +1,207 @@
+/*
+ * 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_SOUNDTRIGGER_V2_3_SOUNDTRIGGERHW_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_V2_3_SOUNDTRIGGERHW_H
+
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
+#include <android/hardware/soundtrigger/2.3/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.3/types.h>
+#include <hardware/sound_trigger.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <stdatomic.h>
+#include <system/sound_trigger.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_3 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V2_0::Uuid;
+
+/**
+ * According to the HIDL C++ Users Guide: client and server implementations
+ * should never directly refer to anything other than the interface header
+ * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so
+ * this V2_3 implementation copies the previous implementations and
+ * then adds the new implementation.
+ */
+struct SoundTriggerHw : public ISoundTriggerHw {
+ // Methods from V2_0::ISoundTriggerHw follow.
+ Return<void> getProperties(getProperties_cb _hidl_cb) override;
+ Return<void> loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+ const sp<V2_0::ISoundTriggerHwCallback>& callback, int32_t cookie,
+ loadSoundModel_cb _hidl_cb) override;
+ Return<void> loadPhraseSoundModel(const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<V2_0::ISoundTriggerHwCallback>& callback,
+ int32_t cookie, loadPhraseSoundModel_cb _hidl_cb) override;
+ Return<int32_t> unloadSoundModel(int32_t modelHandle) override;
+ Return<int32_t> startRecognition(int32_t modelHandle,
+ const V2_0::ISoundTriggerHw::RecognitionConfig& config,
+ const sp<V2_0::ISoundTriggerHwCallback>& callback,
+ int32_t cookie) override;
+ Return<int32_t> stopRecognition(int32_t modelHandle) override;
+ Return<int32_t> stopAllRecognitions() override;
+
+ // Methods from V2_1::ISoundTriggerHw follow.
+ Return<void> loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback,
+ int32_t cookie, loadSoundModel_2_1_cb _hidl_cb) override;
+ Return<void> loadPhraseSoundModel_2_1(const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback,
+ int32_t cookie,
+ loadPhraseSoundModel_2_1_cb _hidl_cb) override;
+ Return<int32_t> startRecognition_2_1(int32_t modelHandle,
+ const V2_1::ISoundTriggerHw::RecognitionConfig& config,
+ const sp<V2_1::ISoundTriggerHwCallback>& callback,
+ int32_t cookie) override;
+
+ // Methods from V2_2::ISoundTriggerHw follow.
+ Return<int32_t> getModelState(int32_t modelHandle) override;
+
+ // Methods from V2_3::ISoundTriggerHw follow.
+ Return<int32_t> setParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam,
+ int32_t value) override;
+ Return<void> getParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam,
+ ISoundTriggerHw::getParameter_cb _hidl_cb) override;
+ Return<void> queryParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam,
+ ISoundTriggerHw::queryParameter_cb _hidl_cb) override;
+
+ SoundTriggerHw();
+
+ // Copied from hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.h
+
+ /**
+ * Client object holding active handles and callback sctructures. Used for referencing
+ * which models map to which client of the HAL. SoundModelClients are stored in the
+ * mClients object while the model is active.
+ */
+ class SoundModelClient : public RefBase {
+ public:
+ SoundModelClient(uint32_t id, V2_0::ISoundTriggerHwCallback::CallbackCookie cookie)
+ : mId(id), mCookie(cookie) {}
+ virtual ~SoundModelClient() {}
+
+ uint32_t getId() const { return mId; }
+ sound_model_handle_t getHalHandle() const { return mHalHandle; }
+ void setHalHandle(sound_model_handle_t handle) { mHalHandle = handle; }
+
+ virtual void recognitionCallback(struct sound_trigger_recognition_event* halEvent) = 0;
+ virtual void soundModelCallback(struct sound_trigger_model_event* halEvent) = 0;
+
+ protected:
+ const uint32_t mId;
+ sound_model_handle_t mHalHandle;
+ V2_0::ISoundTriggerHwCallback::CallbackCookie mCookie;
+ };
+
+ private:
+ static void convertPhaseRecognitionEventFromHal(
+ V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
+ const struct sound_trigger_phrase_recognition_event* halEvent);
+ static void convertRecognitionEventFromHal(
+ V2_0::ISoundTriggerHwCallback::RecognitionEvent* event,
+ const struct sound_trigger_recognition_event* halEvent);
+ static void convertSoundModelEventFromHal(V2_0::ISoundTriggerHwCallback::ModelEvent* event,
+ const struct sound_trigger_model_event* halEvent);
+
+ virtual ~SoundTriggerHw();
+
+ uint32_t nextUniqueModelId();
+ int doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+ sp<SoundModelClient> client);
+
+ // RefBase
+ void onFirstRef() override;
+
+ class SoundModelClient_2_0 : public SoundModelClient {
+ public:
+ SoundModelClient_2_0(uint32_t id, V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,
+ sp<V2_0::ISoundTriggerHwCallback> callback)
+ : SoundModelClient(id, cookie), mCallback(callback) {}
+
+ void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override;
+ void soundModelCallback(struct sound_trigger_model_event* halEvent) override;
+
+ private:
+ sp<V2_0::ISoundTriggerHwCallback> mCallback;
+ };
+
+ void convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid);
+ void convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid);
+ void convertPropertiesFromHal(V2_0::ISoundTriggerHw::Properties* properties,
+ const struct sound_trigger_properties* halProperties);
+ static sound_trigger_model_parameter_t convertModelParameterToHal(ModelParameter param);
+ void convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
+ const V2_0::ISoundTriggerHw::Phrase* triggerPhrase);
+ // returned HAL sound model must be freed by caller
+ struct sound_trigger_sound_model* convertSoundModelToHal(
+ const V2_0::ISoundTriggerHw::SoundModel* soundModel);
+ void convertPhraseRecognitionExtraToHal(struct sound_trigger_phrase_recognition_extra* halExtra,
+ const V2_0::PhraseRecognitionExtra* extra);
+ // returned recognition config must be freed by caller
+ struct sound_trigger_recognition_config* convertRecognitionConfigToHal(
+ const V2_0::ISoundTriggerHw::RecognitionConfig* config);
+
+ static void convertPhraseRecognitionExtraFromHal(
+ V2_0::PhraseRecognitionExtra* extra,
+ const struct sound_trigger_phrase_recognition_extra* halExtra);
+
+ static void soundModelCallback(struct sound_trigger_model_event* halEvent, void* cookie);
+ static void recognitionCallback(struct sound_trigger_recognition_event* halEvent, void* cookie);
+
+ const char* mModuleName;
+ struct sound_trigger_hw_device* mHwDevice;
+ volatile atomic_uint_fast32_t mNextModelId;
+ DefaultKeyedVector<int32_t, sp<SoundModelClient>> mClients;
+ Mutex mLock;
+
+ // Copied from hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.h
+ class SoundModelClient_2_1 : public SoundModelClient {
+ public:
+ SoundModelClient_2_1(uint32_t id, V2_1::ISoundTriggerHwCallback::CallbackCookie cookie,
+ sp<V2_1::ISoundTriggerHwCallback> callback)
+ : SoundModelClient(id, cookie), mCallback(callback) {}
+
+ void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override;
+ void soundModelCallback(struct sound_trigger_model_event* halEvent) override;
+
+ private:
+ sp<V2_1::ISoundTriggerHwCallback> mCallback;
+ };
+};
+
+extern "C" ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* name);
+
+} // namespace implementation
+} // namespace V2_3
+} // namespace soundtrigger
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SOUNDTRIGGER_V2_2_SOUNDTRIGGERHW_H
diff --git a/soundtrigger/2.3/types.hal b/soundtrigger/2.3/types.hal
new file mode 100644
index 0000000..c3a522b
--- /dev/null
+++ b/soundtrigger/2.3/types.hal
@@ -0,0 +1,61 @@
+/*
+ * 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.soundtrigger@2.3;
+
+import android.hidl.safe_union@1.0::Monostate;
+
+/**
+ * Model specific parameters to be used with parameter set and get APIs
+ */
+enum ModelParameter : int32_t {
+ /**
+ * Placeholder for invalid model parameter used for returning error or
+ * passing an invalid value.
+ */
+ INVALID = -1,
+
+ /**
+ * Controls the sensitivity threshold adjustment factor for a given model.
+ * Negative value corresponds to less sensitive model (high threshold) and
+ * a positive value corresponds to a more sensitive model (low threshold).
+ * Default value is 0.
+ */
+ THRESHOLD_FACTOR = 0
+};
+
+/**
+ * Safe union wrapping ModelParameterRange.
+ * Monostate is used to indicate there is no valid range
+ */
+safe_union OptionalModelParameterRange {
+ Monostate noinit;
+ ModelParameterRange range;
+};
+
+/**
+ * Model specific range support for a given parameter
+ */
+struct ModelParameterRange {
+ /**
+ * start of supported value range inclusive
+ */
+ int32_t start;
+ /**
+ * end of supported value range inclusive
+ */
+ int32_t end;
+};
diff --git a/soundtrigger/2.3/vts/functional/Android.bp b/soundtrigger/2.3/vts/functional/Android.bp
new file mode 100644
index 0000000..e3855fc
--- /dev/null
+++ b/soundtrigger/2.3/vts/functional/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_test {
+ name: "VtsHalSoundtriggerV2_3TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalSoundtriggerV2_3TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.soundtrigger@2.0",
+ "android.hardware.soundtrigger@2.1",
+ "android.hardware.soundtrigger@2.2",
+ "android.hardware.soundtrigger@2.3",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
new file mode 100644
index 0000000..202eb6c
--- /dev/null
+++ b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.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.
+ */
+
+#define LOG_TAG "SoundTriggerHidlHalTest"
+
+#include <android-base/logging.h>
+#include <android/hardware/audio/common/2.0/types.h>
+#include <android/hardware/soundtrigger/2.3/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.3/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::soundtrigger::V2_3::ISoundTriggerHw;
+
+/**
+ * Test class holding the instance of the SoundTriggerHW service to test.
+ * The passed parameter is the registered name of the implementing service
+ * supplied by INSTANTIATE_TEST_SUITE_P() call.
+ */
+class SoundTriggerHidlTest : public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ soundtrigger = ISoundTriggerHw::getService(GetParam());
+
+ ASSERT_NE(soundtrigger, nullptr);
+ LOG(INFO) << "Test is remote " << soundtrigger->isRemote();
+ }
+
+ sp<ISoundTriggerHw> soundtrigger;
+};
+
+/**
+ * Empty test is in place to ensure service is initalized.
+ * Due to the nature of SoundTrigger HAL providing an interface for
+ * proprietary or vendor specific implementations, limited testing on
+ * individual APIs is possible.
+ */
+TEST_P(SoundTriggerHidlTest, ServiceIsInstantiated) {}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, SoundTriggerHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/tests/extension/vibrator/aidl/Android.bp b/tests/extension/vibrator/aidl/Android.bp
index ef9b39b..42e0a92 100644
--- a/tests/extension/vibrator/aidl/Android.bp
+++ b/tests/extension/vibrator/aidl/Android.bp
@@ -1,7 +1,7 @@
aidl_interface {
// This is an example test interface showing how to add functionality
// with setExtension/getExtension
- name: "test-vintf-vibrator-ext",
+ name: "test-android.hardware.vibrator-ext",
vendor_available: true,
srcs: [
// Using android.hardware as the package because this is in
@@ -18,7 +18,7 @@
// This happens to use types from a core interface, so we import it, but
// this won't always be needed.
imports: [
- "vintf-vibrator",
+ "android.hardware.vibrator",
],
backend: {
diff --git a/tests/extension/vibrator/aidl/client/Android.bp b/tests/extension/vibrator/aidl/client/Android.bp
index f7b71f7..c707dbe 100644
--- a/tests/extension/vibrator/aidl/client/Android.bp
+++ b/tests/extension/vibrator/aidl/client/Android.bp
@@ -1,26 +1,24 @@
-
// This example client is written as a test, but it is executing from a system
// context. All this code would look the same if it was running in system
// server for example.
cc_test {
- name: "test-vintf-vibrator-ext-client",
+ name: "test-android.hardware.vibrator-ext-client",
srcs: [
- // system code has the option to use the unstable C++ libbinder API
- // or the NDK one. For maximum code portability, using the ndk client
- // makes the most sense, but both are provided here as an example.
- "test-cpp-client.cpp",
- "test-ndk-client.cpp",
+ // system code has the option to use the unstable C++ libbinder API
+ // or the NDK one. For maximum code portability, using the ndk client
+ // makes the most sense, but both are provided here as an example.
+ "test-cpp-client.cpp",
+ "test-ndk-client.cpp",
],
shared_libs: [
- "libbinder",
- "libutils",
- "vintf-vibrator-cpp",
- "test-vintf-vibrator-ext-cpp",
+ "libbinder",
+ "libutils",
+ "android.hardware.vibrator-cpp",
+ "test-android.hardware.vibrator-ext-cpp",
- "libbinder_ndk",
- "vintf-vibrator-ndk_platform",
- "test-vintf-vibrator-ext-ndk_platform",
+ "libbinder_ndk",
+ "android.hardware.vibrator-ndk_platform",
+ "test-android.hardware.vibrator-ext-ndk_platform",
],
}
-
diff --git a/tests/extension/vibrator/aidl/default/Android.bp b/tests/extension/vibrator/aidl/default/Android.bp
index 9869657..7c8fe1f 100644
--- a/tests/extension/vibrator/aidl/default/Android.bp
+++ b/tests/extension/vibrator/aidl/default/Android.bp
@@ -19,7 +19,7 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "vintf-vibrator-ndk_platform",
- "test-vintf-vibrator-ext-ndk_platform",
+ "android.hardware.vibrator-ndk_platform",
+ "test-android.hardware.vibrator-ext-ndk_platform",
],
}
diff --git a/tetheroffload/control/1.0/vts/functional/Android.bp b/tetheroffload/control/1.0/vts/functional/Android.bp
index e8e1414..4af59b6 100644
--- a/tetheroffload/control/1.0/vts/functional/Android.bp
+++ b/tetheroffload/control/1.0/vts/functional/Android.bp
@@ -20,5 +20,5 @@
"android.hardware.tetheroffload.config@1.0",
"android.hardware.tetheroffload.control@1.0",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp b/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp
index 03b6406..b422b2f 100644
--- a/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp
+++ b/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp
@@ -17,15 +17,17 @@
#define LOG_TAG "VtsOffloadControlV1_0TargetTest"
#include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
#include <android/hardware/tetheroffload/control/1.0/IOffloadControl.h>
#include <android/hardware/tetheroffload/control/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netlink.h>
+#include <log/log.h>
#include <net/if.h>
#include <sys/socket.h>
#include <unistd.h>
@@ -110,24 +112,8 @@
NatTimeoutUpdate last_params;
};
-// Test environment for OffloadControl HIDL HAL.
-class OffloadControlHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static OffloadControlHidlEnvironment* Instance() {
- static OffloadControlHidlEnvironment* instance = new OffloadControlHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override {
- registerTestService<IOffloadConfig>();
- registerTestService<IOffloadControl>();
- }
- private:
- OffloadControlHidlEnvironment() {}
-};
-
-class OffloadControlHidlTestBase : public testing::VtsHalHidlTargetTestBase {
+class OffloadControlHidlTestBase
+ : public testing::TestWithParam<std::tuple<std::string, std::string>> {
public:
virtual void SetUp() override {
setupConfigHal();
@@ -144,8 +130,7 @@
// The IOffloadConfig HAL is tested more thoroughly elsewhere. He we just
// setup everything correctly and verify basic readiness.
void setupConfigHal() {
- config = testing::VtsHalHidlTargetTestBase::getService<IOffloadConfig>(
- OffloadControlHidlEnvironment::Instance()->getServiceName<IOffloadConfig>());
+ config = IOffloadConfig::getService(std::get<0>(GetParam()));
ASSERT_NE(nullptr, config.get()) << "Could not get HIDL instance";
unique_fd fd1(conntrackSocket(NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY));
@@ -173,8 +158,7 @@
}
void prepareControlHal() {
- control = testing::VtsHalHidlTargetTestBase::getService<IOffloadControl>(
- OffloadControlHidlEnvironment::Instance()->getServiceName<IOffloadControl>());
+ control = IOffloadControl::getService(std::get<1>(GetParam()));
ASSERT_NE(nullptr, control.get()) << "Could not get HIDL instance";
control_cb = new TetheringOffloadCallback();
@@ -240,7 +224,7 @@
};
// Call initOffload() multiple times. Check that non-first initOffload() calls return false.
-TEST_F(OffloadControlHidlTestBase, AdditionalInitsWithoutStopReturnFalse) {
+TEST_P(OffloadControlHidlTestBase, AdditionalInitsWithoutStopReturnFalse) {
initOffload(true);
initOffload(false);
initOffload(false);
@@ -248,7 +232,7 @@
}
// Check that calling stopOffload() without first having called initOffload() returns false.
-TEST_F(OffloadControlHidlTestBase, MultipleStopsWithoutInitReturnFalse) {
+TEST_P(OffloadControlHidlTestBase, MultipleStopsWithoutInitReturnFalse) {
stopOffload(ExpectBoolean::False);
stopOffload(ExpectBoolean::False);
stopOffload(ExpectBoolean::False);
@@ -267,7 +251,7 @@
}
// Check that calling stopOffload() after a complete init/stop cycle returns false.
-TEST_F(OffloadControlHidlTestBase, AdditionalStopsWithInitReturnFalse) {
+TEST_P(OffloadControlHidlTestBase, AdditionalStopsWithInitReturnFalse) {
initOffload(true);
// Call setUpstreamParameters() so that "offload" can be reasonably said
// to be both requested and operational.
@@ -289,7 +273,7 @@
}
// Check that calling setLocalPrefixes() without first having called initOffload() returns false.
-TEST_F(OffloadControlHidlTestBase, SetLocalPrefixesWithoutInitReturnsFalse) {
+TEST_P(OffloadControlHidlTestBase, SetLocalPrefixesWithoutInitReturnsFalse) {
const vector<hidl_string> prefixes{hidl_string("2001:db8::/64")};
const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_FALSE_CALLBACK);
EXPECT_TRUE(ret.isOk());
@@ -297,14 +281,14 @@
// Check that calling getForwardedStats() without first having called initOffload()
// returns zero bytes statistics.
-TEST_F(OffloadControlHidlTestBase, GetForwardedStatsWithoutInitReturnsZeroValues) {
+TEST_P(OffloadControlHidlTestBase, GetForwardedStatsWithoutInitReturnsZeroValues) {
const hidl_string upstream(TEST_IFACE);
const Return<void> ret = control->getForwardedStats(upstream, ASSERT_ZERO_BYTES_CALLBACK);
EXPECT_TRUE(ret.isOk());
}
// Check that calling setDataLimit() without first having called initOffload() returns false.
-TEST_F(OffloadControlHidlTestBase, SetDataLimitWithoutInitReturnsFalse) {
+TEST_P(OffloadControlHidlTestBase, SetDataLimitWithoutInitReturnsFalse) {
const hidl_string upstream(TEST_IFACE);
const uint64_t limit = 5000ULL;
const Return<void> ret = control->setDataLimit(upstream, limit, ASSERT_FALSE_CALLBACK);
@@ -313,7 +297,7 @@
// Check that calling setUpstreamParameters() without first having called initOffload()
// returns false.
-TEST_F(OffloadControlHidlTestBase, SetUpstreamParametersWithoutInitReturnsFalse) {
+TEST_P(OffloadControlHidlTestBase, SetUpstreamParametersWithoutInitReturnsFalse) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr("192.0.2.0/24");
const hidl_string v4Gw("192.0.2.1");
@@ -325,7 +309,7 @@
// Check that calling addDownstream() with an IPv4 prefix without first having called
// initOffload() returns false.
-TEST_F(OffloadControlHidlTestBase, AddIPv4DownstreamWithoutInitReturnsFalse) {
+TEST_P(OffloadControlHidlTestBase, AddIPv4DownstreamWithoutInitReturnsFalse) {
const hidl_string iface(TEST_IFACE);
const hidl_string prefix("192.0.2.0/24");
const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -334,7 +318,7 @@
// Check that calling addDownstream() with an IPv6 prefix without first having called
// initOffload() returns false.
-TEST_F(OffloadControlHidlTestBase, AddIPv6DownstreamWithoutInitReturnsFalse) {
+TEST_P(OffloadControlHidlTestBase, AddIPv6DownstreamWithoutInitReturnsFalse) {
const hidl_string iface(TEST_IFACE);
const hidl_string prefix("2001:db8::/64");
const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -343,7 +327,7 @@
// Check that calling removeDownstream() with an IPv4 prefix without first having called
// initOffload() returns false.
-TEST_F(OffloadControlHidlTestBase, RemoveIPv4DownstreamWithoutInitReturnsFalse) {
+TEST_P(OffloadControlHidlTestBase, RemoveIPv4DownstreamWithoutInitReturnsFalse) {
const hidl_string iface(TEST_IFACE);
const hidl_string prefix("192.0.2.0/24");
const Return<void> ret = control->removeDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -352,7 +336,7 @@
// Check that calling removeDownstream() with an IPv6 prefix without first having called
// initOffload() returns false.
-TEST_F(OffloadControlHidlTestBase, RemoveIPv6DownstreamWithoutInitReturnsFalse) {
+TEST_P(OffloadControlHidlTestBase, RemoveIPv6DownstreamWithoutInitReturnsFalse) {
const hidl_string iface(TEST_IFACE);
const hidl_string prefix("2001:db8::/64");
const Return<void> ret = control->removeDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -379,21 +363,21 @@
*/
// Test setLocalPrefixes() accepts an IPv4 address.
-TEST_F(OffloadControlHidlTest, SetLocalPrefixesIPv4AddressOk) {
+TEST_P(OffloadControlHidlTest, SetLocalPrefixesIPv4AddressOk) {
const vector<hidl_string> prefixes{hidl_string("192.0.2.1")};
const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_TRUE_CALLBACK);
EXPECT_TRUE(ret.isOk());
}
// Test setLocalPrefixes() accepts an IPv6 address.
-TEST_F(OffloadControlHidlTest, SetLocalPrefixesIPv6AddressOk) {
+TEST_P(OffloadControlHidlTest, SetLocalPrefixesIPv6AddressOk) {
const vector<hidl_string> prefixes{hidl_string("fe80::1")};
const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_TRUE_CALLBACK);
EXPECT_TRUE(ret.isOk());
}
// Test setLocalPrefixes() accepts both IPv4 and IPv6 prefixes.
-TEST_F(OffloadControlHidlTest, SetLocalPrefixesIPv4v6PrefixesOk) {
+TEST_P(OffloadControlHidlTest, SetLocalPrefixesIPv4v6PrefixesOk) {
const vector<hidl_string> prefixes{hidl_string("192.0.2.0/24"), hidl_string("fe80::/64")};
const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_TRUE_CALLBACK);
EXPECT_TRUE(ret.isOk());
@@ -402,14 +386,14 @@
// Test that setLocalPrefixes() fails given empty input. There is always
// a non-empty set of local prefixes; when all networking interfaces are down
// we still apply {127.0.0.0/8, ::1/128, fe80::/64} here.
-TEST_F(OffloadControlHidlTest, SetLocalPrefixesEmptyFails) {
+TEST_P(OffloadControlHidlTest, SetLocalPrefixesEmptyFails) {
const vector<hidl_string> prefixes{};
const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_FALSE_CALLBACK);
EXPECT_TRUE(ret.isOk());
}
// Test setLocalPrefixes() fails on incorrectly formed input strings.
-TEST_F(OffloadControlHidlTest, SetLocalPrefixesInvalidFails) {
+TEST_P(OffloadControlHidlTest, SetLocalPrefixesInvalidFails) {
const vector<hidl_string> prefixes{hidl_string("192.0.2.0/24"), hidl_string("invalid")};
const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_FALSE_CALLBACK);
EXPECT_TRUE(ret.isOk());
@@ -420,7 +404,7 @@
*/
// Test that getForwardedStats() for a non-existent upstream yields zero bytes statistics.
-TEST_F(OffloadControlHidlTest, GetForwardedStatsInvalidUpstreamIface) {
+TEST_P(OffloadControlHidlTest, GetForwardedStatsInvalidUpstreamIface) {
const hidl_string upstream("invalid");
const Return<void> ret = control->getForwardedStats(upstream, ASSERT_ZERO_BYTES_CALLBACK);
EXPECT_TRUE(ret.isOk());
@@ -428,7 +412,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_F(OffloadControlHidlTest, GetForwardedStatsDummyIface) {
+TEST_P(OffloadControlHidlTest, GetForwardedStatsDummyIface) {
const hidl_string upstream(TEST_IFACE);
const Return<void> ret = control->getForwardedStats(upstream, ASSERT_ZERO_BYTES_CALLBACK);
EXPECT_TRUE(ret.isOk());
@@ -439,7 +423,7 @@
*/
// Test that setDataLimit() for an empty interface name fails.
-TEST_F(OffloadControlHidlTest, SetDataLimitEmptyUpstreamIfaceFails) {
+TEST_P(OffloadControlHidlTest, SetDataLimitEmptyUpstreamIfaceFails) {
const hidl_string upstream("");
const uint64_t limit = 5000ULL;
const Return<void> ret = control->setDataLimit(upstream, limit, ASSERT_FALSE_CALLBACK);
@@ -448,7 +432,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_F(OffloadControlHidlTest, SetDataLimitNonZeroOk) {
+TEST_P(OffloadControlHidlTest, SetDataLimitNonZeroOk) {
const hidl_string upstream(TEST_IFACE);
const uint64_t limit = 5000ULL;
const Return<void> ret = control->setDataLimit(upstream, limit, ASSERT_TRUE_CALLBACK);
@@ -457,7 +441,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_F(OffloadControlHidlTest, SetDataLimitZeroOk) {
+TEST_P(OffloadControlHidlTest, SetDataLimitZeroOk) {
const hidl_string upstream(TEST_IFACE);
const uint64_t limit = 0ULL;
const Return<void> ret = control->setDataLimit(upstream, limit, ASSERT_TRUE_CALLBACK);
@@ -470,7 +454,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_F(OffloadControlHidlTest, SetUpstreamParametersIPv6OnlyOk) {
+TEST_P(OffloadControlHidlTest, SetUpstreamParametersIPv6OnlyOk) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr("");
const hidl_string v4Gw("");
@@ -482,7 +466,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_F(OffloadControlHidlTest, SetUpstreamParametersAlternateIPv6OnlyOk) {
+TEST_P(OffloadControlHidlTest, SetUpstreamParametersAlternateIPv6OnlyOk) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr;
const hidl_string v4Gw;
@@ -494,7 +478,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_F(OffloadControlHidlTest, SetUpstreamParametersIPv4OnlyOk) {
+TEST_P(OffloadControlHidlTest, SetUpstreamParametersIPv4OnlyOk) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr("192.0.2.2");
const hidl_string v4Gw("192.0.2.1");
@@ -506,7 +490,7 @@
// TEST_IFACE is presumed to exist on the device and be up. No packets
// are ever actually caused to be forwarded.
-TEST_F(OffloadControlHidlTest, SetUpstreamParametersIPv4v6Ok) {
+TEST_P(OffloadControlHidlTest, SetUpstreamParametersIPv4v6Ok) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr("192.0.2.2");
const hidl_string v4Gw("192.0.2.1");
@@ -517,7 +501,7 @@
}
// Test that setUpstreamParameters() fails when all parameters are empty.
-TEST_F(OffloadControlHidlTest, SetUpstreamParametersEmptyFails) {
+TEST_P(OffloadControlHidlTest, SetUpstreamParametersEmptyFails) {
const hidl_string iface("");
const hidl_string v4Addr("");
const hidl_string v4Gw("");
@@ -528,7 +512,7 @@
}
// Test that setUpstreamParameters() fails when given empty or non-existent interface names.
-TEST_F(OffloadControlHidlTest, SetUpstreamParametersBogusIfaceFails) {
+TEST_P(OffloadControlHidlTest, SetUpstreamParametersBogusIfaceFails) {
const hidl_string v4Addr("192.0.2.2");
const hidl_string v4Gw("192.0.2.1");
const vector<hidl_string> v6Gws{hidl_string("fe80::db8:1")};
@@ -542,7 +526,7 @@
}
// Test that setUpstreamParameters() fails when given unparseable IPv4 addresses.
-TEST_F(OffloadControlHidlTest, SetUpstreamParametersInvalidIPv4AddrFails) {
+TEST_P(OffloadControlHidlTest, SetUpstreamParametersInvalidIPv4AddrFails) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Gw("192.0.2.1");
const vector<hidl_string> v6Gws{hidl_string("fe80::db8:1")};
@@ -556,7 +540,7 @@
}
// Test that setUpstreamParameters() fails when given unparseable IPv4 gateways.
-TEST_F(OffloadControlHidlTest, SetUpstreamParametersInvalidIPv4GatewayFails) {
+TEST_P(OffloadControlHidlTest, SetUpstreamParametersInvalidIPv4GatewayFails) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr("192.0.2.2");
const vector<hidl_string> v6Gws{hidl_string("fe80::db8:1")};
@@ -570,7 +554,7 @@
}
// Test that setUpstreamParameters() fails when given unparseable IPv6 gateways.
-TEST_F(OffloadControlHidlTest, SetUpstreamParametersBadIPv6GatewaysFail) {
+TEST_P(OffloadControlHidlTest, SetUpstreamParametersBadIPv6GatewaysFail) {
const hidl_string iface(TEST_IFACE);
const hidl_string v4Addr("192.0.2.2");
const hidl_string v4Gw("192.0.2.1");
@@ -588,7 +572,7 @@
*/
// Test addDownstream() works given an IPv4 prefix.
-TEST_F(OffloadControlHidlTest, AddDownstreamIPv4) {
+TEST_P(OffloadControlHidlTest, AddDownstreamIPv4) {
const hidl_string iface("dummy0");
const hidl_string prefix("192.0.2.0/24");
const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_TRUE_CALLBACK);
@@ -596,7 +580,7 @@
}
// Test addDownstream() works given an IPv6 prefix.
-TEST_F(OffloadControlHidlTest, AddDownstreamIPv6) {
+TEST_P(OffloadControlHidlTest, AddDownstreamIPv6) {
const hidl_string iface("dummy0");
const hidl_string prefix("2001:db8::/64");
const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_TRUE_CALLBACK);
@@ -604,7 +588,7 @@
}
// Test addDownstream() fails given all empty parameters.
-TEST_F(OffloadControlHidlTest, AddDownstreamEmptyFails) {
+TEST_P(OffloadControlHidlTest, AddDownstreamEmptyFails) {
const hidl_string iface("");
const hidl_string prefix("");
const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -612,7 +596,7 @@
}
// Test addDownstream() fails given empty or non-existent interface names.
-TEST_F(OffloadControlHidlTest, AddDownstreamInvalidIfaceFails) {
+TEST_P(OffloadControlHidlTest, AddDownstreamInvalidIfaceFails) {
const hidl_string prefix("192.0.2.0/24");
for (const auto& bogus : {"", "invalid"}) {
SCOPED_TRACE(StringPrintf("iface='%s'", bogus));
@@ -623,7 +607,7 @@
}
// Test addDownstream() fails given unparseable prefix arguments.
-TEST_F(OffloadControlHidlTest, AddDownstreamBogusPrefixFails) {
+TEST_P(OffloadControlHidlTest, AddDownstreamBogusPrefixFails) {
const hidl_string iface("dummy0");
for (const auto& bogus : {"", "192.0.2/24", "2001:db8/64"}) {
SCOPED_TRACE(StringPrintf("prefix='%s'", bogus));
@@ -638,7 +622,7 @@
*/
// Test removeDownstream() works given an IPv4 prefix.
-TEST_F(OffloadControlHidlTest, RemoveDownstreamIPv4) {
+TEST_P(OffloadControlHidlTest, RemoveDownstreamIPv4) {
const hidl_string iface("dummy0");
const hidl_string prefix("192.0.2.0/24");
// First add the downstream, otherwise removeDownstream logic can reasonably
@@ -650,7 +634,7 @@
}
// Test removeDownstream() works given an IPv6 prefix.
-TEST_F(OffloadControlHidlTest, RemoveDownstreamIPv6) {
+TEST_P(OffloadControlHidlTest, RemoveDownstreamIPv6) {
const hidl_string iface("dummy0");
const hidl_string prefix("2001:db8::/64");
// First add the downstream, otherwise removeDownstream logic can reasonably
@@ -662,7 +646,7 @@
}
// Test removeDownstream() fails given all empty parameters.
-TEST_F(OffloadControlHidlTest, RemoveDownstreamEmptyFails) {
+TEST_P(OffloadControlHidlTest, RemoveDownstreamEmptyFails) {
const hidl_string iface("");
const hidl_string prefix("");
const Return<void> ret = control->removeDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -670,7 +654,7 @@
}
// Test removeDownstream() fails given empty or non-existent interface names.
-TEST_F(OffloadControlHidlTest, RemoveDownstreamBogusIfaceFails) {
+TEST_P(OffloadControlHidlTest, RemoveDownstreamBogusIfaceFails) {
const hidl_string prefix("192.0.2.0/24");
for (const auto& bogus : {"", "invalid"}) {
SCOPED_TRACE(StringPrintf("iface='%s'", bogus));
@@ -681,7 +665,7 @@
}
// Test removeDownstream() fails given unparseable prefix arguments.
-TEST_F(OffloadControlHidlTest, RemoveDownstreamBogusPrefixFails) {
+TEST_P(OffloadControlHidlTest, RemoveDownstreamBogusPrefixFails) {
const hidl_string iface("dummy0");
for (const auto& bogus : {"", "192.0.2/24", "2001:db8/64"}) {
SCOPED_TRACE(StringPrintf("prefix='%s'", bogus));
@@ -691,11 +675,21 @@
}
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(OffloadControlHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- OffloadControlHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGE("Test result with status=%d", status);
- return status;
-}
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, OffloadControlHidlTestBase,
+ testing::Combine(
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IOffloadConfig::descriptor)),
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IOffloadControl::descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
+
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, OffloadControlHidlTest,
+ testing::Combine(
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IOffloadConfig::descriptor)),
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IOffloadControl::descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
+
diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal
index 3ed09f6..94e3c0c 100644
--- a/tv/tuner/1.0/IFilter.hal
+++ b/tv/tuner/1.0/IFilter.hal
@@ -104,11 +104,11 @@
*
* It is used by the client to ask the hardware resource id for the filter.
*
- * @param filterId the hardware resource Id for the filter.
* @return result Result status of the operation.
* SUCCESS if successful,
* INVALID_STATE if failed for wrong state.
* UNKNOWN_ERROR if failed for other reasons.
+ * @return filterId the hardware resource Id for the filter.
*/
getId() generates (Result result, uint32_t filterId);
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index 71a26ab..43c4e3a 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -51,7 +51,8 @@
mFrontendSourceFile = mFrontend->getSourceFile();
mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
- return startBroadcastInputLoop();
+
+ return startFrontendInputLoop();
}
Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
@@ -136,14 +137,14 @@
return Void();
}
- sp<Dvr> dvr = new Dvr(type, bufferSize, cb, this);
+ mDvr = new Dvr(type, bufferSize, cb, this);
- if (!dvr->createDvrMQ()) {
- _hidl_cb(Result::UNKNOWN_ERROR, dvr);
+ if (!mDvr->createDvrMQ()) {
+ _hidl_cb(Result::UNKNOWN_ERROR, mDvr);
return Void();
}
- _hidl_cb(Result::SUCCESS, dvr);
+ _hidl_cb(Result::SUCCESS, mDvr);
return Void();
}
@@ -166,13 +167,14 @@
// resetFilterRecords(filterId);
mUsedFilterIds.erase(filterId);
+ mRecordFilterIds.erase(filterId);
mUnusedFilterIds.insert(filterId);
mFilters.erase(filterId);
return Result::SUCCESS;
}
-void Demux::startTsFilter(vector<uint8_t> data) {
+void Demux::startBroadcastTsFilter(vector<uint8_t> data) {
set<uint32_t>::iterator it;
for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
@@ -185,7 +187,17 @@
}
}
-bool Demux::startFilterDispatcher() {
+void Demux::sendFrontendInputToRecord(vector<uint8_t> data) {
+ set<uint32_t>::iterator it;
+ for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+ if (DEBUG_FILTER) {
+ ALOGW("update record filter output");
+ }
+ mFilters[*it]->updateRecordOutput(data);
+ }
+}
+
+bool Demux::startBroadcastFilterDispatcher() {
set<uint32_t>::iterator it;
// Handle the output data per filter type
@@ -198,6 +210,18 @@
return true;
}
+bool Demux::startRecordFilterDispatcher() {
+ set<uint32_t>::iterator it;
+
+ for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+ if (mFilters[*it]->startRecordFilterHandler() != Result::SUCCESS) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
Result Demux::startFilterHandler(uint32_t filterId) {
return mFilters[filterId]->startFilterHandler();
}
@@ -210,22 +234,22 @@
return mFilters[filterId]->getTpid();
}
-Result Demux::startBroadcastInputLoop() {
- pthread_create(&mBroadcastInputThread, NULL, __threadLoopBroadcast, this);
- pthread_setname_np(mBroadcastInputThread, "broadcast_input_thread");
+Result Demux::startFrontendInputLoop() {
+ pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this);
+ pthread_setname_np(mFrontendInputThread, "frontend_input_thread");
return Result::SUCCESS;
}
-void* Demux::__threadLoopBroadcast(void* user) {
+void* Demux::__threadLoopFrontend(void* user) {
Demux* const self = static_cast<Demux*>(user);
- self->broadcastInputThreadLoop();
+ self->frontendInputThreadLoop();
return 0;
}
-void Demux::broadcastInputThreadLoop() {
- std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
- mBroadcastInputThreadRunning = true;
+void Demux::frontendInputThreadLoop() {
+ std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
+ mFrontendInputThreadRunning = true;
mKeepFetchingDataFromFrontend = true;
// open the stream and get its length
@@ -234,20 +258,20 @@
int packetSize = 188;
int writePacketAmount = 6;
char* buffer = new char[packetSize];
- ALOGW("[Demux] broadcast input thread loop start %s", mFrontendSourceFile.c_str());
+ ALOGW("[Demux] Frontend input thread loop start %s", mFrontendSourceFile.c_str());
if (!inputData.is_open()) {
- mBroadcastInputThreadRunning = false;
+ mFrontendInputThreadRunning = false;
ALOGW("[Demux] Error %s", strerror(errno));
}
- while (mBroadcastInputThreadRunning) {
+ while (mFrontendInputThreadRunning) {
// move the stream pointer for packet size * 6 every read until the end
while (mKeepFetchingDataFromFrontend) {
for (int i = 0; i < writePacketAmount; i++) {
inputData.read(buffer, packetSize);
if (!inputData) {
mKeepFetchingDataFromFrontend = false;
- mBroadcastInputThreadRunning = false;
+ mFrontendInputThreadRunning = false;
break;
}
// filter and dispatch filter output
@@ -256,23 +280,61 @@
for (int index = 0; index < byteBuffer.size(); index++) {
byteBuffer[index] = static_cast<uint8_t>(buffer[index]);
}
- startTsFilter(byteBuffer);
+ if (mIsRecording) {
+ // Feed the data into the Dvr recording input
+ sendFrontendInputToRecord(byteBuffer);
+ } else {
+ // Feed the data into the broadcast demux filter
+ startBroadcastTsFilter(byteBuffer);
+ }
}
- startFilterDispatcher();
+ if (mIsRecording) {
+ // Dispatch the data into the broadcasting filters.
+ startRecordFilterDispatcher();
+ } else {
+ // Dispatch the data into the broadcasting filters.
+ startBroadcastFilterDispatcher();
+ }
usleep(100);
}
}
- ALOGW("[Demux] Broadcast Input thread end.");
+ ALOGW("[Demux] Frontend Input thread end.");
delete[] buffer;
inputData.close();
}
-void Demux::stopBroadcastInput() {
+void Demux::stopFrontendInput() {
ALOGD("[Demux] stop frontend on demux");
mKeepFetchingDataFromFrontend = false;
- mBroadcastInputThreadRunning = false;
- std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
+ mFrontendInputThreadRunning = false;
+ std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
+}
+
+void Demux::setIsRecording(bool isRecording) {
+ mIsRecording = isRecording;
+}
+
+bool Demux::attachRecordFilter(int filterId) {
+ if (mFilters[filterId] == nullptr || mDvr == nullptr) {
+ return false;
+ }
+
+ mRecordFilterIds.insert(filterId);
+ mFilters[filterId]->attachFilterToRecord(mDvr);
+
+ return true;
+}
+
+bool Demux::detachRecordFilter(int filterId) {
+ if (mFilters[filterId] == nullptr || mDvr == nullptr) {
+ return false;
+ }
+
+ mRecordFilterIds.erase(filterId);
+ mFilters[filterId]->detachFilterFromRecord();
+
+ return true;
}
} // namespace implementation
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index 037429d..1405d0c 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -81,11 +81,14 @@
virtual Return<Result> disconnectCiCam() override;
// Functions interacts with Tuner Service
- void stopBroadcastInput();
+ void stopFrontendInput();
Result removeFilter(uint32_t filterId);
+ bool attachRecordFilter(int filterId);
+ bool detachRecordFilter(int filterId);
Result startFilterHandler(uint32_t filterId);
void updateFilterOutput(uint16_t filterId, vector<uint8_t> data);
uint16_t getFilterTpid(uint32_t filterId);
+ void setIsRecording(bool isRecording);
private:
// Tuner service
@@ -101,9 +104,9 @@
uint32_t filterId;
};
- Result startBroadcastInputLoop();
- static void* __threadLoopBroadcast(void* user);
- void broadcastInputThreadLoop();
+ Result startFrontendInputLoop();
+ static void* __threadLoopFrontend(void* user);
+ void frontendInputThreadLoop();
/**
* To create a FilterMQ with the the next available Filter ID.
@@ -117,9 +120,13 @@
/**
* A dispatcher to read and dispatch input data to all the started filters.
* Each filter handler handles the data filtering/output writing/filterEvent updating.
+ * Note that recording filters are not included.
*/
- bool startFilterDispatcher();
- void startTsFilter(vector<uint8_t> data);
+ bool startBroadcastFilterDispatcher();
+ void startBroadcastTsFilter(vector<uint8_t> data);
+
+ void sendFrontendInputToRecord(vector<uint8_t> data);
+ bool startRecordFilterDispatcher();
uint32_t mDemuxId;
uint32_t mCiCamId;
@@ -141,26 +148,40 @@
*/
set<uint32_t> mUnusedFilterIds;
/**
+ * Record all the attached record filter Ids.
+ * Any removed filter id should be removed from this set.
+ */
+ set<uint32_t> mRecordFilterIds;
+ /**
* A list of created FilterMQ ptrs.
* The array number is the filter ID.
*/
std::map<uint32_t, sp<Filter>> mFilters;
+ /**
+ * Local reference to the opened DVR object.
+ */
+ sp<Dvr> mDvr;
+
// Thread handlers
- pthread_t mBroadcastInputThread;
+ pthread_t mFrontendInputThread;
/**
* If a specific filter's writing loop is still running
*/
- bool mBroadcastInputThreadRunning;
+ bool mFrontendInputThreadRunning;
bool mKeepFetchingDataFromFrontend;
/**
+ * If the dvr recording is running.
+ */
+ bool mIsRecording = false;
+ /**
* Lock to protect writes to the FMQs
*/
std::mutex mWriteLock;
/**
* Lock to protect writes to the input status
*/
- std::mutex mBroadcastInputThreadLock;
+ std::mutex mFrontendInputThreadLock;
// temp handle single PES filter
// TODO handle mulptiple Pes filters
diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp
index eb38f90..3088a9d 100644
--- a/tv/tuner/1.0/default/Dvr.cpp
+++ b/tv/tuner/1.0/default/Dvr.cpp
@@ -70,7 +70,14 @@
return status;
}
+ // check if the attached filter is a record filter
+
mFilters[filterId] = filter;
+ mIsRecordFilterAttached = true;
+ if (!mDemux->attachRecordFilter(filterId)) {
+ return Result::INVALID_ARGUMENT;
+ }
+ mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
return Result::SUCCESS;
}
@@ -95,6 +102,15 @@
it = mFilters.find(filterId);
if (it != mFilters.end()) {
mFilters.erase(filterId);
+ if (!mDemux->detachRecordFilter(filterId)) {
+ return Result::INVALID_ARGUMENT;
+ }
+ }
+
+ // If all the filters are detached, record can't be started
+ if (mFilters.empty()) {
+ mIsRecordFilterAttached = false;
+ mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
}
return Result::SUCCESS;
@@ -115,8 +131,9 @@
pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this);
pthread_setname_np(mDvrThread, "playback_waiting_loop");
} else if (mType == DvrType::RECORD) {
- /*pthread_create(&mInputThread, NULL, __threadLoopInput, this);
- pthread_setname_np(mInputThread, "playback_waiting_loop");*/
+ mRecordStatus = RecordStatus::DATA_READY;
+ mIsRecordStarted = true;
+ mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
}
// TODO start another thread to send filter status callback to the framework
@@ -131,12 +148,17 @@
std::lock_guard<std::mutex> lock(mDvrThreadLock);
+ mIsRecordStarted = false;
+ mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
+
return Result::SUCCESS;
}
Return<Result> Dvr::flush() {
ALOGV("%s", __FUNCTION__);
+ mRecordStatus = RecordStatus::DATA_READY;
+
return Result::SUCCESS;
}
@@ -272,6 +294,45 @@
return true;
}
+bool Dvr::writeRecordFMQ(const std::vector<uint8_t>& data) {
+ std::lock_guard<std::mutex> lock(mWriteLock);
+ ALOGW("[Dvr] write record FMQ");
+ if (mDvrMQ->write(data.data(), data.size())) {
+ mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+ maySendRecordStatusCallback();
+ return true;
+ }
+
+ maySendRecordStatusCallback();
+ return false;
+}
+
+void Dvr::maySendRecordStatusCallback() {
+ std::lock_guard<std::mutex> lock(mRecordStatusLock);
+ int availableToRead = mDvrMQ->availableToRead();
+ int availableToWrite = mDvrMQ->availableToWrite();
+
+ RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead,
+ mDvrSettings.record().highThreshold,
+ mDvrSettings.record().lowThreshold);
+ if (mRecordStatus != newStatus) {
+ mCallback->onRecordStatus(newStatus);
+ mRecordStatus = newStatus;
+ }
+}
+
+RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold) {
+ if (availableToWrite == 0) {
+ return DemuxFilterStatus::OVERFLOW;
+ } else if (availableToRead > highThreshold) {
+ return DemuxFilterStatus::HIGH_WATER;
+ } else if (availableToRead < lowThreshold) {
+ return DemuxFilterStatus::LOW_WATER;
+ }
+ return mRecordStatus;
+}
+
} // namespace implementation
} // namespace V1_0
} // namespace tuner
diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h
index fbb778c..f39d8db 100644
--- a/tv/tuner/1.0/default/Dvr.h
+++ b/tv/tuner/1.0/default/Dvr.h
@@ -79,6 +79,8 @@
* Return false is any of the above processes fails.
*/
bool createDvrMQ();
+ void sendBroadcastInputToDvrRecord(vector<uint8_t> byteBuffer);
+ bool writeRecordFMQ(const std::vector<uint8_t>& data);
private:
// Demux service
@@ -95,6 +97,8 @@
void maySendRecordStatusCallback();
PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
uint32_t highThreshold, uint32_t lowThreshold);
+ RecordStatus checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold);
/**
* A dispatcher to read and dispatch input data to all the started filters.
* Each filter handler handles the data filtering/output writing/filterEvent updating.
@@ -103,9 +107,9 @@
void startTpidFilter(vector<uint8_t> data);
bool startFilterDispatcher();
static void* __threadLoopPlayback(void* user);
- static void* __threadLoopBroadcast(void* user);
+ static void* __threadLoopRecord(void* user);
void playbackThreadLoop();
- void broadcastInputThreadLoop();
+ void recordThreadLoop();
unique_ptr<DvrMQ> mDvrMQ;
EventFlag* mDvrEventFlag;
@@ -121,6 +125,7 @@
// FMQ status local records
PlaybackStatus mPlaybackStatus;
+ RecordStatus mRecordStatus;
/**
* If a specific filter's writing loop is still running
*/
@@ -135,10 +140,16 @@
* Lock to protect writes to the input status
*/
std::mutex mPlaybackStatusLock;
+ std::mutex mRecordStatusLock;
std::mutex mBroadcastInputThreadLock;
std::mutex mDvrThreadLock;
const bool DEBUG_DVR = false;
+
+ // Booleans to check if recording is running.
+ // Recording is ready when both of the following are set to true.
+ bool mIsRecordStarted = false;
+ bool mIsRecordFilterAttached = false;
};
} // namespace implementation
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
index befd1e6..b3160fc 100644
--- a/tv/tuner/1.0/default/Filter.cpp
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -265,10 +265,16 @@
void Filter::updateFilterOutput(vector<uint8_t> data) {
std::lock_guard<std::mutex> lock(mFilterOutputLock);
- ALOGD("[Filter] handler output updated");
+ ALOGD("[Filter] filter output updated");
mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end());
}
+void Filter::updateRecordOutput(vector<uint8_t> data) {
+ std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
+ ALOGD("[Filter] record filter output updated");
+ mRecordFilterOutput.insert(mRecordFilterOutput.end(), data.begin(), data.end());
+}
+
Result Filter::startFilterHandler() {
std::lock_guard<std::mutex> lock(mFilterOutputLock);
switch (mType.mainType) {
@@ -292,12 +298,11 @@
case DemuxTsFilterType::PCR:
startPcrFilterHandler();
break;
- case DemuxTsFilterType::RECORD:
- startRecordFilterHandler();
- break;
case DemuxTsFilterType::TEMI:
startTemiFilterHandler();
break;
+ default:
+ break;
}
break;
case DemuxFilterMainType::MMTP:
@@ -342,12 +347,16 @@
if (mPesSizeLeft == 0) {
uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
mFilterOutput[i + 6];
- ALOGD("[Filter] prefix %d", prefix);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] prefix %d", prefix);
+ }
if (prefix == 0x000001) {
// TODO handle mulptiple Pes filters
mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
mPesSizeLeft += 6;
- ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+ }
} else {
continue;
}
@@ -360,7 +369,9 @@
mPesOutput.insert(mPesOutput.end(), first, last);
// size does not match then continue
mPesSizeLeft -= endPoint;
- ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+ }
if (mPesSizeLeft > 0) {
continue;
}
@@ -377,7 +388,9 @@
.streamId = mPesOutput[3],
.dataLength = static_cast<uint16_t>(mPesOutput.size()),
};
- ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
+ }
int size = mFilterEvent.events.size();
mFilterEvent.events.resize(size + 1);
@@ -413,13 +426,23 @@
}
Result Filter::startRecordFilterHandler() {
- DemuxFilterTsRecordEvent tsRecordEvent;
+ /*DemuxFilterTsRecordEvent tsRecordEvent;
tsRecordEvent.pid.tPid(0);
tsRecordEvent.indexMask.tsIndexMask(0x01);
mFilterEvent.events.resize(1);
mFilterEvent.events[0].tsRecord(tsRecordEvent);
+*/
+ std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
+ if (mRecordFilterOutput.empty()) {
+ return Result::SUCCESS;
+ }
- mFilterOutput.clear();
+ if (mDvr == nullptr || !mDvr->writeRecordFMQ(mRecordFilterOutput)) {
+ ALOGD("[Filter] dvr fails to write into record FMQ.");
+ return Result::UNKNOWN_ERROR;
+ }
+
+ mRecordFilterOutput.clear();
return Result::SUCCESS;
}
@@ -462,6 +485,14 @@
return false;
}
+void Filter::attachFilterToRecord(const sp<Dvr> dvr) {
+ mDvr = dvr;
+}
+
+void Filter::detachFilterFromRecord() {
+ mDvr = nullptr;
+}
+
} // namespace implementation
} // namespace V1_0
} // namespace tuner
diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
index fbd965a..d397f73 100644
--- a/tv/tuner/1.0/default/Filter.h
+++ b/tv/tuner/1.0/default/Filter.h
@@ -22,6 +22,7 @@
#include <math.h>
#include <set>
#include "Demux.h"
+#include "Dvr.h"
#include "Frontend.h"
using namespace std;
@@ -44,6 +45,7 @@
using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
class Demux;
+class Dvr;
class Filter : public IFilter {
public:
@@ -80,11 +82,17 @@
bool createFilterMQ();
uint16_t getTpid();
void updateFilterOutput(vector<uint8_t> data);
+ void updateRecordOutput(vector<uint8_t> data);
Result startFilterHandler();
+ Result startRecordFilterHandler();
+ void attachFilterToRecord(const sp<Dvr> dvr);
+ void detachFilterFromRecord();
private:
// Tuner service
sp<Demux> mDemux;
+ // Dvr reference once the filter is attached to any
+ sp<Dvr> mDvr = nullptr;
/**
* Filter callbacks used on filter events or FMQ status
*/
@@ -99,6 +107,7 @@
sp<IFilter> mDataSource;
bool mIsDataSourceDemux = true;
vector<uint8_t> mFilterOutput;
+ vector<uint8_t> mRecordFilterOutput;
unique_ptr<FilterMQ> mFilterMQ;
EventFlag* mFilterEventFlag;
DemuxFilterEvent mFilterEvent;
@@ -120,6 +129,8 @@
*/
const uint16_t SECTION_WRITE_COUNT = 10;
+ bool DEBUG_FILTER = false;
+
/**
* Filter handlers to handle the data filtering.
* They are also responsible to write the filtered output into the filter FMQ
@@ -129,7 +140,6 @@
Result startPesFilterHandler();
Result startTsFilterHandler();
Result startMediaFilterHandler();
- Result startRecordFilterHandler();
Result startPcrFilterHandler();
Result startTemiFilterHandler();
Result startFilterLoop();
@@ -165,6 +175,7 @@
std::mutex mFilterStatusLock;
std::mutex mFilterThreadLock;
std::mutex mFilterOutputLock;
+ std::mutex mRecordFilterOutputLock;
// temp handle single PES filter
// TODO handle mulptiple Pes filters
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index f86b28d..c143d61 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -148,7 +148,7 @@
uint32_t demuxId;
if (it != mFrontendToDemux.end()) {
demuxId = it->second;
- mDemuxes[demuxId]->stopBroadcastInput();
+ mDemuxes[demuxId]->stopFrontendInput();
}
}
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 707f5df..fa3c08b 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -1197,6 +1197,7 @@
/**
* Scan type for Frontend.
*/
+@export
enum FrontendScanType : uint32_t {
SCAN_UNDEFINED = 0,
SCAN_AUTO = 1 << 0,
@@ -1206,6 +1207,7 @@
/**
* Scan Message Type for Frontend.
*/
+@export
enum FrontendScanMessageType : uint32_t {
/**
* Scan locked the signal.
@@ -2230,8 +2232,6 @@
DemuxFilterSectionSettings section;
- DemuxFilterPesDataSettings pesData;
-
/**
* true if the data from IP subtype go to next filter directly
*/
@@ -2248,7 +2248,7 @@
/**
* true if the filtered data is commpressed ip packet
*/
- bool bIsCompressedIpPacket;
+ bool isCompressedIpPacket;
safe_union FilterSettings {
/**
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index da3e300..7977f25 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -65,6 +65,7 @@
using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
@@ -95,6 +96,7 @@
using android::hardware::tv::tuner::V1_0::ITuner;
using android::hardware::tv::tuner::V1_0::PlaybackSettings;
using android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using android::hardware::tv::tuner::V1_0::RecordSettings;
using android::hardware::tv::tuner::V1_0::RecordStatus;
using android::hardware::tv::tuner::V1_0::Result;
@@ -379,7 +381,20 @@
class DvrCallback : public IDvrCallback {
public:
- virtual Return<void> onRecordStatus(RecordStatus /*status*/) override { return Void(); }
+ virtual Return<void> onRecordStatus(DemuxFilterStatus status) override {
+ ALOGW("[vts] record status %hhu", status);
+ switch (status) {
+ case DemuxFilterStatus::DATA_READY:
+ break;
+ case DemuxFilterStatus::LOW_WATER:
+ break;
+ case DemuxFilterStatus::HIGH_WATER:
+ case DemuxFilterStatus::OVERFLOW:
+ ALOGW("[vts] record overflow. Flushing");
+ break;
+ }
+ return Void();
+ }
virtual Return<void> onPlaybackStatus(PlaybackStatus status) override {
// android::Mutex::Autolock autoLock(mMsgLock);
@@ -401,10 +416,17 @@
void testFilterDataOutput();
void stopPlaybackThread();
+ void testRecordOutput();
+ void stopRecordThread();
void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor);
+ void startRecordOutputThread(RecordSettings recordSetting, MQDesc& recordMQDescriptor);
static void* __threadLoopPlayback(void* threadArgs);
+ static void* __threadLoopRecord(void* threadArgs);
void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ);
+ void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ);
+
+ bool readRecordFMQ();
private:
struct PlaybackThreadArgs {
@@ -412,22 +434,31 @@
PlaybackConf* playbackConf;
bool* keepWritingPlaybackFMQ;
};
+ struct RecordThreadArgs {
+ DvrCallback* user;
+ RecordSettings* recordSetting;
+ bool* keepReadingRecordFMQ;
+ };
uint16_t mDataLength = 0;
std::vector<uint8_t> mDataOutputBuffer;
std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
std::unique_ptr<FilterMQ> mPlaybackMQ;
+ std::unique_ptr<FilterMQ> mRecordMQ;
std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
- EventFlag* mPlaybackMQEventFlag;
android::Mutex mMsgLock;
android::Mutex mPlaybackThreadLock;
+ android::Mutex mRecordThreadLock;
android::Condition mMsgCondition;
bool mKeepWritingPlaybackFMQ = true;
+ bool mKeepReadingRecordFMQ = true;
bool mPlaybackThreadRunning;
+ bool mRecordThreadRunning;
pthread_t mPlaybackThread;
+ pthread_t mRecordThread;
int mPidFilterOutputCount = 0;
};
@@ -516,6 +547,92 @@
inputData.close();
}
+void DvrCallback::testRecordOutput() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (mDataOutputBuffer.empty()) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
+ return;
+ }
+ }
+ stopRecordThread();
+ ALOGW("[vts] record pass and stop");
+}
+
+void DvrCallback::startRecordOutputThread(RecordSettings recordSetting,
+ MQDesc& recordMQDescriptor) {
+ mRecordMQ = std::make_unique<FilterMQ>(recordMQDescriptor, true /* resetPointers */);
+ EXPECT_TRUE(mRecordMQ);
+ struct RecordThreadArgs* threadArgs =
+ (struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs));
+ threadArgs->user = this;
+ threadArgs->recordSetting = &recordSetting;
+ threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ;
+
+ pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs);
+ pthread_setname_np(mRecordThread, "test_record_input_loop");
+}
+
+void* DvrCallback::__threadLoopRecord(void* threadArgs) {
+ DvrCallback* const self =
+ static_cast<DvrCallback*>(((struct RecordThreadArgs*)threadArgs)->user);
+ self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSetting,
+ ((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ);
+ return 0;
+}
+
+void DvrCallback::recordThreadLoop(RecordSettings* /*recordSetting*/, bool* keepReadingRecordFMQ) {
+ ALOGD("[vts] DvrCallback record threadLoop start.");
+ android::Mutex::Autolock autoLock(mRecordThreadLock);
+ mRecordThreadRunning = true;
+
+ // Create the EventFlag that is used to signal the HAL impl that data have been
+ // read from the Record FMQ
+ EventFlag* recordMQEventFlag;
+ EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) ==
+ android::OK);
+
+ while (mRecordThreadRunning) {
+ while (*keepReadingRecordFMQ) {
+ uint32_t efState = 0;
+ android::status_t status = recordMQEventFlag->wait(
+ static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
+ true /* retry on spurious wake */);
+ if (status != android::OK) {
+ ALOGD("[vts] wait for data ready on the record FMQ");
+ continue;
+ }
+ // Our current implementation filter the data and write it into the filter FMQ
+ // immediately after the DATA_READY from the VTS/framework
+ if (!readRecordFMQ()) {
+ ALOGD("[vts] record data failed to be filtered. Ending thread");
+ mRecordThreadRunning = false;
+ break;
+ }
+ }
+ }
+
+ mRecordThreadRunning = false;
+ ALOGD("[vts] record thread ended.");
+}
+
+bool DvrCallback::readRecordFMQ() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ bool result = false;
+ mDataOutputBuffer.clear();
+ mDataOutputBuffer.resize(mRecordMQ->availableToRead());
+ result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead());
+ EXPECT_TRUE(result) << "can't read from Record MQ";
+ mMsgCondition.signal();
+ return result;
+}
+
+void DvrCallback::stopRecordThread() {
+ mKeepReadingRecordFMQ = false;
+ mRecordThreadRunning = false;
+ android::Mutex::Autolock autoLock(mRecordThreadLock);
+}
+
// Test environment for Tuner HIDL HAL.
class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
public:
@@ -555,6 +672,7 @@
sp<DvrCallback> mDvrCallback;
MQDesc mFilterMQDescriptor;
MQDesc mPlaybackMQDescriptor;
+ MQDesc mRecordMQDescriptor;
vector<uint32_t> mUsedFilterIds;
uint32_t mDemuxId;
@@ -572,6 +690,8 @@
FrontendSettings settings);
::testing::AssertionResult getPlaybackMQDescriptor();
::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting);
+ ::testing::AssertionResult getRecordMQDescriptor();
+ ::testing::AssertionResult addRecordToDemux(RecordSettings setting);
::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting);
::testing::AssertionResult getFilterMQDescriptor();
::testing::AssertionResult closeDemux();
@@ -581,6 +701,9 @@
::testing::AssertionResult playbackDataFlowTest(vector<FilterConf> filterConf,
PlaybackConf playbackConf,
vector<string> goldenOutputFiles);
+ ::testing::AssertionResult recordDataFlowTest(vector<FilterConf> filterConf,
+ RecordSettings recordSetting,
+ vector<string> goldenOutputFiles);
::testing::AssertionResult broadcastDataFlowTest(vector<FilterConf> filterConf,
vector<string> goldenOutputFiles);
};
@@ -766,6 +889,49 @@
return ::testing::AssertionResult(status == Result::SUCCESS);
}
+::testing::AssertionResult TunerHidlTest::addRecordToDemux(RecordSettings setting) {
+ Result status;
+
+ if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+
+ // Create dvr callback
+ mDvrCallback = new DvrCallback();
+
+ // Add playback input to the local demux
+ mDemux->openDvr(DvrType::RECORD, FMQ_SIZE_1M, mDvrCallback,
+ [&](Result result, const sp<IDvr>& dvr) {
+ mDvr = dvr;
+ status = result;
+ });
+
+ if (status != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+
+ DvrSettings dvrSetting;
+ dvrSetting.record(setting);
+ status = mDvr->configure(dvrSetting);
+
+ return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::getRecordMQDescriptor() {
+ Result status;
+
+ if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) {
+ return ::testing::AssertionFailure();
+ }
+
+ mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+ mRecordMQDescriptor = dvrMQDesc;
+ status = result;
+ });
+
+ return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
::testing::AssertionResult TunerHidlTest::addFilterToDemux(DemuxFilterType type,
DemuxFilterSettings setting) {
Result status;
@@ -997,6 +1163,82 @@
return closeDemux();
}
+::testing::AssertionResult TunerHidlTest::recordDataFlowTest(vector<FilterConf> filterConf,
+ RecordSettings recordSetting,
+ vector<string> /*goldenOutputFiles*/) {
+ Result status;
+ hidl_vec<FrontendId> feIds;
+
+ mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+ status = result;
+ feIds = frontendIds;
+ });
+
+ if (feIds.size() == 0) {
+ ALOGW("[ WARN ] Frontend isn't available");
+ return ::testing::AssertionFailure();
+ }
+
+ FrontendDvbtSettings dvbt{
+ .frequency = 1000,
+ };
+ FrontendSettings settings;
+ settings.dvbt(dvbt);
+
+ int filterIdsSize;
+ // Filter Configuration Module
+ for (int i = 0; i < filterConf.size(); i++) {
+ if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
+ ::testing::AssertionFailure() ||
+ // TODO use a map to save the FMQs/EvenFlags and pass to callback
+ getFilterMQDescriptor() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+ filterIdsSize = mUsedFilterIds.size();
+ mUsedFilterIds.resize(filterIdsSize + 1);
+ mUsedFilterIds[filterIdsSize] = mFilterId;
+ mFilters[mFilterId] = mFilter;
+ }
+
+ // Record Config Module
+ if (addRecordToDemux(recordSetting) == ::testing::AssertionFailure() ||
+ getRecordMQDescriptor() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+ for (int i = 0; i <= filterIdsSize; i++) {
+ if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+ }
+
+ mDvrCallback->startRecordOutputThread(recordSetting, mRecordMQDescriptor);
+ status = mDvr->start();
+ if (status != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+
+ if (createDemuxWithFrontend(feIds[0], settings) != ::testing::AssertionSuccess()) {
+ return ::testing::AssertionFailure();
+ }
+
+ // Data Verify Module
+ mDvrCallback->testRecordOutput();
+
+ // Clean Up Module
+ for (int i = 0; i <= filterIdsSize; i++) {
+ if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+ }
+ if (mFrontend->stopTune() != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+ mUsedFilterIds.clear();
+ mFilterCallbacks.clear();
+ mFilters.clear();
+ return closeDemux();
+}
+
/*
* API STATUS TESTS
*/
@@ -1203,6 +1445,44 @@
ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles));
}
+TEST_F(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) {
+ description("Feed ts data from frontend to recording and test with ts record filter");
+
+ // todo modulize the filter conf parser
+ vector<FilterConf> filterConf;
+ filterConf.resize(1);
+
+ DemuxFilterSettings filterSetting;
+ DemuxTsFilterSettings tsFilterSetting{
+ .tpid = 119,
+ };
+ DemuxFilterRecordSettings recordFilterSetting;
+ tsFilterSetting.filterSettings.record(recordFilterSetting);
+ filterSetting.ts(tsFilterSetting);
+
+ DemuxFilterType type{
+ .mainType = DemuxFilterMainType::TS,
+ };
+ type.subType.tsFilterType(DemuxTsFilterType::RECORD);
+ FilterConf recordFilterConf{
+ .type = type,
+ .setting = filterSetting,
+ };
+ filterConf[0] = recordFilterConf;
+
+ RecordSettings recordSetting{
+ .statusMask = 0xf,
+ .lowThreshold = 0x1000,
+ .highThreshold = 0x07fff,
+ .dataFormat = DataFormat::TS,
+ .packetSize = 188,
+ };
+
+ vector<string> goldenOutputFiles;
+
+ ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles));
+}
+
} // namespace
int main(int argc, char** argv) {
diff --git a/usb/1.1/vts/functional/Android.bp b/usb/1.1/vts/functional/Android.bp
index 1f0972f..32c470b 100644
--- a/usb/1.1/vts/functional/Android.bp
+++ b/usb/1.1/vts/functional/Android.bp
@@ -22,6 +22,6 @@
"android.hardware.usb@1.0",
"android.hardware.usb@1.1",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/usb/1.1/vts/functional/VtsHalUsbV1_1TargetTest.cpp b/usb/1.1/vts/functional/VtsHalUsbV1_1TargetTest.cpp
index caf9c69..d4b2ffd 100644
--- a/usb/1.1/vts/functional/VtsHalUsbV1_1TargetTest.cpp
+++ b/usb/1.1/vts/functional/VtsHalUsbV1_1TargetTest.cpp
@@ -23,8 +23,9 @@
#include <android/hardware/usb/1.1/types.h>
#include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <log/log.h>
#include <stdlib.h>
#include <chrono>
@@ -114,25 +115,12 @@
};
};
-// Test environment for Usb HIDL HAL.
-class UsbHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static UsbHidlEnvironment* Instance() {
- static UsbHidlEnvironment* instance = new UsbHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IUsb>(); }
-};
-
// The main test class for the USB hidl HAL
-class UsbHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class UsbHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
ALOGI(__FUNCTION__);
- usb = ::testing::VtsHalHidlTargetTestBase::getService<IUsb>(
- UsbHidlEnvironment::Instance()->getServiceName<IUsb>());
+ usb = IUsb::getService(GetParam());
ASSERT_NE(usb, nullptr);
usb_cb_2 = new UsbCallback(2);
@@ -158,7 +146,7 @@
* Callback oject is created and registered.
* Check to see if the hidl transaction succeeded.
*/
-TEST_F(UsbHidlTest, setCallback) {
+TEST_P(UsbHidlTest, setCallback) {
usb_cb_1 = new UsbCallback(1);
ASSERT_NE(usb_cb_1, nullptr);
Return<void> ret = usb->setCallback(usb_cb_1);
@@ -171,7 +159,7 @@
* HAL service should call notifyPortStatusChange_1_1
* instead of notifyPortStatusChange of V1_0 interface
*/
-TEST_F(UsbHidlTest, queryPortStatus) {
+TEST_P(UsbHidlTest, queryPortStatus) {
Return<void> ret = usb->queryPortStatus();
ASSERT_TRUE(ret.isOk());
auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_1);
@@ -181,12 +169,7 @@
EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status.supportedModes);
EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status);
}
-
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(UsbHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- UsbHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, UsbHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IUsb::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index 1eec1da..ae7f434 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -1,5 +1,5 @@
aidl_interface {
- name: "vintf-vibrator",
+ name: "android.hardware.vibrator",
vendor_available: true,
srcs: [
"android/hardware/vibrator/*.aidl",
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
index 2a9d0be..b9a80ec 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
@@ -19,11 +19,34 @@
@VintfStability
@Backing(type="int")
enum CompositePrimitive {
+ /**
+ * No haptic effect. Used to generate extended delays between primitives.
+ */
NOOP,
+ /**
+ * This effect should produce a sharp, crisp click sensation.
+ */
CLICK,
+ /**
+ * A haptic effect that simulates downwards movement with gravity. Often
+ * followed by extra energy of hitting and reverberation to augment
+ * physicality.
+ */
THUD,
+ /**
+ * A haptic effect that simulates spinning momentum.
+ */
SPIN,
+ /**
+ * A haptic effect that simulates quick upward movement against gravity.
+ */
QUICK_RISE,
+ /**
+ * A haptic effect that simulates slow upward movement against gravity.
+ */
SLOW_RISE,
+ /**
+ * A haptic effect that simulates quick downwards movement with gravity.
+ */
QUICK_FALL,
}
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index ebf5faa..f553664 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -48,6 +48,10 @@
* Whether compose is supported.
*/
const int CAP_COMPOSE_EFFECTS = 1 << 5;
+ /**
+ * Whether alwaysOnEnable/alwaysOnDisable is supported.
+ */
+ const int CAP_ALWAYS_ON_CONTROL = 1 << 6;
/**
* Determine capabilities of the vibrator HAL (CAP_* mask)
@@ -165,4 +169,31 @@
*/
void compose(in CompositeEffect[] composite, in IVibratorCallback callback);
+ /**
+ * List of supported always-on effects.
+ *
+ * Return the effects which are supported by the alwaysOnEnable (an effect
+ * is expected to be supported at every strength level.
+ */
+ Effect[] getSupportedAlwaysOnEffects();
+
+ /**
+ * Enable an always-on haptic source, assigning a specific effect. An
+ * always-on haptic source is a source that can be triggered externally
+ * once enabled and assigned an effect to play. This may not be supported
+ * and this support is reflected in getCapabilities (CAP_ALWAYS_ON_CONTROL).
+ *
+ * @param id The device-specific always-on source ID to enable.
+ * @param effect The type of haptic event to trigger.
+ * @param strength The intensity of haptic event to trigger.
+ */
+ void alwaysOnEnable(in int id, in Effect effect, in EffectStrength strength);
+
+ /**
+ * Disable an always-on haptic source. This may not be supported and this
+ * support is reflected in getCapabilities (CAP_ALWAYS_ON_CONTROL).
+ *
+ * @param id The device-specific always-on source ID to disable.
+ */
+ void alwaysOnDisable(in int id);
}
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index dc8867f..9e6d9cf 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -4,13 +4,13 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "vintf-vibrator-ndk_platform",
+ "android.hardware.vibrator-ndk_platform",
],
export_include_dirs: ["include"],
srcs: ["Vibrator.cpp"],
visibility: [
- ":__subpackages__",
- "//hardware/interfaces/tests/extension/vibrator:__subpackages__",
+ ":__subpackages__",
+ "//hardware/interfaces/tests/extension/vibrator:__subpackages__",
],
}
@@ -23,7 +23,7 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "vintf-vibrator-ndk_platform",
+ "android.hardware.vibrator-ndk_platform",
],
static_libs: [
"libvibratorexampleimpl",
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index befdeab..cedd9cb 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -31,7 +31,8 @@
LOG(INFO) << "Vibrator reporting capabilities";
*_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
- IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS;
+ IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
+ IVibrator::CAP_ALWAYS_ON_CONTROL;
return ndk::ScopedAStatus::ok();
}
@@ -151,6 +152,28 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) {
+ return getSupportedEffects(_aidl_return);
+}
+
+ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
+ std::vector<Effect> effects;
+ getSupportedAlwaysOnEffects(&effects);
+
+ if (std::find(effects.begin(), effects.end(), effect) == effects.end()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ } else {
+ LOG(INFO) << "Enabling always-on ID " << id << " with " << toString(effect) << "/"
+ << toString(strength);
+ return ndk::ScopedAStatus::ok();
+ }
+}
+
+ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) {
+ LOG(INFO) << "Disabling always-on ID " << id;
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace vibrator
} // namespace hardware
} // namespace android
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index 817ec80..0eb957d 100644
--- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
+++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
@@ -38,6 +38,9 @@
ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize);
ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite,
const std::shared_ptr<IVibratorCallback>& callback) override;
+ ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) override;
+ ndk::ScopedAStatus alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) override;
+ ndk::ScopedAStatus alwaysOnDisable(int32_t id) override;
};
} // namespace vibrator
diff --git a/vibrator/aidl/vts/Android.bp b/vibrator/aidl/vts/Android.bp
index 20d53c7..a01e432 100644
--- a/vibrator/aidl/vts/Android.bp
+++ b/vibrator/aidl/vts/Android.bp
@@ -9,7 +9,7 @@
"libbinder",
],
static_libs: [
- "vintf-vibrator-cpp",
+ "android.hardware.vibrator-cpp",
],
test_suites: [
"vts-core",
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 5c6120b..0e2b3e1 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -34,18 +34,10 @@
using android::hardware::vibrator::EffectStrength;
using android::hardware::vibrator::IVibrator;
-// TODO(b/143992652): autogenerate
-const std::vector<Effect> kEffects = {
- Effect::CLICK, Effect::DOUBLE_CLICK, Effect::TICK, Effect::THUD,
- Effect::POP, Effect::HEAVY_CLICK, Effect::RINGTONE_1, Effect::RINGTONE_2,
- Effect::RINGTONE_3, Effect::RINGTONE_4, Effect::RINGTONE_5, Effect::RINGTONE_6,
- Effect::RINGTONE_7, Effect::RINGTONE_8, Effect::RINGTONE_9, Effect::RINGTONE_10,
- Effect::RINGTONE_11, Effect::RINGTONE_12, Effect::RINGTONE_13, Effect::RINGTONE_14,
- Effect::RINGTONE_15, Effect::TEXTURE_TICK};
-
-// TODO(b/143992652): autogenerate
-const std::vector<EffectStrength> kEffectStrengths = {EffectStrength::LIGHT, EffectStrength::MEDIUM,
- EffectStrength::STRONG};
+const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
+ android::enum_range<Effect>().end()};
+const std::vector<EffectStrength> kEffectStrengths{android::enum_range<EffectStrength>().begin(),
+ android::enum_range<EffectStrength>().end()};
const std::vector<Effect> kInvalidEffects = {
static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
@@ -135,13 +127,12 @@
Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
if (isEffectSupported) {
- EXPECT_TRUE(status.isOk())
- << static_cast<int>(effect) << " " << static_cast<int>(strength);
+ EXPECT_TRUE(status.isOk()) << toString(effect) << " " << toString(strength);
EXPECT_GT(lengthMs, 0);
usleep(lengthMs * 1000);
} else {
EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
- << static_cast<int>(effect) << " " << static_cast<int>(strength);
+ << toString(effect) << " " << toString(strength);
EXPECT_EQ(lengthMs, 0);
}
}
@@ -202,7 +193,7 @@
int32_t lengthMs;
Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
- << static_cast<int>(effect) << " " << static_cast<int>(strength);
+ << toString(effect) << " " << toString(strength);
}
}
for (Effect effect : kEffects) {
@@ -210,7 +201,7 @@
int32_t lengthMs;
Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
- << static_cast<int>(effect) << " " << static_cast<int>(strength);
+ << toString(effect) << " " << toString(strength);
}
}
}
@@ -371,6 +362,32 @@
}
}
+TEST_P(VibratorAidl, AlwaysOn) {
+ if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) {
+ std::vector<Effect> supported;
+ ASSERT_TRUE(vibrator->getSupportedAlwaysOnEffects(&supported).isOk());
+
+ for (Effect effect : kEffects) {
+ bool isEffectSupported =
+ std::find(supported.begin(), supported.end(), effect) != supported.end();
+
+ for (EffectStrength strength : kEffectStrengths) {
+ Status status = vibrator->alwaysOnEnable(0, effect, strength);
+
+ if (isEffectSupported) {
+ EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+ << toString(effect) << " " << toString(strength);
+ } else {
+ EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode())
+ << toString(effect) << " " << toString(strength);
+ }
+ }
+ }
+
+ EXPECT_EQ(Status::EX_NONE, vibrator->alwaysOnDisable(0).exceptionCode());
+ }
+}
+
INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(IVibrator::descriptor)),
android::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
index ec96fcf..62874ef 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
@@ -543,12 +543,16 @@
const auto& status_and_rtt_controller =
HIDL_INVOKE(wifi_chip_, createRttController, iface);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_rtt_controller.first.code);
- EXPECT_NE(nullptr, status_and_rtt_controller.second.get());
+ if (status_and_rtt_controller.first.code !=
+ WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ EXPECT_EQ(WifiStatusCode::SUCCESS,
+ status_and_rtt_controller.first.code);
+ EXPECT_NE(nullptr, status_and_rtt_controller.second.get());
+ }
}
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiChipHidlTest,
testing::ValuesIn(
android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
- android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index d584d4b..26e4821 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -209,23 +209,6 @@
return status_and_iface.second;
}
-sp<IWifiRttController> getWifiRttController(const std::string& instance_name) {
- sp<IWifiChip> wifi_chip = getWifiChip(instance_name);
- if (!wifi_chip.get()) {
- return nullptr;
- }
- sp<IWifiStaIface> wifi_sta_iface = getWifiStaIface(instance_name);
- if (!wifi_sta_iface.get()) {
- return nullptr;
- }
- const auto& status_and_controller =
- HIDL_INVOKE(wifi_chip, createRttController, wifi_sta_iface);
- if (status_and_controller.first.code != WifiStatusCode::SUCCESS) {
- return nullptr;
- }
- return status_and_controller.second;
-}
-
bool configureChipToSupportIfaceType(const sp<IWifiChip>& wifi_chip,
IfaceType type,
ChipModeId* configured_mode_id) {
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
index bdee2ec..8660134 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
@@ -44,8 +44,6 @@
const std::string& instance_name = "");
android::sp<android::hardware::wifi::V1_0::IWifiStaIface> getWifiStaIface(
const std::string& instance_name = "");
-android::sp<android::hardware::wifi::V1_0::IWifiRttController>
-getWifiRttController(const std::string& instance_name = "");
// Configure the chip in a mode to support the creation of the provided
// iface type.
bool configureChipToSupportIfaceType(
diff --git a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
index e1ee34f..6c01995 100644
--- a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -22,11 +22,15 @@
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
+#include "wifi_hidl_call_util.h"
#include "wifi_hidl_test_utils.h"
using ::android::sp;
using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiChip;
using ::android::hardware::wifi::V1_0::IWifiRttController;
+using ::android::hardware::wifi::V1_0::IWifiStaIface;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
/**
* Fixture to use for all RTT controller HIDL interface tests.
@@ -48,11 +52,26 @@
*/
TEST_P(WifiRttControllerHidlTest, Create) {
stopWifi(GetInstanceName());
- EXPECT_NE(nullptr, getWifiRttController(GetInstanceName()).get());
+
+ const std::string& instance_name = GetInstanceName();
+
+ sp<IWifiChip> wifi_chip = getWifiChip(instance_name);
+ EXPECT_NE(nullptr, wifi_chip.get());
+
+ sp<IWifiStaIface> wifi_sta_iface = getWifiStaIface(instance_name);
+ EXPECT_NE(nullptr, wifi_sta_iface.get());
+
+ const auto& status_and_controller =
+ HIDL_INVOKE(wifi_chip, createRttController, wifi_sta_iface);
+ if (status_and_controller.first.code !=
+ WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_controller.first.code);
+ EXPECT_NE(nullptr, status_and_controller.second.get());
+ }
}
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiRttControllerHidlTest,
testing::ValuesIn(
android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
- android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
index 47faec8..93aa0f3 100644
--- a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
@@ -176,11 +176,15 @@
sp<WifiChipEventCallback> wifiChipEventCallback = new WifiChipEventCallback();
const auto& status =
HIDL_INVOKE(wifi_chip_, registerEventCallback_1_2, wifiChipEventCallback);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+
+ if (status.code != WifiStatusCode::SUCCESS) {
+ EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code);
+ return;
+ }
}
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiChipHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
::android::hardware::wifi::V1_2::IWifi::descriptor)),
- android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
index f3f76e1..d5d87ce 100644
--- a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -481,15 +481,18 @@
callbackType = INVALID;
NanEnableRequest nanEnableRequest = {};
NanConfigRequestSupplemental nanConfigRequestSupp = {};
- ASSERT_EQ(WifiStatusCode::SUCCESS,
- HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId,
- nanEnableRequest, nanConfigRequestSupp)
- .code);
- // wait for a callback
- ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
- ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType);
- ASSERT_EQ(id, inputCmdId);
- ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId,
+ nanEnableRequest, nanConfigRequestSupp);
+ if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code);
+
+ // wait for a callback
+ ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
+ ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType);
+ ASSERT_EQ(id, inputCmdId);
+ ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+ }
}
/*
@@ -502,10 +505,12 @@
nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon =
128; // must be <= 127
NanConfigRequestSupplemental nanConfigRequestSupp = {};
- ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS,
- HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId,
- nanEnableRequest, nanConfigRequestSupp)
- .code);
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId,
+ nanEnableRequest, nanConfigRequestSupp);
+ if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code);
+ }
}
/*
@@ -516,15 +521,19 @@
callbackType = INVALID;
NanConfigRequest nanConfigRequest = {};
NanConfigRequestSupplemental nanConfigRequestSupp = {};
- ASSERT_EQ(WifiStatusCode::SUCCESS,
- HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId,
- nanConfigRequest, nanConfigRequestSupp)
- .code);
- // wait for a callback
- ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
- ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType);
- ASSERT_EQ(id, inputCmdId);
- ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId,
+ nanConfigRequest, nanConfigRequestSupp);
+
+ if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code);
+
+ // wait for a callback
+ ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
+ ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType);
+ ASSERT_EQ(id, inputCmdId);
+ ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+ }
}
/*
@@ -536,14 +545,16 @@
NanConfigRequest nanConfigRequest = {};
nanConfigRequest.numberOfPublishServiceIdsInBeacon = 128; // must be <= 127
NanConfigRequestSupplemental nanConfigRequestSupp = {};
- ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS,
- HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId,
- nanConfigRequest, nanConfigRequestSupp)
- .code);
+ const auto& halStatus =
+ HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId,
+ nanConfigRequest, nanConfigRequestSupp);
+ if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+ ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code);
+ }
}
INSTANTIATE_TEST_SUITE_P(
PerInstance, WifiNanIfaceHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
::android::hardware::wifi::V1_2::IWifi::descriptor)),
- android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp
index e63b1eb..3b94619 100644
--- a/wifi/1.4/Android.bp
+++ b/wifi/1.4/Android.bp
@@ -12,9 +12,9 @@
"IWifiApIface.hal",
"IWifiChip.hal",
"IWifiChipEventCallback.hal",
+ "IWifiNanIface.hal",
"IWifiRttController.hal",
"IWifiRttControllerEventCallback.hal",
- "IWifiStaIface.hal",
],
interfaces: [
"android.hardware.wifi@1.0",
diff --git a/wifi/1.4/IWifiChip.hal b/wifi/1.4/IWifiChip.hal
index de5a64e..07f4a65 100644
--- a/wifi/1.4/IWifiChip.hal
+++ b/wifi/1.4/IWifiChip.hal
@@ -39,8 +39,7 @@
* |WifiStatusCode.ERROR_NOT_SUPPORTED|,
* |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
*/
- registerEventCallback_1_4(IWifiChipEventCallback callback)
- generates (WifiStatus status);
+ registerEventCallback_1_4(IWifiChipEventCallback callback) generates (WifiStatus status);
/**
* Create a RTTController instance.
diff --git a/wifi/1.4/IWifiChipEventCallback.hal b/wifi/1.4/IWifiChipEventCallback.hal
index ecd0a44..9ead344 100644
--- a/wifi/1.4/IWifiChipEventCallback.hal
+++ b/wifi/1.4/IWifiChipEventCallback.hal
@@ -33,6 +33,7 @@
* only for debugging purposes.
*/
uint32_t radioId;
+
/**
* List of bands on which this radio chain is operating.
* Can be one of:
@@ -47,7 +48,10 @@
* time sharing across the 3 bands).
*/
WifiBand bandInfo;
- /** List of interfaces on this radio chain (hardware MAC). */
+
+ /**
+ * List of interfaces on this radio chain (hardware MAC).
+ */
vec<IfaceInfo> ifaceInfos;
};
diff --git a/wifi/1.4/IWifiNanIface.hal b/wifi/1.4/IWifiNanIface.hal
new file mode 100644
index 0000000..881d06c
--- /dev/null
+++ b/wifi/1.4/IWifiNanIface.hal
@@ -0,0 +1,78 @@
+/*
+ * 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.wifi@1.4;
+
+import @1.0::CommandIdShort;
+import @1.0::WifiStatus;
+import @1.2::IWifiNanIface;
+import @1.2::NanConfigRequestSupplemental;
+import NanConfigRequest;
+import NanEnableRequest;
+
+/**
+ * Interface used to represent a single NAN (Neighbour Aware Network) iface.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIface extends @1.2::IWifiNanIface {
+ /**
+ * Enable NAN: configures and activates NAN clustering (does not start
+ * a discovery session or set up data-interfaces or data-paths). Use the
+ * |IWifiNanIface.configureRequest| method to change the configuration of an already enabled
+ * NAN interface.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyEnableResponse|.
+ *
+ * Note: supersedes the @1.2::IWifiNanIface.enableRequest() method which is deprecated as of
+ * HAL version 1.4.
+ *
+ * @param cmdId command Id to use for this invocation.
+ * @param msg1 Instance of |NanEnableRequest|.
+ * @param msg2 Instance of |NanConfigRequestSupplemental|.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ enableRequest_1_4(CommandIdShort cmdId, NanEnableRequest msg1,
+ NanConfigRequestSupplemental msg2) generates (WifiStatus status);
+
+ /**
+ * Configure NAN: configures an existing NAN functionality (i.e. assumes
+ * |IWifiNanIface.enableRequest| already submitted and succeeded).
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyConfigResponse|.
+ *
+ * Note: supersedes the @1.2::IWifiNanIface.configRequest() method which is deprecated as of
+ * HAL version 1.4.
+ *
+ * @param cmdId command Id to use for this invocation.
+ * @param msg1 Instance of |NanConfigRequest|.
+ * @param msg1 Instance of |NanConfigRequestSupplemental|.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ configRequest_1_4(CommandIdShort cmdId, NanConfigRequest msg1,
+ NanConfigRequestSupplemental msg2) generates (WifiStatus status);
+};
diff --git a/wifi/1.4/IWifiStaIface.hal b/wifi/1.4/IWifiStaIface.hal
deleted file mode 100644
index fb658cd..0000000
--- a/wifi/1.4/IWifiStaIface.hal
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.wifi@1.4;
-
-import @1.0::WifiStatus;
-import @1.0::MacAddress;
-import @1.0::IWifiStaIface;
-import @1.3::IWifiStaIface;
-
-/**
- * Interface used to represent a single STA iface.
- *
- * IWifiChip.createStaIface() may return a @1.4::IWifiStaIface when supported.
- */
-interface IWifiStaIface extends @1.3::IWifiStaIface {
-
- enum StaIfaceCapabilityMask : @1.0::IWifiStaIface.StaIfaceCapabilityMask {
- STA_6G = 1 << 15
- };
-
- /**
- * Get the capabilities supported by this STA iface.
- *
- * @return status WifiStatus of the operation.
- * Possible status codes:
- * |WifiStatusCode.SUCCESS|,
- * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
- * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
- * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
- * |WifiStatusCode.ERROR_UNKNOWN|
- * @return capabilities Bitset of |StaIfaceCapabilityMask| values.
- */
- getCapabilities_1_4()
- generates (WifiStatus status,
- bitfield<StaIfaceCapabilityMask> capabilities);
-};
diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp
index 35c6839..4996e35 100644
--- a/wifi/1.4/default/hidl_struct_util.cpp
+++ b/wifi/1.4/default/hidl_struct_util.cpp
@@ -120,8 +120,6 @@
return HidlStaIfaceCaps::ND_OFFLOAD;
case WIFI_FEATURE_MKEEP_ALIVE:
return HidlStaIfaceCaps::KEEP_ALIVE;
- case WIFI_FEATURE_INFRA_6G:
- return HidlStaIfaceCaps::STA_6G;
};
CHECK(false) << "Unknown legacy feature: " << feature;
return {};
@@ -394,8 +392,7 @@
WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND,
WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO,
WIFI_FEATURE_TDLS, WIFI_FEATURE_TDLS_OFFCHANNEL,
- WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE,
- WIFI_FEATURE_INFRA_6G}) {
+ WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) {
if (feature & legacy_feature_set) {
*hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
}
@@ -1135,9 +1132,9 @@
legacy_request->disc_mac_addr_rand_interval_sec =
hidl_request.configParams.macAddressRandomizationIntervalSec;
legacy_request->config_2dot4g_rssi_close = 1;
- if (hidl_request.configParams.bandSpecificConfig.size() != 2) {
+ if (hidl_request.configParams.bandSpecificConfig.size() != 3) {
LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
- "bandSpecificConfig.size() != 2";
+ "bandSpecificConfig.size() != 3";
return false;
}
legacy_request->rssi_close_2dot4g_val =
@@ -1270,16 +1267,20 @@
hidl_request.debugConfigs
.useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+ /* TODO: b/145609058
+ * Missing updates needed to legacy_hal::NanEnableRequest and conversion to
+ * it for 6GHz band */
+
return true;
}
-bool convertHidlNanEnableRequest_1_2ToLegacy(
+bool convertHidlNanEnableRequest_1_4ToLegacy(
const NanEnableRequest& hidl_request1,
const V1_2::NanConfigRequestSupplemental& hidl_request2,
legacy_hal::NanEnableRequest* legacy_request) {
if (!legacy_request) {
LOG(ERROR)
- << "convertHidlNanEnableRequest_1_2ToLegacy: null legacy_request";
+ << "convertHidlNanEnableRequest_1_4ToLegacy: null legacy_request";
return false;
}
@@ -1780,16 +1781,19 @@
legacy_request->config_dw.dw_5g_interval_val =
hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
.discoveryWindowIntervalVal;
+ /* TODO: b/145609058
+ * Missing updates needed to legacy_hal::NanConfigRequest and conversion to
+ * it for 6GHz band */
return true;
}
-bool convertHidlNanConfigRequest_1_2ToLegacy(
+bool convertHidlNanConfigRequest_1_4ToLegacy(
const NanConfigRequest& hidl_request1,
const V1_2::NanConfigRequestSupplemental& hidl_request2,
legacy_hal::NanConfigRequest* legacy_request) {
if (!legacy_request) {
- LOG(ERROR) << "convertHidlNanConfigRequest_1_2ToLegacy: legacy_request "
+ LOG(ERROR) << "convertHidlNanConfigRequest_1_4ToLegacy: legacy_request "
"is null";
return false;
}
diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h
index 987891b..d040c1f 100644
--- a/wifi/1.4/default/hidl_struct_util.h
+++ b/wifi/1.4/default/hidl_struct_util.h
@@ -25,7 +25,6 @@
#include <android/hardware/wifi/1.3/IWifiChip.h>
#include <android/hardware/wifi/1.3/types.h>
#include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
-#include <android/hardware/wifi/1.4/IWifiStaIface.h>
#include <android/hardware/wifi/1.4/types.h>
#include "wifi_legacy_hal.h"
@@ -118,11 +117,11 @@
bool convertHidlNanConfigRequestToLegacy(
const NanConfigRequest& hidl_request,
legacy_hal::NanConfigRequest* legacy_request);
-bool convertHidlNanEnableRequest_1_2ToLegacy(
+bool convertHidlNanEnableRequest_1_4ToLegacy(
const NanEnableRequest& hidl_request1,
const V1_2::NanConfigRequestSupplemental& hidl_request2,
legacy_hal::NanEnableRequest* legacy_request);
-bool convertHidlNanConfigRequest_1_2ToLegacy(
+bool convertHidlNanConfigRequest_1_4ToLegacy(
const NanConfigRequest& hidl_request1,
const V1_2::NanConfigRequestSupplemental& hidl_request2,
legacy_hal::NanConfigRequest* legacy_request);
diff --git a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
index 90e81e1..d35adbc 100644
--- a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
@@ -720,13 +720,16 @@
ASSERT_EQ(iface_names[0], "wlan0");
});
// Retrieve the exact iface object.
- sp<IWifiNanIface> nan_iface;
- chip_->getNanIface("wlan0", [&nan_iface](const WifiStatus& status,
- const sp<IWifiNanIface>& iface) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- ASSERT_NE(iface.get(), nullptr);
- nan_iface = iface;
- });
+ sp<android::hardware::wifi::V1_0::IWifiNanIface> nan_iface;
+ chip_->getNanIface(
+ "wlan0",
+ [&nan_iface](
+ const WifiStatus& status,
+ const sp<android::hardware::wifi::V1_0::IWifiNanIface>& iface) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ ASSERT_NE(iface.get(), nullptr);
+ nan_iface = iface;
+ });
// Remove the STA iface.
removeIface(IfaceType::STA, "wlan0");
diff --git a/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
index 8aefa92..9022792 100644
--- a/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
+++ b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -41,6 +41,9 @@
namespace V1_4 {
namespace implementation {
+using android::hardware::wifi::V1_2::IWifiNanIfaceEventCallback;
+using android::hardware::wifi::V1_2::NanDataPathConfirmInd;
+
bool CaptureIfaceEventHandlers(
const std::string& /* iface_name*/,
iface_util::IfaceEventHandlers in_iface_event_handlers,
@@ -96,9 +99,15 @@
Return<void>(uint16_t, const WifiNanStatus&));
MOCK_METHOD1(eventDataPathRequest,
Return<void>(const NanDataPathRequestInd&));
- MOCK_METHOD1(eventDataPathConfirm,
- Return<void>(const NanDataPathConfirmInd&));
+ MOCK_METHOD1(
+ eventDataPathConfirm,
+ Return<void>(
+ const android::hardware::wifi::V1_0::NanDataPathConfirmInd&));
MOCK_METHOD1(eventDataPathTerminated, Return<void>(uint32_t));
+ MOCK_METHOD1(eventDataPathConfirm_1_2,
+ Return<void>(const NanDataPathConfirmInd&));
+ MOCK_METHOD1(eventDataPathScheduleUpdate,
+ Return<void>(const NanDataPathScheduleUpdateInd&));
};
class WifiNanIfaceTest : public Test {
diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp
index 2b015d3..3498510 100644
--- a/wifi/1.4/default/wifi_chip.cpp
+++ b/wifi/1.4/default/wifi_chip.cpp
@@ -938,7 +938,8 @@
return createWifiStatus(WifiStatusCode::SUCCESS);
}
-std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::createStaIfaceInternal() {
+std::pair<WifiStatus, sp<V1_3::IWifiStaIface>>
+WifiChip::createStaIfaceInternal() {
if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) {
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
@@ -962,7 +963,7 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
}
-std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::getStaIfaceInternal(
+std::pair<WifiStatus, sp<V1_3::IWifiStaIface>> WifiChip::getStaIfaceInternal(
const std::string& ifname) {
const auto iface = findUsingName(sta_ifaces_, ifname);
if (!iface.get()) {
@@ -991,7 +992,7 @@
std::pair<WifiStatus, sp<V1_0::IWifiRttController>>
WifiChip::createRttControllerInternal(const sp<IWifiIface>& /*bound_iface*/) {
LOG(ERROR) << "createRttController is not supported on this HAL";
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
}
std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
diff --git a/wifi/1.4/default/wifi_chip.h b/wifi/1.4/default/wifi_chip.h
index c76eabf..3323ade 100644
--- a/wifi/1.4/default/wifi_chip.h
+++ b/wifi/1.4/default/wifi_chip.h
@@ -197,9 +197,9 @@
std::pair<WifiStatus, sp<IWifiP2pIface>> getP2pIfaceInternal(
const std::string& ifname);
WifiStatus removeP2pIfaceInternal(const std::string& ifname);
- std::pair<WifiStatus, sp<IWifiStaIface>> createStaIfaceInternal();
+ std::pair<WifiStatus, sp<V1_3::IWifiStaIface>> createStaIfaceInternal();
std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
- std::pair<WifiStatus, sp<IWifiStaIface>> getStaIfaceInternal(
+ std::pair<WifiStatus, sp<V1_3::IWifiStaIface>> getStaIfaceInternal(
const std::string& ifname);
WifiStatus removeStaIfaceInternal(const std::string& ifname);
std::pair<WifiStatus, sp<V1_0::IWifiRttController>>
diff --git a/wifi/1.4/default/wifi_nan_iface.cpp b/wifi/1.4/default/wifi_nan_iface.cpp
index 981acb2..073101c 100644
--- a/wifi/1.4/default/wifi_nan_iface.cpp
+++ b/wifi/1.4/default/wifi_nan_iface.cpp
@@ -576,7 +576,7 @@
}
Return<void> WifiNanIface::enableRequest(uint16_t cmd_id,
- const NanEnableRequest& msg,
+ const V1_0::NanEnableRequest& msg,
enableRequest_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::enableRequestInternal, hidl_status_cb,
@@ -584,7 +584,7 @@
}
Return<void> WifiNanIface::configRequest(uint16_t cmd_id,
- const NanConfigRequest& msg,
+ const V1_0::NanConfigRequest& msg,
configRequest_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::configRequestInternal, hidl_status_cb,
@@ -687,7 +687,7 @@
}
Return<void> WifiNanIface::enableRequest_1_2(
- uint16_t cmd_id, const NanEnableRequest& msg1,
+ uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
const V1_2::NanConfigRequestSupplemental& msg2,
enableRequest_1_2_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
@@ -696,7 +696,7 @@
}
Return<void> WifiNanIface::configRequest_1_2(
- uint16_t cmd_id, const NanConfigRequest& msg1,
+ uint16_t cmd_id, const V1_0::NanConfigRequest& msg1,
const V1_2::NanConfigRequestSupplemental& msg2,
configRequest_1_2_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
@@ -704,6 +704,24 @@
hidl_status_cb, cmd_id, msg1, msg2);
}
+Return<void> WifiNanIface::enableRequest_1_4(
+ uint16_t cmd_id, const NanEnableRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2,
+ enableRequest_1_4_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::enableRequest_1_4Internal,
+ hidl_status_cb, cmd_id, msg1, msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_4(
+ uint16_t cmd_id, const NanConfigRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2,
+ configRequest_1_4_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::configRequest_1_4Internal,
+ hidl_status_cb, cmd_id, msg1, msg2);
+}
+
std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
}
@@ -727,12 +745,12 @@
}
WifiStatus WifiNanIface::enableRequestInternal(
- uint16_t /* cmd_id */, const NanEnableRequest& /* msg */) {
+ uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg */) {
return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
}
WifiStatus WifiNanIface::configRequestInternal(
- uint16_t /* cmd_id */, const NanConfigRequest& /* msg */) {
+ uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg */) {
return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
}
@@ -855,10 +873,22 @@
}
WifiStatus WifiNanIface::enableRequest_1_2Internal(
+ uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg1 */,
+ const V1_2::NanConfigRequestSupplemental& /*msg2 */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequest_1_2Internal(
+ uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg1 */,
+ const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_4Internal(
uint16_t cmd_id, const NanEnableRequest& msg1,
const V1_2::NanConfigRequestSupplemental& msg2) {
legacy_hal::NanEnableRequest legacy_msg;
- if (!hidl_struct_util::convertHidlNanEnableRequest_1_2ToLegacy(
+ if (!hidl_struct_util::convertHidlNanEnableRequest_1_4ToLegacy(
msg1, msg2, &legacy_msg)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
@@ -867,11 +897,11 @@
return createWifiStatusFromLegacyError(legacy_status);
}
-WifiStatus WifiNanIface::configRequest_1_2Internal(
+WifiStatus WifiNanIface::configRequest_1_4Internal(
uint16_t cmd_id, const NanConfigRequest& msg1,
const V1_2::NanConfigRequestSupplemental& msg2) {
legacy_hal::NanConfigRequest legacy_msg;
- if (!hidl_struct_util::convertHidlNanConfigRequest_1_2ToLegacy(
+ if (!hidl_struct_util::convertHidlNanConfigRequest_1_4ToLegacy(
msg1, msg2, &legacy_msg)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
diff --git a/wifi/1.4/default/wifi_nan_iface.h b/wifi/1.4/default/wifi_nan_iface.h
index e3a5c34..c16628b 100644
--- a/wifi/1.4/default/wifi_nan_iface.h
+++ b/wifi/1.4/default/wifi_nan_iface.h
@@ -19,7 +19,7 @@
#include <android-base/macros.h>
#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
-#include <android/hardware/wifi/1.2/IWifiNanIface.h>
+#include <android/hardware/wifi/1.4/IWifiNanIface.h>
#include "hidl_callback_util.h"
#include "wifi_iface_util.h"
@@ -31,11 +31,12 @@
namespace V1_4 {
namespace implementation {
using namespace android::hardware::wifi::V1_0;
+using namespace android::hardware::wifi::V1_2;
/**
* HIDL interface object used to control a NAN Iface instance.
*/
-class WifiNanIface : public V1_2::IWifiNanIface {
+class WifiNanIface : public V1_4::IWifiNanIface {
public:
WifiNanIface(const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
@@ -53,9 +54,11 @@
registerEventCallback_cb hidl_status_cb) override;
Return<void> getCapabilitiesRequest(
uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) override;
- Return<void> enableRequest(uint16_t cmd_id, const NanEnableRequest& msg,
+ Return<void> enableRequest(uint16_t cmd_id,
+ const V1_0::NanEnableRequest& msg,
enableRequest_cb hidl_status_cb) override;
- Return<void> configRequest(uint16_t cmd_id, const NanConfigRequest& msg,
+ Return<void> configRequest(uint16_t cmd_id,
+ const V1_0::NanConfigRequest& msg,
configRequest_cb hidl_status_cb) override;
Return<void> disableRequest(uint16_t cmd_id,
disableRequest_cb hidl_status_cb) override;
@@ -94,10 +97,18 @@
const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
registerEventCallback_1_2_cb hidl_status_cb) override;
Return<void> enableRequest_1_2(
- uint16_t cmd_id, const NanEnableRequest& msg1,
+ uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
const V1_2::NanConfigRequestSupplemental& msg2,
enableRequest_1_2_cb hidl_status_cb) override;
Return<void> configRequest_1_2(
+ uint16_t cmd_id, const V1_0::NanConfigRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2,
+ configRequest_1_2_cb hidl_status_cb) override;
+ Return<void> enableRequest_1_4(
+ uint16_t cmd_id, const NanEnableRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2,
+ enableRequest_1_2_cb hidl_status_cb) override;
+ Return<void> configRequest_1_4(
uint16_t cmd_id, const NanConfigRequest& msg1,
const V1_2::NanConfigRequestSupplemental& msg2,
configRequest_1_2_cb hidl_status_cb) override;
@@ -110,9 +121,9 @@
const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
WifiStatus enableRequestInternal(uint16_t cmd_id,
- const NanEnableRequest& msg);
+ const V1_0::NanEnableRequest& msg);
WifiStatus configRequestInternal(uint16_t cmd_id,
- const NanConfigRequest& msg);
+ const V1_0::NanConfigRequest& msg);
WifiStatus disableRequestInternal(uint16_t cmd_id);
WifiStatus startPublishRequestInternal(uint16_t cmd_id,
const NanPublishRequest& msg);
@@ -136,9 +147,15 @@
WifiStatus registerEventCallback_1_2Internal(
const sp<V1_2::IWifiNanIfaceEventCallback>& callback);
WifiStatus enableRequest_1_2Internal(
- uint16_t cmd_id, const NanEnableRequest& msg1,
+ uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
const V1_2::NanConfigRequestSupplemental& msg2);
WifiStatus configRequest_1_2Internal(
+ uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
+ const V1_2::NanConfigRequestSupplemental& msg2);
+ WifiStatus enableRequest_1_4Internal(
+ uint16_t cmd_id, const NanEnableRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2);
+ WifiStatus configRequest_1_4Internal(
uint16_t cmd_id, const NanConfigRequest& msg,
const V1_2::NanConfigRequestSupplemental& msg2);
diff --git a/wifi/1.4/default/wifi_sta_iface.cpp b/wifi/1.4/default/wifi_sta_iface.cpp
index 68c989d..e2ea6e4 100644
--- a/wifi/1.4/default/wifi_sta_iface.cpp
+++ b/wifi/1.4/default/wifi_sta_iface.cpp
@@ -266,13 +266,6 @@
hidl_status_cb);
}
-Return<void> WifiStaIface::getCapabilities_1_4(
- getCapabilities_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getCapabilitiesInternal_1_4,
- hidl_status_cb);
-}
-
std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
}
@@ -290,7 +283,26 @@
}
std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
+ legacy_hal::wifi_error legacy_status;
+ uint64_t legacy_feature_set;
+ std::tie(legacy_status, legacy_feature_set) =
+ legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), 0};
+ }
+ uint32_t legacy_logger_feature_set;
+ std::tie(legacy_status, legacy_logger_feature_set) =
+ legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ // some devices don't support querying logger feature set
+ legacy_logger_feature_set = 0;
+ }
+ uint32_t hidl_caps;
+ if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
+ legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
}
std::pair<WifiStatus, StaApfPacketFilterCapabilities>
@@ -628,29 +640,6 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
}
-std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal_1_4() {
- legacy_hal::wifi_error legacy_status;
- uint64_t legacy_feature_set;
- std::tie(legacy_status, legacy_feature_set) =
- legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- return {createWifiStatusFromLegacyError(legacy_status), 0};
- }
- uint32_t legacy_logger_feature_set;
- std::tie(legacy_status, legacy_logger_feature_set) =
- legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- // some devices don't support querying logger feature set
- legacy_logger_feature_set = 0;
- }
- uint32_t hidl_caps;
- if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
- legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
- return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
} // namespace implementation
} // namespace V1_4
} // namespace wifi
diff --git a/wifi/1.4/default/wifi_sta_iface.h b/wifi/1.4/default/wifi_sta_iface.h
index e85e39d..dee04f2 100644
--- a/wifi/1.4/default/wifi_sta_iface.h
+++ b/wifi/1.4/default/wifi_sta_iface.h
@@ -19,7 +19,7 @@
#include <android-base/macros.h>
#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
-#include <android/hardware/wifi/1.4/IWifiStaIface.h>
+#include <android/hardware/wifi/1.3/IWifiStaIface.h>
#include "hidl_callback_util.h"
#include "wifi_iface_util.h"
@@ -35,7 +35,7 @@
/**
* HIDL interface object used to control a STA Iface instance.
*/
-class WifiStaIface : public V1_4::IWifiStaIface {
+class WifiStaIface : public V1_3::IWifiStaIface {
public:
WifiStaIface(const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
@@ -112,8 +112,6 @@
setMacAddress_cb hidl_status_cb) override;
Return<void> getFactoryMacAddress(
getFactoryMacAddress_cb hidl_status_cb) override;
- Return<void> getCapabilities_1_4(
- getCapabilities_1_4_cb hidl_status_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -162,7 +160,6 @@
WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
std::pair<WifiStatus, std::array<uint8_t, 6>>
getFactoryMacAddressInternal();
- std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_4();
std::string ifname_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
diff --git a/wifi/1.4/types.hal b/wifi/1.4/types.hal
index 0db0c2c..4f1d22e 100644
--- a/wifi/1.4/types.hal
+++ b/wifi/1.4/types.hal
@@ -17,6 +17,8 @@
package android.hardware.wifi@1.4;
import @1.0::MacAddress;
+import @1.0::NanBandIndex;
+import @1.0::NanBandSpecificConfig;
import @1.0::Rssi;
import @1.0::RttBw;
import @1.0::RttConfig;
@@ -28,6 +30,7 @@
import @1.0::TimeStampInUs;
import @1.0::WifiBand;
import @1.0::WifiChannelInfo;
+import @1.0::WifiChannelInMhz;
import @1.0::WifiChannelWidthInMhz;
import @1.0::WifiInformationElement;
import @1.0::WifiRateNss;
@@ -37,22 +40,32 @@
* Wifi bands defined in 80211 spec.
*/
enum WifiBand : @1.0::WifiBand {
- /**
- * 6 GHz.
- */
- BAND_6GHZ = 8,
- /**
- * 5 GHz no DFS + 6 GHz.
- */
- BAND_5GHZ_6GHZ = 10,
- /**
- * 2.4 GHz + 5 GHz no DFS + 6 GHz.
- */
- BAND_24GHZ_5GHZ_6GHZ = 11,
- /**
- * 2.4 GHz + 5 GHz with DFS + 6 GHz.
- */
- BAND_24GHZ_5GHZ_WITH_DFS_6GHZ = 15
+ /**
+ * 6 GHz.
+ */
+ BAND_6GHZ = 8,
+ /**
+ * 5 GHz no DFS + 6 GHz.
+ */
+ BAND_5GHZ_6GHZ = 10,
+ /**
+ * 2.4 GHz + 5 GHz no DFS + 6 GHz.
+ */
+ BAND_24GHZ_5GHZ_6GHZ = 11,
+ /**
+ * 2.4 GHz + 5 GHz with DFS + 6 GHz.
+ */
+ BAND_24GHZ_5GHZ_WITH_DFS_6GHZ = 15,
+};
+
+/**
+ * The discovery bands supported by NAN.
+ */
+enum NanBandIndex : @1.0::NanBandIndex {
+ /**
+ * Index for 6 GHz band.
+ */
+ NAN_BAND_6GHZ = 2,
};
/**
@@ -76,6 +89,183 @@
};
/**
+ * Debug configuration parameters. Many of these allow non-standard-compliant operation and are
+ * not intended for normal operational mode.
+ */
+struct NanDebugConfig {
+ /**
+ * Specification of the lower 2 bytes of the cluster ID. The cluster ID is 50-60-9a-01-00-00 to
+ * 50-60-9a-01-FF-FF. Configuration of the bottom and top values of the range (which defaults to
+ * 0x0000 and 0xFFFF respectively).
+ * Configuration is only used if |validClusterIdVals| is set to true.
+ */
+ bool validClusterIdVals;
+
+ uint16_t clusterIdBottomRangeVal;
+
+ uint16_t clusterIdTopRangeVal;
+
+ /**
+ * NAN management interface address, if specified (|validIntfAddrVal| is true) then overrides any
+ * other configuration (specifically the default randomization configured by
+ * |NanConfigRequest.macAddressRandomizationIntervalSec|).
+ */
+ bool validIntfAddrVal;
+
+ MacAddress intfAddrVal;
+
+ /**
+ * Combination of the 24 bit Organizationally Unique ID (OUI) and the 8 bit OUI Type.
+ * Used if |validOuiVal| is set to true.
+ */
+ bool validOuiVal;
+
+ uint32_t ouiVal;
+
+ /**
+ * Force the Random Factor to the specified value for all transmitted Sync/Discovery beacons.
+ * Used if |validRandomFactorForceVal| is set to true.
+ * NAN Spec: Master Indication Attribute / Random Factor
+ */
+ bool validRandomFactorForceVal;
+
+ uint8_t randomFactorForceVal;
+
+ /**
+ * Forces the hop-count for all transmitted Sync and Discovery Beacons NO matter the real
+ * hop-count being received over the air. Used if the |validHopCountForceVal}| flag is set to
+ * true.
+ * NAN Spec: Cluster Attribute / Anchor Master Information / Hop Count to Anchor Master
+ */
+ bool validHopCountForceVal;
+
+ uint8_t hopCountForceVal;
+
+ /**
+ * Frequency in MHz to of the discovery channel in the specified band. Indexed by |NanBandIndex|.
+ * Used if the |validDiscoveryChannelVal| is set to true.
+ */
+ bool validDiscoveryChannelVal;
+
+ WifiChannelInMhz[3] discoveryChannelMhzVal;
+
+ /**
+ * Specifies whether sync/discovery beacons are transmitted in the specified band. Indexed by
+ * |NanBandIndex|. Used if the |validUseBeaconsInBandVal| is set to true.
+ */
+ bool validUseBeaconsInBandVal;
+
+ bool[3] useBeaconsInBandVal;
+
+ /**
+ * Specifies whether SDF (service discovery frames) are transmitted in the specified band. Indexed
+ * by |NanBandIndex|. Used if the |validUseSdfInBandVal| is set to true.
+ */
+ bool validUseSdfInBandVal;
+
+ bool[3] useSdfInBandVal;
+};
+
+/**
+ * Configuration parameters of NAN: used when enabling and re-configuring a NAN cluster.
+ */
+struct NanConfigRequest {
+ /**
+ * Master preference of this device.
+ * NAN Spec: Master Indication Attribute / Master Preference
+ */
+ uint8_t masterPref;
+
+ /**
+ * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered
+ * for |NanClusterEventType.DISCOVERY_MAC_ADDRESS_CHANGED|.
+ */
+ bool disableDiscoveryAddressChangeIndication;
+
+ /**
+ * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered
+ * for |NanClusterEventType.STARTED_CLUSTER|.
+ */
+ bool disableStartedClusterIndication;
+
+ /**
+ * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered
+ * for |NanClusterEventType.JOINED_CLUSTER|.
+ */
+ bool disableJoinedClusterIndication;
+
+ /**
+ * Control whether publish service IDs are included in Sync/Discovery beacons.
+ * NAN Spec: Service ID List Attribute
+ */
+ bool includePublishServiceIdsInBeacon;
+
+ /**
+ * If |includePublishServiceIdsInBeacon| is true then specifies the number of publish service IDs
+ * to include in the Sync/Discovery beacons:
+ * Value = 0: include as many service IDs as will fit into the maximum allowed beacon frame size.
+ * Value must fit within 7 bits - i.e. <= 127.
+ */
+ uint8_t numberOfPublishServiceIdsInBeacon;
+
+ /**
+ * Control whether subscribe service IDs are included in Sync/Discovery beacons.
+ * Spec: Subscribe Service ID List Attribute
+ */
+ bool includeSubscribeServiceIdsInBeacon;
+
+ /**
+ * If |includeSubscribeServiceIdsInBeacon| is true then specifies the number of subscribe service
+ * IDs to include in the Sync/Discovery beacons:
+ * Value = 0: include as many service IDs as will fit into the maximum allowed beacon frame size.
+ * Value must fit within 7 bits - i.e. <= 127.
+ */
+ uint8_t numberOfSubscribeServiceIdsInBeacon;
+
+ /**
+ * Number of samples used to calculate RSSI.
+ */
+ uint16_t rssiWindowSize;
+
+ /**
+ * Specifies the interval in seconds that the NAN management interface MAC address is randomized.
+ * A value of 0 is used to disable the MAC address randomization
+ */
+ uint32_t macAddressRandomizationIntervalSec;
+
+ /**
+ * Additional configuration provided per band: indexed by |NanBandIndex|.
+ */
+ NanBandSpecificConfig[3] bandSpecificConfig;
+};
+
+/**
+ * Enable requests for NAN: start-up configuration |IWifiNanIface.enableRequest|.
+ */
+struct NanEnableRequest {
+ /**
+ * Enable operation in a specific band: indexed by |NanBandIndex|.
+ */
+ bool[3] operateInBand;
+
+ /**
+ * Specify extent of cluster by specifying the max hop count.
+ */
+ uint8_t hopCountMax;
+
+ /**
+ * Configurations of NAN cluster operation. Can also be modified at run-time using
+ * |IWifiNanIface.configRequest|.
+ */
+ NanConfigRequest configParams;
+
+ /**
+ * Non-standard configurations of NAN cluster operation - useful for debugging operations.
+ */
+ NanDebugConfig debugConfigs;
+};
+
+/**
* RTT configuration.
*/
struct RttConfig {
diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp
index f3be25d..46ac3ee 100644
--- a/wifi/1.4/vts/functional/Android.bp
+++ b/wifi/1.4/vts/functional/Android.bp
@@ -21,7 +21,8 @@
srcs: [
"VtsHalWifiV1_4TargetTest.cpp",
"wifi_ap_iface_hidl_test.cpp",
- "wifi_chip_hidl_test.cpp"
+ "wifi_chip_hidl_test.cpp",
+ "wifi_nan_iface_hidl_test.cpp"
],
static_libs: [
"VtsHalWifiV1_0TargetTestUtil",
diff --git a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
new file mode 100644
index 0000000..245e906
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -0,0 +1,544 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Nanache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include <android/hardware/wifi/1.2/IWifiNanIfaceEventCallback.h>
+#include <android/hardware/wifi/1.4/IWifi.h>
+#include <android/hardware/wifi/1.4/IWifiNanIface.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using namespace ::android::hardware::wifi::V1_0;
+using namespace ::android::hardware::wifi::V1_2;
+using namespace ::android::hardware::wifi::V1_4;
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+#define TIMEOUT_PERIOD 10
+
+android::sp<android::hardware::wifi::V1_4::IWifiNanIface> getWifiNanIface_1_4(
+ const std::string& instance_name) {
+ return android::hardware::wifi::V1_4::IWifiNanIface::castFrom(
+ getWifiNanIface(instance_name));
+}
+
+/**
+ * Fixture to use for all NAN Iface HIDL interface tests.
+ */
+class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ iwifiNanIface = getWifiNanIface_1_4(GetInstanceName());
+ ASSERT_NE(nullptr, iwifiNanIface.get());
+ ASSERT_EQ(WifiStatusCode::SUCCESS,
+ HIDL_INVOKE(iwifiNanIface, registerEventCallback_1_2,
+ new WifiNanIfaceEventCallback(*this))
+ .code);
+ }
+
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+ /* Used as a mechanism to inform the test about data/event callback */
+ inline void notify() {
+ std::unique_lock<std::mutex> lock(mtx_);
+ count_++;
+ cv_.notify_one();
+ }
+
+ enum CallbackType {
+ INVALID = -2,
+ ANY_CALLBACK = -1,
+
+ NOTIFY_CAPABILITIES_RESPONSE = 0,
+ NOTIFY_ENABLE_RESPONSE,
+ NOTIFY_CONFIG_RESPONSE,
+ NOTIFY_DISABLE_RESPONSE,
+ NOTIFY_START_PUBLISH_RESPONSE,
+ NOTIFY_STOP_PUBLISH_RESPONSE,
+ NOTIFY_START_SUBSCRIBE_RESPONSE,
+ NOTIFY_STOP_SUBSCRIBE_RESPONSE,
+ NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE,
+ NOTIFY_CREATE_DATA_INTERFACE_RESPONSE,
+ NOTIFY_DELETE_DATA_INTERFACE_RESPONSE,
+ NOTIFY_INITIATE_DATA_PATH_RESPONSE,
+ NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE,
+ NOTIFY_TERMINATE_DATA_PATH_RESPONSE,
+
+ EVENT_CLUSTER_EVENT,
+ EVENT_DISABLED,
+ EVENT_PUBLISH_TERMINATED,
+ EVENT_SUBSCRIBE_TERMINATED,
+ EVENT_MATCH,
+ EVENT_MATCH_EXPIRED,
+ EVENT_FOLLOWUP_RECEIVED,
+ EVENT_TRANSMIT_FOLLOWUP,
+ EVENT_DATA_PATH_REQUEST,
+ EVENT_DATA_PATH_CONFIRM,
+ EVENT_DATA_PATH_TERMINATED,
+ EVENT_DATA_PATH_CONFIRM_1_2,
+ EVENT_DATA_PATH_SCHEDULE_UPDATE
+ };
+
+ /* Test code calls this function to wait for data/event callback */
+ /* Must set callbackType = INVALID before call this function */
+ inline std::cv_status wait(CallbackType waitForCallbackType) {
+ std::unique_lock<std::mutex> lock(mtx_);
+
+ EXPECT_NE(INVALID, waitForCallbackType); // can't ASSERT in a
+ // non-void-returning method
+
+ std::cv_status status = std::cv_status::no_timeout;
+ auto now = std::chrono::system_clock::now();
+ while (count_ == 0) {
+ status = cv_.wait_until(lock,
+ now + std::chrono::seconds(TIMEOUT_PERIOD));
+ if (status == std::cv_status::timeout) return status;
+ if (waitForCallbackType != ANY_CALLBACK &&
+ callbackType != INVALID &&
+ callbackType != waitForCallbackType) {
+ count_--;
+ }
+ }
+ count_--;
+ return status;
+ }
+
+ class WifiNanIfaceEventCallback
+ : public ::android::hardware::wifi::V1_2::IWifiNanIfaceEventCallback {
+ WifiNanIfaceHidlTest& parent_;
+
+ public:
+ WifiNanIfaceEventCallback(WifiNanIfaceHidlTest& parent)
+ : parent_(parent){};
+
+ virtual ~WifiNanIfaceEventCallback() = default;
+
+ Return<void> notifyCapabilitiesResponse(
+ uint16_t id, const WifiNanStatus& status,
+ const NanCapabilities& capabilities) override {
+ parent_.callbackType = NOTIFY_CAPABILITIES_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.capabilities = capabilities;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyEnableResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_ENABLE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyConfigResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_CONFIG_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyDisableResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_DISABLE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyStartPublishResponse(uint16_t id,
+ const WifiNanStatus& status,
+ uint8_t sessionId) override {
+ parent_.callbackType = NOTIFY_START_PUBLISH_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.sessionId = sessionId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyStopPublishResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_STOP_PUBLISH_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyStartSubscribeResponse(uint16_t id,
+ const WifiNanStatus& status,
+ uint8_t sessionId) override {
+ parent_.callbackType = NOTIFY_START_SUBSCRIBE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.sessionId = sessionId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyStopSubscribeResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_STOP_SUBSCRIBE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyTransmitFollowupResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyCreateDataInterfaceResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyDeleteDataInterfaceResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyInitiateDataPathResponse(
+ uint16_t id, const WifiNanStatus& status,
+ uint32_t ndpInstanceId) override {
+ parent_.callbackType = NOTIFY_INITIATE_DATA_PATH_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+ parent_.ndpInstanceId = ndpInstanceId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyRespondToDataPathIndicationResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType =
+ NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> notifyTerminateDataPathResponse(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = NOTIFY_TERMINATE_DATA_PATH_RESPONSE;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventClusterEvent(
+ const NanClusterEventInd& event) override {
+ parent_.callbackType = EVENT_CLUSTER_EVENT;
+
+ parent_.nanClusterEventInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDisabled(const WifiNanStatus& status) override {
+ parent_.callbackType = EVENT_DISABLED;
+
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventPublishTerminated(
+ uint8_t sessionId, const WifiNanStatus& status) override {
+ parent_.callbackType = EVENT_PUBLISH_TERMINATED;
+
+ parent_.sessionId = sessionId;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventSubscribeTerminated(
+ uint8_t sessionId, const WifiNanStatus& status) override {
+ parent_.callbackType = EVENT_SUBSCRIBE_TERMINATED;
+
+ parent_.sessionId = sessionId;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventMatch(const NanMatchInd& event) override {
+ parent_.callbackType = EVENT_MATCH;
+
+ parent_.nanMatchInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventMatchExpired(uint8_t discoverySessionId,
+ uint32_t peerId) override {
+ parent_.callbackType = EVENT_MATCH_EXPIRED;
+
+ parent_.sessionId = discoverySessionId;
+ parent_.peerId = peerId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventFollowupReceived(
+ const NanFollowupReceivedInd& event) override {
+ parent_.callbackType = EVENT_FOLLOWUP_RECEIVED;
+
+ parent_.nanFollowupReceivedInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventTransmitFollowup(
+ uint16_t id, const WifiNanStatus& status) override {
+ parent_.callbackType = EVENT_TRANSMIT_FOLLOWUP;
+
+ parent_.id = id;
+ parent_.status = status;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathRequest(
+ const NanDataPathRequestInd& event) override {
+ parent_.callbackType = EVENT_DATA_PATH_REQUEST;
+
+ parent_.nanDataPathRequestInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathConfirm(
+ const ::android::hardware::wifi::V1_0::NanDataPathConfirmInd& event)
+ override {
+ parent_.callbackType = EVENT_DATA_PATH_CONFIRM;
+
+ parent_.nanDataPathConfirmInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathTerminated(uint32_t ndpInstanceId) override {
+ parent_.callbackType = EVENT_DATA_PATH_TERMINATED;
+
+ parent_.ndpInstanceId = ndpInstanceId;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathConfirm_1_2(
+ const ::android::hardware::wifi::V1_2::NanDataPathConfirmInd& event)
+ override {
+ parent_.callbackType = EVENT_DATA_PATH_CONFIRM_1_2;
+
+ parent_.nanDataPathConfirmInd_1_2 = event;
+
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> eventDataPathScheduleUpdate(
+ const NanDataPathScheduleUpdateInd& event) override {
+ parent_.callbackType = EVENT_DATA_PATH_SCHEDULE_UPDATE;
+
+ parent_.nanDataPathScheduleUpdateInd = event;
+
+ parent_.notify();
+ return Void();
+ }
+ };
+
+ private:
+ // synchronization objects
+ std::mutex mtx_;
+ std::condition_variable cv_;
+ int count_;
+
+ protected:
+ android::sp<::android::hardware::wifi::V1_4::IWifiNanIface> iwifiNanIface;
+
+ // Data from IWifiNanIfaceEventCallback callbacks: this is the collection of
+ // all arguments to all callbacks. They are set by the callback
+ // (notifications or events) and can be retrieved by tests.
+ CallbackType callbackType;
+ uint16_t id;
+ WifiNanStatus status;
+ NanCapabilities capabilities;
+ uint8_t sessionId;
+ uint32_t ndpInstanceId;
+ NanClusterEventInd nanClusterEventInd;
+ NanMatchInd nanMatchInd;
+ uint32_t peerId;
+ NanFollowupReceivedInd nanFollowupReceivedInd;
+ NanDataPathRequestInd nanDataPathRequestInd;
+ ::android::hardware::wifi::V1_0::NanDataPathConfirmInd
+ nanDataPathConfirmInd;
+ ::android::hardware::wifi::V1_2::NanDataPathConfirmInd
+ nanDataPathConfirmInd_1_2;
+ NanDataPathScheduleUpdateInd nanDataPathScheduleUpdateInd;
+
+ std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * Create:
+ * Ensures that an instance of the IWifiNanIface proxy object is
+ * successfully created.
+ */
+TEST_P(WifiNanIfaceHidlTest, Create) {
+ // The creation of a proxy object is tested as part of SetUp method.
+}
+
+/*
+ * enableRequest_1_4InvalidArgs: validate that fails with invalid arguments
+ */
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_4InvalidArgs) {
+ uint16_t inputCmdId = 10;
+ callbackType = INVALID;
+ ::android::hardware::wifi::V1_4::NanEnableRequest nanEnableRequest = {};
+ NanConfigRequestSupplemental nanConfigRequestSupp = {};
+ ASSERT_EQ(WifiStatusCode::SUCCESS,
+ HIDL_INVOKE(iwifiNanIface, enableRequest_1_4, inputCmdId,
+ nanEnableRequest, nanConfigRequestSupp)
+ .code);
+ // wait for a callback
+ ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
+ ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType);
+ ASSERT_EQ(id, inputCmdId);
+ ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+}
+
+/*
+ * enableRequest_1_4ShimInvalidArgs: validate that fails with invalid arguments
+ * to the shim
+ */
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_4ShimInvalidArgs) {
+ uint16_t inputCmdId = 10;
+ ::android::hardware::wifi::V1_4::NanEnableRequest nanEnableRequest = {};
+ nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon =
+ 128; // must be <= 127
+ NanConfigRequestSupplemental nanConfigRequestSupp = {};
+ ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS,
+ HIDL_INVOKE(iwifiNanIface, enableRequest_1_4, inputCmdId,
+ nanEnableRequest, nanConfigRequestSupp)
+ .code);
+}
+
+/*
+ * configRequest_1_4InvalidArgs: validate that fails with invalid arguments
+ */
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_4InvalidArgs) {
+ uint16_t inputCmdId = 10;
+ callbackType = INVALID;
+ ::android::hardware::wifi::V1_4::NanConfigRequest nanConfigRequest = {};
+ NanConfigRequestSupplemental nanConfigRequestSupp = {};
+ ASSERT_EQ(WifiStatusCode::SUCCESS,
+ HIDL_INVOKE(iwifiNanIface, configRequest_1_4, inputCmdId,
+ nanConfigRequest, nanConfigRequestSupp)
+ .code);
+ // wait for a callback
+ ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
+ ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType);
+ ASSERT_EQ(id, inputCmdId);
+ ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+}
+
+/*
+ * configRequest_1_4ShimInvalidArgs: validate that fails with invalid arguments
+ * to the shim
+ */
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_4ShimInvalidArgs) {
+ uint16_t inputCmdId = 10;
+ ::android::hardware::wifi::V1_4::NanConfigRequest nanConfigRequest = {};
+ nanConfigRequest.numberOfPublishServiceIdsInBeacon = 128; // must be <= 127
+ NanConfigRequestSupplemental nanConfigRequestSupp = {};
+ ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS,
+ HIDL_INVOKE(iwifiNanIface, configRequest_1_4, inputCmdId,
+ nanConfigRequest, nanConfigRequestSupp)
+ .code);
+}
diff --git a/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp
deleted file mode 100644
index ec4b2c9..0000000
--- a/wifi/1.4/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Staache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-
-#include <android/hardware/wifi/1.4/IWifiStaIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-
-#include "wifi_hidl_call_util.h"
-#include "wifi_hidl_test_utils.h"
-
-using ::android::sp;
-using ::android::hardware::hidl_array;
-using ::android::hardware::wifi::V1_0::WifiStatus;
-using ::android::hardware::wifi::V1_0::WifiStatusCode;
-using ::android::hardware::wifi::V1_4::IWifiStaIface;
-
-/**
- * Fixture to use for all STA Iface HIDL interface tests.
- */
-class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
- virtual void SetUp() override {
- wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface());
- ASSERT_NE(nullptr, wifi_sta_iface_.get());
- }
-
- virtual void TearDown() override { stopWifi(); }
-
- protected:
- sp<IWifiStaIface> wifi_sta_iface_;
-};
-
-/*
- * GetCapabilities_1_4
- */
-TEST_F(WifiStaIfaceHidlTest, GetCapabilities_1_4) {
- configureChipForIfaceType(IfaceType::STA, true);
-
- const auto& status_and_caps =
- HIDL_INVOKE(wifi_sta_iface_, getCapabilities_1_4);
- if (status_and_caps.first.code != WifiStatusCode::SUCCESS) {
- EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED,
- status_and_caps.first.code);
- return;
- }
- EXPECT_NE(0u, status_and_caps.second);
-}
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 1804d8c..345cf31 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
@@ -233,7 +233,11 @@
TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
getIfaceParamsWithoutAcs(), getPskNwParams());
- EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ // FAILURE_UNKNOWN is used by higher versions to indicate this API is no
+ // longer supported (replaced by an upgraded API)
+ if (status.code != HostapdStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ }
}
/**
@@ -243,7 +247,11 @@
TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
getIfaceParamsWithoutAcs(), getOpenNwParams());
- EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ // FAILURE_UNKNOWN is used by higher versions to indicate this API is no
+ // longer supported (replaced by an upgraded API)
+ if (status.code != HostapdStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ }
}
/**
@@ -269,10 +277,14 @@
TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
getIfaceParamsWithoutAcs(), getPskNwParams());
- EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
- status =
- HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
- EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ // FAILURE_UNKNOWN is used by higher versions to indicate this API is no
+ // longer supported (replaced by an upgraded API)
+ if (status.code != HostapdStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ status =
+ HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ }
}
/**
diff --git a/wifi/hostapd/1.2/Android.bp b/wifi/hostapd/1.2/Android.bp
new file mode 100644
index 0000000..3dcad71
--- /dev/null
+++ b/wifi/hostapd/1.2/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.wifi.hostapd@1.2",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IHostapd.hal",
+ ],
+ interfaces: [
+ "android.hardware.wifi.hostapd@1.0",
+ "android.hardware.wifi.hostapd@1.1",
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/wifi/hostapd/1.2/IHostapd.hal b/wifi/hostapd/1.2/IHostapd.hal
new file mode 100644
index 0000000..b25ea97
--- /dev/null
+++ b/wifi/hostapd/1.2/IHostapd.hal
@@ -0,0 +1,167 @@
+/*
+ * 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.wifi.hostapd@1.2;
+
+import @1.0::IHostapd.NetworkParams;
+import @1.1::IHostapd;
+import HostapdStatus;
+import MacAddress;
+import Ieee80211ReasonCode;
+import DebugLevel;
+
+/**
+ * Top-level object for managing SoftAPs.
+ */
+interface IHostapd extends @1.1::IHostapd {
+ /**
+ * Band bitmMask to use for the SoftAp operations.
+ * A combinatoin of these bits are used to identify the allowed bands
+ * to start the softAp
+ */
+ enum BandMask : uint32_t {
+ /**
+ * 2.4 GHz band.
+ */
+ BAND_2_GHZ = 1 << 0,
+ /**
+ * 5 GHz band.
+ */
+ BAND_5_GHZ = 1 << 1,
+ /**
+ * 6 GHz band.
+ */
+ BAND_6_GHZ = 1 << 2,
+ };
+
+ /**
+ * Parameters to control the HW mode for the interface.
+ */
+ struct HwModeParams {
+ /**
+ * Whether IEEE 802.11ax (HE) is enabled or not.
+ * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is
+ * used with HE.
+ */
+ bool enable80211AX;
+ /**
+ * Whether 6GHz band enabled or not on softAp.
+ * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is
+ * used.
+ */
+ bool enable6GhzBand;
+
+ /**
+ * Whether HE single user beamformer in enabled or not on softAp.
+ * Note: this is only applicable if 802.11ax is supported for softAp
+ */
+ bool enableHeSingleUserBeamformer;
+
+ /**
+ * Whether HE single user beamformee is enabled or not on softAp.
+ * Note: this is only applicable if 802.11ax is supported for softAp
+ */
+ bool enableHeSingleUserBeamformee;
+
+ /**
+ * Whether HE multiple user beamformer is enabled or not on softAp.
+ * Note: this is only applicable if 802.11ax is supported for softAp
+ */
+ bool enableHeMultiUserBeamformer;
+
+ /**
+ * Used BSS Color for softAp running in 802.11ax mode
+ * Note: this is only applicable if 802.11ax is supported for softAp
+ */
+ uint32_t heBssColor;
+
+ /**
+ * Whether HE Target Wait Time (TWT) is enabled or not on softAp.
+ * Note: this is only applicable if 802.11ax is supported for softAp
+ */
+ bool enableHeTargetWakeTime;
+ };
+
+ /**
+ * Parameters to control the channel selection for the interface.
+ */
+ struct ChannelParams {
+ /**
+ * Band to use for the SoftAp operations.
+ */
+ bitfield<BandMask> bandMask;
+ };
+
+ /**
+ * Parameters to use for setting up the access point interface.
+ */
+ struct IfaceParams {
+ /**
+ * Baseline information as defined in HAL 1.1.
+ */
+ @1.1::IHostapd.IfaceParams V1_1;
+ /** Additional Hw mode params for the interface */
+ HwModeParams hwModeParams;
+ /** Additional Channel params for the interface */
+ ChannelParams channelParams;
+ };
+
+ /**
+ * Adds a new access point for hostapd to control.
+ *
+ * This should trigger the setup of an access point with the specified
+ * interface and network params.
+ *
+ * @param ifaceParams AccessPoint Params for the access point.
+ * @param nwParams Network Params for the access point.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |HostapdStatusCode.SUCCESS|,
+ * |HostapdStatusCode.FAILURE_ARGS_INVALID|,
+ * |HostapdStatusCode.FAILURE_UNKNOWN|,
+ * |HostapdStatusCode.FAILURE_IFACE_EXISTS|
+ */
+ addAccessPoint_1_2(IfaceParams ifaceParams, NetworkParams nwParams)
+ generates(HostapdStatus status);
+
+ /**
+ * force one of the hotspot clients disconnect..
+ *
+ * @param ifaceName Name of the interface.
+ * @param clientAddress Mac Address of the hotspot client.
+ * @param reasonCode One of disconnect reason code which defined by 802.11.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |HostapdStatusCode.SUCCESS|,
+ * |HostapdStatusCode.FAILURE_IFACE_UNKNOWN|
+ * |HostapdStatusCode.FAILURE_CLIENT_UNKNOWN|
+ */
+ forceClientDisconnect(string ifaceName, MacAddress clientAddress,
+ Ieee80211ReasonCode reasonCode) generates (HostapdStatus status);
+
+ /**
+ * Set debug parameters for the hostapd.
+ *
+ * @param level Debug logging level for the hostapd.
+ * (one of |DebugLevel| values).
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |HostapdStatusCode.SUCCESS|,
+ * |HostapdStatusCode.FAILURE_UNKNOWN|
+ */
+ setDebugParams(DebugLevel level)
+ generates (HostapdStatus status);
+};
diff --git a/wifi/hostapd/1.2/types.hal b/wifi/hostapd/1.2/types.hal
new file mode 100644
index 0000000..54e6529
--- /dev/null
+++ b/wifi/hostapd/1.2/types.hal
@@ -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.
+ */
+
+package android.hardware.wifi.hostapd@1.2;
+
+import @1.0::HostapdStatusCode;
+
+/**
+ * Enum values indicating the status of any hostapd operation.
+ */
+enum HostapdStatusCode : @1.0::HostapdStatusCode {
+ /**
+ * Failure because unknown the client.
+ */
+ FAILURE_CLIENT_UNKNOWN,
+};
+
+/**
+ * Enum values indicating the reason code for disconnect packet.
+ * Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45).
+ */
+enum Ieee80211ReasonCode : uint16_t {
+ WLAN_REASON_UNSPECIFIED = 1,
+ WLAN_REASON_PREV_AUTH_NOT_VALID = 2,
+ WLAN_REASON_DISASSOC_AP_BUSY = 5,
+};
+
+typedef uint8_t[6] MacAddress;
+
+/**
+ * Generic structure to return the status of any hostapd operation.
+ */
+struct HostapdStatus {
+ HostapdStatusCode code;
+
+ /**
+ * A vendor-specific error message to provide more information beyond the
+ * status code.
+ * This must be used for debugging purposes only.
+ */
+ string debugMessage;
+};
+
+/**
+ * Debug levels for the hostapd.
+ * Only log messages with a level greater than the set level
+ * (via |setDebugParams|) will be logged.
+ */
+enum DebugLevel : uint32_t {
+ EXCESSIVE = 0,
+ MSGDUMP = 1,
+ DEBUG = 2,
+ INFO = 3,
+ WARNING = 4,
+ ERROR = 5
+};
diff --git a/wifi/hostapd/1.2/vts/OWNERS b/wifi/hostapd/1.2/vts/OWNERS
new file mode 100644
index 0000000..8bfb148
--- /dev/null
+++ b/wifi/hostapd/1.2/vts/OWNERS
@@ -0,0 +1,2 @@
+rpius@google.com
+etancohen@google.com
diff --git a/wifi/hostapd/1.2/vts/functional/Android.bp b/wifi/hostapd/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..50cfdee
--- /dev/null
+++ b/wifi/hostapd/1.2/vts/functional/Android.bp
@@ -0,0 +1,37 @@
+//
+// 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: "VtsHalWifiHostapdV1_2TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "VtsHalWifiHostapdV1_2TargetTest.cpp",
+ "hostapd_hidl_test.cpp",
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiHostapdV1_0TargetTestUtil",
+ "android.hardware.wifi.hostapd@1.0",
+ "android.hardware.wifi.hostapd@1.1",
+ "android.hardware.wifi.hostapd@1.2",
+ "android.hardware.wifi@1.0",
+ "libgmock",
+ "libwifi-system",
+ "libwifi-system-iface",
+ ],
+ test_suites: ["general-tests", "vts-core"],
+}
+
diff --git a/wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp b/wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp
new file mode 100644
index 0000000..7e0f3cd
--- /dev/null
+++ b/wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp
@@ -0,0 +1,21 @@
+/*
+ * 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 <VtsHalHidlTargetTestEnvBase.h>
+
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr;
\ No newline at end of file
diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
new file mode 100644
index 0000000..8245f8f
--- /dev/null
+++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/hostapd/1.2/IHostapd.h>
+
+#include "hostapd_hidl_call_util.h"
+#include "hostapd_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::hostapd::V1_2::DebugLevel;
+using ::android::hardware::wifi::hostapd::V1_2::HostapdStatusCode;
+using ::android::hardware::wifi::hostapd::V1_2::Ieee80211ReasonCode;
+using ::android::hardware::wifi::hostapd::V1_2::IHostapd;
+using ::android::hardware::wifi::V1_0::IWifi;
+
+namespace {
+constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1',
+ '2', '3', '4', '5'};
+constexpr char kNwPassphrase[] = "test12345";
+constexpr int kIfaceChannel = 6;
+constexpr int kIfaceInvalidChannel = 567;
+constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0};
+constexpr Ieee80211ReasonCode kTestDisconnectReasonCode =
+ Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED;
+} // namespace
+
+class HostapdHidlTest
+ : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+ public:
+ virtual void SetUp() override {
+ wifi_instance_name_ = std::get<0>(GetParam());
+ hostapd_instance_name_ = std::get<1>(GetParam());
+ stopSupplicantIfNeeded(wifi_instance_name_);
+ startHostapdAndWaitForHidlService(wifi_instance_name_,
+ hostapd_instance_name_);
+ hostapd_ = IHostapd::getService(hostapd_instance_name_);
+ ASSERT_NE(hostapd_.get(), nullptr);
+ }
+
+ virtual void TearDown() override { stopHostapd(wifi_instance_name_); }
+
+ 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();
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithoutAcs() {
+ ::android::hardware::wifi::hostapd::V1_0::IHostapd::IfaceParams
+ iface_params;
+ ::android::hardware::wifi::hostapd::V1_1::IHostapd::IfaceParams
+ iface_params_1_1;
+ IHostapd::IfaceParams iface_params_1_2;
+
+ iface_params.ifaceName = getPrimaryWlanIfaceName();
+ iface_params.hwModeParams.enable80211N = true;
+ iface_params.hwModeParams.enable80211AC = false;
+ iface_params.channelParams.enableAcs = false;
+ iface_params.channelParams.acsShouldExcludeDfs = false;
+ iface_params.channelParams.channel = kIfaceChannel;
+ iface_params_1_1.V1_0 = iface_params;
+ iface_params_1_2.V1_1 = iface_params_1_1;
+ // Newly added attributes in V1_2
+ iface_params_1_2.hwModeParams.enable80211AX = false;
+ iface_params_1_2.hwModeParams.enable6GhzBand = false;
+ iface_params_1_2.channelParams.bandMask = 0;
+ iface_params_1_2.channelParams.bandMask |=
+ IHostapd::BandMask::BAND_2_GHZ;
+ return iface_params_1_2;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithAcs() {
+ // First get the settings for WithoutAcs and then make changes
+ IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs();
+ iface_params_1_2.V1_1.V1_0.channelParams.enableAcs = true;
+ iface_params_1_2.V1_1.V1_0.channelParams.acsShouldExcludeDfs = true;
+ iface_params_1_2.V1_1.V1_0.channelParams.channel = 0;
+ iface_params_1_2.channelParams.bandMask |=
+ IHostapd::BandMask::BAND_5_GHZ;
+
+ return iface_params_1_2;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithAcsAndChannelRange() {
+ IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithAcs();
+ ::android::hardware::wifi::hostapd::V1_1::IHostapd::ChannelParams
+ channelParams;
+ ::android::hardware::wifi::hostapd::V1_1::IHostapd::AcsChannelRange
+ acsChannelRange;
+ acsChannelRange.start = 1;
+ acsChannelRange.end = 11;
+ std::vector<
+ ::android::hardware::wifi::hostapd::V1_1::IHostapd::AcsChannelRange>
+ vec_acsChannelRange;
+ vec_acsChannelRange.push_back(acsChannelRange);
+ channelParams.acsChannelRanges = vec_acsChannelRange;
+ iface_params_1_2.V1_1.channelParams = channelParams;
+ return iface_params_1_2;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidChannelRange() {
+ IHostapd::IfaceParams iface_params_1_2 =
+ getIfaceParamsWithAcsAndChannelRange();
+ iface_params_1_2.V1_1.channelParams.acsChannelRanges[0].start = 222;
+ iface_params_1_2.V1_1.channelParams.acsChannelRanges[0].end = 999;
+ return iface_params_1_2;
+ }
+
+ IHostapd::NetworkParams getOpenNwParams() {
+ IHostapd::NetworkParams nw_params;
+ nw_params.ssid =
+ std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+ nw_params.isHidden = false;
+ nw_params.encryptionType = IHostapd::EncryptionType::NONE;
+ return nw_params;
+ }
+
+ IHostapd::NetworkParams getPskNwParams() {
+ IHostapd::NetworkParams nw_params;
+ nw_params.ssid =
+ std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+ nw_params.isHidden = false;
+ nw_params.encryptionType = IHostapd::EncryptionType::WPA2;
+ nw_params.pskPassphrase = kNwPassphrase;
+ return nw_params;
+ }
+
+ IHostapd::NetworkParams getInvalidPskNwParams() {
+ IHostapd::NetworkParams nw_params;
+ nw_params.ssid =
+ std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+ nw_params.isHidden = false;
+ nw_params.encryptionType = IHostapd::EncryptionType::WPA2;
+ return nw_params;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithInvalidChannel() {
+ IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs();
+ iface_params_1_2.V1_1.V1_0.channelParams.channel = kIfaceInvalidChannel;
+ return iface_params_1_2;
+ }
+
+ // IHostapd object used for all tests in this fixture.
+ sp<IHostapd> hostapd_;
+ std::string wifi_instance_name_;
+ std::string hostapd_instance_name_;
+};
+
+/**
+ * Adds an access point with PSK network config & ACS enabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcs(), getPskNwParams());
+ // TODO: b/140172237, fix this in R.
+ // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with PSK network config, ACS enabled & channel Range.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndChannelRange) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcsAndChannelRange(), getPskNwParams());
+ // TODO: b/140172237, fix this in R
+ // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid channel range.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidChannelRange) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcsAndInvalidChannelRange(),
+ getPskNwParams());
+ // TODO: b/140172237, fix this in R
+ // EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with Open network config & ACS enabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcs(), getOpenNwParams());
+ // TODO: b/140172237, fix this in R
+ // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with PSK network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(), getPskNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with Open network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(), getOpenNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds & then removes an access point with PSK network config & ACS enabled.
+ * Access point creation & removal should pass.
+ */
+TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcs(), getPskNwParams());
+ // TODO: b/140172237, fix this in R
+ /*
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ status =
+ HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+ */
+}
+
+/**
+ * Adds & then removes an access point with PSK network config & ACS disabled.
+ * Access point creation & removal should pass.
+ */
+TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
+ auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(), getPskNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+ auto status =
+ HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+ EXPECT_EQ(
+ android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
+ status.code);
+}
+
+/**
+ * Adds an access point with invalid channel.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithInvalidChannel(), getPskNwParams());
+ EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid PSK network config.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+ getInvalidPskNwParams());
+ EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * forceClientDisconnect should return FAILURE_IFACE_UNKNOWN
+ * when hotspot interface doesn't init..
+ */
+TEST_P(HostapdHidlTest, DisconnectClientWhenIfaceNotAvailable) {
+ auto status =
+ HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(),
+ kTestZeroMacAddr, kTestDisconnectReasonCode);
+ EXPECT_EQ(HostapdStatusCode::FAILURE_IFACE_UNKNOWN, status.code);
+}
+
+/**
+ * forceClientDisconnect should return FAILURE_CLIENT_UNKNOWN
+ * when hotspot interface available.
+ */
+TEST_P(HostapdHidlTest, DisconnectClientWhenIfacAvailable) {
+ auto status_1_2 =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+ getOpenNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+
+ status_1_2 =
+ HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(),
+ kTestZeroMacAddr, kTestDisconnectReasonCode);
+ EXPECT_EQ(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, status_1_2.code);
+}
+
+/*
+ * SetDebugParams
+ */
+TEST_P(HostapdHidlTest, SetDebugParams) {
+ auto status = HIDL_INVOKE(hostapd_, setDebugParams, DebugLevel::EXCESSIVE);
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, HostapdHidlTest,
+ testing::Combine(
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::hostapd::V1_2::IHostapd::descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp
index 15525bb..332ee4a 100644
--- a/wifi/supplicant/1.0/vts/functional/Android.bp
+++ b/wifi/supplicant/1.0/vts/functional/Android.bp
@@ -19,7 +19,7 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["supplicant_hidl_test_utils.cpp"],
export_include_dirs: [
- "."
+ ".",
],
static_libs: [
"VtsHalWifiV1_0TargetTestUtil",
@@ -51,14 +51,17 @@
"libwifi-system",
"libwifi-system-iface",
],
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
cc_test {
name: "VtsHalWifiSupplicantP2pV1_0TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
- "VtsHalWifiSupplicantV1_0TargetTest.cpp",
+ "VtsHalWifiSupplicantP2pV1_0TargetTest.cpp",
"supplicant_p2p_iface_hidl_test.cpp",
],
static_libs: [
@@ -71,5 +74,8 @@
"libwifi-system",
"libwifi-system-iface",
],
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
new file mode 100644
index 0000000..a132707
--- /dev/null
+++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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 <VtsCoreUtil.h>
+#include "supplicant_hidl_test_utils.h"
+
+// TODO(b/143892896): Remove this line after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
+
+int main(int argc, char** argv) {
+ if (!::testing::deviceSupportsFeature("android.hardware.wifi.direct"))
+ return 0;
+
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp
index b7949d1..7e9d4f6 100644
--- a/wifi/supplicant/1.2/vts/functional/Android.bp
+++ b/wifi/supplicant/1.2/vts/functional/Android.bp
@@ -51,6 +51,7 @@
"android.hardware.wifi.supplicant@1.0",
"android.hardware.wifi.supplicant@1.1",
"android.hardware.wifi.supplicant@1.2",
+ "android.hardware.wifi.supplicant@1.3",
"android.hardware.wifi@1.0",
"android.hardware.wifi@1.1",
"libgmock",
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 2ff7751..6272d30 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -22,6 +22,8 @@
#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
#include <android/hardware/wifi/supplicant/1.2/types.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.3/types.h>
#include <hidl/HidlSupport.h>
#include <hidl/Status.h>
@@ -318,6 +320,19 @@
return;
}
+ /* Check if the underlying HAL version is 1.3 or higher and skip the test
+ * in this case. The 1.3 HAL uses different callbacks which are not
+ * supported by 1.2. This will cause this test to fail because the callbacks
+ * it is waiting for will never be called. Note that this test is also
+ * implemented in the 1.3 VTS test.
+ */
+ sp<::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface> v1_3 =
+ ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface::
+ castFrom(sta_iface_);
+ if (v1_3 != nullptr) {
+ GTEST_SKIP() << "Test not supported with this HAL version";
+ }
+
hidl_string uri =
"DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
"0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
@@ -369,6 +384,21 @@
return;
}
+ /* Check if the underlying HAL version is 1.3 or higher and skip the test
+ * in this case. The 1.3 HAL uses different callbacks which are not
+ * supported by 1.2. This will cause this test to fail because the callbacks
+ * it is waiting for will never be called. Note that this test is also
+ * implemented in the 1.3 VTS test.
+ */
+ sp<::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface> v1_3 =
+ ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface::
+ castFrom(sta_iface_);
+
+ if (v1_3 != nullptr) {
+ GTEST_SKIP() << "Test not supported with this HAL version";
+ return;
+ }
+
hidl_string uri =
"DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
"0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal
index bfd8946..58ef165 100644
--- a/wifi/supplicant/1.3/ISupplicantStaIface.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal
@@ -18,6 +18,7 @@
import @1.0::SupplicantStatus;
import @1.2::ISupplicantStaIface;
+import ISupplicantStaNetwork;
import ISupplicantStaIfaceCallback;
/**
@@ -76,4 +77,17 @@
* |SupplicantStatusCode.FAILURE_UNKNOWN|
*/
setMboCellularDataStatus(bool available) generates (SupplicantStatus status);
+
+ /**
+ * Get Key management capabilities of the device
+ *
+ * @return status Status of the operation, and a bitmap of key management mask.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ getKeyMgmtCapabilities_1_3()
+ generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
};
diff --git a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
index 107e0fc..72ba160 100644
--- a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
@@ -28,6 +28,121 @@
*/
interface ISupplicantStaIfaceCallback extends @1.2::ISupplicantStaIfaceCallback {
/**
+ * IEEE Std 802.11-2016 - Table 9-357.
+ * BTM status code filled in BSS transition management response frame.
+ */
+ enum BssTmStatusCode : uint8_t {
+ ACCEPT = 0,
+ REJECT_UNSPECIFIED = 1,
+ REJECT_INSUFFICIENT_BEACON = 2,
+ REJECT_INSUFFICIENT_CAPABITY = 3,
+ REJECT_BSS_TERMINATION_UNDESIRED = 4,
+ REJECT_BSS_TERMINATION_DELAY_REQUEST = 5,
+ REJECT_STA_CANDIDATE_LIST_PROVIDED = 6,
+ REJECT_NO_SUITABLE_CANDIDATES = 7,
+ REJECT_LEAVING_ESS = 8,
+ };
+
+ /**
+ * Bitmask of various information retrieved from BSS transition management request frame.
+ */
+ enum BssTmDataFlagsMask : uint32_t {
+ /**
+ * Preferred candidate list included.
+ */
+ WNM_MODE_PREFERRED_CANDIDATE_LIST_INCLUDED = 1 << 0,
+ /**
+ * Abridged.
+ */
+ WNM_MODE_ABRIDGED = 1 << 1,
+ /**
+ * Disassociation Imminent.
+ */
+ WNM_MODE_DISASSOCIATION_IMMINENT = 1 << 2,
+ /**
+ * BSS termination included.
+ */
+ WNM_MODE_BSS_TERMINATION_INCLUDED = 1 << 3,
+ /**
+ * ESS Disassociation Imminent.
+ */
+ WNM_MODE_ESS_DISASSOCIATION_IMMINENT = 1 << 4,
+ /**
+ * MBO transition reason code included.
+ */
+ MBO_TRANSITION_REASON_CODE_INCLUDED = 1 << 5,
+ /**
+ * MBO retry delay time included.
+ */
+ MBO_ASSOC_RETRY_DELAY_INCLUDED = 1 << 6,
+ /**
+ * MBO cellular data connection preference value included.
+ */
+ MBO_CELLULAR_DATA_CONNECTION_PREFERENCE_INCLUDED = 1 << 7,
+ };
+
+ /**
+ * MBO spec v1.2, 4.2.6 Table 18: MBO transition reason code attribute
+ * values.
+ */
+ enum MboTransitionReasonCode : uint8_t {
+ UNSPECIFIED = 0,
+ EXCESSIVE_FRAME_LOSS = 1,
+ EXCESSIVE_TRAFFIC_DELAY = 2,
+ INSUFFICIENT_BANDWIDTH = 3,
+ LOAD_BALANCING = 4,
+ LOW_RSSI = 5,
+ RX_EXCESSIVE_RETRIES = 6,
+ HIGH_INTERFERENCE = 7,
+ GRAY_ZONE = 8,
+ TRANSITION_TO_PREMIUM_AP = 9,
+ };
+
+ /**
+ * MBO spec v1.2, 4.2.5 Table 16: MBO Cellular Data connection preference
+ * attribute values. AP use this to indicate STA, its preference for the
+ * STA to move from BSS to cellular network.
+ */
+ enum MboCellularDataConnectionPrefValue : uint8_t {
+ EXCLUDED = 0,
+ NOT_PREFERRED = 1,
+ /*
+ * 2-254 Reserved.
+ */
+ PREFERRED = 255,
+ };
+
+ /**
+ * Data retrieved from received BSS transition management request frame.
+ */
+ struct BssTmData {
+ /*
+ * Status code filled in BSS transition management response frame
+ */
+ BssTmStatusCode status;
+
+ /*
+ * Bitmask of BssTmDataFlagsMask
+ */
+ bitfield<BssTmDataFlagsMask> flags;
+
+ /*
+ * Duration for which STA shouldn't try to re-associate.
+ */
+ uint32_t assocRetryDelayMs;
+
+ /*
+ * Reason for BSS transition request.
+ */
+ MboTransitionReasonCode mboTransitionReason;
+
+ /*
+ * Cellular Data Connection preference value.
+ */
+ MboCellularDataConnectionPrefValue mboCellPreference;
+ };
+
+ /**
* Indicates PMK cache added event.
*
* @param expirationTimeInSec expiration time in seconds
@@ -35,4 +150,39 @@
* opaque for the framework and depends on the native implementation.
*/
oneway onPmkCacheAdded(int64_t expirationTimeInSec, vec<uint8_t> serializedEntry);
+
+ /**
+ * Indicates a DPP success event.
+ */
+ oneway onDppSuccess(DppSuccessCode code);
+
+ /**
+ * Indicates a DPP progress event.
+ */
+ oneway onDppProgress_1_3(DppProgressCode code);
+
+ /**
+ * Indicates a DPP failure event.
+ *
+ * ssid: A string indicating the SSID for the AP that the Enrollee attempted to connect.
+ * channelList: A string containing a list of operating channels and operating classes
+ * indicating the channels that the Enrollee scanned in attempting to discover the AP.
+ * The list conforms to the following ABNF syntax:
+ * channel-list2 = class-and-channels *(“,” class-and-channels)
+ * class-and-channels = class “/” channel *(“,” channel)
+ * class = 1*3DIGIT
+ * channel = 1*3DIGIT
+ * bandList: A list of band parameters that are supported by the Enrollee expressed as the
+ * Operating Class.
+ */
+ oneway onDppFailure_1_3(DppFailureCode code, string ssid, string channelList,
+ vec<uint16_t> bandList);
+
+ /**
+ * Indicates BTM request frame handling status.
+ *
+ * @param BssTmData Data retrieved from received BSS transition management
+ * request frame.
+ */
+ oneway onBssTmHandlingDone(BssTmData tmData);
};
diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
index ab08cff..c18bffc 100644
--- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
@@ -16,6 +16,7 @@
package android.hardware.wifi.supplicant@1.3;
+import @1.0::ISupplicantStaNetwork;
import @1.0::SupplicantStatus;
import @1.2::ISupplicantStaNetwork;
@@ -25,6 +26,47 @@
*/
interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork {
/**
+ * Possble mask of values for Proto param.
+ */
+ enum ProtoMask : @1.0::ISupplicantStaNetwork.ProtoMask {
+ WAPI = 1 << 2,
+ };
+
+ /**
+ * Possble mask of values for KeyMgmt param.
+ */
+ enum KeyMgmtMask : @1.2::ISupplicantStaNetwork.KeyMgmtMask {
+ /*
+ * WAPI Psk
+ */
+ WAPI_PSK = 1 << 12,
+ /**
+ * WAPI Cert
+ */
+ WAPI_CERT = 1 << 13,
+ };
+
+ /**
+ * Possble mask of values for PairwiseCipher param.
+ */
+ enum PairwiseCipherMask : @1.2::ISupplicantStaNetwork.PairwiseCipherMask {
+ /**
+ * SMS4 Pairwise Cipher
+ */
+ SMS4 = 1 << 7,
+ };
+
+ /**
+ * Possble mask of values for GroupCipher param.
+ */
+ enum GroupCipherMask : @1.2::ISupplicantStaNetwork.GroupCipherMask {
+ /**
+ * SMS4 Group Cipher
+ */
+ SMS4 = 1 << 7,
+ };
+
+ /**
* Set OCSP (Online Certificate Status Protocol) type for this network.
*
* @param ocspType value to set.
@@ -49,6 +91,139 @@
getOcsp() generates (SupplicantStatus status, OcspType ocspType);
/**
+ * Set key management mask for the network.
+ *
+ * @param keyMgmtMask value to set.
+ * Combination of |KeyMgmtMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ setKeyMgmt_1_3(bitfield<KeyMgmtMask> keyMgmtMask) generates (SupplicantStatus status);
+
+ /**
+ * Get the key mgmt mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * @return keyMgmtMask Combination of |KeyMgmtMask| values.
+ */
+ getKeyMgmt_1_3() generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
+
+ /**
+ * Set proto mask for the network.
+ *
+ * @param protoMask value to set.
+ * Combination of |ProtoMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ setProto_1_3(bitfield<ProtoMask> protoMask) generates (SupplicantStatus status);
+
+ /**
+ * Get the proto mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * @return protoMask Combination of |ProtoMask| values.
+ */
+ getProto_1_3() generates (SupplicantStatus status, bitfield<ProtoMask> protoMask);
+
+ /**
+ * Set group cipher mask for the network.
+ *
+ * @param groupCipherMask value to set.
+ * Combination of |ProtoMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ setGroupCipher_1_3(bitfield<GroupCipherMask> groupCipherMask)
+ generates (SupplicantStatus status);
+
+ /**
+ * Get the pairwise cipher mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * @return pairwiseCipherMask Combination of |PairwiseCipherMask| values.
+ */
+ getPairwiseCipher_1_3()
+ generates (SupplicantStatus status, bitfield<PairwiseCipherMask> pairwiseCipherMask);
+
+ /**
+ * Set pairwise cipher mask for the network.
+ *
+ * @param pairwiseCipherMask value to set.
+ * Combination of |ProtoMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ setPairwiseCipher_1_3(bitfield<PairwiseCipherMask> pairwiseCipherMask)
+ generates (SupplicantStatus status);
+
+ /**
+ * Get the group cipher mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * @return groupCipherMask Combination of |GroupCipherMask| values.
+ */
+ getGroupCipher_1_3()
+ generates (SupplicantStatus status, bitfield<GroupCipherMask> groupCipherMask);
+
+ /**
+ * Set WAPI certificate suite for this network.
+ *
+ * @param suite value to set.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ setWapiCertSuite(string suite) generates (SupplicantStatus status);
+
+ /**
+ * Get WAPI certificate suite set for this network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * @return suite The name of a suite.
+ */
+ getWapiCertSuite() generates (SupplicantStatus status, string suite);
+
+ /**
* Add a PMK into supplicant PMK cache.
*
* @param serializedEntry is serialized PMK cache entry, the content is
diff --git a/wifi/supplicant/1.3/types.hal b/wifi/supplicant/1.3/types.hal
index 4e01ab1..05f4760 100644
--- a/wifi/supplicant/1.3/types.hal
+++ b/wifi/supplicant/1.3/types.hal
@@ -16,6 +16,9 @@
package android.hardware.wifi.supplicant@1.3;
+import @1.2::DppProgressCode;
+import @1.2::DppFailureCode;
+
/**
* OcspType: The type of OCSP request.
*/
@@ -72,3 +75,31 @@
*/
OCE = 1 << 1,
};
+
+/**
+ * DppProgressCode: Progress codes for DPP (Easy Connect)
+ */
+enum DppProgressCode : @1.2::DppProgressCode {
+ CONFIGURATION_SENT_WAITING_RESPONSE,
+ CONFIGURATION_ACCEPTED,
+};
+
+/**
+ * DppSuccessCode: Success codes for DPP (Easy Connect) Configurator
+ */
+enum DppSuccessCode : uint32_t {
+ /*
+ * Replaces @1.2::onDppSuccessConfigSent()
+ */
+ CONFIGURATION_SENT,
+ CONFIGURATION_APPLIED,
+};
+
+/**
+ * DppFailureCode: Error codes for DPP (Easy Connect)
+ */
+enum DppFailureCode : @1.2::DppFailureCode {
+ CONFIGURATION_REJECTED,
+ CANNOT_FIND_NETWORK,
+ ENROLLEE_AUTHENTICATION,
+};
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 2cf5881..adc955e 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -36,13 +36,18 @@
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
using ::android::hardware::wifi::supplicant::V1_2::DppAkm;
using ::android::hardware::wifi::supplicant::V1_2::DppFailureCode;
+using ::android::hardware::wifi::supplicant::V1_2::DppNetRole;
using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode;
using ::android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities;
+using ::android::hardware::wifi::supplicant::V1_3::DppSuccessCode;
using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIfaceCallback;
using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
using ::android::hardware::wifi::supplicant::V1_3::WpaDriverCapabilitiesMask;
+#define TIMEOUT_PERIOD 60
+class IfaceDppCallback;
+
class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {
@@ -57,9 +62,66 @@
int64_t pmkCacheExpirationTimeInSec;
std::vector<uint8_t> serializedPmkCacheEntry;
+ // Data retrieved from BSS transition management frame.
+ ISupplicantStaIfaceCallback::BssTmData tmData;
+
+ enum DppCallbackType {
+ ANY_CALLBACK = -2,
+ INVALID = -1,
+
+ EVENT_SUCCESS = 0,
+ EVENT_PROGRESS,
+ EVENT_FAILURE,
+ };
+
+ DppCallbackType dppCallbackType;
+ uint32_t code;
+
+ /* Used as a mechanism to inform the test about data/event callback */
+ inline void notify() {
+ std::unique_lock<std::mutex> lock(mtx_);
+ count_++;
+ cv_.notify_one();
+ }
+
+ /* Test code calls this function to wait for data/event callback */
+ inline std::cv_status wait(DppCallbackType waitForCallbackType) {
+ std::unique_lock<std::mutex> lock(mtx_);
+ EXPECT_NE(INVALID, waitForCallbackType); // can't ASSERT in a
+ // non-void-returning method
+ auto now = std::chrono::system_clock::now();
+ std::cv_status status =
+ cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+ return status;
+ }
+
+ private:
+ // synchronization objects
+ std::mutex mtx_;
+ std::condition_variable cv_;
+ int count_;
+
protected:
// ISupplicantStaIface object used for all tests in this fixture.
sp<ISupplicantStaIface> sta_iface_;
+ bool isDppSupported() {
+ uint32_t keyMgmtMask = 0;
+
+ // We need to first get the key management capabilities from the device.
+ // If DPP is not supported, we just pass the test.
+ sta_iface_->getKeyMgmtCapabilities_1_3(
+ [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ keyMgmtMask = keyMgmtMaskInternal;
+ });
+
+ if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::DPP)) {
+ // DPP not supported
+ return false;
+ }
+
+ return true;
+ }
};
class IfaceCallback : public ISupplicantStaIfaceCallback {
@@ -150,11 +212,29 @@
Return<void> onDppFailure(DppFailureCode /* code */) override {
return Void();
}
+ Return<void> onDppSuccess(DppSuccessCode /* code */) override {
+ return Void();
+ }
+ Return<void> onDppProgress_1_3(
+ ::android::hardware::wifi::supplicant::V1_3::DppProgressCode /* code */)
+ override {
+ return Void();
+ }
+ Return<void> onDppFailure_1_3(
+ ::android::hardware::wifi::supplicant::V1_3::DppFailureCode /* code */,
+ const hidl_string& /* ssid */, const hidl_string& /* channelList */,
+ const hidl_vec<uint16_t>& /* bandList */) override {
+ return Void();
+ }
Return<void> onPmkCacheAdded(
int64_t /* expirationTimeInSec */,
const hidl_vec<uint8_t>& /* serializedEntry */) override {
return Void();
}
+ Return<void> onBssTmHandlingDone(
+ const ISupplicantStaIfaceCallback::BssTmData& /* data */) override {
+ return Void();
+ }
};
class IfacePmkCacheCallback : public IfaceCallback {
@@ -172,6 +252,53 @@
: parent_(parent) {}
};
+class IfaceDppCallback : public IfaceCallback {
+ SupplicantStaIfaceHidlTest& parent_;
+ Return<void> onDppSuccess(DppSuccessCode code) override {
+ parent_.code = (uint32_t)code;
+ parent_.dppCallbackType =
+ SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_SUCCESS;
+ parent_.notify();
+ return Void();
+ }
+ Return<void> onDppProgress_1_3(
+ ::android::hardware::wifi::supplicant::V1_3::DppProgressCode code)
+ override {
+ parent_.code = (uint32_t)code;
+ parent_.dppCallbackType =
+ SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_PROGRESS;
+ parent_.notify();
+ return Void();
+ }
+ Return<void> onDppFailure_1_3(
+ ::android::hardware::wifi::supplicant::V1_3::DppFailureCode code,
+ const hidl_string& ssid __attribute__((unused)),
+ const hidl_string& channelList __attribute__((unused)),
+ const hidl_vec<uint16_t>& bandList __attribute__((unused))) override {
+ parent_.code = (uint32_t)code;
+ parent_.dppCallbackType =
+ SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE;
+ parent_.notify();
+ return Void();
+ }
+
+ public:
+ IfaceDppCallback(SupplicantStaIfaceHidlTest& parent) : parent_(parent){};
+};
+
+class IfaceBssTmHandlingDoneCallback : public IfaceCallback {
+ SupplicantStaIfaceHidlTest& parent_;
+ Return<void> onBssTmHandlingDone(
+ const ISupplicantStaIfaceCallback::BssTmData& data) override {
+ parent_.tmData = data;
+ return Void();
+ }
+
+ public:
+ IfaceBssTmHandlingDoneCallback(SupplicantStaIfaceHidlTest& parent)
+ : parent_(parent) {}
+};
+
/*
* RegisterCallback_1_3
*/
@@ -227,3 +354,129 @@
EXPECT_EQ(expectedStatusCode, status.code);
});
}
+
+/*
+ * GetKeyMgmtCapabilities_1_3
+ */
+TEST_F(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities_1_3) {
+ sta_iface_->getKeyMgmtCapabilities_1_3([&](const SupplicantStatus& status,
+ uint32_t keyMgmtMask) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ // Even though capabilities vary, these two are always set in HAL
+ // v1.3
+ EXPECT_TRUE(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::NONE);
+ EXPECT_TRUE(keyMgmtMask &
+ ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X);
+ }
+ });
+}
+
+/*
+ * StartDppEnrolleeInitiator
+ */
+TEST_F(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) {
+ // We need to first get the key management capabilities from the device.
+ // If DPP is not supported, we just pass the test.
+ if (!isDppSupported()) {
+ // DPP not supported
+ return;
+ }
+
+ hidl_string uri =
+ "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+ "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
+ uint32_t peer_id = 0;
+
+ // Register callbacks
+ sta_iface_->registerCallback_1_3(
+ new IfaceDppCallback(*this), [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ // Add a peer URI
+ sta_iface_->addDppPeerUri(
+ uri, [&](const SupplicantStatus& status, uint32_t id) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_NE(0, id);
+ EXPECT_NE(-1, id);
+
+ peer_id = id;
+ });
+
+ // Start DPP as Enrollee-Initiator. Since this operation requires two
+ // devices, we start the operation and expect a timeout.
+ sta_iface_->startDppEnrolleeInitiator(
+ peer_id, 0, [&](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ // Wait for the timeout callback
+ ASSERT_EQ(std::cv_status::no_timeout,
+ wait(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE));
+ ASSERT_EQ(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE,
+ dppCallbackType);
+
+ // ...and then remove the peer URI.
+ sta_iface_->removeDppUri(peer_id, [&](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * StartDppConfiguratorInitiator
+ */
+TEST_F(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) {
+ // We need to first get the key management capabilities from the device.
+ // If DPP is not supported, we just pass the test.
+ if (!isDppSupported()) {
+ // DPP not supported
+ return;
+ }
+
+ hidl_string uri =
+ "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+ "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
+ uint32_t peer_id = 0;
+
+ // Register callbacks
+ sta_iface_->registerCallback_1_3(
+ new IfaceDppCallback(*this), [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ // Add a peer URI
+ sta_iface_->addDppPeerUri(
+ uri, [&](const SupplicantStatus& status, uint32_t id) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_NE(0, id);
+ EXPECT_NE(-1, id);
+
+ peer_id = id;
+ });
+
+ std::string ssid =
+ "6D795F746573745F73736964"; // 'my_test_ssid' encoded in hex
+ std::string password = "746F70736563726574"; // 'topsecret' encoded in hex
+
+ // Start DPP as Configurator-Initiator. Since this operation requires two
+ // devices, we start the operation and expect a timeout.
+ sta_iface_->startDppConfiguratorInitiator(
+ peer_id, 0, ssid, password, NULL, DppNetRole::STA, DppAkm::PSK,
+ [&](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ // Wait for the timeout callback
+ ASSERT_EQ(std::cv_status::no_timeout,
+ wait(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE));
+ ASSERT_EQ(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE,
+ dppCallbackType);
+
+ // ...and then remove the peer URI.
+ sta_iface_->removeDppUri(peer_id, [&](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
index 07bc9d8..d6f55f5 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -17,15 +17,18 @@
#include <android-base/logging.h>
#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
#include "supplicant_hidl_test_utils.h"
#include "supplicant_hidl_test_utils_1_3.h"
using ::android::sp;
+using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
using ::android::hardware::wifi::supplicant::V1_3::OcspType;
namespace {
@@ -39,15 +42,37 @@
virtual void SetUp() override {
startSupplicantAndWaitForHidlService();
EXPECT_TRUE(turnOnExcessiveLogging());
+ sta_iface_ = getSupplicantStaIface_1_3();
+ ASSERT_NE(nullptr, sta_iface_.get());
sta_network_ = createSupplicantStaNetwork_1_3();
- ASSERT_NE(sta_network_.get(), nullptr);
+ ASSERT_NE(nullptr, sta_network_.get());
}
virtual void TearDown() override { stopSupplicant(); }
protected:
+ sp<ISupplicantStaIface> sta_iface_;
// ISupplicantStaNetwork object used for all tests in this fixture.
sp<ISupplicantStaNetwork> sta_network_;
+
+ bool isWapiSupported() {
+ uint32_t keyMgmtMask = 0;
+
+ // We need to first get the key management capabilities from the device.
+ // If WAPI is not supported, we just pass the test.
+ sta_iface_->getKeyMgmtCapabilities_1_3(
+ [&](const SupplicantStatus &status, uint32_t keyMgmtMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ keyMgmtMask = keyMgmtMaskInternal;
+ });
+
+ if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK)) {
+ // WAPI not supported
+ return false;
+ }
+
+ return true;
+ }
};
/*
@@ -84,3 +109,160 @@
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
});
}
+
+/*
+ * SetGetKeyMgmt_1_3, check new WAPI proto support
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_3) {
+ uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK;
+
+ sta_network_->setKeyMgmt_1_3(keyMgmt, [](const SupplicantStatus &status) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ }
+ });
+
+ sta_network_->getKeyMgmt_1_3(
+ [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ EXPECT_EQ(keyMgmtOut, keyMgmt);
+ }
+ });
+
+ keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::WAPI_CERT;
+ sta_network_->setKeyMgmt_1_3(keyMgmt, [](const SupplicantStatus &status) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ }
+ });
+
+ sta_network_->getKeyMgmt_1_3(
+ [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ EXPECT_EQ(keyMgmtOut, keyMgmt);
+ }
+ });
+}
+
+/*
+ * SetGetProto_1_3, check new WAPI proto support
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetProto_1_3) {
+ uint32_t wapiProto = (uint32_t)ISupplicantStaNetwork::ProtoMask::WAPI;
+ sta_network_->setProto(wapiProto, [](const SupplicantStatus &status) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ }
+ });
+ sta_network_->getProto([&](const SupplicantStatus &status, uint32_t proto) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ EXPECT_EQ(proto, wapiProto);
+ }
+ });
+}
+
+/*
+ * SetGetGroupCipher_1_3, check new WAPI support
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_3) {
+ uint32_t groupCipher =
+ (uint32_t)ISupplicantStaNetwork::GroupCipherMask::SMS4;
+
+ sta_network_->setGroupCipher_1_3(
+ groupCipher, [](const SupplicantStatus &status) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ }
+ });
+
+ sta_network_->getGroupCipher_1_3(
+ [&groupCipher](const SupplicantStatus &status,
+ uint32_t groupCipherOut) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ EXPECT_EQ(groupCipherOut, groupCipher);
+ }
+ });
+}
+
+/*
+ * SetGetPairwiseCipher_1_3, check new WAPI support
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_3) {
+ uint32_t pairwiseCipher =
+ (uint32_t)ISupplicantStaNetwork::PairwiseCipherMask::SMS4;
+
+ sta_network_->setPairwiseCipher_1_3(
+ pairwiseCipher, [](const SupplicantStatus &status) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ }
+ });
+
+ sta_network_->getPairwiseCipher_1_3(
+ [&pairwiseCipher](const SupplicantStatus &status,
+ uint32_t pairwiseCipherOut) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ EXPECT_EQ(pairwiseCipherOut, pairwiseCipher);
+ }
+ });
+}
+
+/*
+ * SetGetWapiCertSuite
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetWapiCertSuite) {
+ hidl_string testWapiCertSuite = "suite";
+
+ if (isWapiSupported()) {
+ sta_network_->setWapiCertSuite(
+ testWapiCertSuite, [](const SupplicantStatus &status) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN,
+ status.code);
+ }
+ });
+
+ sta_network_->getWapiCertSuite([testWapiCertSuite](
+ const SupplicantStatus &status,
+ const hidl_string &wapiCertSuite) {
+ if (SupplicantStatusCode::SUCCESS != status.code) {
+ // for unsupport case
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ } else {
+ EXPECT_EQ(testWapiCertSuite, wapiCertSuite);
+ }
+ });
+ } else {
+ sta_network_->setWapiCertSuite(
+ testWapiCertSuite, [](const SupplicantStatus &status) {
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+
+ sta_network_->getWapiCertSuite(
+ [testWapiCertSuite](const SupplicantStatus &status,
+ const hidl_string &wapiCertSuite __unused) {
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+ }
+}