Merge "drm vts: introduce helper library" am: 3a8eb92143 am: d3411d0ce4 am: c1d3ef566c
Change-Id: I43c820f1595ee9111b5c9999d3f41845e8c7553d
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/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal
index 2347696..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.
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 adab3d2..6b49e5e 100644
--- a/audio/6.0/config/api/current.txt
+++ b/audio/6.0/config/api/current.txt
@@ -258,8 +258,10 @@
public class GlobalConfiguration {
ctor public GlobalConfiguration();
+ method public boolean getCall_screen_mode_supported();
method public audio.policy.configuration.V6_0.EngineSuffix getEngine_library();
method public boolean getSpeaker_drc_enabled();
+ method public void setCall_screen_mode_supported(boolean);
method public void setEngine_library(audio.policy.configuration.V6_0.EngineSuffix);
method public void setSpeaker_drc_enabled(boolean);
}
diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd
index 3fc60e2..341c6b3 100644
--- a/audio/6.0/config/audio_policy_configuration.xsd
+++ b/audio/6.0/config/audio_policy_configuration.xsd
@@ -66,6 +66,7 @@
</xs:element>
<xs:complexType name="globalConfiguration">
<xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/>
+ <xs:attribute name="call_screen_mode_supported" type="xs:boolean" use="optional"/>
<xs:attribute name="engine_library" type="engineSuffix" use="optional"/>
</xs:complexType>
<xs:complexType name="modules">
diff --git a/audio/README b/audio/README
index abe979c..afafbe3 100644
--- a/audio/README
+++ b/audio/README
@@ -1,5 +1,8 @@
Directory structure of the audio HIDL related code.
+Run `common/all-versions/copyHAL.sh` to create a new version of the audio HAL
+based on an existing one.
+
audio
|-- 2.0 <== core 2.0 HIDL API. .hal can not be moved into the core directory
| because that would change its namespace and include path
@@ -11,13 +14,13 @@
| |-- 2.0 <== HIDL API of V2
| |-- 4.0
| |-- ...
-| `-- all_versions <== code common to all version of both core and effect API
+| `-- all-versions <== code common to all version of both core and effect API
| |-- default <== implementation shared code between core and effect impl
| |-- test <== utilities used by tests
| `-- util <== utilities used by both implementation and tests
|
|-- core <== VTS and default implementation of the core API (not HIDL, see /audio/2.0))
-| `-- all_versions <== Code is version independent through #if and separate files
+| `-- all-versions <== Code is version independent through #if and separate files
| |-- default <== code that wraps the legacy API
| `-- vts <== vts of core API
| |-- 2.0 <== 2.0 specific tests and helpers
@@ -28,6 +31,6 @@
|-- 2.0
|-- 4.0
|-- ...
- `-- all_versions
+ `-- all-versions
|-- default
`-- vts
diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal
index da506d6..26e8acb 100644
--- a/audio/common/6.0/types.hal
+++ b/audio/common/6.0/types.hal
@@ -562,6 +562,8 @@
IN_CALL = 2,
/** Calls handled by apps (Eg: Hangout). */
IN_COMMUNICATION = 3,
+ /** Call screening in progress */
+ CALL_SCREEN = 4,
};
@export(name="", value_prefix="AUDIO_DEVICE_")
@@ -738,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_")
@@ -758,6 +761,11 @@
GAME = 14,
VIRTUAL_SOURCE = 15,
ASSISTANT = 16,
+ CALL_ASSISTANT = 17,
+ EMERGENCY = 1000,
+ SAFETY = 1001,
+ VEHICLE_STATUS = 1002,
+ ANNOUNCEMENT = 1003,
};
/** 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/Android.bp b/audio/core/all-versions/default/Android.bp
index 6f18d1d..b8b7fee 100644
--- a/audio/core/all-versions/default/Android.bp
+++ b/audio/core/all-versions/default/Android.bp
@@ -26,6 +26,7 @@
"libhardware",
"libhidlbase",
"liblog",
+ "libmedia_helper",
"libutils",
"android.hardware.audio.common-util",
],
@@ -37,10 +38,6 @@
"libhardware_headers",
"libmedia_headers",
],
-
- whole_static_libs: [
- "libmedia_helper",
- ],
}
cc_library_shared {
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index ad841ca..47e31c1 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -269,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));
@@ -282,8 +291,7 @@
patch = static_cast<AudioPatchHandle>(halPatch);
}
}
- _hidl_cb(retval, patch);
- return Void();
+ return {retval, patch};
}
Return<Result> Device::releaseAudioPatch(int32_t patch) {
@@ -438,6 +446,19 @@
}
}
+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 0f1aba0..11c1c5a 100644
--- a/audio/core/all-versions/default/PrimaryDevice.cpp
+++ b/audio/core/all-versions/default/PrimaryDevice.cpp
@@ -176,6 +176,13 @@
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.
@@ -196,6 +203,9 @@
case AudioMode::RINGTONE:
case AudioMode::IN_CALL:
case AudioMode::IN_COMMUNICATION:
+#if MAJOR_VERSION >= 6
+ case AudioMode::CALL_SCREEN:
+#endif
break; // Valid values
default:
return Result::INVALID_ARGUMENTS;
diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h
index 80a9638..b0e72d9 100644
--- a/audio/core/all-versions/default/include/core/default/Device.h
+++ b/audio/core/all-versions/default/include/core/default/Device.h
@@ -118,6 +118,9 @@
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;
@@ -136,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 9fc90c3..ccdb7b2 100644
--- a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
+++ b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
@@ -100,6 +100,9 @@
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/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index 709b7cd..b0eb2e0 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -244,7 +244,13 @@
TEST_P(AudioPrimaryHidlTest, setMode) {
doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
// Test Invalid values
- for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) {
+#if MAJOR_VERSION >= 6
+ int maxMode = int(AudioMode::CALL_SCREEN);
+#else
+ int maxMode = int(AudioMode::IN_COMMUNICATION);
+#endif
+
+ for (int mode : {-2, -1, maxMode + 1}) {
ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode)))
<< "mode=" << mode;
}
@@ -253,6 +259,10 @@
AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode);
}
+ // AudioMode::CALL_SCREEN as support is optional
+#if MAJOR_VERSION >= 6
+ ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setMode(AudioMode::CALL_SCREEN));
+#endif
}
TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) {
diff --git a/audio/core/all-versions/vts/functional/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/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index d3545c8..715f376 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -19,12 +19,13 @@
defaults: ["VtsHalTargetTestDefaults"],
static_libs: [
"android.hardware.audio.common.test.utility",
+ "libaudiofoundation",
"libaudiopolicycomponents",
"libmedia_helper",
"libxml2",
],
shared_libs: [
- "libaudiofoundation",
+ "libbinder",
"libfmq",
],
header_libs: [
diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp
index 33ec996..406a571 100644
--- a/audio/effect/all-versions/default/Effect.cpp
+++ b/audio/effect/all-versions/default/Effect.cpp
@@ -307,12 +307,11 @@
Result Effect::getCurrentConfigImpl(uint32_t featureId, uint32_t configSize,
GetCurrentConfigSuccessCallback onSuccess) {
uint32_t halCmd = featureId;
- uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize)];
- memset(halResult, 0, sizeof(halResult));
+ std::vector<uint32_t> halResult(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize), 0);
uint32_t halResultSize = 0;
- return sendCommandReturningStatusAndData(EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG",
- sizeof(uint32_t), &halCmd, &halResultSize, halResult,
- sizeof(uint32_t), [&] { onSuccess(&halResult[1]); });
+ return sendCommandReturningStatusAndData(
+ EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG", sizeof(uint32_t), &halCmd,
+ &halResultSize, &halResult[0], sizeof(uint32_t), [&] { onSuccess(&halResult[1]); });
}
Result Effect::getParameterImpl(uint32_t paramSize, const void* paramData,
@@ -339,8 +338,7 @@
GetSupportedConfigsSuccessCallback onSuccess) {
uint32_t halCmd[2] = {featureId, maxConfigs};
uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * sizeof(configSize);
- uint8_t halResult[halResultSize];
- memset(&halResult[0], 0, halResultSize);
+ std::vector<uint8_t> halResult(static_cast<size_t>(halResultSize), 0);
return sendCommandReturningStatusAndData(
EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS", sizeof(halCmd),
halCmd, &halResultSize, &halResult[0], 2 * sizeof(uint32_t), [&] {
@@ -519,9 +517,9 @@
uint32_t halDataSize;
std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
uint32_t halResultSize = halDataSize;
- uint32_t halResult[volumes.size()];
+ std::vector<uint32_t> halResult(volumes.size(), 0);
Result retval = sendCommandReturningData(EFFECT_CMD_SET_VOLUME, "SET_VOLUME", halDataSize,
- &halData[0], &halResultSize, halResult);
+ &halData[0], &halResultSize, &halResult[0]);
hidl_vec<uint32_t> result;
if (retval == Result::OK) {
result.setToExternal(&halResult[0], halResultSize);
@@ -581,8 +579,6 @@
}
Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
- uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
- memset(halResult, 0, sizeof(halResult));
EffectAuxChannelsConfig result;
Result retval = getCurrentConfigImpl(
EFFECT_FEATURE_AUX_CHANNELS, sizeof(channel_config_t), [&](void* configData) {
@@ -594,11 +590,12 @@
}
Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
- uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
+ std::vector<uint32_t> halCmd(
+ alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t)), 0);
halCmd[0] = EFFECT_FEATURE_AUX_CHANNELS;
effectAuxChannelsConfigToHal(config, reinterpret_cast<channel_config_t*>(&halCmd[1]));
return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG,
- "SET_FEATURE_CONFIG AUX_CHANNELS", sizeof(halCmd), halCmd);
+ "SET_FEATURE_CONFIG AUX_CHANNELS", halCmd.size(), &halCmd[0]);
}
Return<Result> Effect::setAudioSource(AudioSource source) {
@@ -692,12 +689,11 @@
Return<Result> Effect::setCurrentConfigForFeature(uint32_t featureId,
const hidl_vec<uint8_t>& configData) {
- uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size())];
- memset(halCmd, 0, sizeof(halCmd));
+ std::vector<uint32_t> halCmd(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size()), 0);
halCmd[0] = featureId;
memcpy(&halCmd[1], &configData[0], configData.size());
return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG",
- sizeof(halCmd), halCmd);
+ halCmd.size(), &halCmd[0]);
}
Return<Result> Effect::close() {
diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt
index ccbc828..29a9cd4 100644
--- a/audio/policy/1.0/xml/api/current.txt
+++ b/audio/policy/1.0/xml/api/current.txt
@@ -129,6 +129,7 @@
enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_BEACON;
enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY;
enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_BYPASS_MUTE;
+ enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_CAPTURE_PRIVATE;
enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_DEEP_BUFFER;
enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_HW_AV_SYNC;
enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_HW_HOTWORD;
@@ -212,6 +213,7 @@
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANT;
+ enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_GAME;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_MEDIA;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION;
diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
index a23d9a8..842e724 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -342,6 +342,7 @@
<xs:enumeration value="AUDIO_USAGE_GAME"/>
<xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE"/>
<xs:enumeration value="AUDIO_USAGE_ASSISTANT"/>
+ <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT"/>
</xs:restriction>
</xs:simpleType>
@@ -370,6 +371,7 @@
<xs:enumeration value="AUDIO_FLAG_NO_MEDIA_PROJECTION"/>
<xs:enumeration value="AUDIO_FLAG_MUTE_HAPTIC"/>
<xs:enumeration value="AUDIO_FLAG_NO_SYSTEM_CAPTURE"/>
+ <xs:enumeration value="AUDIO_FLAG_CAPTURE_PRIVATE"/>
</xs:restriction>
</xs:simpleType>
diff --git a/automotive/OWNERS b/automotive/OWNERS
index 3cf4489..83ee63c 100644
--- a/automotive/OWNERS
+++ b/automotive/OWNERS
@@ -1,4 +1,5 @@
-randolphs@google.com
pirozzoj@google.com
twasilczyk@google.com
pfg@google.com
+gurunagarajan@google.com
+keunyoung@google.com
diff --git a/automotive/audiocontrol/1.0/IAudioControl.hal b/automotive/audiocontrol/1.0/IAudioControl.hal
index 3c8b086..2e7ef75 100644
--- a/automotive/audiocontrol/1.0/IAudioControl.hal
+++ b/automotive/audiocontrol/1.0/IAudioControl.hal
@@ -29,6 +29,11 @@
*
* For every context, a valid bus number (0 - num busses-1) must be returned. If an
* unrecognized contextNumber is encountered, then -1 shall be returned.
+ *
+ * Deprecated: usage of this API and car_volume_groups.xml has been replaced with
+ * car_audio_configuration.xml. If using car_audio_configuration.xml, then the framework
+ * will not call this method. If it doesn't, then it will load car_volume_groups.xml and
+ * call this method.
*/
getBusForContext(ContextNumber contextNumber)
generates (int32_t busNumber);
diff --git a/automotive/audiocontrol/1.0/default/Android.bp b/automotive/audiocontrol/1.0/default/Android.bp
index 314830b..3d04c89 100644
--- a/automotive/audiocontrol/1.0/default/Android.bp
+++ b/automotive/audiocontrol/1.0/default/Android.bp
@@ -29,7 +29,7 @@
"liblog",
"libutils",
],
-
+ vintf_fragments: ["audiocontrol_manifest.xml"],
cflags: [
"-DLOG_TAG=\"AudCntrlDrv\"",
"-O0",
diff --git a/automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml b/automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml
new file mode 100644
index 0000000..0981eb7
--- /dev/null
+++ b/automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.automotive.audiocontrol</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IAudioControl</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
\ No newline at end of file
diff --git a/automotive/audiocontrol/2.0/Android.bp b/automotive/audiocontrol/2.0/Android.bp
new file mode 100644
index 0000000..2a9f849
--- /dev/null
+++ b/automotive/audiocontrol/2.0/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.automotive.audiocontrol@2.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IAudioControl.hal",
+ "ICloseHandle.hal",
+ "IFocusListener.hal",
+ ],
+ interfaces: [
+ "android.hidl.base@1.0",
+ "android.hardware.audio.common@6.0",
+ ],
+ gen_java: true,
+}
diff --git a/automotive/audiocontrol/2.0/IAudioControl.hal b/automotive/audiocontrol/2.0/IAudioControl.hal
new file mode 100644
index 0000000..1073498
--- /dev/null
+++ b/automotive/audiocontrol/2.0/IAudioControl.hal
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+import ICloseHandle;
+import IFocusListener;
+import android.hardware.audio.common@6.0::AudioUsage;
+
+/**
+ * Interacts with the car's audio subsystem to manage audio sources and volumes
+ */
+interface IAudioControl {
+ /**
+ * Registers focus listener to be used by HAL for requesting and abandoning audio focus.
+ *
+ * It is expected that there will only ever be a single focus listener registered. If the
+ * observer dies, the HAL implementation must unregister observer automatically. If called when
+ * a listener is already registered, the existing one should be unregistered and replaced with
+ * the new listener.
+ *
+ * @param listener the listener interface
+ * @return closeHandle A handle to unregister observer.
+ */
+ registerFocusListener(IFocusListener listener) generates (ICloseHandle closeHandle);
+
+ /**
+ * Notifies HAL of changes in audio focus status for focuses requested or abandoned by the HAL.
+ *
+ * This will be called in response to IFocusListener's requestAudioFocus and
+ * abandonAudioFocus, as well as part of any change in focus being held by the HAL due focus
+ * request from other activities or services.
+ *
+ * The HAL is not required to wait for an callback of AUDIOFOCUS_GAIN before playing audio, nor
+ * is it required to stop playing audio in the event of a AUDIOFOCUS_LOSS callback is received.
+ *
+ * @param usage The audio usage associated with the focus change {@code AttributeUsage}
+ * @param zoneId The identifier for the audio zone that the HAL is playing the stream in
+ * @param focusChange the AudioFocusChange that has occurred
+ */
+ oneway onAudioFocusChange(bitfield<AudioUsage> usage, int32_t zoneId,
+ bitfield<AudioFocusChange> focusChange);
+
+ /**
+ * Control the right/left balance setting of the car speakers.
+ *
+ * This is intended to shift the speaker volume toward the right (+) or left (-) side of
+ * the car. 0.0 means "centered". +1.0 means fully right. -1.0 means fully left.
+ *
+ * A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1
+ * range.
+ */
+ oneway setBalanceTowardRight(float value);
+
+ /**
+ * Control the fore/aft fade setting of the car speakers.
+ *
+ * This is intended to shift the speaker volume toward the front (+) or back (-) of the car.
+ * 0.0 means "centered". +1.0 means fully forward. -1.0 means fully rearward.
+ *
+ * A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1
+ * range.
+ */
+ oneway setFadeTowardFront(float value);
+};
diff --git a/automotive/audiocontrol/2.0/ICloseHandle.hal b/automotive/audiocontrol/2.0/ICloseHandle.hal
new file mode 100644
index 0000000..537af6d
--- /dev/null
+++ b/automotive/audiocontrol/2.0/ICloseHandle.hal
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+/**
+ * Represents a generic close handle to remove a callback that doesn't need
+ * active interface.
+ *
+ * When close() is called OR when the interface is released, the underlying
+ * resources must be freed.
+ */
+interface ICloseHandle {
+ /**
+ * Closes the handle.
+ *
+ * The call must not fail and must be issued by the client at most once.
+ * Otherwise, the server must ignore subsequent calls.
+ */
+ close();
+};
diff --git a/automotive/audiocontrol/2.0/IFocusListener.hal b/automotive/audiocontrol/2.0/IFocusListener.hal
new file mode 100644
index 0000000..4fd5ef0
--- /dev/null
+++ b/automotive/audiocontrol/2.0/IFocusListener.hal
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+import android.hardware.audio.common@6.0::AudioUsage;
+
+/**
+ * Callback interface for audio focus listener.
+ *
+ * For typical configuration, the listener the car audio service.
+ */
+interface IFocusListener {
+ /**
+ * Called whenever HAL is requesting focus as it is starting to play audio of a given usage in a
+ * specified zone.
+ *
+ * In response, IAudioControl#onAudioFocusChange will be called with focusChange status. This
+ * interaction is oneway to avoid blocking HAL so that it is not required to wait for a response
+ * before playing audio.
+ *
+ * @param usage The audio usage associated with the focus request {@code AttributeUsage}
+ * @param zoneId The identifier for the audio zone where the HAL is requesting focus
+ * @param focusGain The AudioFocusChange associated with this request. Should be one of the
+ * following: GAIN, GAIN_TRANSIENT, GAIN_TRANSIENT_MAY_DUCK, GAIN_TRANSIENT_EXCLUSIVE.
+ */
+ oneway requestAudioFocus(bitfield<AudioUsage> usage, int32_t zoneId,
+ bitfield<AudioFocusChange> focusGain);
+
+ /**
+ * Called whenever HAL is abandoning focus as it is finished playing audio of a given usage in a
+ * specific zone.
+ *
+ * In response, IAudioControl#onAudioFocusChange will be called with focusChange status. This
+ * interaction is oneway to avoid blocking HAL so that it is not required to wait for a response
+ * before stopping audio playback.
+ *
+ * @param usage The audio usage for which the HAL is abandoning focus {@code AttributeUsage}
+ * @param zoneId The identifier for the audio zone that the HAL abandoning focus
+ */
+ oneway abandonAudioFocus(bitfield<AudioUsage> usage, int32_t zoneId);
+};
diff --git a/automotive/audiocontrol/2.0/default/Android.bp b/automotive/audiocontrol/2.0/default/Android.bp
new file mode 100644
index 0000000..44ad028
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+ name: "android.hardware.automotive.audiocontrol@2.0-service",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "AudioControl.cpp",
+ "service.cpp",
+ "CloseHandle.cpp",
+ ],
+ init_rc: ["android.hardware.automotive.audiocontrol@2.0-service.rc"],
+
+ shared_libs: [
+ "android.hardware.automotive.audiocontrol@2.0",
+ "libbase",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ vintf_fragments: ["audiocontrol2_manifest.xml"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/automotive/audiocontrol/2.0/default/AudioControl.cpp b/automotive/audiocontrol/2.0/default/AudioControl.cpp
new file mode 100644
index 0000000..6505e34
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/AudioControl.cpp
@@ -0,0 +1,60 @@
+#include "AudioControl.h"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "CloseHandle.h"
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+AudioControl::AudioControl() {}
+
+Return<sp<ICloseHandle>> AudioControl::registerFocusListener(const sp<IFocusListener>& listener) {
+ LOG(DEBUG) << "registering focus listener";
+ sp<ICloseHandle> closeHandle(nullptr);
+
+ if (listener) {
+ mFocusListener = listener;
+
+ closeHandle = new CloseHandle([this, listener]() {
+ if (mFocusListener == listener) {
+ mFocusListener = nullptr;
+ }
+ });
+ } else {
+ LOG(ERROR) << "Unexpected nullptr for listener resulting in no-op.";
+ }
+
+ return closeHandle;
+}
+
+Return<void> AudioControl::setBalanceTowardRight(float value) {
+ // For completeness, lets bounds check the input...
+ if (isValidValue(value)) {
+ LOG(ERROR) << "Balance value out of range -1 to 1 at " << value;
+ } else {
+ // Just log in this default mock implementation
+ LOG(INFO) << "Balance set to " << value;
+ }
+ return Void();
+}
+
+Return<void> AudioControl::setFadeTowardFront(float value) {
+ // For completeness, lets bounds check the input...
+ if (isValidValue(value)) {
+ LOG(ERROR) << "Fader value out of range -1 to 1 at " << value;
+ } else {
+ // Just log in this default mock implementation
+ LOG(INFO) << "Fader set to " << value;
+ }
+ return Void();
+}
+
+Return<void> AudioControl::onAudioFocusChange(hidl_bitfield<AudioUsage> usage, int zoneId,
+ hidl_bitfield<AudioFocusChange> focusChange) {
+ LOG(INFO) << "Focus changed: " << static_cast<int>(focusChange) << " for usage "
+ << static_cast<int>(usage) << " in zone " << zoneId;
+ return Void();
+}
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/automotive/audiocontrol/2.0/default/AudioControl.h b/automotive/audiocontrol/2.0/default/AudioControl.h
new file mode 100644
index 0000000..475a693
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/AudioControl.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H
+
+#include <android/hardware/audio/common/6.0/types.h>
+#include <android/hardware/automotive/audiocontrol/2.0/IAudioControl.h>
+#include <android/hardware/automotive/audiocontrol/2.0/ICloseHandle.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+using android::hardware::audio::common::V6_0::AudioUsage;
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+class AudioControl : public IAudioControl {
+ public:
+ // Methods from ::android::hardware::automotive::audiocontrol::V2_0::IAudioControl follow.
+ Return<sp<ICloseHandle>> registerFocusListener(const sp<IFocusListener>& listener);
+ Return<void> onAudioFocusChange(hidl_bitfield<AudioUsage> usage, int zoneId,
+ hidl_bitfield<AudioFocusChange> focusChange);
+ Return<void> setBalanceTowardRight(float value) override;
+ Return<void> setFadeTowardFront(float value) override;
+
+ // Implementation details
+ AudioControl();
+
+ private:
+ sp<IFocusListener> mFocusListener;
+ static bool isValidValue(float value) { return (value > 1.0f) || (value < -1.0f); }
+};
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H
diff --git a/automotive/audiocontrol/2.0/default/CloseHandle.cpp b/automotive/audiocontrol/2.0/default/CloseHandle.cpp
new file mode 100644
index 0000000..bc47931
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/CloseHandle.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CloseHandle.h"
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {}
+
+CloseHandle::~CloseHandle() {
+ close();
+}
+
+Return<void> CloseHandle::close() {
+ const auto wasClosed = mIsClosed.exchange(true);
+ if (wasClosed) return {};
+
+ if (mCallback) mCallback();
+ return {};
+}
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/automotive/audiocontrol/2.0/default/CloseHandle.h b/automotive/audiocontrol/2.0/default/CloseHandle.h
new file mode 100644
index 0000000..6caf0bf
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/CloseHandle.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android/hardware/automotive/audiocontrol/2.0/ICloseHandle.h>
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+/** Generic ICloseHandle implementation ignoring double-close events. */
+class CloseHandle : public ICloseHandle {
+ public:
+ using Callback = std::function<void()>;
+
+ /**
+ * Create a handle with a callback.
+ *
+ * The callback is guaranteed to be called exactly once.
+ *
+ * \param callback Called on the first close() call, or on destruction of the handle
+ */
+ CloseHandle(Callback callback = nullptr);
+ virtual ~CloseHandle();
+
+ Return<void> close() override;
+
+ private:
+ const Callback mCallback;
+ std::atomic<bool> mIsClosed = false;
+
+ DISALLOW_COPY_AND_ASSIGN(CloseHandle);
+};
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc b/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc
new file mode 100644
index 0000000..81c9be4
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.audiocontrol-hal-2.0 /vendor/bin/hw/android.hardware.automotive.audiocontrol@2.0-service
+ class hal
+ user audioserver
+ group system
diff --git a/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml b/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml
new file mode 100644
index 0000000..42d23ed
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.automotive.audiocontrol</name>
+ <transport>hwbinder</transport>
+ <version>2.0</version>
+ <interface>
+ <name>IAudioControl</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
\ No newline at end of file
diff --git a/automotive/audiocontrol/2.0/default/service.cpp b/automotive/audiocontrol/2.0/default/service.cpp
new file mode 100644
index 0000000..dcc46c3
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/service.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "AudioControl.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::automotive::audiocontrol::V2_0::IAudioControl;
+
+// The namespace in which all our implementation code lives
+using namespace android::hardware::automotive::audiocontrol::V2_0::implementation;
+using namespace android;
+
+// Main service entry point
+int main() {
+ // Create an instance of our service class
+ android::sp<IAudioControl> service = new AudioControl();
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+ if (service->registerAsService() != OK) {
+ LOG(ERROR) << "registerAsService failed";
+ return 1;
+ }
+
+ // Join (forever) the thread pool we created for the service above
+ joinRpcThreadpool();
+
+ // We don't ever actually expect to return, so return an error if we do get here
+ return 2;
+}
\ No newline at end of file
diff --git a/automotive/audiocontrol/2.0/types.hal b/automotive/audiocontrol/2.0/types.hal
new file mode 100644
index 0000000..65b0988
--- /dev/null
+++ b/automotive/audiocontrol/2.0/types.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+/**
+ * Changes in audio focus that can be experienced
+ */
+enum AudioFocusChange : uint32_t {
+ NONE = 0,
+ GAIN = 1,
+ GAIN_TRANSIENT = 2,
+ GAIN_TRANSIENT_MAY_DUCK = 3,
+ GAIN_TRANSIENT_EXCLUSIVE = 4,
+ LOSS = -1 * GAIN,
+ LOSS_TRANSIENT = -1 * GAIN_TRANSIENT,
+ LOSS_TRANSIENT_CAN_DUCK = -1 * GAIN_TRANSIENT_MAY_DUCK,
+};
diff --git a/automotive/audiocontrol/2.0/vts/functional/Android.bp b/automotive/audiocontrol/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..520b042
--- /dev/null
+++ b/automotive/audiocontrol/2.0/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalAudioControlV2_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalAudioControlV2_0TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.automotive.audiocontrol@2.0",
+ "libgmock",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
new file mode 100644
index 0000000..0c10664
--- /dev/null
+++ b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalAudioControlTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/ProcessState.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include <android/hardware/audio/common/6.0/types.h>
+#include <android/hardware/automotive/audiocontrol/2.0/IAudioControl.h>
+#include <android/hardware/automotive/audiocontrol/2.0/types.h>
+#include <android/log.h>
+
+using namespace ::android::hardware::automotive::audiocontrol::V2_0;
+using ::android::sp;
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V6_0::AudioUsage;
+
+// The main test class for the automotive AudioControl HAL
+class CarAudioControlHidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ // Make sure we can connect to the driver
+ pAudioControl = IAudioControl::getService(GetParam());
+ ASSERT_NE(pAudioControl.get(), nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+ protected:
+ sp<IAudioControl> pAudioControl; // Every test needs access to the service
+};
+
+//
+// Tests start here...
+//
+
+/*
+ * Fader exercise test. Note that only a subjective observer could determine if the
+ * fader actually works. The only thing we can do is exercise the HAL and if the HAL crashes,
+ * we _might_ get a test failure if that breaks the connection to the driver.
+ */
+TEST_P(CarAudioControlHidlTest, FaderExercise) {
+ ALOGI("Fader exercise test (silent)");
+
+ // Set the fader all the way to the back
+ pAudioControl->setFadeTowardFront(-1.0f);
+
+ // Set the fader all the way to the front
+ pAudioControl->setFadeTowardFront(1.0f);
+
+ // Set the fader part way toward the back
+ pAudioControl->setFadeTowardFront(-0.333f);
+
+ // Set the fader to a out of bounds value (driver should clamp)
+ pAudioControl->setFadeTowardFront(99999.9f);
+
+ // Set the fader back to the middle
+ pAudioControl->setFadeTowardFront(0.0f);
+}
+
+/*
+ * Balance exercise test.
+ */
+TEST_P(CarAudioControlHidlTest, BalanceExercise) {
+ ALOGI("Balance exercise test (silent)");
+
+ // Set the balance all the way to the left
+ pAudioControl->setBalanceTowardRight(-1.0f);
+
+ // Set the balance all the way to the right
+ pAudioControl->setBalanceTowardRight(1.0f);
+
+ // Set the balance part way toward the left
+ pAudioControl->setBalanceTowardRight(-0.333f);
+
+ // Set the balance to a out of bounds value (driver should clamp)
+ pAudioControl->setBalanceTowardRight(99999.9f);
+
+ // Set the balance back to the middle
+ pAudioControl->setBalanceTowardRight(0.0f);
+}
+
+struct FocusListenerMock : public IFocusListener {
+ MOCK_METHOD(Return<void>, requestAudioFocus,
+ (hidl_bitfield<AudioUsage> usage, int zoneId,
+ hidl_bitfield<AudioFocusChange> focusGain));
+ MOCK_METHOD(Return<void>, abandonAudioFocus, (hidl_bitfield<AudioUsage> usage, int zoneId));
+};
+
+/*
+ * Test focus listener registration.
+ *
+ * Verifies that:
+ * - registerFocusListener succeeds;
+ * - registering a second listener succeeds in replacing the first;
+ * - closing handle does not crash;
+ */
+TEST_P(CarAudioControlHidlTest, FocusListenerRegistration) {
+ ALOGI("Focus listener test");
+
+ sp<FocusListenerMock> listener = new FocusListenerMock();
+
+ auto hidlResult = pAudioControl->registerFocusListener(listener);
+ ASSERT_TRUE(hidlResult.isOk());
+
+ sp<FocusListenerMock> listener2 = new FocusListenerMock();
+
+ auto hidlResult2 = pAudioControl->registerFocusListener(listener2);
+ ASSERT_TRUE(hidlResult2.isOk());
+
+ const sp<ICloseHandle>& closeHandle = hidlResult2;
+ closeHandle->close();
+};
+
+TEST_P(CarAudioControlHidlTest, FocusChangeExercise) {
+ ALOGI("Focus Change test");
+
+ pAudioControl->onAudioFocusChange(AudioUsage::MEDIA | 0, 0,
+ AudioFocusChange::GAIN_TRANSIENT | 0);
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, CarAudioControlHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/automotive/can/1.0/Android.bp b/automotive/can/1.0/Android.bp
new file mode 100644
index 0000000..2221e66
--- /dev/null
+++ b/automotive/can/1.0/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.automotive.can@1.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "ICanBus.hal",
+ "ICanController.hal",
+ "ICanErrorListener.hal",
+ "ICanMessageListener.hal",
+ "ICloseHandle.hal",
+ ],
+ interfaces: [
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/automotive/can/1.0/ICanBus.hal b/automotive/can/1.0/ICanBus.hal
new file mode 100644
index 0000000..e68f16c
--- /dev/null
+++ b/automotive/can/1.0/ICanBus.hal
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can@1.0;
+
+import ICanErrorListener;
+import ICanMessageListener;
+import ICloseHandle;
+
+/**
+ * Represents a CAN bus interface that's up and configured.
+ *
+ * Configuration part is done in ICanController.
+ */
+interface ICanBus {
+ /**
+ * Send CAN message.
+ *
+ * @param message CAN message to send out
+ * @return result OK in the case of success
+ * PAYLOAD_TOO_LONG if the payload is too long
+ * INTERFACE_DOWN if the bus is down
+ * TRANSMISSION_FAILURE in case of transmission failure
+ */
+ send(CanMessage message) generates (Result result);
+
+ /**
+ * Requests HAL implementation to listen for specific CAN messages.
+ *
+ * HAL is responsible for maintaining listener set and sending out messages
+ * to each listener that matches given filter against received message.
+ *
+ * Empty filter list means no filtering. If two or more listeners requested
+ * different filters, HAL server must merge these to fulfill the superset of
+ * these filters. HAL must not send out a message to a listener which filter
+ * doesn't match given message id.
+ *
+ * If filtering is not supported at the hardware level (what's strongly
+ * recommended), it must be covered in the HAL.
+ *
+ * @param filter The set of requested filters
+ * @param listener The interface to receive the messages on
+ * @return result OK in the case of success
+ * INTERFACE_DOWN if the bus is down
+ * @return close A handle to call in order to remove the listener
+ */
+ listen(vec<CanMessageFilter> filter, ICanMessageListener listener)
+ generates (Result result, ICloseHandle close);
+
+ /**
+ * Adds a new listener for CAN bus or interface errors.
+ *
+ * If the error is fatal, the client is supposed to drop any references to
+ * this specific ICanBus instance (see ICanErrorListener).
+ *
+ * @param listener The interface to receive the error events on
+ * @return close A handle to call in order to remove the listener
+ */
+ listenForErrors(ICanErrorListener listener) generates (ICloseHandle close);
+};
diff --git a/automotive/can/1.0/ICanController.hal b/automotive/can/1.0/ICanController.hal
new file mode 100644
index 0000000..0c6f53e
--- /dev/null
+++ b/automotive/can/1.0/ICanController.hal
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can@1.0;
+
+/**
+ * Represents a CAN controller that's capable of configuring CAN bus interfaces.
+ *
+ * The goal of this service is to configure CAN interfaces and bring up HIDL
+ * server instances of ICanBus for each one that's up.
+ *
+ * Providing an ICanController interface to configure CAN buses is optional.
+ * A system can elect to publish only ICanBus if the hardware is hardcoded
+ * for a specific application.
+ */
+interface ICanController {
+ /**
+ * Type of an interface, a mean to express the domain of device address.
+ */
+ enum InterfaceType : uint8_t {
+ /**
+ * Virtual SocketCAN interface.
+ *
+ * The address is an interface name, such as vcan0. If the interface
+ * doesn't exist, HAL server must create it.
+ *
+ * Valid InterfaceIdentifier types:
+ * - address.
+ */
+ VIRTUAL,
+
+ /**
+ * Native SocketCAN interface.
+ *
+ * The address is an interface name, such as can0.
+ *
+ * Valid InterfaceIdentifier types:
+ * - address;
+ * - serialno.
+ */
+ SOCKETCAN,
+
+ /**
+ * Serial-based interface.
+ *
+ * The address is a patch to a device, such as /dev/ttyUSB0.
+ *
+ * Valid InterfaceIdentifier types:
+ * - address;
+ * - serialno.
+ */
+ SLCAN,
+
+ /**
+ * Proprietary interface, specific to the hardware system Android
+ * is running on. Instead of using address field, the interface is
+ * addressed with 0-based index.
+ *
+ * Valid InterfaceIdentifier types:
+ * - index
+ */
+ INDEXED
+ };
+
+ enum Result : uint8_t {
+ OK,
+
+ /**
+ * General error class, if others are not applicable.
+ */
+ UNKNOWN_ERROR,
+
+ /**
+ * Up request was called out of order (i.e. trying to up the
+ * interface twice).
+ */
+ INVALID_STATE,
+
+ /** Interface type is not supported. */
+ NOT_SUPPORTED,
+
+ /**
+ * Provided address (interface name, device path) doesn't exist or there
+ * is no device with a given serial no.
+ */
+ BAD_ADDRESS,
+
+ /** Provided bit rate is not supported by the hardware. */
+ BAD_BITRATE,
+ };
+
+ /**
+ * Configuration of the (physical or virtual) CAN bus.
+ *
+ * ISO TP and CAN FD are currently not supported.
+ */
+ struct BusConfiguration {
+ /**
+ * Name under which ICanBus HIDL service should be published.
+ *
+ * It must consist of only alphanumeric characters and underscore
+ * (a-z, A-Z, 0-9, '_'), at least 1 and at most 32 characters long.
+ */
+ string name;
+
+ /**
+ * Type of the hardware (or virtual) CAN interface.
+ */
+ InterfaceType iftype;
+
+ /**
+ * Identification of hardware interface to configure.
+ */
+ safe_union InterfaceIdentifier {
+ /**
+ * Interface name or other mean of identification of the specific
+ * interface port. Syntax depends on {@see iftype}, for details
+ * {@see InterfaceType}.
+ */
+ string address;
+
+ /**
+ * Numerical identifier of interface, used for InterfaceType#INDEXED.
+ */
+ uint8_t index;
+
+ /**
+ * Alternatively to providing {@see address}, one may provide a list
+ * of interface serial number suffixes. If there happens to be
+ * a device (like USB2CAN) with a matching serial number suffix,
+ * it gets selected.
+ *
+ * Client may utilize this in two ways: by matching against the
+ * entire serial number, or the last few characters (usually one).
+ * The former is better for small-scale test deployments (with just
+ * a handful of vehicles), the latter is good for larger scale
+ * (where a small suffix list may support large test fleet).
+ */
+ vec<string> serialno;
+ } interfaceId;
+
+ /**
+ * Bit rate for CAN communication.
+ *
+ * Typical bit rates are: 100000, 125000, 250000, 500000.
+ *
+ * For virtual interfaces this value is ignored.
+ */
+ uint32_t bitrate;
+ };
+
+ /**
+ * Fetches the list of interface types supported by this HAL server.
+ *
+ * @return iftypes The list of supported interface types
+ */
+ getSupportedInterfaceTypes() generates (vec<InterfaceType> iftypes);
+
+ /**
+ * Bring up the CAN interface and publish ICanBus server instance.
+ *
+ * @param config Configuration of the CAN interface
+ * @return result OK if the operation succeeded; error code otherwise.
+ */
+ upInterface(BusConfiguration config) generates (Result result);
+
+ /**
+ * Unpublish ICanBus server instance and bring down the CAN interface.
+ *
+ * In case of failure, at least the ICanBus server instance must be
+ * unpublished and resources freed on best-effort basis.
+ *
+ * @param name Name of the interface (@see BusConfiguration#name} to
+ * bring down
+ * @return success true in case of success, false otherwise
+ */
+ downInterface(string name) generates (bool success);
+};
diff --git a/automotive/can/1.0/ICanErrorListener.hal b/automotive/can/1.0/ICanErrorListener.hal
new file mode 100644
index 0000000..8a6ba05
--- /dev/null
+++ b/automotive/can/1.0/ICanErrorListener.hal
@@ -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.
+ */
+package android.hardware.automotive.can@1.0;
+
+/**
+ * CAN error listener.
+ */
+interface ICanErrorListener {
+ /**
+ * Called on error event.
+ *
+ * If the error is fatal, the client is supposed to drop any references to
+ * this specific ICanBus instance.
+ *
+ * @param error Error type
+ * @param isFatal Whether an error would result with ICanBus instance being unusable.
+ */
+ onError(ErrorEvent error, bool isFatal);
+};
diff --git a/automotive/can/1.0/ICanMessageListener.hal b/automotive/can/1.0/ICanMessageListener.hal
new file mode 100644
index 0000000..28161fa
--- /dev/null
+++ b/automotive/can/1.0/ICanMessageListener.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can@1.0;
+
+/**
+ * CAN message listener.
+ */
+interface ICanMessageListener {
+ /**
+ * Called on received CAN message.
+ *
+ * The timestamp field of message struct is set to time when the message
+ * was received by the hardware. If it's not possible to fetch exact
+ * hardware time, this field should be set as early as possible to decrease
+ * potential time delta.
+ *
+ * @param message Received CAN message
+ */
+ onReceive(CanMessage message);
+};
diff --git a/automotive/can/1.0/ICloseHandle.hal b/automotive/can/1.0/ICloseHandle.hal
new file mode 100644
index 0000000..924c58b
--- /dev/null
+++ b/automotive/can/1.0/ICloseHandle.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can@1.0;
+
+/**
+ * Represents a generic close handle to remove a callback that doesn't need
+ * active interface.
+ *
+ * When close() is called OR when the interface is released, the underlying
+ * resources must be freed.
+ */
+interface ICloseHandle {
+ /**
+ * Closes the handle.
+ *
+ * The call must not fail and must be issued by the client at most once.
+ * Otherwise, the server must ignore subsequent calls.
+ */
+ close();
+};
diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp
new file mode 100644
index 0000000..ee2e92b
--- /dev/null
+++ b/automotive/can/1.0/default/Android.bp
@@ -0,0 +1,55 @@
+//
+// 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_defaults {
+ name: "android.hardware.automotive.can@defaults",
+ cpp_std: "experimental",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION=1",
+ ],
+ shared_libs: [
+ "libbase",
+ "libutils",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.automotive.can@1.0-service",
+ init_rc: ["android.hardware.automotive.can@1.0-service.rc"],
+ defaults: ["android.hardware.automotive.can@defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "CanBus.cpp",
+ "CanBusNative.cpp",
+ "CanBusVirtual.cpp",
+ "CanBusSlcan.cpp",
+ "CanController.cpp",
+ "CanSocket.cpp",
+ "CloseHandle.cpp",
+ "service.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.automotive.can@1.0",
+ "libhidlbase",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can@libnetdevice",
+ ],
+}
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
new file mode 100644
index 0000000..8fb09eb
--- /dev/null
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -0,0 +1,346 @@
+/*
+ * 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 "CanBus.h"
+
+#include "CloseHandle.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+#include <linux/can.h>
+#include <linux/can/error.h>
+#include <linux/can/raw.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+/** Whether to log sent/received packets. */
+static constexpr bool kSuperVerbose = false;
+
+Return<Result> CanBus::send(const CanMessage& message) {
+ std::lock_guard<std::mutex> lck(mIsUpGuard);
+ if (!mIsUp) return Result::INTERFACE_DOWN;
+
+ if (UNLIKELY(kSuperVerbose)) {
+ LOG(VERBOSE) << "Sending " << toString(message);
+ }
+
+ if (message.payload.size() > CAN_MAX_DLEN) return Result::PAYLOAD_TOO_LONG;
+
+ 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());
+
+ if (!mSocket->send(frame)) return Result::TRANSMISSION_FAILURE;
+
+ return Result::OK;
+}
+
+Return<void> CanBus::listen(const hidl_vec<CanMessageFilter>& filter,
+ const sp<ICanMessageListener>& listenerCb, listen_cb _hidl_cb) {
+ std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+ if (listenerCb == nullptr) {
+ _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
+ return {};
+ }
+ if (!mIsUp) {
+ _hidl_cb(Result::INTERFACE_DOWN, nullptr);
+ return {};
+ }
+
+ std::lock_guard<std::mutex> lckListeners(mMsgListenersGuard);
+
+ sp<CloseHandle> closeHandle = new CloseHandle([this, listenerCb]() {
+ std::lock_guard<std::mutex> lck(mMsgListenersGuard);
+ std::erase_if(mMsgListeners, [&](const auto& e) { return e.callback == listenerCb; });
+ });
+ mMsgListeners.emplace_back(CanMessageListener{listenerCb, filter, closeHandle});
+ auto& listener = mMsgListeners.back();
+
+ // fix message IDs to have all zeros on bits not covered by mask
+ std::for_each(listener.filter.begin(), listener.filter.end(),
+ [](auto& rule) { rule.id &= rule.mask; });
+
+ _hidl_cb(Result::OK, closeHandle);
+ return {};
+}
+
+CanBus::CanBus() {}
+
+CanBus::CanBus(const std::string& ifname) : mIfname(ifname) {}
+
+CanBus::~CanBus() {
+ std::lock_guard<std::mutex> lck(mIsUpGuard);
+ CHECK(!mIsUp) << "Interface is still up while being destroyed";
+
+ std::lock_guard<std::mutex> lckListeners(mMsgListenersGuard);
+ CHECK(mMsgListeners.empty()) << "Listener list is not empty while interface is being destroyed";
+}
+
+void CanBus::setErrorCallback(ErrorCallback errcb) {
+ CHECK(!mIsUp) << "Can't set error callback while interface is up";
+ CHECK(mErrCb == nullptr) << "Error callback is already set";
+ mErrCb = errcb;
+ CHECK(!mIsUp) << "Can't set error callback while interface is up";
+}
+
+ICanController::Result CanBus::preUp() {
+ return ICanController::Result::OK;
+}
+
+bool CanBus::postDown() {
+ return true;
+}
+
+ICanController::Result CanBus::up() {
+ std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+ if (mIsUp) {
+ LOG(WARNING) << "Interface is already up";
+ return ICanController::Result::INVALID_STATE;
+ }
+
+ const auto preResult = preUp();
+ if (preResult != ICanController::Result::OK) return preResult;
+
+ const auto isUp = netdevice::isUp(mIfname);
+ if (!isUp.has_value()) {
+ // preUp() should prepare the interface (either create or make sure it's there)
+ LOG(ERROR) << "Interface " << mIfname << " didn't get prepared";
+ return ICanController::Result::BAD_ADDRESS;
+ }
+
+ if (!*isUp && !netdevice::up(mIfname)) {
+ LOG(ERROR) << "Can't bring " << mIfname << " up";
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+ mDownAfterUse = !*isUp;
+
+ using namespace std::placeholders;
+ CanSocket::ReadCallback rdcb = std::bind(&CanBus::onRead, this, _1, _2);
+ CanSocket::ErrorCallback errcb = std::bind(&CanBus::onError, this, _1);
+ mSocket = CanSocket::open(mIfname, rdcb, errcb);
+ if (!mSocket) {
+ if (mDownAfterUse) netdevice::down(mIfname);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ mIsUp = true;
+ return ICanController::Result::OK;
+}
+
+void CanBus::clearMsgListeners() {
+ std::vector<wp<ICloseHandle>> listenersToClose;
+ {
+ std::lock_guard<std::mutex> lck(mMsgListenersGuard);
+ std::transform(mMsgListeners.begin(), mMsgListeners.end(),
+ std::back_inserter(listenersToClose),
+ [](const auto& e) { return e.closeHandle; });
+ }
+
+ for (auto& weakListener : listenersToClose) {
+ /* Between populating listenersToClose and calling close method here, some listeners might
+ * have been already removed from the original mMsgListeners list (resulting in a dangling
+ * weak pointer here). It's fine - we just want to clean them up. */
+ auto listener = weakListener.promote();
+ if (listener != nullptr) listener->close();
+ }
+
+ std::lock_guard<std::mutex> lck(mMsgListenersGuard);
+ CHECK(mMsgListeners.empty()) << "Listeners list wasn't emptied";
+}
+
+void CanBus::clearErrListeners() {
+ std::lock_guard<std::mutex> lck(mErrListenersGuard);
+ mErrListeners.clear();
+}
+
+Return<sp<ICloseHandle>> CanBus::listenForErrors(const sp<ICanErrorListener>& listener) {
+ if (listener == nullptr) {
+ return new CloseHandle();
+ }
+
+ std::lock_guard<std::mutex> upLck(mIsUpGuard);
+ if (!mIsUp) {
+ listener->onError(ErrorEvent::INTERFACE_DOWN, true);
+ return new CloseHandle();
+ }
+
+ std::lock_guard<std::mutex> errLck(mErrListenersGuard);
+ mErrListeners.emplace_back(listener);
+
+ return new CloseHandle([this, listener]() {
+ std::lock_guard<std::mutex> lck(mErrListenersGuard);
+ std::erase(mErrListeners, listener);
+ });
+}
+
+bool CanBus::down() {
+ std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+ if (!mIsUp) {
+ LOG(WARNING) << "Interface is already down";
+ return false;
+ }
+ mIsUp = false;
+
+ clearMsgListeners();
+ clearErrListeners();
+ mSocket.reset();
+
+ bool success = true;
+
+ if (mDownAfterUse && !netdevice::down(mIfname)) {
+ LOG(ERROR) << "Can't bring " << mIfname << " down";
+ // don't return yet, let's try to do best-effort cleanup
+ success = false;
+ }
+
+ if (!postDown()) success = false;
+
+ return success;
+}
+
+/**
+ * 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
+ * the HAL definition (types.hal).
+ *
+ * \param filter Filter to match against
+ * \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, bool isRtr,
+ bool isExtendedId) {
+ if (filter.size() == 0) return true;
+
+ bool anyNonExcludeRulePresent = false;
+ bool anyNonExcludeRuleSatisfied = false;
+ for (auto& rule : filter) {
+ 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 {
+ anyNonExcludeRulePresent = true;
+ if (satisfied) anyNonExcludeRuleSatisfied = true;
+ }
+ }
+ 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 & 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);
+ }
+
+ std::lock_guard<std::mutex> lck(mMsgListenersGuard);
+ for (auto& listener : mMsgListeners) {
+ 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";
+ }
+ }
+}
+
+void CanBus::onError(int errnoVal) {
+ auto eventType = ErrorEvent::HARDWARE_ERROR;
+
+ if (errnoVal == ENODEV || errnoVal == ENETDOWN) {
+ mDownAfterUse = false;
+ eventType = ErrorEvent::INTERFACE_DOWN;
+ }
+ notifyErrorListeners(eventType, true);
+
+ const auto errcb = mErrCb;
+ if (errcb != nullptr) errcb();
+}
+
+} // 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
new file mode 100644
index 0000000..8b73258
--- /dev/null
+++ b/automotive/can/1.0/default/CanBus.h
@@ -0,0 +1,112 @@
+/*
+ * 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 "CanSocket.h"
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <utils/Mutex.h>
+
+#include <atomic>
+#include <thread>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+struct CanBus : public ICanBus {
+ using ErrorCallback = std::function<void()>;
+
+ virtual ~CanBus();
+
+ Return<Result> send(const CanMessage& message) override;
+ Return<void> listen(const hidl_vec<CanMessageFilter>& filter,
+ const sp<ICanMessageListener>& listener, listen_cb _hidl_cb) override;
+ Return<sp<ICloseHandle>> listenForErrors(const sp<ICanErrorListener>& listener) override;
+
+ void setErrorCallback(ErrorCallback errcb);
+ ICanController::Result up();
+ bool down();
+
+ protected:
+ /**
+ * Blank constructor, since some interface types (such as SLCAN) don't get a name until after
+ * being initialized.
+ *
+ * If using this constructor, you MUST initialize mIfname prior to the completion of preUp().
+ */
+ CanBus();
+
+ CanBus(const std::string& ifname);
+
+ /**
+ * Prepare the SocketCAN interface.
+ *
+ * After calling this method, mIfname network interface is available and ready to be brought up.
+ *
+ * \return OK on success, or an error state on failure. See ICanController::Result
+ */
+ virtual ICanController::Result preUp();
+
+ /**
+ * Cleanup after bringing the interface down.
+ *
+ * This is a counterpart to preUp().
+ *
+ * \return true upon success and false upon failure
+ */
+ virtual bool postDown();
+
+ /** Network interface name. */
+ std::string mIfname;
+
+ private:
+ struct CanMessageListener {
+ sp<ICanMessageListener> callback;
+ hidl_vec<CanMessageFilter> filter;
+ wp<ICloseHandle> closeHandle;
+ bool failedOnce = false;
+ };
+ 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);
+
+ std::mutex mMsgListenersGuard;
+ std::vector<CanMessageListener> mMsgListeners GUARDED_BY(mMsgListenersGuard);
+
+ std::mutex mErrListenersGuard;
+ std::vector<sp<ICanErrorListener>> mErrListeners GUARDED_BY(mErrListenersGuard);
+
+ std::unique_ptr<CanSocket> mSocket;
+ bool mDownAfterUse;
+
+ /**
+ * Guard for up flag is required to be held for entire time when the interface is being used
+ * (i.e. message being sent), because we don't want the interface to be torn down while
+ * executing that operation.
+ */
+ std::mutex mIsUpGuard;
+ bool mIsUp GUARDED_BY(mIsUpGuard) = false;
+
+ ErrorCallback mErrCb;
+};
+
+} // 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
new file mode 100644
index 0000000..ef04d01
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusNative.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "CanBusNative.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+CanBusNative::CanBusNative(const std::string& ifname, uint32_t bitrate)
+ : CanBus(ifname), mBitrate(bitrate) {}
+
+ICanController::Result CanBusNative::preUp() {
+ if (!netdevice::exists(mIfname)) {
+ LOG(ERROR) << "Interface " << mIfname << " doesn't exist";
+ return ICanController::Result::BAD_ADDRESS;
+ }
+
+ if (mBitrate == 0) {
+ // interface is already up and we just want to register it
+ return ICanController::Result::OK;
+ }
+
+ if (!netdevice::down(mIfname)) {
+ LOG(ERROR) << "Can't bring " << mIfname << " down (to configure it)";
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ if (!netdevice::can::setBitrate(mIfname, mBitrate)) {
+ LOG(ERROR) << "Can't set bitrate " << mBitrate << " for " << mIfname;
+ return ICanController::Result::BAD_BITRATE;
+ }
+
+ return ICanController::Result::OK;
+}
+
+} // 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
new file mode 100644
index 0000000..04d7194
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusNative.h
@@ -0,0 +1,33 @@
+/*
+ * 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 "CanBus.h"
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+struct CanBusNative : public CanBus {
+ CanBusNative(const std::string& ifname, uint32_t bitrate);
+
+ protected:
+ virtual ICanController::Result preUp() override;
+
+ private:
+ const uint32_t mBitrate;
+};
+
+} // 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
new file mode 100644
index 0000000..0feee8f
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusSlcan.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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 "CanBusSlcan.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <termios.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+namespace slcanprotocol {
+static const std::string kOpenCommand = "O\r";
+static const std::string kCloseCommand = "C\r";
+static constexpr int kSlcanDiscipline = N_SLCAN;
+static constexpr int kDefaultDiscipline = N_TTY;
+
+static const std::map<uint32_t, std::string> kBitrateCommands = {
+ {10000, "C\rS0\r"}, {20000, "C\rS1\r"}, {50000, "C\rS2\r"},
+ {100000, "C\rS3\r"}, {125000, "C\rS4\r"}, {250000, "C\rS5\r"},
+ {500000, "C\rS6\r"}, {800000, "C\rS7\r"}, {1000000, "C\rS8\r"}};
+} // namespace slcanprotocol
+
+/**
+ * Serial Line CAN constructor
+ * \param string uartName - name of slcan device (e.x. /dev/ttyUSB0)
+ * \param uint32_t bitrate - speed of the CAN bus (125k = MSCAN, 500k = HSCAN)
+ */
+CanBusSlcan::CanBusSlcan(const std::string& uartName, uint32_t bitrate)
+ : CanBus(), mUartName(uartName), kBitrate(bitrate) {}
+
+/** helper function to update CanBusSlcan object's iface name */
+ICanController::Result CanBusSlcan::updateIfaceName(base::unique_fd& uartFd) {
+ struct ifreq ifrequest = {};
+ /*
+ * Fetching the iface name with an ioctl won't interfere with an open socketCAN iface attached
+ * to this tty. This is important in the event we are trying to register a SLCAN based iface
+ * that has already been configured and brought up.
+ */
+ if (ioctl(uartFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) {
+ LOG(ERROR) << "Failed to get the name of the created device: " << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ // Update the CanBus object with name that was assigned to it
+ mIfname = ifrequest.ifr_name;
+ return ICanController::Result::OK;
+}
+
+ICanController::Result CanBusSlcan::preUp() {
+ // verify valid bitrate and translate to serial command format
+ std::optional<std::string> canBitrateCommand = std::nullopt;
+ if (kBitrate != 0) {
+ const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate);
+ if (lookupIt == slcanprotocol::kBitrateCommands.end()) {
+ return ICanController::Result::BAD_BITRATE;
+ }
+ canBitrateCommand = lookupIt->second;
+ }
+
+ /* Attempt to open the uart in r/w without blocking or becoming the
+ * controlling terminal */
+ mFd = base::unique_fd(open(mUartName.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY));
+ if (!mFd.ok()) {
+ LOG(ERROR) << "SLCAN Failed to open " << mUartName << ": " << strerror(errno);
+ return ICanController::Result::BAD_ADDRESS;
+ }
+
+ // If the device is already up, update the iface name in our CanBusSlcan object
+ if (kBitrate == 0) {
+ return updateIfaceName(mFd);
+ }
+
+ // blank terminal settings and pull them from the device
+ struct termios terminalSettings = {};
+ if (tcgetattr(mFd.get(), &terminalSettings) < 0) {
+ LOG(ERROR) << "Failed to read attrs of" << mUartName << ": " << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ // change settings to raw mode
+ cfmakeraw(&terminalSettings);
+
+ // disable software flow control
+ terminalSettings.c_iflag &= ~IXOFF;
+ // enable hardware flow control
+ terminalSettings.c_cflag |= CRTSCTS;
+
+ struct serial_struct serialSettings;
+ // get serial settings
+ if (ioctl(mFd.get(), TIOCGSERIAL, &serialSettings) < 0) {
+ LOG(ERROR) << "Failed to read serial settings from " << mUartName << ": "
+ << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+ // set low latency mode
+ serialSettings.flags |= ASYNC_LOW_LATENCY;
+ // apply serial settings
+ if (ioctl(mFd.get(), TIOCSSERIAL, &serialSettings) < 0) {
+ LOG(ERROR) << "Failed to set low latency mode on " << mUartName << ": " << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ /* TCSADRAIN applies settings after we finish writing the rest of our
+ * changes (as opposed to TCSANOW, which changes immediately) */
+ if (tcsetattr(mFd.get(), TCSADRAIN, &terminalSettings) < 0) {
+ LOG(ERROR) << "Failed to apply terminal settings to " << mUartName << ": "
+ << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ // apply speed setting for CAN
+ if (write(mFd.get(), canBitrateCommand->c_str(), canBitrateCommand->length()) <= 0) {
+ LOG(ERROR) << "Failed to apply CAN bitrate: " << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ // set open flag TODO: also support listen only
+ if (write(mFd.get(), slcanprotocol::kOpenCommand.c_str(),
+ slcanprotocol::kOpenCommand.length()) <= 0) {
+ LOG(ERROR) << "Failed to set open flag: " << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ // set line discipline to slcan
+ if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kSlcanDiscipline) < 0) {
+ LOG(ERROR) << "Failed to set line discipline to slcan: " << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ // Update the CanBus object with name that was assigned to it
+ return updateIfaceName(mFd);
+}
+
+bool CanBusSlcan::postDown() {
+ // reset the line discipline to TTY mode
+ if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kDefaultDiscipline) < 0) {
+ LOG(ERROR) << "Failed to reset line discipline!";
+ return false;
+ }
+
+ // issue the close command
+ if (write(mFd.get(), slcanprotocol::kCloseCommand.c_str(),
+ slcanprotocol::kCloseCommand.length()) <= 0) {
+ LOG(ERROR) << "Failed to close tty!";
+ return false;
+ }
+
+ // close our unique_fd
+ mFd.reset();
+
+ return true;
+}
+
+} // 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
new file mode 100644
index 0000000..2328a2c
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusSlcan.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <net/if.h>
+#include <termios.h>
+#include "CanBus.h"
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+struct CanBusSlcan : public CanBus {
+ CanBusSlcan(const std::string& uartName, uint32_t bitrate);
+
+ protected:
+ virtual ICanController::Result preUp() override;
+ virtual bool postDown() override;
+
+ private:
+ ICanController::Result updateIfaceName(base::unique_fd& uartFd);
+
+ const std::string mUartName;
+ const uint32_t kBitrate;
+ base::unique_fd mFd;
+};
+
+} // 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
new file mode 100644
index 0000000..32fe8d6
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusVirtual.cpp
@@ -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.
+ */
+
+#include "CanBusVirtual.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+CanBusVirtual::CanBusVirtual(const std::string& ifname) : CanBus(ifname) {}
+
+ICanController::Result CanBusVirtual::preUp() {
+ if (netdevice::exists(mIfname)) return ICanController::Result::OK;
+
+ LOG(DEBUG) << "Virtual interface " << mIfname << " doesn't exist, creating...";
+ mWasCreated = true;
+ if (!netdevice::add(mIfname, "vcan")) {
+ LOG(ERROR) << "Can't create vcan interface " << mIfname;
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ return ICanController::Result::OK;
+}
+
+bool CanBusVirtual::postDown() {
+ if (mWasCreated) {
+ mWasCreated = false;
+ if (!netdevice::del(mIfname)) {
+ LOG(ERROR) << "Couldn't remove vcan interface " << mIfname;
+ return false;
+ }
+ }
+ return true;
+}
+
+} // 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
new file mode 100644
index 0000000..3990b20
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusVirtual.h
@@ -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.
+ */
+
+#pragma once
+
+#include "CanBus.h"
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+struct CanBusVirtual : public CanBus {
+ CanBusVirtual(const std::string& ifname);
+
+ protected:
+ virtual ICanController::Result preUp() override;
+ virtual bool postDown() override;
+
+ private:
+ bool mWasCreated = false;
+};
+
+} // 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
new file mode 100644
index 0000000..fb648c1
--- /dev/null
+++ b/automotive/can/1.0/default/CanController.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 "CanController.h"
+
+#include "CanBusNative.h"
+#include "CanBusSlcan.h"
+#include "CanBusVirtual.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+
+#include <regex>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
+
+Return<void> CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) {
+ _hidl_cb({ICanController::InterfaceType::VIRTUAL, ICanController::InterfaceType::SOCKETCAN,
+ ICanController::InterfaceType::SLCAN});
+ return {};
+}
+
+static bool isValidName(const std::string& name) {
+ static const std::regex nameRE("^[a-zA-Z0-9_]{1,32}$");
+ return std::regex_match(name, nameRE);
+}
+
+Return<ICanController::Result> CanController::upInterface(
+ const ICanController::BusConfiguration& config) {
+ LOG(VERBOSE) << "Attempting to bring interface up: " << toString(config);
+
+ std::lock_guard<std::mutex> lck(mCanBusesGuard);
+
+ if (!isValidName(config.name)) {
+ LOG(ERROR) << "Bus name " << config.name << " is invalid";
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ if (mCanBuses.find(config.name) != mCanBuses.end()) {
+ LOG(ERROR) << "Bus " << config.name << " is already up";
+ return ICanController::Result::INVALID_STATE;
+ }
+
+ sp<CanBus> busService;
+
+ if (config.iftype == ICanController::InterfaceType::SOCKETCAN) {
+ // TODO(b/135918744): support serialno
+ if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
+ busService = new CanBusNative(config.interfaceId.address(), config.bitrate);
+ } else {
+ return ICanController::Result::BAD_ADDRESS;
+ }
+ } else if (config.iftype == ICanController::InterfaceType::VIRTUAL) {
+ if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
+ busService = new CanBusVirtual(config.interfaceId.address());
+ } else {
+ return ICanController::Result::BAD_ADDRESS;
+ }
+ } else if (config.iftype == ICanController::InterfaceType::SLCAN) {
+ if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
+ busService = new CanBusSlcan(config.interfaceId.address(), config.bitrate);
+ } else {
+ return ICanController::Result::BAD_ADDRESS;
+ }
+ } else {
+ return ICanController::Result::NOT_SUPPORTED;
+ }
+
+ busService->setErrorCallback([this, name = config.name]() { downInterface(name); });
+
+ const auto result = busService->up();
+ if (result != ICanController::Result::OK) return result;
+
+ if (busService->registerAsService(config.name) != OK) {
+ LOG(ERROR) << "Failed to register ICanBus/" << config.name;
+ if (!busService->down()) {
+ LOG(WARNING) << "Failed to bring down CAN bus that failed to register";
+ }
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ mCanBuses[config.name] = busService;
+
+ return ICanController::Result::OK;
+}
+
+static bool unregisterCanBusService(const hidl_string& name, sp<CanBus> busService) {
+ auto manager = hidl::manager::V1_2::IServiceManager::getService();
+ if (!manager) return false;
+ const auto res = manager->tryUnregister(ICanBus::descriptor, name, busService);
+ if (!res.isOk()) return false;
+ return res;
+}
+
+Return<bool> CanController::downInterface(const hidl_string& name) {
+ LOG(VERBOSE) << "Attempting to bring interface down: " << name;
+
+ std::lock_guard<std::mutex> lck(mCanBusesGuard);
+
+ auto busEntry = mCanBuses.extract(name);
+ if (!busEntry) {
+ LOG(WARNING) << "Interface " << name << " is not up";
+ return false;
+ }
+
+ auto success = true;
+
+ if (!unregisterCanBusService(name, busEntry.mapped())) {
+ LOG(ERROR) << "Couldn't unregister " << name;
+ // don't return yet, let's try to do best-effort cleanup
+ success = false;
+ }
+
+ if (!busEntry.mapped()->down()) {
+ LOG(ERROR) << "Couldn't bring " << name << " down";
+ success = false;
+ }
+
+ return success;
+}
+
+} // 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
new file mode 100644
index 0000000..99a551a
--- /dev/null
+++ b/automotive/can/1.0/default/CanController.h
@@ -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.
+ */
+
+#pragma once
+
+#include "CanBus.h"
+
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+struct CanController : public ICanController {
+ Return<void> getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) override;
+
+ Return<ICanController::Result> upInterface(
+ const ICanController::BusConfiguration& config) override;
+ Return<bool> downInterface(const hidl_string& name) override;
+
+ private:
+ std::mutex mCanBusesGuard;
+ std::map<std::string, sp<CanBus>> mCanBuses GUARDED_BY(mCanBusesGuard);
+};
+
+} // 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
new file mode 100644
index 0000000..86ccc0e
--- /dev/null
+++ b/automotive/can/1.0/default/CanSocket.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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 "CanSocket.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+#include <linux/can.h>
+#include <utils/SystemClock.h>
+
+#include <chrono>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+using namespace std::chrono_literals;
+
+/* How frequently the read thread checks whether the interface was asked to be down.
+ *
+ * Note: This does *not* affect read timing or bandwidth, just CPU load vs time to
+ * down the interface. */
+static constexpr auto kReadPooling = 100ms;
+
+std::unique_ptr<CanSocket> CanSocket::open(const std::string& ifname, ReadCallback rdcb,
+ ErrorCallback errcb) {
+ auto sock = netdevice::can::socket(ifname);
+ if (!sock.ok()) {
+ LOG(ERROR) << "Can't open CAN socket on " << ifname;
+ return nullptr;
+ }
+
+ // Can't use std::make_unique due to private CanSocket constructor.
+ return std::unique_ptr<CanSocket>(new CanSocket(std::move(sock), rdcb, errcb));
+}
+
+CanSocket::CanSocket(base::unique_fd socket, ReadCallback rdcb, ErrorCallback errcb)
+ : mReadCallback(rdcb),
+ mErrorCallback(errcb),
+ mSocket(std::move(socket)),
+ mReaderThread(&CanSocket::readerThread, this) {}
+
+CanSocket::~CanSocket() {
+ mStopReaderThread = true;
+
+ /* CanSocket can be brought down as a result of read failure, from the same thread,
+ * so let's just detach and let it finish on its own. */
+ if (mReaderThreadFinished) {
+ mReaderThread.detach();
+ } else {
+ mReaderThread.join();
+ }
+}
+
+bool CanSocket::send(const struct canfd_frame& frame) {
+ const auto res = write(mSocket.get(), &frame, CAN_MTU);
+ if (res < 0) {
+ LOG(DEBUG) << "CanSocket send failed: " << errno;
+ return false;
+ }
+ if (res != CAN_MTU) {
+ LOG(DEBUG) << "CanSocket sent wrong number of bytes: " << res;
+ return false;
+ }
+ return true;
+}
+
+static struct timeval toTimeval(std::chrono::microseconds t) {
+ struct timeval tv;
+ tv.tv_sec = t / 1s;
+ tv.tv_usec = (t % 1s) / 1us;
+ return tv;
+}
+
+static int selectRead(const base::unique_fd& fd, std::chrono::microseconds timeout) {
+ auto timeouttv = toTimeval(timeout);
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(fd.get(), &readfds);
+ return select(fd.get() + 1, &readfds, nullptr, nullptr, &timeouttv);
+}
+
+void CanSocket::readerThread() {
+ LOG(VERBOSE) << "Reader thread started";
+ int errnoCopy = 0;
+
+ while (!mStopReaderThread) {
+ /* The ideal would be to have a blocking read(3) call and interrupt it with shutdown(3).
+ * This is unfortunately not supported for SocketCAN, so we need to rely on select(3). */
+ const auto sel = selectRead(mSocket, kReadPooling);
+ if (sel == 0) continue; // timeout
+ if (sel == -1) {
+ LOG(ERROR) << "Select failed: " << errno;
+ break;
+ }
+
+ struct canfd_frame frame;
+ const auto nbytes = read(mSocket.get(), &frame, CAN_MTU);
+
+ /* We could use SIOCGSTAMP to get a precise UNIX timestamp for a given packet, but what
+ * we really need is a time since boot. There is no direct way to convert between these
+ * clocks. We could implement a class to calculate the difference between the clocks
+ * (querying both several times and picking the smallest difference); apply the difference
+ * to a SIOCGSTAMP returned value; re-synchronize if the elapsed time is too much in the
+ * past (indicating the UNIX timestamp might have been adjusted).
+ *
+ * Apart from the added complexity, it's possible the added calculations and system calls
+ * would add so much time to the processing pipeline so the precision of the reported time
+ * was buried under the subsystem latency. Let's just use a local time since boot here and
+ * leave precise hardware timestamps for custom proprietary implementations (if needed). */
+ const std::chrono::nanoseconds ts(elapsedRealtimeNano());
+
+ if (nbytes != CAN_MTU) {
+ if (nbytes >= 0) {
+ LOG(ERROR) << "Failed to read CAN packet, got " << nbytes << " bytes";
+ break;
+ }
+ if (errno == EAGAIN) continue;
+
+ errnoCopy = errno;
+ LOG(ERROR) << "Failed to read CAN packet: " << strerror(errno) << " (" << errno << ")";
+ break;
+ }
+
+ mReadCallback(frame, ts);
+ }
+
+ bool failed = !mStopReaderThread;
+ auto errCb = mErrorCallback;
+ mReaderThreadFinished = true;
+
+ // Don't access any fields from here, see CanSocket::~CanSocket comment about detached thread
+ if (failed) errCb(errnoCopy);
+
+ LOG(VERBOSE) << "Reader thread stopped";
+}
+
+} // 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
new file mode 100644
index 0000000..fd956b5
--- /dev/null
+++ b/automotive/can/1.0/default/CanSocket.h
@@ -0,0 +1,69 @@
+/*
+ * 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-base/macros.h>
+#include <android-base/unique_fd.h>
+#include <linux/can.h>
+
+#include <atomic>
+#include <chrono>
+#include <thread>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+/** Wrapper around SocketCAN socket. */
+struct CanSocket {
+ using ReadCallback = std::function<void(const struct canfd_frame&, std::chrono::nanoseconds)>;
+ using ErrorCallback = std::function<void(int errnoVal)>;
+
+ /**
+ * Open and bind SocketCAN socket.
+ *
+ * \param ifname SocketCAN network interface name (such as can0)
+ * \param rdcb Callback on received messages
+ * \param errcb Callback on socket failure
+ * \return Socket instance, or nullptr if it wasn't possible to open one
+ */
+ static std::unique_ptr<CanSocket> open(const std::string& ifname, ReadCallback rdcb,
+ ErrorCallback errcb);
+ virtual ~CanSocket();
+
+ /**
+ * Send CAN frame.
+ *
+ * \param frame Frame to send
+ * \return true in case of success, false otherwise
+ */
+ bool send(const struct canfd_frame& frame);
+
+ private:
+ CanSocket(base::unique_fd socket, ReadCallback rdcb, ErrorCallback errcb);
+ void readerThread();
+
+ ReadCallback mReadCallback;
+ ErrorCallback mErrorCallback;
+
+ const base::unique_fd mSocket;
+ std::thread mReaderThread;
+ std::atomic<bool> mStopReaderThread = false;
+ std::atomic<bool> mReaderThreadFinished = false;
+
+ DISALLOW_COPY_AND_ASSIGN(CanSocket);
+};
+
+} // 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
new file mode 100644
index 0000000..e1ffe2b
--- /dev/null
+++ b/automotive/can/1.0/default/CloseHandle.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CloseHandle.h"
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {}
+
+CloseHandle::~CloseHandle() {
+ close();
+}
+
+Return<void> CloseHandle::close() {
+ const auto wasClosed = mIsClosed.exchange(true);
+ if (wasClosed) return {};
+
+ if (mCallback != nullptr) mCallback();
+ return {};
+}
+
+} // 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
new file mode 100644
index 0000000..c332d74
--- /dev/null
+++ b/automotive/can/1.0/default/CloseHandle.h
@@ -0,0 +1,47 @@
+/*
+ * 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-base/macros.h>
+#include <android/hardware/automotive/can/1.0/ICloseHandle.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+/** Generic ICloseHandle implementation ignoring double-close events. */
+struct CloseHandle : public ICloseHandle {
+ using Callback = std::function<void()>;
+
+ /**
+ * Create a handle with a callback.
+ *
+ * The callback is guaranteed to be called exactly once.
+ *
+ * \param callback Called on the first close() call, or on destruction of the handle
+ */
+ CloseHandle(Callback callback = nullptr);
+ virtual ~CloseHandle();
+
+ Return<void> close() override;
+
+ private:
+ const Callback mCallback;
+ std::atomic<bool> mIsClosed = false;
+
+ DISALLOW_COPY_AND_ASSIGN(CloseHandle);
+};
+
+} // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc b/automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc
new file mode 100644
index 0000000..a629bda
--- /dev/null
+++ b/automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc
@@ -0,0 +1,5 @@
+service can-hal-1.0-service /vendor/bin/hw/android.hardware.automotive.can@1.0-service
+ class hal
+ capabilities NET_ADMIN
+ user vehicle_network
+ group system inet
diff --git a/automotive/can/1.0/default/libnetdevice/Android.bp b/automotive/can/1.0/default/libnetdevice/Android.bp
new file mode 100644
index 0000000..31e5ad0
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/Android.bp
@@ -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.
+//
+
+cc_library_static {
+ name: "android.hardware.automotive.can@libnetdevice",
+ defaults: ["android.hardware.automotive.can@defaults"],
+ vendor_available: true,
+ relative_install_path: "hw",
+ srcs: [
+ "NetlinkRequest.cpp",
+ "NetlinkSocket.cpp",
+ "can.cpp",
+ "common.cpp",
+ "libnetdevice.cpp",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
new file mode 100644
index 0000000..556debf
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 "NetlinkRequest.h"
+
+#include <android-base/logging.h>
+
+namespace android::netdevice::impl {
+
+static struct rtattr* nlmsg_tail(struct nlmsghdr* n) {
+ return reinterpret_cast<struct rtattr*>( //
+ reinterpret_cast<uintptr_t>(n) + NLMSG_ALIGN(n->nlmsg_len));
+}
+
+struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
+ size_t dataLen) {
+ size_t newLen = NLMSG_ALIGN(n->nlmsg_len) + RTA_SPACE(dataLen);
+ if (newLen > maxLen) {
+ LOG(ERROR) << "addattr_l failed - exceeded maxLen: " << newLen << " > " << maxLen;
+ return nullptr;
+ }
+
+ auto attr = nlmsg_tail(n);
+ attr->rta_len = RTA_SPACE(dataLen);
+ attr->rta_type = type;
+ if (dataLen > 0) memcpy(RTA_DATA(attr), data, dataLen);
+
+ n->nlmsg_len = newLen;
+ return attr;
+}
+
+struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type) {
+ return addattr_l(n, maxLen, type, nullptr, 0);
+}
+
+void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest) {
+ size_t nestLen = reinterpret_cast<uintptr_t>(nlmsg_tail(n)) - reinterpret_cast<uintptr_t>(nest);
+ nest->rta_len = nestLen;
+}
+
+} // namespace android::netdevice::impl
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
new file mode 100644
index 0000000..3e28d78
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
@@ -0,0 +1,153 @@
+/*
+ * 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-base/macros.h>
+#include <linux/rtnetlink.h>
+
+#include <string>
+
+namespace android::netdevice {
+
+typedef unsigned short rtattrtype_t; // as in rtnetlink.h
+typedef __u16 nlmsgtype_t; // as in netlink.h
+
+/** Implementation details, do not use outside NetlinkRequest template. */
+namespace impl {
+
+struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
+ size_t dataLen);
+struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type);
+void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest);
+
+} // namespace impl
+
+/**
+ * Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
+ *
+ * \param T specific message header (such as struct ifinfomsg)
+ * \param BUFSIZE how much space to reserve for payload (not counting the header size)
+ */
+template <class T, unsigned int BUFSIZE = 128>
+struct NetlinkRequest {
+ /**
+ * Create empty message.
+ *
+ * \param type Message type (such as RTM_NEWLINK)
+ * \param flags Message flags (such as NLM_F_REQUEST)
+ */
+ NetlinkRequest(nlmsgtype_t type, uint16_t flags) {
+ mRequest.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(mRequest.data));
+ mRequest.nlmsg.nlmsg_type = type;
+ mRequest.nlmsg.nlmsg_flags = flags;
+ }
+
+ /** \return pointer to raw netlink message header. */
+ struct nlmsghdr* header() {
+ return &mRequest.nlmsg;
+ }
+ /** Reference to message-specific header. */
+ T& data() { return mRequest.data; }
+
+ /**
+ * Adds an attribute of a simple type.
+ *
+ * If this method fails (i.e. due to insufficient space), the message will be marked
+ * as bad (\see isGood).
+ *
+ * \param type attribute type (such as IFLA_IFNAME)
+ * \param attr attribute data
+ */
+ template <class A>
+ void addattr(rtattrtype_t type, const A& attr) {
+ if (!mIsGood) return;
+ auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, &attr, sizeof(attr));
+ if (ap == nullptr) mIsGood = false;
+ }
+
+ template <>
+ void addattr(rtattrtype_t type, const std::string& s) {
+ if (!mIsGood) return;
+ auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, s.c_str(), s.size() + 1);
+ if (ap == nullptr) mIsGood = false;
+ }
+
+ /** Guard class to frame nested attributes. See nest(int). */
+ struct Nest {
+ Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
+ ~Nest() { mReq.nestEnd(mAttr); }
+
+ private:
+ NetlinkRequest& mReq;
+ struct rtattr* mAttr;
+
+ DISALLOW_COPY_AND_ASSIGN(Nest);
+ };
+
+ /**
+ * Add nested attribute.
+ *
+ * The returned object is a guard for auto-nesting children inside the argument attribute.
+ * When the Nest object goes out of scope, the nesting attribute is closed.
+ *
+ * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
+ * inside IFLA_LINKINFO:
+ * NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+ * {
+ * auto linkinfo = req.nest(IFLA_LINKINFO);
+ * req.addattr(IFLA_INFO_KIND, "can");
+ * {
+ * auto infodata = req.nest(IFLA_INFO_DATA);
+ * req.addattr(IFLA_CAN_BITTIMING, bitTimingStruct);
+ * }
+ * }
+ * // use req
+ *
+ * \param type attribute type (such as IFLA_LINKINFO)
+ */
+ Nest nest(int type) { return Nest(*this, type); }
+
+ /**
+ * Indicates, whether the message is in a good state.
+ *
+ * The bad state is usually a result of payload buffer being too small.
+ * You can modify BUFSIZE template parameter to fix this.
+ */
+ bool isGood() const { return mIsGood; }
+
+ private:
+ bool mIsGood = true;
+
+ struct {
+ struct nlmsghdr nlmsg;
+ T data;
+ char buf[BUFSIZE];
+ } mRequest = {};
+
+ struct rtattr* nestStart(rtattrtype_t type) {
+ if (!mIsGood) return nullptr;
+ auto attr = impl::addattr_nest(&mRequest.nlmsg, sizeof(mRequest), type);
+ if (attr == nullptr) mIsGood = false;
+ return attr;
+ }
+
+ void nestEnd(struct rtattr* nest) {
+ if (mIsGood && nest != nullptr) impl::addattr_nest_end(&mRequest.nlmsg, nest);
+ }
+};
+
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
new file mode 100644
index 0000000..6a7f506
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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 "NetlinkSocket.h"
+
+#include <android-base/logging.h>
+
+namespace android::netdevice {
+
+NetlinkSocket::NetlinkSocket(int protocol) {
+ mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
+ if (!mFd.ok()) {
+ LOG(ERROR) << "Can't open Netlink socket: " << errno;
+ mFailed = true;
+ return;
+ }
+
+ struct sockaddr_nl sa = {};
+ sa.nl_family = AF_NETLINK;
+
+ if (bind(mFd.get(), reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)) < 0) {
+ LOG(ERROR) << "Can't bind Netlink socket: " << errno;
+ mFd.reset();
+ mFailed = true;
+ }
+}
+
+bool NetlinkSocket::send(struct nlmsghdr* nlmsg) {
+ if (mFailed) return false;
+
+ nlmsg->nlmsg_pid = 0; // kernel
+ nlmsg->nlmsg_seq = mSeq++;
+ nlmsg->nlmsg_flags |= NLM_F_ACK;
+
+ struct iovec iov = {nlmsg, nlmsg->nlmsg_len};
+
+ struct sockaddr_nl sa = {};
+ sa.nl_family = AF_NETLINK;
+
+ struct msghdr msg = {};
+ msg.msg_name = &sa;
+ msg.msg_namelen = sizeof(sa);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ if (sendmsg(mFd.get(), &msg, 0) < 0) {
+ LOG(ERROR) << "Can't send Netlink message: " << errno;
+ return false;
+ }
+ return true;
+}
+
+bool NetlinkSocket::receiveAck() {
+ if (mFailed) return false;
+
+ char buf[8192];
+
+ struct sockaddr_nl sa;
+ struct iovec iov = {buf, sizeof(buf)};
+
+ struct msghdr msg = {};
+ msg.msg_name = &sa;
+ msg.msg_namelen = sizeof(sa);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ const ssize_t status = recvmsg(mFd.get(), &msg, 0);
+ if (status < 0) {
+ LOG(ERROR) << "Failed to receive Netlink message: " << errno;
+ return false;
+ }
+ size_t remainingLen = status;
+
+ if (msg.msg_flags & MSG_TRUNC) {
+ LOG(ERROR) << "Failed to receive Netlink message: truncated";
+ return false;
+ }
+
+ for (auto nlmsg = reinterpret_cast<struct nlmsghdr*>(buf); NLMSG_OK(nlmsg, remainingLen);
+ nlmsg = NLMSG_NEXT(nlmsg, remainingLen)) {
+ // We're looking for error/ack message only, ignoring others.
+ if (nlmsg->nlmsg_type != NLMSG_ERROR) {
+ LOG(WARNING) << "Received unexpected Netlink message (ignored): " << nlmsg->nlmsg_type;
+ continue;
+ }
+
+ // Found error/ack message, return status.
+ auto nlerr = reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(nlmsg));
+ if (nlerr->error != 0) {
+ LOG(ERROR) << "Received Netlink error message: " << nlerr->error;
+ return false;
+ }
+ return true;
+ }
+ // Couldn't find any error/ack messages.
+ return false;
+}
+
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
new file mode 100644
index 0000000..2b40ea2
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
@@ -0,0 +1,66 @@
+/*
+ * 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 "NetlinkRequest.h"
+
+#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
+
+#include <linux/netlink.h>
+
+namespace android::netdevice {
+
+/**
+ * A wrapper around AF_NETLINK sockets.
+ *
+ * This class is not thread safe to use a single instance between multiple threads, but it's fine to
+ * use multiple instances over multiple threads.
+ */
+struct NetlinkSocket {
+ NetlinkSocket(int protocol);
+
+ /**
+ * Send Netlink message to Kernel.
+ *
+ * \param msg Message to send, nlmsg_seq will be set to next sequence number
+ * \return true, if succeeded
+ */
+ template <class T, unsigned int BUFSIZE>
+ bool send(NetlinkRequest<T, BUFSIZE>& req) {
+ if (!req.isGood()) return false;
+ return send(req.header());
+ }
+
+ /**
+ * Receive Netlink ACK message from Kernel.
+ *
+ * \return true if received ACK message, false in case of error
+ */
+ bool receiveAck();
+
+ private:
+ uint32_t mSeq = 0;
+ base::unique_fd mFd;
+ bool mFailed = false;
+
+ bool send(struct nlmsghdr* msg);
+
+ DISALLOW_COPY_AND_ASSIGN(NetlinkSocket);
+};
+
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp
new file mode 100644
index 0000000..06d45d3
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 <libnetdevice/libnetdevice.h>
+
+#include "NetlinkRequest.h"
+#include "NetlinkSocket.h"
+#include "common.h"
+
+#include <android-base/logging.h>
+#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::netdevice::can {
+
+static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK;
+
+base::unique_fd socket(const std::string& ifname) {
+ struct sockaddr_can addr = {};
+ addr.can_family = AF_CAN;
+ addr.can_ifindex = nametoindex(ifname);
+ if (addr.can_ifindex == 0) {
+ LOG(ERROR) << "Interface " << ifname << " doesn't exists";
+ return {};
+ }
+
+ base::unique_fd sock(::socket(PF_CAN, SOCK_RAW, CAN_RAW));
+ if (!sock.ok()) {
+ LOG(ERROR) << "Failed to create CAN socket";
+ 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 {};
+ }
+
+ if (0 != bind(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) {
+ LOG(ERROR) << "Can't bind to CAN interface " << ifname;
+ return {};
+ }
+
+ return sock;
+}
+
+bool setBitrate(std::string ifname, uint32_t bitrate) {
+ struct can_bittiming bt = {};
+ bt.bitrate = bitrate;
+
+ NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+
+ const auto ifidx = nametoindex(ifname);
+ if (ifidx == 0) {
+ LOG(ERROR) << "Can't find interface " << ifname;
+ return false;
+ }
+ req.data().ifi_index = ifidx;
+
+ {
+ auto linkinfo = req.nest(IFLA_LINKINFO);
+ req.addattr(IFLA_INFO_KIND, "can");
+ {
+ auto infodata = req.nest(IFLA_INFO_DATA);
+ /* For CAN FD, it would require to add IFLA_CAN_DATA_BITTIMING
+ * and IFLA_CAN_CTRLMODE as well. */
+ req.addattr(IFLA_CAN_BITTIMING, bt);
+ }
+ }
+
+ NetlinkSocket sock(NETLINK_ROUTE);
+ return sock.send(req) && sock.receiveAck();
+}
+
+} // namespace android::netdevice::can
diff --git a/automotive/can/1.0/default/libnetdevice/common.cpp b/automotive/can/1.0/default/libnetdevice/common.cpp
new file mode 100644
index 0000000..5c62443
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/common.cpp
@@ -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.
+ */
+
+#include "common.h"
+
+#include <android-base/logging.h>
+
+#include <net/if.h>
+
+namespace android::netdevice {
+
+unsigned int nametoindex(const std::string& ifname) {
+ const auto ifidx = if_nametoindex(ifname.c_str());
+ if (ifidx != 0) return ifidx;
+
+ const auto err = errno;
+ if (err != ENODEV) {
+ LOG(ERROR) << "if_nametoindex(" << ifname << ") failed: " << err;
+ }
+ return 0;
+}
+
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h
new file mode 100644
index 0000000..8097f37
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/common.h
@@ -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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android::netdevice {
+
+/**
+ * Returns the index of a given network interface.
+ *
+ * If the syscall to check the index fails with other error than ENODEV, it gets logged and the
+ * return value indicates the interface doesn't exists.
+ *
+ * \param ifname Interface to check
+ * \return Interface index, or 0 if the interface doesn't exist
+ */
+unsigned int nametoindex(const std::string& ifname);
+
+} // 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
new file mode 100644
index 0000000..3886acf
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
@@ -0,0 +1,41 @@
+/*
+ * 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-base/unique_fd.h>
+
+#include <string>
+
+namespace android::netdevice::can {
+
+/**
+ * Opens and binds SocketCAN socket.
+ *
+ * \param ifname Interface to open a socket against
+ * \return Socket's FD or -1 in case of failure
+ */
+base::unique_fd socket(const std::string& ifname);
+
+/**
+ * Sets CAN interface bitrate.
+ *
+ * \param ifname Interface for which the bitrate is to be set
+ * \return true on success, false on failure
+ */
+bool setBitrate(std::string ifname, uint32_t bitrate);
+
+} // 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
new file mode 100644
index 0000000..3818a31
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
@@ -0,0 +1,73 @@
+/*
+ * 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 <optional>
+#include <string>
+
+namespace android::netdevice {
+
+/**
+ * Checks, if the network interface exists.
+ *
+ * \param ifname Interface to check
+ * \return true if it exists, false otherwise
+ */
+bool exists(std::string ifname);
+
+/**
+ * Checks if network interface is up.
+ *
+ * \param ifname Interface to check
+ * \return true/false if the check succeeded, nullopt otherwise
+ */
+std::optional<bool> isUp(std::string ifname);
+
+/**
+ * Brings network interface up.
+ *
+ * \param ifname Interface to bring up
+ * \return true in case of success, false otherwise
+ */
+bool up(std::string ifname);
+
+/**
+ * Brings network interface down.
+ *
+ * \param ifname Interface to bring down
+ * \return true in case of success, false otherwise
+ */
+bool down(std::string ifname);
+
+/**
+ * Adds virtual link.
+ *
+ * \param dev the name of the new virtual device
+ * \param type the type of the new device
+ * \return true in case of success, false otherwise
+ */
+bool add(std::string dev, std::string type);
+
+/**
+ * Deletes virtual link.
+ *
+ * \param dev the name of the device to remove
+ * \return true in case of success, false otherwise
+ */
+bool del(std::string dev);
+
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
new file mode 100644
index 0000000..aee8205
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 <libnetdevice/libnetdevice.h>
+
+#include "NetlinkRequest.h"
+#include "NetlinkSocket.h"
+#include "common.h"
+
+#include <android-base/logging.h>
+
+#include <linux/can.h>
+#include <net/if.h>
+
+namespace android::netdevice {
+
+bool exists(std::string ifname) {
+ return nametoindex(ifname) != 0;
+}
+
+static bool sendIfreq(unsigned long request, struct ifreq& ifr) {
+ /* For general interfaces it would be socket(AF_INET, SOCK_DGRAM, 0),
+ * but SEPolicy forces us to limit our flexibility here. */
+ base::unique_fd sock(socket(PF_CAN, SOCK_RAW, CAN_RAW));
+ if (!sock.ok()) {
+ LOG(ERROR) << "Can't create socket";
+ return false;
+ }
+
+ if (ioctl(sock.get(), request, &ifr) < 0) {
+ LOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed: " << errno;
+ return false;
+ }
+
+ return true;
+}
+
+static struct ifreq ifreqFromName(const std::string& ifname) {
+ struct ifreq ifr = {};
+ strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE);
+ return ifr;
+}
+
+std::optional<bool> isUp(std::string ifname) {
+ struct ifreq ifr = ifreqFromName(ifname);
+ if (!sendIfreq(SIOCGIFFLAGS, ifr)) return std::nullopt;
+ return ifr.ifr_flags & IFF_UP;
+}
+
+bool up(std::string ifname) {
+ struct ifreq ifr = ifreqFromName(ifname);
+ if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
+ ifr.ifr_flags |= IFF_UP;
+ return sendIfreq(SIOCSIFFLAGS, ifr);
+}
+
+bool down(std::string ifname) {
+ struct ifreq ifr = ifreqFromName(ifname);
+ if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
+ ifr.ifr_flags &= ~IFF_UP;
+ return sendIfreq(SIOCSIFFLAGS, ifr);
+}
+
+bool add(std::string dev, std::string type) {
+ NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
+ req.addattr(IFLA_IFNAME, dev);
+
+ {
+ auto linkinfo = req.nest(IFLA_LINKINFO);
+ req.addattr(IFLA_INFO_KIND, type);
+ }
+
+ NetlinkSocket sock(NETLINK_ROUTE);
+ return sock.send(req) && sock.receiveAck();
+}
+
+bool del(std::string dev) {
+ NetlinkRequest<struct ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST);
+ req.addattr(IFLA_IFNAME, dev);
+
+ NetlinkSocket sock(NETLINK_ROUTE);
+ return sock.send(req) && sock.receiveAck();
+}
+
+} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/service.cpp b/automotive/can/1.0/default/service.cpp
new file mode 100644
index 0000000..b52a54a
--- /dev/null
+++ b/automotive/can/1.0/default/service.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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 "CanController.h"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+static void canControllerService() {
+ base::SetDefaultTag("CanController");
+ base::SetMinimumLogSeverity(android::base::VERBOSE);
+ configureRpcThreadpool(16, true);
+ LOG(DEBUG) << "CAN controller service starting...";
+
+ sp<CanController> canController(new CanController);
+ if (canController->registerAsService("socketcan") != OK) {
+ LOG(FATAL) << "Failed to register CAN controller";
+ return;
+ }
+
+ LOG(INFO) << "CAN controller service ready";
+ joinRpcThreadpool();
+}
+
+} // namespace android::hardware::automotive::can::V1_0::implementation
+
+int main() {
+ ::android::hardware::automotive::can::V1_0::implementation::canControllerService();
+ return 1; // canBusService (joinRpcThreadpool) shouldn't exit
+}
diff --git a/automotive/can/1.0/hidl-utils/Android.bp b/automotive/can/1.0/hidl-utils/Android.bp
new file mode 100644
index 0000000..63b07c9
--- /dev/null
+++ b/automotive/can/1.0/hidl-utils/Android.bp
@@ -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.
+//
+
+cc_library_headers {
+ name: "android.hardware.automotive.can@hidl-utils-lib",
+ export_include_dirs: ["include"],
+ vendor_available: true,
+}
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
new file mode 100644
index 0000000..f63d43c
--- /dev/null
+++ b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h
@@ -0,0 +1,61 @@
+/*
+ * 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
+
+namespace android::hardware::automotive::hidl_utils {
+
+/**
+ * Helper functor to fetch results from multi-return HIDL calls.
+ * It's meant to be used in place of _hidl_cb callbacks.
+ *
+ * Please note extracting these return variables outside of the callback scope requires making
+ * a copy of each return variable. This may be costly for frequently called HIDL methods with
+ * non-negligible return object size. Please be cautious about performance when using this.
+ *
+ * Example usage:
+ * Result result;
+ * sp<ISomeInterface> iface;
+ * hidlObject->someMethod(arg1, arg2, hidl_utils::fill(&result, &iface)).assertOk();
+ * // use result and iface
+ */
+template <typename... T>
+struct fill : public std::function<void(const T&...)> {
+ /**
+ * Create _hidl_cb functor that copies the call arguments to specified pointers.
+ *
+ * \param args... Targets to copy the call arguments to
+ */
+ fill(T*... args) : mTargets(args...) {}
+
+ void operator()(const T&... args) { copy<0, T...>(args...); }
+
+ private:
+ std::tuple<T*...> mTargets;
+
+ template <int Pos, typename First>
+ inline void copy(const First& first) {
+ *std::get<Pos>(mTargets) = first;
+ }
+
+ template <int Pos, typename First, typename... Rest>
+ inline void copy(const First& first, const Rest&... rest) {
+ *std::get<Pos>(mTargets) = first;
+ copy<Pos + 1, Rest...>(rest...);
+ }
+};
+
+} // namespace android::hardware::automotive::hidl_utils
diff --git a/automotive/can/1.0/tools/Android.bp b/automotive/can/1.0/tools/Android.bp
new file mode 100644
index 0000000..21f364b
--- /dev/null
+++ b/automotive/can/1.0/tools/Android.bp
@@ -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.
+//
+
+cc_binary {
+ name: "canhalctrl",
+ defaults: ["android.hardware.automotive.can@defaults"],
+ srcs: [
+ "canhalctrl.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.automotive.can@1.0",
+ "libhidlbase",
+ ],
+ header_libs: [
+ "android.hardware.automotive.can@hidl-utils-lib",
+ ],
+}
+
+cc_binary {
+ name: "canhaldump",
+ defaults: ["android.hardware.automotive.can@defaults"],
+ srcs: [
+ "canhaldump.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.automotive.can@1.0",
+ "libhidlbase",
+ ],
+ header_libs: [
+ "android.hardware.automotive.can@hidl-utils-lib",
+ ],
+}
+
+cc_binary {
+ name: "canhalsend",
+ defaults: ["android.hardware.automotive.can@defaults"],
+ srcs: [
+ "canhalsend.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.automotive.can@1.0",
+ "libhidlbase",
+ ],
+}
diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp
new file mode 100644
index 0000000..5494ba3
--- /dev/null
+++ b/automotive/can/1.0/tools/canhalctrl.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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 <android/hardware/automotive/can/1.0/ICanController.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl-utils/hidl-utils.h>
+
+#include <iostream>
+#include <string>
+
+namespace android::hardware::automotive::can {
+
+using ICanController = V1_0::ICanController;
+
+static void usage() {
+ std::cerr << "CAN bus HAL Control tool" << std::endl;
+ std::cerr << std::endl << "usage:" << std::endl << std::endl;
+ std::cerr << "canhalctrl up <bus name> <type> <interface> [bitrate]" << std::endl;
+ std::cerr << "where:" << std::endl;
+ std::cerr << " bus name - name under which ICanBus will be published" << std::endl;
+ std::cerr << " type - one of: virtual, socketcan, slcan, indexed" << std::endl;
+ std::cerr << " interface - hardware identifier (like can0, vcan0, /dev/ttyUSB0)" << std::endl;
+ std::cerr << " bitrate - such as 100000, 125000, 250000, 500000" << std::endl;
+ std::cerr << std::endl;
+ std::cerr << "canhalctrl down <bus name>" << std::endl;
+ std::cerr << "where:" << std::endl;
+ std::cerr << " bus name - name under which ICanBus will be published" << std::endl;
+}
+
+static hidl_vec<hidl_string> getControlServices() {
+ auto manager = hidl::manager::V1_2::IServiceManager::getService();
+ hidl_vec<hidl_string> services;
+ manager->listManifestByInterface(ICanController::descriptor, hidl_utils::fill(&services));
+ if (services.size() == 0) {
+ std::cerr << "No ICanController services registered (missing privileges?)" << std::endl;
+ exit(-1);
+ }
+ return services;
+}
+
+static bool isSupported(sp<ICanController> ctrl, ICanController::InterfaceType iftype) {
+ hidl_vec<ICanController::InterfaceType> supported;
+ if (!ctrl->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).isOk()) return false;
+ return supported.contains(iftype);
+}
+
+static int up(const std::string& busName, ICanController::InterfaceType type,
+ const std::string& interface, uint32_t bitrate) {
+ bool anySupported = false;
+ for (auto&& service : getControlServices()) {
+ auto ctrl = ICanController::getService(service);
+ if (ctrl == nullptr) {
+ std::cerr << "Couldn't open ICanController/" << service;
+ continue;
+ }
+
+ if (!isSupported(ctrl, type)) continue;
+ anySupported = true;
+
+ ICanController::BusConfiguration config = {};
+ config.name = busName;
+ config.iftype = type;
+ config.bitrate = bitrate;
+
+ if (type == ICanController::InterfaceType::INDEXED) {
+ config.interfaceId.index(std::stol(interface));
+ } else {
+ config.interfaceId.address(interface);
+ }
+
+ const auto upresult = ctrl->upInterface(config);
+ if (upresult == ICanController::Result::OK) return 0;
+ std::cerr << "Failed to bring interface up: " << toString(upresult) << std::endl;
+ // Let's continue the loop to try other controllers.
+ }
+
+ if (!anySupported) {
+ std::cerr << "No controller supports " << toString(type) << std::endl;
+ }
+ return -1;
+}
+
+static int down(const std::string& busName) {
+ for (auto&& service : getControlServices()) {
+ auto ctrl = ICanController::getService(service);
+ if (ctrl == nullptr) continue;
+
+ if (ctrl->downInterface(busName)) return 0;
+ }
+
+ std::cerr << "Failed to bring interface " << busName << " down (maybe it's down already?)"
+ << std::endl;
+ return -1;
+}
+
+static std::optional<ICanController::InterfaceType> parseInterfaceType(const std::string& str) {
+ if (str == "virtual") return ICanController::InterfaceType::VIRTUAL;
+ if (str == "socketcan") return ICanController::InterfaceType::SOCKETCAN;
+ if (str == "slcan") return ICanController::InterfaceType::SLCAN;
+ if (str == "indexed") return ICanController::InterfaceType::INDEXED;
+ return std::nullopt;
+}
+
+static int main(int argc, char* argv[]) {
+ base::SetDefaultTag("CanHalControl");
+ base::SetMinimumLogSeverity(android::base::VERBOSE);
+
+ if (argc == 0) {
+ usage();
+ return 0;
+ }
+
+ std::string cmd(argv[0]);
+ argv++;
+ argc--;
+
+ if (cmd == "up") {
+ if (argc < 3 || argc > 4) {
+ std::cerr << "Invalid number of arguments to up command: " << argc << std::endl;
+ usage();
+ return -1;
+ }
+
+ const std::string busName(argv[0]);
+ const std::string typeStr(argv[1]);
+ const std::string interface(argv[2]);
+
+ const auto type = parseInterfaceType(typeStr);
+ if (!type) {
+ std::cerr << "Invalid interface type: " << typeStr << std::endl;
+ usage();
+ return -1;
+ }
+
+ long long bitrate = 0;
+ if (argc == 4) {
+ bitrate = std::stoll(argv[3]);
+ }
+
+ return up(busName, *type, interface, bitrate);
+ } else if (cmd == "down") {
+ if (argc != 1) {
+ std::cerr << "Invalid number of arguments to down command: " << argc << std::endl;
+ usage();
+ return -1;
+ }
+
+ return down(argv[0]);
+ } else {
+ std::cerr << "Invalid command: " << cmd << std::endl;
+ usage();
+ return -1;
+ }
+}
+
+} // namespace android::hardware::automotive::can
+
+int main(int argc, char* argv[]) {
+ if (argc < 1) return -1;
+ return ::android::hardware::automotive::can::main(--argc, ++argv);
+}
diff --git a/automotive/can/1.0/tools/canhaldump.cpp b/automotive/can/1.0/tools/canhaldump.cpp
new file mode 100644
index 0000000..2f5ca61
--- /dev/null
+++ b/automotive/can/1.0/tools/canhaldump.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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 <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanMessageListener.h>
+#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::hardware::automotive::can {
+
+using namespace std::chrono_literals;
+
+using ICanBus = V1_0::ICanBus;
+using Result = V1_0::Result;
+
+struct CanMessageListener : public V1_0::ICanMessageListener {
+ const std::string name;
+
+ CanMessageListener(std::string name) : name(name) {}
+
+ virtual Return<void> onReceive(const V1_0::CanMessage& message) {
+ 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 << "remote request";
+ } else {
+ for (const auto byte : message.payload) {
+ std::cout << " " << std::setfill('0') << std::setw(2) << unsigned(byte);
+ }
+ }
+ std::cout << std::nouppercase << std::dec << std::endl;
+ return {};
+ }
+
+ virtual Return<void> onError(V1_0::ErrorEvent error) {
+ std::cout << " " << name << " " << toString(error) << std::endl;
+ return {};
+ }
+};
+
+static void usage() {
+ std::cerr << "canhaldump - dump CAN bus traffic" << std::endl;
+ std::cerr << std::endl << "usage:" << std::endl << std::endl;
+ std::cerr << "canhaldump <bus name>" << std::endl;
+ std::cerr << "where:" << std::endl;
+ std::cerr << " bus name - name under which ICanBus is be published" << std::endl;
+}
+
+// TODO(b/135918744): extract to a new library
+static sp<ICanBus> tryOpen(const std::string& busname) {
+ auto bus = ICanBus::tryGetService(busname);
+ if (bus != nullptr) return bus;
+
+ /* Fallback for interfaces not registered in manifest. For testing purposes only,
+ * one should not depend on this in production deployment. */
+ auto manager = hidl::manager::V1_2::IServiceManager::getService();
+ auto ret = manager->get(ICanBus::descriptor, busname).withDefault(nullptr);
+ if (ret == nullptr) return nullptr;
+
+ std::cerr << "WARNING: bus " << busname << " is not registered in device manifest, "
+ << "trying to fetch it directly..." << std::endl;
+
+ return ICanBus::castFrom(ret);
+}
+
+static int candump(const std::string& busname) {
+ auto bus = tryOpen(busname);
+ if (bus == nullptr) {
+ std::cerr << "Bus " << busname << " is not available" << std::endl;
+ return -1;
+ }
+
+ Result result;
+ sp<V1_0::ICloseHandle> chnd;
+ // TODO(b/135918744): extract to library
+ bus->listen({}, new CanMessageListener(busname), hidl_utils::fill(&result, &chnd)).assertOk();
+
+ if (result != Result::OK) {
+ std::cerr << "Listen call failed: " << toString(result) << std::endl;
+ return -1;
+ }
+
+ while (true) std::this_thread::sleep_for(1h);
+}
+
+static int main(int argc, char* argv[]) {
+ base::SetDefaultTag("CanHalDump");
+ base::SetMinimumLogSeverity(android::base::VERBOSE);
+
+ if (argc == 0) {
+ usage();
+ return 0;
+ }
+
+ if (argc != 1) {
+ std::cerr << "Invalid number of arguments" << std::endl;
+ usage();
+ return -1;
+ }
+
+ return candump(argv[0]);
+}
+
+} // namespace android::hardware::automotive::can
+
+int main(int argc, char* argv[]) {
+ if (argc < 1) return -1;
+ return ::android::hardware::automotive::can::main(--argc, ++argv);
+}
diff --git a/automotive/can/1.0/tools/canhalsend.cpp b/automotive/can/1.0/tools/canhalsend.cpp
new file mode 100644
index 0000000..7e6833a
--- /dev/null
+++ b/automotive/can/1.0/tools/canhalsend.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+
+#include <iostream>
+#include <string>
+
+namespace android::hardware::automotive::can {
+
+using ICanBus = V1_0::ICanBus;
+using Result = V1_0::Result;
+
+static void usage() {
+ std::cerr << "cansend - simple command line tool to send raw CAN frames" << std::endl;
+ std::cerr << std::endl << "usage:" << std::endl << std::endl;
+ std::cerr << "canhalsend <bus name> <can id>#<data>" << std::endl;
+ std::cerr << "where:" << std::endl;
+ std::cerr << " bus name - name under which ICanBus is be published" << std::endl;
+ std::cerr << " can id - such as 1a5" << std::endl;
+ std::cerr << " data - such as deadbeef or 010203" << std::endl;
+}
+
+// TODO(b/135918744): extract to a new library
+static sp<ICanBus> tryOpen(const std::string& busname) {
+ auto bus = ICanBus::tryGetService(busname);
+ if (bus != nullptr) return bus;
+
+ /* Fallback for interfaces not registered in manifest. For testing purposes only,
+ * one should not depend on this in production deployment. */
+ auto manager = hidl::manager::V1_2::IServiceManager::getService();
+ auto ret = manager->get(ICanBus::descriptor, busname).withDefault(nullptr);
+ if (ret == nullptr) return nullptr;
+
+ std::cerr << "WARNING: bus " << busname << " is not registered in device manifest, "
+ << "trying to fetch it directly..." << std::endl;
+
+ return ICanBus::castFrom(ret);
+}
+
+static int cansend(const std::string& busname, V1_0::CanMessageId msgid,
+ std::vector<uint8_t> payload) {
+ auto bus = tryOpen(busname);
+ if (bus == nullptr) {
+ std::cerr << "Bus " << busname << " is not available" << std::endl;
+ return -1;
+ }
+
+ V1_0::CanMessage msg = {};
+ msg.id = msgid;
+ msg.payload = payload;
+
+ const auto result = bus->send(msg);
+ if (result != Result::OK) {
+ std::cerr << "Send call failed: " << toString(result) << std::endl;
+ return -1;
+ }
+ return 0;
+}
+
+static std::optional<std::tuple<V1_0::CanMessageId, std::vector<uint8_t>>> parseCanMessage(
+ const std::string& msg) {
+ const auto hashpos = msg.find("#");
+ if (hashpos == std::string::npos) return std::nullopt;
+
+ const std::string msgidStr = msg.substr(0, hashpos);
+ const std::string payloadStr = msg.substr(hashpos + 1);
+
+ size_t idx = 0;
+ V1_0::CanMessageId msgid = std::stoi(msgidStr, &idx, 16);
+ if (msgidStr[idx] != '\0') return std::nullopt;
+
+ std::vector<uint8_t> payload;
+ if (payloadStr.size() % 2 != 0) return std::nullopt;
+ for (size_t i = 0; i < payloadStr.size(); i += 2) {
+ std::string byteStr(payloadStr, i, 2);
+ payload.emplace_back(std::stoi(byteStr, &idx, 16));
+ if (byteStr[idx] != '\0') return std::nullopt;
+ }
+
+ return {{msgid, payload}};
+}
+
+static int main(int argc, char* argv[]) {
+ base::SetDefaultTag("CanHalSend");
+ base::SetMinimumLogSeverity(android::base::VERBOSE);
+
+ if (argc == 0) {
+ usage();
+ return 0;
+ }
+
+ if (argc != 2) {
+ std::cerr << "Invalid number of arguments" << std::endl;
+ usage();
+ return -1;
+ }
+
+ std::string busname(argv[0]);
+ const auto canmsg = parseCanMessage(argv[1]);
+ if (!canmsg) {
+ std::cerr << "Failed to parse CAN message argument" << std::endl;
+ return -1;
+ }
+ const auto [msgid, payload] = *canmsg;
+
+ return cansend(busname, msgid, payload);
+}
+
+} // namespace android::hardware::automotive::can
+
+int main(int argc, char* argv[]) {
+ if (argc < 1) return -1;
+ return ::android::hardware::automotive::can::main(--argc, ++argv);
+}
diff --git a/automotive/can/1.0/types.hal b/automotive/can/1.0/types.hal
new file mode 100644
index 0000000..5eeed53
--- /dev/null
+++ b/automotive/can/1.0/types.hal
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can@1.0;
+
+/**
+ * CAN message ID.
+ *
+ * Does not include any flags like RTR nor ERR, only a plain 11-bit
+ * or 29-bit identifier, as defined in CAN 1.x/2.0x.
+ *
+ * Unused bits must be set to zero.
+ */
+typedef uint32_t CanMessageId;
+
+/**
+ * CAN message being sent or received.
+ */
+struct CanMessage {
+ CanMessageId id;
+
+ /**
+ * CAN message payload, as defined in CAN 1.x and CAN 2.x standards.
+ *
+ * The length of the payload vector directly translates to the length
+ * of the data frame (i.e. includes any padding bytes), so it may be in
+ * a range of:
+ * - 0-8 bytes for standard CAN;
+ * - up to 64 bytes for CAN FD.
+ * ISO TP is not supported directly for now.
+ */
+ vec<uint8_t> payload;
+
+ /**
+ * Time in nanoseconds since boot.
+ *
+ * Ignored for outgoing messages.
+ */
+ uint64_t timestamp;
+
+ /**
+ * A request to proactively pull certain data from other ECU in CAN network.
+ *
+ * For details please refer to CAN standard.
+ *
+ * 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)) == !exclude
+ *
+ * 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;
+ /** 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 {
+ OK,
+ UNKNOWN_ERROR,
+ PAYLOAD_TOO_LONG,
+ INTERFACE_DOWN,
+ TRANSMISSION_FAILURE,
+ INVALID_ARGUMENTS,
+};
+
+/**
+ * @see ICanMessageListener#onError
+ */
+enum ErrorEvent : uint8_t {
+ UNKNOWN_ERROR,
+
+ /** A problem with CAN interface HW. */
+ HARDWARE_ERROR,
+
+ /** CAN interface is down. */
+ INTERFACE_DOWN,
+
+ /** TX buffer overflow: client is sending too many packets. */
+ TX_OVERFLOW,
+
+ /** RX buffer overflow: client is not reading packets fast enough. */
+ RX_OVERFLOW,
+
+ /** Received malformed input. */
+ MALFORMED_INPUT,
+
+ /** Bus overload: there is too much traffic on the bus. */
+ BUS_OVERLOAD,
+
+ /** Bus error: shorted Hi/Lo line, bus off etc. */
+ BUS_ERROR,
+};
diff --git a/automotive/can/1.0/vts/functional/Android.bp b/automotive/can/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..e3e770b
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/Android.bp
@@ -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.
+//
+
+cc_defaults {
+ name: "android.hardware.automotive.can@vts-defaults",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "android.hardware.automotive.can@defaults",
+ ],
+ header_libs: [
+ "android.hardware.automotive.can@hidl-utils-lib",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can@1.0",
+ "android.hardware.automotive.can@vts-utils-lib",
+ "libgmock",
+ ],
+ test_suites: ["general-tests"],
+}
+
+cc_test {
+ name: "VtsHalCanControllerV1_0TargetTest",
+ defaults: ["android.hardware.automotive.can@vts-defaults"],
+ srcs: ["VtsHalCanControllerV1_0TargetTest.cpp"],
+}
+
+cc_test {
+ name: "VtsHalCanBusV1_0TargetTest",
+ defaults: ["android.hardware.automotive.can@vts-defaults"],
+ srcs: ["VtsHalCanBusV1_0TargetTest.cpp"],
+}
+
+cc_test {
+ name: "VtsHalCanBusVirtualV1_0TargetTest",
+ defaults: ["android.hardware.automotive.can@vts-defaults"],
+ srcs: ["VtsHalCanBusVirtualV1_0TargetTest.cpp"],
+}
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
new file mode 100644
index 0000000..cdea8b6
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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 <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/types.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::hardware::automotive::can::V1_0::vts {
+
+using hardware::hidl_vec;
+
+static utils::SimpleHidlEnvironment<ICanBus>* gEnv = nullptr;
+
+struct CanMessageListener : public can::V1_0::ICanMessageListener {
+ virtual Return<void> onReceive(const can::V1_0::CanMessage&) override { return {}; }
+};
+
+struct CanErrorListener : public can::V1_0::ICanErrorListener {
+ virtual Return<void> onError(ErrorEvent, bool) override { return {}; }
+};
+
+class CanBusHalTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ virtual void SetUp() override;
+ virtual void TearDown() override;
+
+ std::tuple<Result, sp<ICloseHandle>> listen(const hidl_vec<CanMessageFilter>& filter,
+ const sp<ICanMessageListener>& listener);
+ sp<ICloseHandle> listenForErrors(const sp<ICanErrorListener>& listener);
+
+ sp<ICanBus> mCanBus;
+};
+
+void CanBusHalTest::SetUp() {
+ const auto serviceName = gEnv->getServiceName<ICanBus>();
+ mCanBus = getService<ICanBus>(serviceName);
+ ASSERT_TRUE(mCanBus) << "Couldn't open CAN Bus: " << serviceName;
+}
+
+void CanBusHalTest::TearDown() {
+ mCanBus.clear();
+}
+
+std::tuple<Result, sp<ICloseHandle>> CanBusHalTest::listen(
+ const hidl_vec<CanMessageFilter>& filter, const sp<ICanMessageListener>& listener) {
+ Result halResult;
+ sp<ICloseHandle> closeHandle;
+ mCanBus->listen(filter, listener, hidl_utils::fill(&halResult, &closeHandle)).assertOk();
+
+ return {halResult, closeHandle};
+}
+
+sp<ICloseHandle> CanBusHalTest::listenForErrors(const sp<ICanErrorListener>& listener) {
+ const auto res = mCanBus->listenForErrors(listener);
+ res.assertOk();
+ return res;
+}
+
+TEST_F(CanBusHalTest, SendNoPayload) {
+ CanMessage msg = {};
+ msg.id = 0x123;
+ ASSERT_NE(mCanBus, nullptr);
+ const auto result = mCanBus->send(msg);
+ ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(CanBusHalTest, Send8B) {
+ CanMessage msg = {};
+ msg.id = 0x234;
+ msg.payload = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ const auto result = mCanBus->send(msg);
+ ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(CanBusHalTest, SendZeroId) {
+ CanMessage msg = {};
+ msg.payload = {1, 2, 3};
+
+ const auto result = mCanBus->send(msg);
+ ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(CanBusHalTest, SendTooLong) {
+ CanMessage msg = {};
+ msg.id = 0x123;
+ msg.payload = hidl_vec<uint8_t>(102400); // 100kiB
+
+ const auto result = mCanBus->send(msg);
+ ASSERT_EQ(Result::PAYLOAD_TOO_LONG, result);
+}
+
+TEST_F(CanBusHalTest, ListenNoFilter) {
+ const auto [result, closeHandle] = listen({}, new CanMessageListener());
+ ASSERT_EQ(Result::OK, result);
+
+ closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, ListenSomeFilter) {
+ hidl_vec<CanMessageFilter> filters = {
+ {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());
+ ASSERT_EQ(Result::OK, result);
+
+ closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, ListenNull) {
+ const auto [result, closeHandle] = listen({}, nullptr);
+ ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
+}
+
+TEST_F(CanBusHalTest, DoubleCloseListener) {
+ const auto [result, closeHandle] = listen({}, new CanMessageListener());
+ ASSERT_EQ(Result::OK, result);
+
+ closeHandle->close().assertOk();
+ closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, DontCloseListener) {
+ const auto [result, closeHandle] = listen({}, new CanMessageListener());
+ ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(CanBusHalTest, DoubleCloseErrorListener) {
+ auto closeHandle = listenForErrors(new CanErrorListener());
+ ASSERT_NE(nullptr, closeHandle.get());
+
+ closeHandle->close().assertOk();
+ closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, DoubleCloseNullErrorListener) {
+ auto closeHandle = listenForErrors(nullptr);
+ ASSERT_NE(nullptr, closeHandle.get());
+
+ closeHandle->close().assertOk();
+ closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, DontCloseErrorListener) {
+ auto closeHandle = listenForErrors(new CanErrorListener());
+ ASSERT_NE(nullptr, closeHandle.get());
+}
+
+} // 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/<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>;
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
new file mode 100644
index 0000000..efaad53
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -0,0 +1,892 @@
+/*
+ * 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 <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#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>
+#include <utils/Mutex.h>
+#include <utils/SystemClock.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android::hardware::automotive::can::V1_0::vts {
+
+using namespace std::chrono_literals;
+
+using hardware::hidl_vec;
+using InterfaceType = ICanController::InterfaceType;
+
+static utils::SimpleHidlEnvironment<ICanController>* gEnv = nullptr;
+
+struct CanMessageListener : public can::V1_0::ICanMessageListener {
+ DISALLOW_COPY_AND_ASSIGN(CanMessageListener);
+
+ CanMessageListener() {}
+
+ virtual Return<void> onReceive(const can::V1_0::CanMessage& msg) override {
+ std::unique_lock<std::mutex> lk(mMessagesGuard);
+ mMessages.push_back(msg);
+ mMessagesUpdated.notify_one();
+ return {};
+ }
+
+ virtual ~CanMessageListener() { mCloseHandle->close(); }
+
+ void assignCloseHandle(sp<ICloseHandle> closeHandle) {
+ EXPECT_TRUE(closeHandle);
+ EXPECT_FALSE(mCloseHandle);
+ mCloseHandle = closeHandle;
+ }
+
+ std::vector<can::V1_0::CanMessage> fetchMessages(std::chrono::milliseconds timeout,
+ unsigned atLeast = 1) {
+ std::unique_lock<std::mutex> lk(mMessagesGuard);
+ mMessagesUpdated.wait_for(lk, timeout, [&] { return mMessages.size() >= atLeast; });
+ const auto messages = mMessages;
+ mMessages.clear();
+ return messages;
+ }
+
+ private:
+ sp<ICloseHandle> mCloseHandle;
+
+ std::mutex mMessagesGuard;
+ std::condition_variable mMessagesUpdated GUARDED_BY(mMessagesGuard);
+ std::vector<can::V1_0::CanMessage> mMessages GUARDED_BY(mMessagesGuard);
+};
+
+struct Bus {
+ DISALLOW_COPY_AND_ASSIGN(Bus);
+
+ Bus(sp<ICanController> controller, const ICanController::BusConfiguration& config)
+ : mIfname(config.name), mController(controller) {
+ const auto result = controller->upInterface(config);
+ EXPECT_EQ(ICanController::Result::OK, result);
+
+ /* Not using ICanBus::getService here, since it ignores interfaces not in the manifest
+ * file -- this is a test, so we don't want to add dummy services to a device manifest. */
+ auto manager = hidl::manager::V1_2::IServiceManager::getService();
+ auto service = manager->get(ICanBus::descriptor, config.name);
+ mBus = ICanBus::castFrom(service);
+ EXPECT_TRUE(mBus) << "ICanBus/" << config.name << " failed to register";
+ }
+
+ virtual ~Bus() { reset(); }
+
+ void reset() {
+ mBus.clear();
+ if (mController) {
+ const auto res = mController->downInterface(mIfname);
+ EXPECT_TRUE(res);
+ mController.clear();
+ }
+ }
+
+ ICanBus* operator->() const { return mBus.get(); }
+ sp<ICanBus> get() { return mBus; }
+
+ sp<CanMessageListener> listen(const hidl_vec<CanMessageFilter>& filter) {
+ sp<CanMessageListener> listener = new CanMessageListener();
+
+ Result result;
+ sp<ICloseHandle> closeHandle;
+ mBus->listen(filter, listener, hidl_utils::fill(&result, &closeHandle)).assertOk();
+ EXPECT_EQ(Result::OK, result);
+ listener->assignCloseHandle(closeHandle);
+
+ return listener;
+ }
+
+ void send(const CanMessage& msg) {
+ EXPECT_NE(mBus, nullptr);
+ const auto result = mBus->send(msg);
+ EXPECT_EQ(Result::OK, result);
+ }
+
+ private:
+ const std::string mIfname;
+ sp<ICanController> mController;
+ sp<ICanBus> mBus;
+};
+
+class CanBusVirtualHalTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ virtual void SetUp() override;
+
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+
+ 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, bool rtr, bool extended) {
+ CanMessage msg = {};
+ msg.id = id;
+ msg.remoteTransmissionRequest = rtr;
+ msg.isExtendedId = extended;
+ return msg;
+}
+
+static void clearTimestamps(std::vector<CanMessage>& messages) {
+ std::for_each(messages.begin(), messages.end(), [](auto& msg) { msg.timestamp = 0; });
+}
+
+void CanBusVirtualHalTest::SetUp() {
+ if (!mVirtualSupported) GTEST_SKIP();
+ ASSERT_TRUE(mTestCaseInitialized);
+}
+
+void CanBusVirtualHalTest::SetUpTestCase() {
+ const auto serviceName = gEnv->getServiceName<ICanController>();
+ mCanController = getService<ICanController>(serviceName);
+ ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName;
+
+ 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() {
+ mCanController.clear();
+}
+
+Bus CanBusVirtualHalTest::makeBus() {
+ const auto idx = mLastIface++;
+ EXPECT_LT(idx, mBusNames.size());
+
+ ICanController::BusConfiguration config = {};
+ config.name = mBusNames[idx];
+ config.iftype = InterfaceType::VIRTUAL;
+ config.interfaceId.address("vcan50");
+
+ return Bus(mCanController, config);
+}
+
+TEST_F(CanBusVirtualHalTest, Send) {
+ auto bus = makeBus();
+
+ CanMessage msg = {};
+ msg.id = 0x123;
+ msg.payload = {1, 2, 3};
+
+ bus.send(msg);
+}
+
+TEST_F(CanBusVirtualHalTest, SendAfterClose) {
+ auto bus = makeBus();
+ auto zombie = bus.get();
+ bus.reset();
+
+ const auto result = zombie->send({});
+ ASSERT_EQ(Result::INTERFACE_DOWN, result);
+}
+
+TEST_F(CanBusVirtualHalTest, SendAndRecv) {
+ if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+ auto bus1 = makeBus();
+ auto bus2 = makeBus();
+
+ auto listener = bus2.listen({});
+
+ CanMessage msg = {};
+ msg.id = 0x123;
+ msg.payload = {1, 2, 3};
+ bus1.send(msg);
+
+ auto messages = listener->fetchMessages(100ms);
+ ASSERT_EQ(1u, messages.size());
+ ASSERT_NEAR(uint64_t(elapsedRealtimeNano()), messages[0].timestamp,
+ std::chrono::nanoseconds(100ms).count());
+ clearTimestamps(messages);
+ ASSERT_EQ(msg, messages[0]);
+}
+
+TEST_F(CanBusVirtualHalTest, DownOneOfTwo) {
+ if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+
+ auto bus1 = makeBus();
+ auto bus2 = makeBus();
+
+ bus2.reset();
+
+ bus1.send({});
+}
+
+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 = {
+ {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);
+
+ // 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));
+
+ // 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(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 messagesPositive = listenerPositive->fetchMessages(100ms, expectedPositive.size());
+ clearTimestamps(messagesPositive);
+ ASSERT_EQ(expectedPositive, messagesPositive);
+}
+
+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:
+ * adb shell /data/nativetest64/VtsHalCanBusVirtualV1_0TargetTest/VtsHalCanBusVirtualV1_0TargetTest\
+ * --hal_service_instance=android.hardware.automotive.can@1.0::ICanController/socketcan
+ */
+int main(int argc, char** argv) {
+ using android::hardware::automotive::can::V1_0::ICanController;
+ using android::hardware::automotive::can::V1_0::vts::gEnv;
+ using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+ android::base::SetDefaultTag("CanBusVirtualVts");
+ android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+ gEnv = new SimpleHidlEnvironment<ICanController>;
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
new file mode 100644
index 0000000..b2edd78
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -0,0 +1,267 @@
+/*
+ * 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 <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#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::hardware::automotive::can::V1_0::vts {
+
+using hardware::hidl_vec;
+using InterfaceType = ICanController::InterfaceType;
+
+static utils::SimpleHidlEnvironment<ICanController>* gEnv = nullptr;
+
+class CanControllerHalTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ virtual void SetUp() override;
+ virtual void TearDown() override;
+ static void SetUpTestCase();
+
+ hidl_vec<InterfaceType> getSupportedInterfaceTypes();
+ bool isSupported(InterfaceType iftype);
+
+ bool up(InterfaceType iftype, const std::string srvname, std::string ifname,
+ ICanController::Result expected);
+ 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;
+}
+
+void CanControllerHalTest::TearDown() {
+ 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();
+ return iftypesResult;
+}
+
+bool CanControllerHalTest::isSupported(InterfaceType iftype) {
+ const auto supported = getSupportedInterfaceTypes();
+ return std::find(supported.begin(), supported.end(), iftype) != supported.end();
+}
+
+bool CanControllerHalTest::up(InterfaceType iftype, std::string srvname, std::string ifname,
+ ICanController::Result expected) {
+ ICanController::BusConfiguration config = {};
+ config.name = srvname;
+ config.iftype = iftype;
+ config.interfaceId.address(ifname);
+
+ const auto upresult = mCanController->upInterface(config);
+
+ if (!isSupported(iftype)) {
+ LOG(INFO) << iftype << " interfaces not supported";
+ EXPECT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
+ return false;
+ }
+
+ EXPECT_EQ(expected, upresult);
+ return true;
+}
+
+void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegistered) {
+ /* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest
+ * file -- this is a test, so we don't want to add dummy services to a device manifest. */
+ auto manager = hidl::manager::V1_2::IServiceManager::getService();
+ auto busService = manager->get(ICanBus::descriptor, srvname);
+ ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr)
+ << "ICanBus/" << srvname << (expectRegistered ? " is not " : " is ") << "registered"
+ << " (should be otherwise)";
+}
+
+TEST_F(CanControllerHalTest, SupportsSomething) {
+ const auto supported = getSupportedInterfaceTypes();
+ ASSERT_GT(supported.size(), 0u);
+}
+
+TEST_F(CanControllerHalTest, BringUpDown) {
+ const std::string name = mBusNames[0];
+
+ assertRegistered(name, false);
+ if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::OK)) GTEST_SKIP();
+ assertRegistered(name, true);
+
+ const auto dnresult = mCanController->downInterface(name);
+ ASSERT_TRUE(dnresult);
+
+ assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, DownDummy) {
+ const auto result = mCanController->downInterface("imnotup");
+ ASSERT_FALSE(result);
+}
+
+TEST_F(CanControllerHalTest, UpTwice) {
+ const std::string name = mBusNames[0];
+
+ assertRegistered(name, false);
+ if (!up(InterfaceType::VIRTUAL, name, "vcan72", ICanController::Result::OK)) GTEST_SKIP();
+ assertRegistered(name, true);
+ if (!up(InterfaceType::VIRTUAL, name, "vcan73", ICanController::Result::INVALID_STATE)) {
+ GTEST_SKIP();
+ }
+ assertRegistered(name, true);
+
+ const auto result = mCanController->downInterface(name);
+ ASSERT_TRUE(result);
+ assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, IdentifierCompatibility) {
+ using IdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
+ static const std::map<InterfaceType, std::vector<IdDisc>> compatMatrix = {
+ {InterfaceType::VIRTUAL, {IdDisc::address}},
+ {InterfaceType::SOCKETCAN, {IdDisc::address, IdDisc::serialno}},
+ {InterfaceType::SLCAN, {IdDisc::address, IdDisc::serialno}},
+ {InterfaceType::INDEXED, {IdDisc::index}},
+ };
+ static const std::vector<IdDisc> allDisc = {IdDisc::address, IdDisc::index, IdDisc::serialno};
+
+ for (const auto [iftype, supported] : compatMatrix) {
+ for (const auto iddisc : allDisc) {
+ LOG(INFO) << "Compatibility testing: " << iftype << " / " << iddisc;
+
+ ICanController::BusConfiguration config = {};
+ config.name = "compattestsrv";
+ config.iftype = iftype;
+ config.bitrate = 125000;
+
+ // using random-ish addresses, which may not be valid - we can't test the success case
+ if (iddisc == IdDisc::address) {
+ config.interfaceId.address("can0");
+ } else if (iddisc == IdDisc::index) {
+ config.interfaceId.index(0);
+ } else if (iddisc == IdDisc::serialno) {
+ config.interfaceId.serialno({"dummy", "dummier"});
+ }
+
+ const auto upresult = mCanController->upInterface(config);
+
+ if (!isSupported(iftype)) {
+ ASSERT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
+ continue;
+ }
+ ASSERT_NE(ICanController::Result::NOT_SUPPORTED, upresult);
+
+ bool isSupportedDisc =
+ std::find(supported.begin(), supported.end(), iddisc) != supported.end();
+ if (!isSupportedDisc) {
+ ASSERT_EQ(ICanController::Result::BAD_ADDRESS, upresult);
+ continue;
+ }
+
+ if (upresult == ICanController::Result::OK) {
+ const auto dnresult = mCanController->downInterface(config.name);
+ ASSERT_TRUE(dnresult);
+ continue;
+ }
+ }
+ }
+}
+
+TEST_F(CanControllerHalTest, FailEmptyName) {
+ const std::string name = "";
+
+ assertRegistered(name, false);
+ if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) {
+ GTEST_SKIP();
+ }
+ assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, FailBadName) {
+ // 33 characters (name can be at most 32 characters long)
+ const std::string name = "ab012345678901234567890123456789c";
+
+ assertRegistered(name, false);
+ if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) {
+ GTEST_SKIP();
+ }
+ assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, FailBadVirtualAddress) {
+ const std::string name = mBusNames[0];
+
+ assertRegistered(name, false);
+ if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_ADDRESS)) GTEST_SKIP();
+ assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, FailBadSocketcanAddress) {
+ const std::string name = mBusNames[0];
+
+ assertRegistered(name, false);
+ if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_ADDRESS)) {
+ GTEST_SKIP();
+ }
+ assertRegistered(name, false);
+}
+
+} // namespace android::hardware::automotive::can::V1_0::vts
+
+/**
+ * Example manual invocation:
+ * adb shell /data/nativetest64/VtsHalCanControllerV1_0TargetTest/VtsHalCanControllerV1_0TargetTest\
+ * --hal_service_instance=android.hardware.automotive.can@1.0::ICanController/socketcan
+ */
+int main(int argc, char** argv) {
+ using android::hardware::automotive::can::V1_0::ICanController;
+ using android::hardware::automotive::can::V1_0::vts::gEnv;
+ using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+ android::base::SetDefaultTag("CanControllerVts");
+ android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+ gEnv = new SimpleHidlEnvironment<ICanController>;
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/automotive/can/1.0/vts/utils/Android.bp b/automotive/can/1.0/vts/utils/Android.bp
new file mode 100644
index 0000000..d03ead3
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/Android.bp
@@ -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.
+//
+
+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
new file mode 100644
index 0000000..3c30744
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
@@ -0,0 +1,47 @@
+/*
+ * 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/ICanController.h>
+
+namespace android::hardware::automotive::can::V1_0 {
+
+/**
+ * Define gTest printer for a given HIDL type, but skip definition for Return<T>.
+ */
+#define DEFINE_CAN_HAL_PRINTER_SIMPLE(T, converter) \
+ std::ostream& operator<<(std::ostream& os, const T& v) { return os << converter(v); }
+
+/**
+ * Define gTest printer for a given HIDL type.
+ */
+#define DEFINE_CAN_HAL_PRINTER(T, converter) \
+ DEFINE_CAN_HAL_PRINTER_SIMPLE(T, converter) \
+ std::ostream& operator<<(std::ostream& os, const Return<T>& v) { return os << converter(v); }
+
+DEFINE_CAN_HAL_PRINTER(CanMessage, toString)
+DEFINE_CAN_HAL_PRINTER(ErrorEvent, toString)
+DEFINE_CAN_HAL_PRINTER_SIMPLE(
+ ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator, int)
+DEFINE_CAN_HAL_PRINTER(ICanController::InterfaceType, toString)
+DEFINE_CAN_HAL_PRINTER(ICanController::Result, toString)
+DEFINE_CAN_HAL_PRINTER(Result, toString)
+
+#undef DEFINE_CAN_HAL_PRINTER
+#undef DEFINE_CAN_HAL_PRINTER_SIMPLE
+
+} // 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
new file mode 100644
index 0000000..3eb9cc1
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+namespace android::hardware::automotive::can::V1_0::vts::utils {
+
+/**
+ * Simple test environment.
+ *
+ * This is a helper class to instantiate a test environment without boilerplate code for cases where
+ * there is no need to pass more parameters than just HIDL service instance name.
+ *
+ * The class implements registerTestServices() by calling registerTestService() on every HIDL
+ * interface provided as parameter to this template.
+ *
+ * Example usage:
+ * static utils::SimpleHidlEnvironment<IMyService>* gEnv = nullptr;
+ *
+ * void CanBusHalTest::SetUp() {
+ * const auto serviceName = gEnv->getServiceName<IMyService>();
+ * (...)
+ * }
+ *
+ * int main(int argc, char** argv) {
+ * gEnv = new SimpleHidlEnvironment<IMyService>;
+ * ::testing::AddGlobalTestEnvironment(gEnv);
+ * ::testing::InitGoogleTest(&argc, argv);
+ * gEnv->init(&argc, argv);
+ * return RUN_ALL_TESTS();
+ * }
+ *
+ * \param T... HIDL interface names to register for a test service
+ */
+template <typename... T>
+class SimpleHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ virtual void registerTestServices() override {
+ // Call registerTestService() for every HIDL interface using this template.
+ using expander = int[];
+ (void)expander{0, (registerTestService<T>(), 0)...};
+ }
+};
+
+} // namespace android::hardware::automotive::can::V1_0::vts::utils
diff --git a/automotive/evs/1.0/IEvsCamera.hal b/automotive/evs/1.0/IEvsCamera.hal
index dbcaf92..464dafb 100644
--- a/automotive/evs/1.0/IEvsCamera.hal
+++ b/automotive/evs/1.0/IEvsCamera.hal
@@ -16,7 +16,6 @@
package android.hardware.automotive.evs@1.0;
-import types;
import IEvsCameraStream;
@@ -28,8 +27,8 @@
/**
* Returns the ID of this camera.
*
- * Returns the description of this camera. This must be the same value as reported
- * by EvsEnumerator::getCamerList().
+ * @return info The description of this camera. This must be the same value as
+ * reported by EvsEnumerator::getCameraList().
*/
getCameraInfo() generates (CameraDesc info);
@@ -43,16 +42,20 @@
* in which case buffers should be added or removed from the chain as appropriate.
* If no call is made to this entry point, the IEvsCamera must support at least one
* frame by default. More is acceptable.
- * BUFFER_NOT_AVAILABLE is returned if the implementation cannot support the
- * requested number of concurrent frames.
+ *
+ * @param bufferCount Number of buffers the client of IEvsCamera may hold concurrently.
+ * @return result EvsResult::OK is returned if this call is successful.
*/
setMaxFramesInFlight(uint32_t bufferCount) generates (EvsResult result);
/**
- * Request delivery of EVS camera frames from this camera.
+ * Request to start EVS camera stream from this camera.
*
- * The IEvsCameraStream must begin receiving periodic calls with new image
- * frames until stopVideoStream() is called.
+ * The IEvsCameraStream must begin receiving calls with various events
+ * including new image frame ready until stopVideoStream() is called.
+ *
+ * @param receiver IEvsCameraStream implementation.
+ * @return result EvsResult::OK is returned if this call is successful.
*/
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
@@ -64,6 +67,8 @@
* A small, finite number of buffers are available (possibly as small
* as one), and if the supply is exhausted, no further frames may be
* delivered until a buffer is returned.
+ *
+ * @param buffer A buffer to be returned.
*/
oneway doneWithFrame(BufferDesc buffer);
@@ -83,6 +88,11 @@
* The values allowed for opaqueIdentifier are driver specific,
* but no value passed in may crash the driver. The driver should
* return 0 for any unrecognized opaqueIdentifier.
+ *
+ * @param opaqueIdentifier An unique identifier of the information to
+ * request.
+ * @return value Requested information. Zero is returned if the
+ * driver does not recognize a given identifier.
*/
getExtendedInfo(uint32_t opaqueIdentifier) generates (int32_t value);
@@ -94,6 +104,11 @@
* in order to function in a default state.
* INVALID_ARG is returned if the opaqueValue is not meaningful to
* the driver implementation.
+ *
+ * @param opaqueIdentifier An unique identifier of the information to
+ * program.
+ * opaqueValue A value to program.
+ * @return result EvsResult::OK is returned if this call is successful.
*/
setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) generates (EvsResult result);
};
diff --git a/automotive/evs/1.0/IEvsCameraStream.hal b/automotive/evs/1.0/IEvsCameraStream.hal
index 4e743b2..ec18f6a 100644
--- a/automotive/evs/1.0/IEvsCameraStream.hal
+++ b/automotive/evs/1.0/IEvsCameraStream.hal
@@ -31,6 +31,8 @@
* When the last frame in the stream has been delivered, a NULL bufferHandle
* must be delivered, signifying the end of the stream. No further frame
* deliveries may happen thereafter.
+ *
+ * @param buffer a buffer descriptor of a delivered image frame.
*/
oneway deliverFrame(BufferDesc buffer);
};
diff --git a/automotive/evs/1.0/IEvsDisplay.hal b/automotive/evs/1.0/IEvsDisplay.hal
index 12541f3..72f767e 100644
--- a/automotive/evs/1.0/IEvsDisplay.hal
+++ b/automotive/evs/1.0/IEvsDisplay.hal
@@ -16,8 +16,6 @@
package android.hardware.automotive.evs@1.0;
-import types;
-
/**
* Represents a single camera and is the primary interface for capturing images.
@@ -28,6 +26,9 @@
* Returns basic information about the EVS display provided by the system.
*
* See the description of the DisplayDesc structure for details.
+ *
+ * @return info The description of this display. Please see the description
+ * of the DisplayDesc structure for details.
*/
getDisplayInfo() generates (DisplayDesc info);
@@ -42,6 +43,9 @@
* video. When the display is no longer required, the client is expected to request
* the NOT_VISIBLE state after passing the last video frame.
* Returns INVALID_ARG if the requested state is not a recognized value.
+ *
+ * @param state Desired new DisplayState.
+ * @return result EvsResult::OK is returned if this call is successful.
*/
setDisplayState(DisplayState state) generates (EvsResult result);
@@ -54,6 +58,8 @@
* the logic responsible for changing display states should generally live above
* the device layer, making it undesirable for the HAL implementation to spontaneously
* change display states.
+ *
+ * @return state Current DisplayState of this Display.
*/
getDisplayState() generates (DisplayState state);
@@ -61,9 +67,11 @@
/**
* This call returns a handle to a frame buffer associated with the display.
*
- * The returned buffer may be locked and written to by software and/or GL. This buffer
- * must be returned via a call to returnTargetBufferForDisplay() even if the
- * display is no longer visible.
+ * @return buffer A handle to a frame buffer. The returned buffer may be
+ * locked and written to by software and/or GL. This buffer
+ * must be returned via a call to
+ * returnTargetBufferForDisplay() even if the display is no
+ * longer visible.
*/
getTargetBuffer() generates (BufferDesc buffer);
@@ -75,6 +83,9 @@
* There is no maximum time the caller may hold onto the buffer before making this
* call. The buffer may be returned at any time and in any DisplayState, but all
* buffers are expected to be returned before the IEvsDisplay interface is destroyed.
+ *
+ * @param buffer A buffer handle to the frame that is ready for display.
+ * @return result EvsResult::OK is returned if this call is successful.
*/
returnTargetBufferForDisplay(BufferDesc buffer) generates (EvsResult result);
};
diff --git a/automotive/evs/1.0/IEvsEnumerator.hal b/automotive/evs/1.0/IEvsEnumerator.hal
index ee51e7e..e5633df 100644
--- a/automotive/evs/1.0/IEvsEnumerator.hal
+++ b/automotive/evs/1.0/IEvsEnumerator.hal
@@ -16,7 +16,6 @@
package android.hardware.automotive.evs@1.0;
-import types;
import IEvsCamera;
import IEvsDisplay;
@@ -28,6 +27,8 @@
/**
* Returns a list of all EVS cameras available to the system
+ *
+ * @return cameras A list of cameras availale for EVS service.
*/
getCameraList() generates (vec<CameraDesc> cameras);
@@ -37,9 +38,9 @@
* Given a camera's unique cameraId from CameraDesc, returns the
* IEvsCamera interface associated with the specified camera. When
* done using the camera, the caller may release it by calling closeCamera().
- * Note: Reliance on the sp<> going out of scope is not recommended
- * because the resources may not be released right away due to asynchronos
- * behavior in the hardware binder (ref b/36122635).
+ *
+ * @param cameraId A unique identifier of the camera.
+ * @return carCamera EvsCamera object associated with a given cameraId.
*/
openCamera(string cameraId) generates (IEvsCamera carCamera);
@@ -48,6 +49,8 @@
*
* When the IEvsCamera object is no longer required, it must be released.
* NOTE: Video streaming must be cleanly stopped before making this call.
+ *
+ * @param carCamera EvsCamera object to be closed.
*/
closeCamera(IEvsCamera carCamera);
@@ -60,8 +63,8 @@
* the old instance shall be closed and give the new caller exclusive
* access.
* When done using the display, the caller may release it by calling closeDisplay().
- * TODO(b/36122635) Reliance on the sp<> going out of scope is not recommended because the
- * resources may not be released right away due to asynchronos behavior in the hardware binder.
+ *
+ * @return display EvsDisplay object to be used.
*/
openDisplay() generates (IEvsDisplay display);
@@ -70,6 +73,8 @@
*
* When the IEvsDisplay object is no longer required, it must be released.
* NOTE: All buffers must have been returned to the display before making this call.
+ *
+ * @param display EvsDisplay object to be closed.
*/
closeDisplay(IEvsDisplay display);
@@ -80,6 +85,8 @@
* the actual state of the active display. This call is replicated on the IEvsEnumerator
* interface in order to allow secondary clients to monitor the state of the EVS display
* without acquiring exclusive ownership of the display.
+ *
+ * @return state Current DisplayState of this Display.
*/
getDisplayState() generates (DisplayState state);
};
diff --git a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
index 117c249..8dcd969 100644
--- a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
+++ b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
@@ -2,3 +2,4 @@
class hal
user automotive_evs
group automotive_evs
+ disabled # do not start automatically
diff --git a/automotive/evs/1.0/types.hal b/automotive/evs/1.0/types.hal
index 7cebf6d..1efd5eb 100644
--- a/automotive/evs/1.0/types.hal
+++ b/automotive/evs/1.0/types.hal
@@ -24,8 +24,15 @@
* EVS camera in the system.
*/
struct CameraDesc {
+ /* Unique identifier for camera devices. This may be a path to detected
+ * camera device; for example, "/dev/video0".
+ */
string cameraId;
- uint32_t vendorFlags; // Opaque value from driver
+
+ /* Opaque value from driver. Vendor may use this field to store additional
+ * information; for example, sensor and bridge chip id.
+ */
+ uint32_t vendorFlags;
};
@@ -38,8 +45,11 @@
* presentation device.
*/
struct DisplayDesc {
+ /* Unique identifier for the display */
string displayId;
- uint32_t vendorFlags; // Opaque value from driver
+
+ /* Opaque value from driver */
+ uint32_t vendorFlags;
};
@@ -56,14 +66,31 @@
* Specifically consider if format and/or usage should become enumerated types.
*/
struct BufferDesc {
- uint32_t width; // Units of pixels
- uint32_t height; // Units of pixels
- uint32_t stride; // Units of pixels to match gralloc
- uint32_t pixelSize; // Units of bytes
- uint32_t format; // May contain values from android_pixel_format_t
- uint32_t usage; // May contain values from from Gralloc.h
- uint32_t bufferId; // Opaque value from driver
- handle memHandle; // gralloc memory buffer handle
+ /* A frame width in the units of pixels */
+ uint32_t width;
+
+ /* A frame height in the units of pixels */
+ uint32_t height;
+
+ /* A frame stride in the units of pixels, to match gralloc */
+ uint32_t stride;
+
+ /* The size of a pixel in the units of bytes */
+ uint32_t pixelSize;
+
+ /* The image format of the frame; may contain values from
+ * android_pixel_format_t
+ */
+ uint32_t format;
+
+ /* May contain values from Gralloc.h */
+ uint32_t usage;
+
+ /* Opaque value from driver */
+ uint32_t bufferId;
+
+ /* Gralloc memory buffer handle */
+ handle memHandle;
};
@@ -77,12 +104,23 @@
* presentation device.
*/
enum DisplayState : uint32_t {
- NOT_OPEN = 0, // Display has not been requested by any application
- NOT_VISIBLE, // Display is inhibited
- VISIBLE_ON_NEXT_FRAME, // Will become visible with next frame
- VISIBLE, // Display is currently active
- DEAD, // Driver is in an undefined state. Interface should be closed.
- NUM_STATES // Must be last
+ /* Display has not been requested by any application yet */
+ NOT_OPEN = 0,
+
+ /* Display is inhibited */
+ NOT_VISIBLE,
+
+ /* Will become visible with next frame */
+ VISIBLE_ON_NEXT_FRAME,
+
+ /* Display is currently active */
+ VISIBLE,
+
+ /* Driver is in an undefined state. Interface should be closed. */
+ DEAD,
+
+ /* Must be the last */
+ NUM_STATES
};
diff --git a/automotive/evs/1.0/vts/functional/Android.bp b/automotive/evs/1.0/vts/functional/Android.bp
index 2ef33fd..8988bfd 100644
--- a/automotive/evs/1.0/vts/functional/Android.bp
+++ b/automotive/evs/1.0/vts/functional/Android.bp
@@ -19,13 +19,15 @@
srcs: [
"VtsHalEvsV1_0TargetTest.cpp",
"FrameHandler.cpp",
- "FormatConvert.cpp"
],
defaults: ["VtsHalTargetTestDefaults"],
shared_libs: [
"libui",
],
- static_libs: ["android.hardware.automotive.evs@1.0"],
+ static_libs: [
+ "android.hardware.automotive.evs@1.0",
+ "android.hardware.automotive.evs@common-default-lib",
+ ],
test_suites: ["general-tests"],
cflags: [
"-O0",
diff --git a/automotive/evs/1.0/vts/functional/FormatConvert.cpp b/automotive/evs/1.0/vts/functional/FormatConvert.cpp
deleted file mode 100644
index 3d82d32..0000000
--- a/automotive/evs/1.0/vts/functional/FormatConvert.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "VtsHalEvsTest"
-
-#include "FormatConvert.h"
-
-
-// Round up to the nearest multiple of the given alignment value
-template<unsigned alignment>
-int align(int value) {
- static_assert((alignment && !(alignment & (alignment - 1))),
- "alignment must be a power of 2");
-
- unsigned mask = alignment - 1;
- return (value + mask) & ~mask;
-}
-
-
-// Limit the given value to the provided range. :)
-static inline float clamp(float v, float min, float max) {
- if (v < min) return min;
- if (v > max) return max;
- return v;
-}
-
-
-static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin,
- bool bgrxFormat = false) {
- // Don't use this if you want to see the best performance. :)
- // Better to do this in a pixel shader if we really have to, but on actual
- // embedded hardware we expect to be able to texture directly from the YUV data
- float U = Uin - 128.0f;
- float V = Vin - 128.0f;
-
- float Rf = Y + 1.140f*V;
- float Gf = Y - 0.395f*U - 0.581f*V;
- float Bf = Y + 2.032f*U;
- unsigned char R = (unsigned char)clamp(Rf, 0.0f, 255.0f);
- unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f);
- unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f);
-
- if (!bgrxFormat) {
- return (R ) |
- (G << 8) |
- (B << 16) |
- 0xFF000000; // Fill the alpha channel with ones
- } else {
- return (R << 16) |
- (G << 8) |
- (B ) |
- 0xFF000000; // Fill the alpha channel with ones
- }
-}
-
-
-void copyNV21toRGB32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels,
- bool bgrxFormat)
-{
- // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
- // U/V array. It assumes an even width and height for the overall image, and a horizontal
- // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
- unsigned strideLum = align<16>(width);
- unsigned sizeY = strideLum * height;
- unsigned strideColor = strideLum; // 1/2 the samples, but two interleaved channels
- unsigned offsetUV = sizeY;
-
- uint8_t* srcY = src;
- uint8_t* srcUV = src+offsetUV;
-
- for (unsigned r = 0; r < height; r++) {
- // Note that we're walking the same UV row twice for even/odd luminance rows
- uint8_t* rowY = srcY + r*strideLum;
- uint8_t* rowUV = srcUV + (r/2 * strideColor);
-
- uint32_t* rowDest = dst + r*dstStridePixels;
-
- for (unsigned c = 0; c < width; c++) {
- unsigned uCol = (c & ~1); // uCol is always even and repeats 1:2 with Y values
- unsigned vCol = uCol | 1; // vCol is always odd
- rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol], bgrxFormat);
- }
- }
-}
-
-
-void copyYV12toRGB32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels,
- bool bgrxFormat)
-{
- // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
- // by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image,
- // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
- // and V arrays.
- unsigned strideLum = align<16>(width);
- unsigned sizeY = strideLum * height;
- unsigned strideColor = align<16>(strideLum/2);
- unsigned sizeColor = strideColor * height/2;
- unsigned offsetU = sizeY;
- unsigned offsetV = sizeY + sizeColor;
-
- uint8_t* srcY = src;
- uint8_t* srcU = src+offsetU;
- uint8_t* srcV = src+offsetV;
-
- for (unsigned r = 0; r < height; r++) {
- // Note that we're walking the same U and V rows twice for even/odd luminance rows
- uint8_t* rowY = srcY + r*strideLum;
- uint8_t* rowU = srcU + (r/2 * strideColor);
- uint8_t* rowV = srcV + (r/2 * strideColor);
-
- uint32_t* rowDest = dst + r*dstStridePixels;
-
- for (unsigned c = 0; c < width; c++) {
- rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c], bgrxFormat);
- }
- }
-}
-
-
-void copyYUYVtoRGB32(unsigned width, unsigned height,
- uint8_t* src, unsigned srcStridePixels,
- uint32_t* dst, unsigned dstStridePixels,
- bool bgrxFormat)
-{
- uint32_t* srcWords = (uint32_t*)src;
-
- const int srcRowPadding32 = srcStridePixels/2 - width/2; // 2 bytes per pixel, 4 bytes per word
- const int dstRowPadding32 = dstStridePixels - width; // 4 bytes per pixel, 4 bytes per word
-
- for (unsigned r = 0; r < height; r++) {
- for (unsigned c = 0; c < width/2; c++) {
- // Note: we're walking two pixels at a time here (even/odd)
- uint32_t srcPixel = *srcWords++;
-
- uint8_t Y1 = (srcPixel) & 0xFF;
- uint8_t U = (srcPixel >> 8) & 0xFF;
- uint8_t Y2 = (srcPixel >> 16) & 0xFF;
- uint8_t V = (srcPixel >> 24) & 0xFF;
-
- // On the RGB output, we're writing one pixel at a time
- *(dst+0) = yuvToRgbx(Y1, U, V, bgrxFormat);
- *(dst+1) = yuvToRgbx(Y2, U, V, bgrxFormat);
- dst += 2;
- }
-
- // Skip over any extra data or end of row alignment padding
- srcWords += srcRowPadding32;
- dst += dstRowPadding32;
- }
-}
-
-
-void copyNV21toBGR32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels)
-{
- return copyNV21toRGB32(width, height, src, dst, dstStridePixels, true);
-}
-
-
-void copyYV12toBGR32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels)
-{
- return copyYV12toRGB32(width, height, src, dst, dstStridePixels, true);
-}
-
-
-void copyYUYVtoBGR32(unsigned width, unsigned height,
- uint8_t* src, unsigned srcStridePixels,
- uint32_t* dst, unsigned dstStridePixels)
-{
- return copyYUYVtoRGB32(width, height, src, srcStridePixels, dst, dstStridePixels, true);
-}
-
-
-void copyMatchedInterleavedFormats(unsigned width, unsigned height,
- void* src, unsigned srcStridePixels,
- void* dst, unsigned dstStridePixels,
- unsigned pixelSize) {
- for (unsigned row = 0; row < height; row++) {
- // Copy the entire row of pixel data
- memcpy(dst, src, width * pixelSize);
-
- // Advance to the next row (keeping in mind that stride here is in units of pixels)
- src = (uint8_t*)src + srcStridePixels * pixelSize;
- dst = (uint8_t*)dst + dstStridePixels * pixelSize;
- }
-}
diff --git a/automotive/evs/1.0/vts/functional/FormatConvert.h b/automotive/evs/1.0/vts/functional/FormatConvert.h
deleted file mode 100644
index 4a94f99..0000000
--- a/automotive/evs/1.0/vts/functional/FormatConvert.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef EVS_VTS_FORMATCONVERT_H
-#define EVS_VTS_FORMATCONVERT_H
-
-#include <queue>
-#include <stdint.h>
-
-
-// Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx/BGRx
-// values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
-// U/V array. It assumes an even width and height for the overall image, and a horizontal
-// stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-void copyNV21toRGB32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels,
- bool bgrxFormat = false);
-
-void copyNV21toBGR32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels);
-
-
-// Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx/BGRx values.
-// The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
-// by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image,
-// and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
-// and V arrays.
-void copyYV12toRGB32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels,
- bool bgrxFormat = false);
-
-void copyYV12toBGR32(unsigned width, unsigned height,
- uint8_t* src,
- uint32_t* dst, unsigned dstStridePixels);
-
-// Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx/BGRx
-// values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
-// U/V array. It assumes an even width and height for the overall image, and a horizontal
-// stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-void copyYUYVtoRGB32(unsigned width, unsigned height,
- uint8_t* src, unsigned srcStrideBytes,
- uint32_t* dst, unsigned dstStrideBytes,
- bool bgrxFormat = false);
-
-void copyYUYVtoBGR32(unsigned width, unsigned height,
- uint8_t* src, unsigned srcStrideBytes,
- uint32_t* dst, unsigned dstStrideBytes);
-
-
-// Given an simple rectangular image buffer with an integer number of bytes per pixel,
-// copy the pixel values into a new rectangular buffer (potentially with a different stride).
-// This is typically used to copy RGBx data into an RGBx output buffer.
-void copyMatchedInterleavedFormats(unsigned width, unsigned height,
- void* src, unsigned srcStridePixels,
- void* dst, unsigned dstStridePixels,
- unsigned pixelSize);
-
-#endif // EVS_VTS_FORMATCONVERT_H
diff --git a/automotive/evs/1.0/vts/functional/FrameHandler.cpp b/automotive/evs/1.0/vts/functional/FrameHandler.cpp
index bc3790f..6a01a44 100644
--- a/automotive/evs/1.0/vts/functional/FrameHandler.cpp
+++ b/automotive/evs/1.0/vts/functional/FrameHandler.cpp
@@ -240,46 +240,47 @@
tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
if (srcPixels && tgtPixels) {
+ using namespace ::android::hardware::automotive::evs::common;
if (tgtBuffer.format == HAL_PIXEL_FORMAT_RGBA_8888) {
if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21
- copyNV21toRGB32(width, height,
- srcPixels,
- tgtPixels, tgtBuffer.stride);
+ Utils::copyNV21toRGB32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
} else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
- copyYV12toRGB32(width, height,
- srcPixels,
- tgtPixels, tgtBuffer.stride);
+ Utils::copyYV12toRGB32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
} else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
- copyYUYVtoRGB32(width, height,
- srcPixels, srcBuffer.stride,
- tgtPixels, tgtBuffer.stride);
+ Utils::copyYUYVtoRGB32(width, height,
+ srcPixels, srcBuffer.stride,
+ tgtPixels, tgtBuffer.stride);
} else if (srcBuffer.format == tgtBuffer.format) { // 32bit RGBA
- copyMatchedInterleavedFormats(width, height,
- srcPixels, srcBuffer.stride,
- tgtPixels, tgtBuffer.stride,
- tgtBuffer.pixelSize);
+ Utils::copyMatchedInterleavedFormats(width, height,
+ srcPixels, srcBuffer.stride,
+ tgtPixels, tgtBuffer.stride,
+ tgtBuffer.pixelSize);
} else {
ALOGE("Camera buffer format is not supported");
success = false;
}
} else if (tgtBuffer.format == HAL_PIXEL_FORMAT_BGRA_8888) {
if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21
- copyNV21toBGR32(width, height,
- srcPixels,
- tgtPixels, tgtBuffer.stride);
+ Utils::copyNV21toBGR32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
} else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
- copyYV12toBGR32(width, height,
- srcPixels,
- tgtPixels, tgtBuffer.stride);
+ Utils::copyYV12toBGR32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
} else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
- copyYUYVtoBGR32(width, height,
- srcPixels, srcBuffer.stride,
- tgtPixels, tgtBuffer.stride);
+ Utils::copyYUYVtoBGR32(width, height,
+ srcPixels, srcBuffer.stride,
+ tgtPixels, tgtBuffer.stride);
} else if (srcBuffer.format == tgtBuffer.format) { // 32bit RGBA
- copyMatchedInterleavedFormats(width, height,
- srcPixels, srcBuffer.stride,
- tgtPixels, tgtBuffer.stride,
- tgtBuffer.pixelSize);
+ Utils::copyMatchedInterleavedFormats(width, height,
+ srcPixels, srcBuffer.stride,
+ tgtPixels, tgtBuffer.stride,
+ tgtBuffer.pixelSize);
} else {
ALOGE("Camera buffer format is not supported");
success = false;
diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp
new file mode 100644
index 0000000..c850c91
--- /dev/null
+++ b/automotive/evs/1.1/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.automotive.evs@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IEvsCamera.hal",
+ "IEvsCameraStream.hal",
+ "IEvsEnumerator.hal",
+ ],
+ interfaces: [
+ "android.hardware.automotive.evs@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal
new file mode 100644
index 0000000..fc68e60
--- /dev/null
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.evs@1.1;
+
+import @1.0::IEvsCamera;
+import @1.0::IEvsDisplay;
+import @1.0::EvsResult;
+import IEvsCameraStream;
+
+/**
+ * Represents a single camera and is the primary interface for capturing images.
+ */
+interface IEvsCamera extends @1.0::IEvsCamera {
+ /**
+ * Returns the description of this camera.
+ *
+ * @return info The description of this camera. This must be the same value as
+ * reported by EvsEnumerator::getCameraList_1_1().
+ */
+ 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
+ * after this call returns. Delivered frame buffers must be returned.
+ *
+ * @return result EvsResult::OK is returned if this call is successful.
+ */
+ pauseVideoStream() generates (EvsResult result);
+
+ /**
+ * Requests to resume EVS camera stream.
+ *
+ * @return result EvsResult::OK is returned if this call is successful.
+ */
+ resumeVideoStream() generates (EvsResult result);
+
+ /**
+ * Returns 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.
+ * A small, finite number of buffers are available (possibly as small
+ * as one), and if the supply is exhausted, no further frames may be
+ * delivered until a buffer is returned.
+ *
+ * @param buffer Buffers to be returned.
+ * @return result Return EvsResult::OK if this call is successful.
+ */
+ doneWithFrame_1_1(vec<BufferDesc> buffer) generates (EvsResult result);
+
+ /**
+ * Requests to be a master client.
+ *
+ * When multiple clients subscribe to a single camera hardware and one of
+ * them adjusts a camera parameter such as the contrast, it may disturb
+ * other clients' operations. Therefore, the client must call this method
+ * to be a master client. Once it becomes a master, it will be able to
+ * change camera parameters until either it dies or explicitly gives up the
+ * role.
+ *
+ * @return result EvsResult::OK if a master role is granted.
+ * EvsResult::OWNERSHIP_LOST if there is already a
+ * master client.
+ */
+ setMaster() generates (EvsResult result);
+
+ /**
+ * Sets to be a master client forcibly.
+ *
+ * The client, which owns the display, has a high priority and can take over
+ * a master role from other clients without the display.
+ *
+ * @param display IEvsDisplay handle. If a given display is in either
+ * NOT_VISIBLE, VISIBLE_ON_NEXT_FRAME, or VISIBLE state, the
+ * calling client is considered as the high priority client
+ * and therefore allowed to take over a master role from
+ * existing master client.
+ *
+ * @return result EvsResult::OK if a master role is granted.
+ * EvsResult::INVALID_ARG if a given display handle is null
+ * or in valid states.
+ */
+ forceMaster(IEvsDisplay display) generates (EvsResult result);
+
+ /**
+ * Retires from a master client role.
+ *
+ * @return result EvsResult::OK if this call is successful.
+ * EvsResult::INVALID_ARG if the caller client is not a
+ * master client.
+ */
+ unsetMaster() generates (EvsResult result);
+
+ /**
+ * Retrieves a list of parameters this camera supports.
+ *
+ * @return params A list of CameraParam that this camera supports.
+ */
+ getParameterList() generates (vec<CameraParam> params);
+
+ /**
+ * Requests a valid value range of a camera parameter
+ *
+ * @param id The identifier of camera parameter, CameraParam enum.
+ *
+ * @return min The lower bound of valid parameter value range.
+ * @return max The upper bound of valid parameter value range.
+ * @return step The resolution of values in valid range.
+ */
+ getIntParameterRange(CameraParam id)
+ 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.
+ * 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.
+ * @return result EvsResult::OK if it succeeds to set a parameter.
+ * EvsResult::INVALID_ARG if either the request is
+ * not made by a master client, or a requested
+ * parameter is not supported.
+ * EvsResult::UNDERLYING_SERVICE_ERROR if it fails to
+ * program a value by any other reason.
+ * 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, vec<int32_t> effectiveValue);
+
+ /**
+ * 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 Values of requested camera parameter, the same number of
+ * values as backing camera devices.
+ */
+ 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
new file mode 100644
index 0000000..aa35c62
--- /dev/null
+++ b/automotive/evs/1.1/IEvsCameraStream.hal
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.evs@1.1;
+
+import @1.0::IEvsCameraStream;
+import @1.1::BufferDesc;
+import @1.1::EvsEventDesc;
+
+/**
+ * Implemented on client side to receive asynchronous streaming event deliveries.
+ */
+interface IEvsCameraStream extends @1.0::IEvsCameraStream {
+
+ /**
+ * 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
+ * some time as the pipeline drains. Each frame must still be returned.
+ * When the last frame in the stream has been delivered, STREAM_STOPPED
+ * event must be delivered. No further frame deliveries may happen
+ * thereafter.
+ *
+ * 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(vec<BufferDesc> buffer);
+
+ /**
+ * Receives calls from the HAL each time an event happens.
+ *
+ * @param event EVS event with possible event information.
+ */
+ oneway notify(EvsEventDesc event);
+};
diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal
new file mode 100644
index 0000000..1695821
--- /dev/null
+++ b/automotive/evs/1.1/IEvsEnumerator.hal
@@ -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.
+ */
+
+package android.hardware.automotive.evs@1.1;
+
+import IEvsCamera;
+import @1.0::IEvsEnumerator;
+import @1.0::EvsResult;
+import android.hardware.camera.device@3.2::Stream;
+
+/**
+ * Provides the mechanism for EVS camera discovery
+ */
+interface IEvsEnumerator extends @1.0::IEvsEnumerator {
+ /**
+ * Returns a list of all EVS cameras available to the system
+ *
+ * @return cameras A list of cameras availale for EVS service.
+ */
+ getCameraList_1_1() generates (vec<CameraDesc> cameras);
+
+ /**
+ * Gets the IEvsCamera associated with a cameraId from a CameraDesc
+ *
+ * Given a camera's unique cameraId from CameraDesc, returns the
+ * IEvsCamera interface associated with the specified camera. When
+ * done using the camera, the caller may release it by calling closeCamera().
+ *
+ * @param cameraId A unique identifier of the camera.
+ * @param streamCfg A stream configuration the client wants to use.
+ * @return evsCamera EvsCamera object associated with a given cameraId.
+ * Returned object would be null if a camera device does
+ * not support a given stream configuration or is already
+ * configured differently by another client.
+ */
+ openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera);
+};
diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp
new file mode 100644
index 0000000..88fd657
--- /dev/null
+++ b/automotive/evs/1.1/default/Android.bp
@@ -0,0 +1,47 @@
+cc_binary {
+ name: "android.hardware.automotive.evs@1.1-service",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: [
+ "service.cpp",
+ "EvsCamera.cpp",
+ "EvsEnumerator.cpp",
+ "EvsDisplay.cpp",
+ "ConfigManager.cpp",
+ "ConfigManagerUtil.cpp",
+ ],
+ init_rc: ["android.hardware.automotive.evs@1.1-service.rc"],
+
+ shared_libs: [
+ "android.hardware.automotive.evs@1.0",
+ "android.hardware.automotive.evs@1.1",
+ "android.hardware.camera.device@3.3",
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libui",
+ "libutils",
+ "libcamera_metadata",
+ "libtinyxml2",
+ ],
+
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+
+ required: [
+ "evs_default_configuration.xml",
+ ],
+}
+
+prebuilt_etc {
+ name: "evs_default_configuration.xml",
+
+ src: "resources/evs_default_configuration.xml",
+ sub_dir: "automotive/evs",
+}
diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp
new file mode 100644
index 0000000..986793e
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.cpp
@@ -0,0 +1,512 @@
+/*
+ * 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 <sstream>
+#include <fstream>
+#include <thread>
+
+#include <hardware/gralloc.h>
+#include <utils/SystemClock.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+
+#include "ConfigManager.h"
+
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+
+
+ConfigManager::~ConfigManager() {
+ /* Nothing to do */
+}
+
+
+void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) {
+ if (aCameraElem == nullptr) {
+ ALOGW("XML file does not have required camera element");
+ return;
+ }
+
+ const XMLElement *curElem = aCameraElem->FirstChildElement();
+ while (curElem != nullptr) {
+ if (!strcmp(curElem->Name(), "group")) {
+ /* camera group identifier */
+ const char *id = curElem->FindAttribute("id")->Value();
+
+ /* create a camera group to be filled */
+ CameraGroupInfo *aCamera = new CameraGroupInfo();
+
+ /* 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();
+ 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 */
+ 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();
+
+ /* 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.insert_or_assign(id, unique_ptr<CameraInfo>(aCamera));
+
+ /* assign a camera device to a position group */
+ mCameraPosition[pos].emplace(id);
+ } else {
+ /* ignore other device types */
+ ALOGD("Unknown element %s is ignored", curElem->Name());
+ }
+
+ curElem = curElem->NextSiblingElement();
+ }
+}
+
+
+bool
+ConfigManager::readCameraDeviceInfo(CameraInfo *aCamera,
+ const XMLElement *aDeviceElem) {
+ if (aCamera == nullptr || aDeviceElem == nullptr) {
+ return false;
+ }
+
+ /* size information to allocate camera_metadata_t */
+ size_t totalEntries = 0;
+ size_t totalDataSize = 0;
+
+ /* read device capabilities */
+ totalEntries +=
+ readCameraCapabilities(aDeviceElem->FirstChildElement("caps"),
+ aCamera,
+ totalDataSize);
+
+
+ /* read camera metadata */
+ totalEntries +=
+ readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"),
+ aCamera,
+ totalDataSize);
+
+ /* construct camera_metadata_t */
+ if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) {
+ ALOGW("Either failed to allocate memory or "
+ "allocated memory was not large enough");
+ }
+
+ return true;
+}
+
+
+size_t
+ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
+ CameraInfo *aCamera,
+ size_t &dataSize) {
+ if (aCapElem == nullptr || aCamera == nullptr) {
+ return 0;
+ }
+
+ string token;
+ const XMLElement *curElem = nullptr;
+
+ /* a list of supported camera parameters/controls */
+ curElem = aCapElem->FirstChildElement("supported_controls");
+ if (curElem != nullptr) {
+ const XMLElement *ctrlElem = curElem->FirstChildElement("control");
+ while (ctrlElem != nullptr) {
+ const char *nameAttr = ctrlElem->FindAttribute("name")->Value();;
+ const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value());
+ const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value());
+
+ int32_t stepVal = 1;
+ const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step");
+ if (stepAttr != nullptr) {
+ stepVal = stoi(stepAttr->Value());
+ }
+
+ CameraParam aParam;
+ if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr,
+ aParam)) {
+ aCamera->controls.emplace(
+ aParam,
+ make_tuple(minVal, maxVal, stepVal)
+ );
+ }
+
+ ctrlElem = ctrlElem->NextSiblingElement("control");
+ }
+ }
+
+ /* a list of camera stream configurations */
+ curElem = aCapElem->FirstChildElement("stream");
+ while (curElem != nullptr) {
+ /* read 5 attributes */
+ const XMLAttribute *idAttr = curElem->FindAttribute("id");
+ const XMLAttribute *widthAttr = curElem->FindAttribute("width");
+ const XMLAttribute *heightAttr = curElem->FindAttribute("height");
+ const XMLAttribute *fmtAttr = curElem->FindAttribute("format");
+ const XMLAttribute *fpsAttr = curElem->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
+ };
+ aCamera->streamConfigurations.insert_or_assign(id, cfg);
+ }
+
+ curElem = curElem->NextSiblingElement("stream");
+ }
+
+ dataSize = calculate_camera_metadata_entry_data_size(
+ get_camera_metadata_tag_type(
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ ),
+ aCamera->streamConfigurations.size() * kStreamCfgSz
+ );
+
+ /* a single camera metadata entry contains multiple stream configurations */
+ return dataSize > 0 ? 1 : 0;
+}
+
+
+size_t
+ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
+ CameraInfo *aCamera,
+ size_t &dataSize) {
+ if (aParamElem == nullptr || aCamera == nullptr) {
+ return 0;
+ }
+
+ const XMLElement *curElem = aParamElem->FirstChildElement("parameter");
+ size_t numEntries = 0;
+ camera_metadata_tag_t tag;
+ while (curElem != nullptr) {
+ if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(),
+ tag)) {
+ switch(tag) {
+ case ANDROID_LENS_DISTORTION:
+ case ANDROID_LENS_POSE_ROTATION:
+ case ANDROID_LENS_POSE_TRANSLATION:
+ case ANDROID_LENS_INTRINSIC_CALIBRATION: {
+ /* float[] */
+ size_t count = 0;
+ void *data = ConfigManagerUtil::convertFloatArray(
+ curElem->FindAttribute("size")->Value(),
+ curElem->FindAttribute("value")->Value(),
+ count
+ );
+
+ aCamera->cameraMetadata.insert_or_assign(
+ tag, make_pair(make_unique<void *>(data), count)
+ );
+
+ ++numEntries;
+ dataSize += calculate_camera_metadata_entry_data_size(
+ get_camera_metadata_tag_type(tag), count
+ );
+
+ 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());
+ break;
+ }
+ }
+
+ curElem = curElem->NextSiblingElement("parameter");
+ }
+
+ return numEntries;
+}
+
+
+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;
+ }
+
+ const size_t numStreamConfigs = aCamera->streamConfigurations.size();
+ unique_ptr<int32_t[]> data(new int32_t[kStreamCfgSz * numStreamConfigs]);
+ int32_t *ptr = data.get();
+ for (auto &cfg : aCamera->streamConfigurations) {
+ for (auto i = 0; i < kStreamCfgSz; ++i) {
+ *ptr++ = cfg.second[i];
+ }
+ }
+ int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ data.get(),
+ numStreamConfigs * kStreamCfgSz);
+
+ if (err) {
+ ALOGE("Failed to add stream configurations to metadata, ignored");
+ return false;
+ }
+
+ bool success = true;
+ for (auto &[tag, entry] : aCamera->cameraMetadata) {
+ /* try to add new camera metadata entry */
+ int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+ tag,
+ entry.first.get(),
+ entry.second);
+ if (err) {
+ ALOGE("Failed to add an entry with a tag 0x%X", tag);
+
+ /* may exceed preallocated capacity */
+ ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
+ (long)get_camera_metadata_entry_count(aCamera->characteristics),
+ (long)get_camera_metadata_entry_capacity(aCamera->characteristics),
+ (long)get_camera_metadata_data_count(aCamera->characteristics),
+ (long)get_camera_metadata_data_capacity(aCamera->characteristics));
+ ALOGE("\tCurrent metadata entry requires %ld bytes",
+ (long)calculate_camera_metadata_entry_data_size(tag, entry.second));
+
+ success = false;
+ }
+ }
+
+ ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
+ (long)get_camera_metadata_entry_count(aCamera->characteristics),
+ (long)get_camera_metadata_entry_capacity(aCamera->characteristics),
+ (long)get_camera_metadata_data_count(aCamera->characteristics),
+ (long)get_camera_metadata_data_capacity(aCamera->characteristics));
+
+ return success;
+}
+
+
+void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) {
+ if (aSysElem == nullptr) {
+ return;
+ }
+
+ /*
+ * Please note that this function assumes that a given system XML element
+ * and its child elements follow DTD. If it does not, it will cause a
+ * segmentation fault due to the failure of finding expected attributes.
+ */
+
+ /* read number of cameras available in the system */
+ const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras");
+ if (xmlElem != nullptr) {
+ mSystemInfo.numCameras =
+ stoi(xmlElem->FindAttribute("value")->Value());
+ }
+}
+
+
+void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) {
+ if (aDisplayElem == nullptr) {
+ ALOGW("XML file does not have required camera element");
+ return;
+ }
+
+ const XMLElement *curDev = aDisplayElem->FirstChildElement("device");
+ while (curDev != nullptr) {
+ const char *id = curDev->FindAttribute("id")->Value();
+ //const char *pos = curDev->FirstAttribute("position")->Value();
+
+ unique_ptr<DisplayInfo> dpy(new DisplayInfo());
+ if (dpy == nullptr) {
+ ALOGE("Failed to allocate memory for DisplayInfo");
+ return;
+ }
+
+ const XMLElement *cap = curDev->FirstChildElement("caps");
+ if (cap != nullptr) {
+ const XMLElement *curStream = cap->FirstChildElement("stream");
+ while (curStream != nullptr) {
+ /* read 4 attributes */
+ const XMLAttribute *idAttr = curStream->FindAttribute("id");
+ const XMLAttribute *widthAttr = curStream->FindAttribute("width");
+ const XMLAttribute *heightAttr = curStream->FindAttribute("height");
+ const XMLAttribute *fmtAttr = curStream->FindAttribute("format");
+
+ const int32_t id = stoi(idAttr->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_INPUT,
+ 0 // unused
+ };
+ dpy->streamConfigurations.insert_or_assign(id, cfg);
+ }
+
+ curStream = curStream->NextSiblingElement("stream");
+ }
+ }
+
+ mDisplayInfo.insert_or_assign(id, std::move(dpy));
+ curDev = curDev->NextSiblingElement("device");
+ }
+
+ return;
+}
+
+
+bool ConfigManager::readConfigDataFromXML() noexcept {
+ XMLDocument xmlDoc;
+
+ const int64_t parsingStart = android::elapsedRealtimeNano();
+
+ /* load and parse a configuration file */
+ xmlDoc.LoadFile(mConfigFilePath);
+ if (xmlDoc.ErrorID() != XML_SUCCESS) {
+ ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr());
+ return false;
+ }
+
+ /* retrieve the root element */
+ const XMLElement *rootElem = xmlDoc.RootElement();
+ if (strcmp(rootElem->Name(), "configuration")) {
+ ALOGE("A configuration file is not in the required format. "
+ "See /etc/automotive/evs/evs_configuration.dtd");
+ return false;
+ }
+
+ /*
+ * parse camera information; this needs to be done before reading system
+ * information
+ */
+ readCameraInfo(rootElem->FirstChildElement("camera"));
+
+ /* parse system information */
+ readSystemInfo(rootElem->FirstChildElement("system"));
+
+ /* parse display information */
+ readDisplayInfo(rootElem->FirstChildElement("display"));
+
+ const int64_t parsingEnd = android::elapsedRealtimeNano();
+ ALOGI("Parsing configuration file takes %lf (ms)",
+ (double)(parsingEnd - parsingStart) / 1000000.0);
+
+
+ return true;
+}
+
+
+std::unique_ptr<ConfigManager> ConfigManager::Create(const char *path) {
+ unique_ptr<ConfigManager> cfgMgr(new ConfigManager(path));
+
+ /*
+ * Read a configuration from XML file
+ *
+ * If this is too slow, ConfigManager::readConfigDataFromBinary() and
+ * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object
+ * to the filesystem and construct CameraInfo instead; this was
+ * evaluated as 10x faster.
+ */
+ if (!cfgMgr->readConfigDataFromXML()) {
+ return nullptr;
+ } else {
+ return cfgMgr;
+ }
+}
+
diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h
new file mode 100644
index 0000000..870af1c
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -0,0 +1,318 @@
+/*
+ * 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 CONFIG_MANAGER_H
+#define CONFIG_MANAGER_H
+
+#include <vector>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <tinyxml2.h>
+
+#include <system/camera_metadata.h>
+#include <log/log.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+#include "ConfigManagerUtil.h"
+
+using namespace std;
+using namespace tinyxml2;
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+/*
+ * Plese note that this is different from what is defined in
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+const size_t kStreamCfgSz = 6;
+typedef std::array<int32_t, kStreamCfgSz> RawStreamConfiguration;
+
+class ConfigManager {
+public:
+ static std::unique_ptr<ConfigManager> Create(const char *path = "");
+ ConfigManager(const ConfigManager&) = delete;
+ ConfigManager& operator=(const ConfigManager&) = delete;
+
+ virtual ~ConfigManager();
+
+ /* Camera device's capabilities and metadata */
+ class CameraInfo {
+ public:
+ CameraInfo() :
+ characteristics(nullptr) {
+ /* Nothing to do */
+ }
+
+ virtual ~CameraInfo() {
+ free_camera_metadata(characteristics);
+ }
+
+ /* Allocate memory for camera_metadata_t */
+ bool allocate(size_t entry_cap, size_t data_cap) {
+ if (characteristics != nullptr) {
+ ALOGE("Camera metadata is already allocated");
+ return false;
+ }
+
+ characteristics = allocate_camera_metadata(entry_cap, data_cap);
+ return characteristics != nullptr;
+ }
+
+ /*
+ * List of supported controls that the master client can program.
+ * Paraemters are stored with its valid range
+ */
+ unordered_map<CameraParam,
+ tuple<int32_t, int32_t, int32_t>> controls;
+
+ /*
+ * List of supported output stream configurations; each array stores
+ * format, width, height, and direction values in the order.
+ */
+ unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+
+ /*
+ * Internal storage for camera metadata. Each entry holds a pointer to
+ * data and number of elements
+ */
+ unordered_map<camera_metadata_tag_t,
+ pair<unique_ptr<void *>, size_t>> cameraMetadata;
+
+ /* Camera module characteristics */
+ camera_metadata_t *characteristics;
+ };
+
+ class CameraGroupInfo : public CameraInfo {
+ public:
+ CameraGroupInfo() {}
+
+ /* ID of member camera devices */
+ unordered_set<string> devices;
+
+ /* The capture operation of member camera devices are synchronized */
+ bool synchronized = false;
+ };
+
+ class SystemInfo {
+ public:
+ /* number of available cameras */
+ int32_t numCameras = 0;
+ };
+
+ class DisplayInfo {
+ public:
+ /*
+ * List of supported input stream configurations; each array stores
+ * format, width, height, and direction values in the order.
+ */
+ unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+ };
+
+ /*
+ * Return system information
+ *
+ * @return SystemInfo
+ * Constant reference of SystemInfo.
+ */
+ const SystemInfo &getSystemInfo() {
+ return mSystemInfo;
+ }
+
+ /*
+ * Return a list of cameras
+ *
+ * This function assumes that it is not being called frequently.
+ *
+ * @return vector<string>
+ * A vector that contains unique camera device identifiers.
+ */
+ vector<string> getCameraList() {
+ vector<string> aList;
+ for (auto &v : mCameraInfo) {
+ aList.emplace_back(v.first);
+ }
+
+ return aList;
+ }
+
+
+ /*
+ * Return a list of cameras
+ *
+ * @return CameraGroupInfo
+ * A pointer to a camera group identified by a given id.
+ */
+ unique_ptr<CameraGroupInfo>& getCameraGroupInfo(const string& gid) {
+ return mCameraGroupInfos[gid];
+ }
+
+
+ /*
+ * Return a camera metadata
+ *
+ * @param cameraId
+ * Unique camera node identifier in string
+ *
+ * @return unique_ptr<CameraInfo>
+ * A pointer to CameraInfo that is associated with a given camera
+ * ID. This returns a null pointer if this does not recognize a
+ * given camera identifier.
+ */
+ unique_ptr<CameraInfo>& getCameraInfo(const string cameraId) noexcept {
+ return mCameraInfo[cameraId];
+ }
+
+private:
+ /* Constructors */
+ ConfigManager(const char *xmlPath) :
+ mConfigFilePath(xmlPath) {
+ }
+
+ /* System configuration */
+ SystemInfo mSystemInfo;
+
+ /* Internal data structure for camera device information */
+ unordered_map<string, unique_ptr<CameraInfo>> mCameraInfo;
+
+ /* Internal data structure for camera device information */
+ unordered_map<string, unique_ptr<DisplayInfo>> mDisplayInfo;
+
+ /* 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.
+ * The position must be one of front, rear, left, and right.
+ */
+ unordered_map<string, unordered_set<string>> mCameraPosition;
+
+ /* A path to XML configuration file */
+ const char *mConfigFilePath;
+
+ /*
+ * Parse a given EVS configuration file and store the information
+ * internally.
+ *
+ * @return bool
+ * True if it completes parsing a file successfully.
+ */
+ bool readConfigDataFromXML() noexcept;
+
+ /*
+ * read the information of the vehicle
+ *
+ * @param aSysElem
+ * A pointer to "system" XML element.
+ */
+ void readSystemInfo(const XMLElement * const aSysElem);
+
+ /*
+ * read the information of camera devices
+ *
+ * @param aCameraElem
+ * A pointer to "camera" XML element that may contain multiple
+ * "device" elements.
+ */
+ void readCameraInfo(const XMLElement * const aCameraElem);
+
+ /*
+ * read display device information
+ *
+ * @param aDisplayElem
+ * A pointer to "display" XML element that may contain multiple
+ * "device" elements.
+ */
+ void readDisplayInfo(const XMLElement * const aDisplayElem);
+
+ /*
+ * read camera device information
+ *
+ * @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 bool
+ * Return false upon any failure in reading and processing camera
+ * device information.
+ */
+ bool readCameraDeviceInfo(CameraInfo *aCamera,
+ const XMLElement *aDeviceElem);
+
+ /*
+ * read camera metadata
+ *
+ * @param aCapElem
+ * A pointer to "cap" XML element.
+ * @param aCamera
+ * A pointer to CameraInfo that is being filled by this method.
+ * @param dataSize
+ * Required size of memory to store camera metadata found in this
+ * method. This is calculated in this method and returned to the
+ * caller for camera_metadata allocation.
+ *
+ * @return size_t
+ * Number of camera metadata entries
+ */
+ size_t readCameraCapabilities(const XMLElement * const aCapElem,
+ CameraInfo *aCamera,
+ size_t &dataSize);
+
+ /*
+ * read camera metadata
+ *
+ * @param aParamElem
+ * A pointer to "characteristics" XML element.
+ * @param aCamera
+ * A pointer to CameraInfo that is being filled by this method.
+ * @param dataSize
+ * Required size of memory to store camera metadata found in this
+ * method.
+ *
+ * @return size_t
+ * Number of camera metadata entries
+ */
+ size_t readCameraMetadata(const XMLElement * const aParamElem,
+ CameraInfo *aCamera,
+ size_t &dataSize);
+
+ /*
+ * construct camera_metadata_t from camera capabilities and metadata
+ *
+ * @param aCamera
+ * A pointer to CameraInfo that is being filled by this method.
+ * @param totalEntries
+ * Number of camera metadata entries to be added.
+ * @param totalDataSize
+ * Sum of sizes of camera metadata entries to be added.
+ *
+ * @return bool
+ * False if either it fails to allocate memory for camera metadata
+ * or its size is not large enough to add all found camera metadata
+ * entries.
+ */
+ bool constructCameraMetadata(CameraInfo *aCamera,
+ const size_t totalEntries,
+ const size_t totalDataSize);
+};
+#endif // CONFIG_MANAGER_H
+
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
new file mode 100644
index 0000000..d10f236
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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 "ConfigManagerUtil.h"
+
+#include <string>
+#include <sstream>
+#include <linux/videodev2.h>
+
+#include <log/log.h>
+#include <system/graphics-base-v1.0.h>
+
+
+bool ConfigManagerUtil::convertToEvsCameraParam(const string &id,
+ CameraParam &camParam) {
+ string trimmed = ConfigManagerUtil::trimString(id);
+ bool success = true;
+
+ if (!trimmed.compare("BRIGHTNESS")) {
+ camParam = CameraParam::BRIGHTNESS;
+ } else if (!trimmed.compare("CONTRAST")) {
+ camParam = CameraParam::CONTRAST;
+ } else if (!trimmed.compare("AUTOGAIN")) {
+ camParam = CameraParam::AUTOGAIN;
+ } else if (!trimmed.compare("GAIN")) {
+ camParam = CameraParam::GAIN;
+ } else if (!trimmed.compare("AUTO_WHITE_BALANCE")) {
+ camParam = CameraParam::AUTO_WHITE_BALANCE;
+ } else if (!trimmed.compare("WHITE_BALANCE_TEMPERATURE")) {
+ camParam = CameraParam::WHITE_BALANCE_TEMPERATURE;
+ } else if (!trimmed.compare("SHARPNESS")) {
+ camParam = CameraParam::SHARPNESS;
+ } else if (!trimmed.compare("AUTO_EXPOSURE")) {
+ camParam = CameraParam::AUTO_EXPOSURE;
+ } else if (!trimmed.compare("ABSOLUTE_EXPOSURE")) {
+ camParam = CameraParam::ABSOLUTE_EXPOSURE;
+ } else if (!trimmed.compare("ABSOLUTE_FOCUS")) {
+ camParam = CameraParam::ABSOLUTE_FOCUS;
+ } else if (!trimmed.compare("AUTO_FOCUS")) {
+ camParam = CameraParam::AUTO_FOCUS;
+ } else if (!trimmed.compare("ABSOLUTE_ZOOM")) {
+ camParam = CameraParam::ABSOLUTE_ZOOM;
+ } else {
+ success = false;
+ }
+
+ return success;
+}
+
+
+bool ConfigManagerUtil::convertToPixelFormat(const string &format,
+ int32_t &pixFormat) {
+ string trimmed = ConfigManagerUtil::trimString(format);
+ bool success = true;
+
+ if (!trimmed.compare("RGBA_8888")) {
+ pixFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ } else if (!trimmed.compare("YCRCB_420_SP")) {
+ pixFormat = HAL_PIXEL_FORMAT_YCRCB_420_SP;
+ } else if (!trimmed.compare("YCBCR_422_I")) {
+ pixFormat = HAL_PIXEL_FORMAT_YCBCR_422_I;
+ } else {
+ success = false;
+ }
+
+ return success;
+}
+
+
+bool ConfigManagerUtil::convertToMetadataTag(const char *name,
+ camera_metadata_tag &aTag) {
+ if (!strcmp(name, "LENS_DISTORTION")) {
+ aTag = ANDROID_LENS_DISTORTION;
+ } else if (!strcmp(name, "LENS_INTRINSIC_CALIBRATION")) {
+ aTag = ANDROID_LENS_INTRINSIC_CALIBRATION;
+ } else if (!strcmp(name, "LENS_POSE_ROTATION")) {
+ 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;
+ }
+
+ return true;
+}
+
+
+float *ConfigManagerUtil::convertFloatArray(const char *sz, const char *vals,
+ size_t &count, const char delimiter) {
+ string size_string(sz);
+ string value_string(vals);
+
+ count = stoi(size_string);
+ float *result = new float[count];
+ stringstream values(value_string);
+
+ int32_t idx = 0;
+ string token;
+ while (getline(values, token, delimiter)) {
+ result[idx++] = stof(token);
+ }
+
+ return result;
+}
+
+
+string ConfigManagerUtil::trimString(const string &src, const string &ws) {
+ const auto s = src.find_first_not_of(ws);
+ if (s == string::npos) {
+ return "";
+ }
+
+ const auto e = src.find_last_not_of(ws);
+ const auto r = e - s + 1;
+
+ return src.substr(s, r);
+}
+
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h
new file mode 100644
index 0000000..1710cac
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.h
@@ -0,0 +1,69 @@
+/*
+ * 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 CONFIG_MANAGER_UTIL_H
+#define CONFIG_MANAGER_UTIL_H
+
+#include <utility>
+#include <string>
+#include <system/camera_metadata.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+using namespace std;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+
+class ConfigManagerUtil {
+public:
+ /**
+ * Convert a given string into V4L2_CID_*
+ */
+ static bool convertToEvsCameraParam(const string &id,
+ CameraParam &camParam);
+ /**
+ * Convert a given string into android.hardware.graphics.common.PixelFormat
+ */
+ static bool convertToPixelFormat(const string &format,
+ int32_t &pixelFormat);
+ /**
+ * Convert a given string into corresponding camera metadata data tag defined in
+ * system/media/camera/include/system/camera_metadta_tags.h
+ */
+ static bool convertToMetadataTag(const char *name,
+ camera_metadata_tag &aTag);
+ /**
+ * Convert a given string into a floating value array
+ */
+ static float *convertFloatArray(const char *sz,
+ const char *vals,
+ size_t &count,
+ const char delimiter = ',');
+ /**
+ * Trim a string
+ */
+ 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
new file mode 100644
index 0000000..b7e4efa
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.automotive.evs@1.1-service"
+
+#include "EvsCamera.h"
+#include "EvsEnumerator.h"
+
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+// Special camera names for which we'll initialize alternate test data
+const char EvsCamera::kCameraName_Backup[] = "backup";
+
+
+// Arbitrary limit on number of graphics buffers allowed to be allocated
+// Safeguards against unreasonable resource consumption and provides a testable limit
+const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
+
+
+EvsCamera::EvsCamera(const char *id,
+ unique_ptr<ConfigManager::CameraInfo> &camInfo) :
+ mFramesAllowed(0),
+ mFramesInUse(0),
+ mStreamState(STOPPED),
+ mCameraInfo(camInfo) {
+
+ ALOGD("EvsCamera instantiated");
+
+ /* set a camera id */
+ mDescription.v1.cameraId = id;
+
+ /* set camera metadata */
+ mDescription.metadata.setToExternal((uint8_t *)camInfo->characteristics,
+ get_camera_metadata_size(camInfo->characteristics));
+}
+
+
+EvsCamera::~EvsCamera() {
+ ALOGD("EvsCamera being destroyed");
+ forceShutdown();
+}
+
+
+//
+// This gets called if another caller "steals" ownership of the camera
+//
+void EvsCamera::forceShutdown()
+{
+ ALOGD("EvsCamera forceShutdown");
+
+ // Make sure our output stream is cleaned up
+ // (It really should be already)
+ stopVideoStream();
+
+ // Claim the lock while we work on internal state
+ std::lock_guard <std::mutex> lock(mAccessLock);
+
+ // Drop all the graphics buffers we've been using
+ if (mBuffers.size() > 0) {
+ GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ for (auto&& rec : mBuffers) {
+ if (rec.inUse) {
+ ALOGE("Error - releasing buffer despite remote ownership");
+ }
+ alloc.free(rec.handle);
+ rec.handle = nullptr;
+ }
+ mBuffers.clear();
+ }
+
+ // Put this object into an unrecoverable error state since somebody else
+ // is going to own the underlying camera now
+ mStreamState = DEAD;
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+Return<void> EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
+ ALOGD("getCameraInfo");
+
+ // Send back our self description
+ _hidl_cb(mDescription.v1);
+ return Void();
+}
+
+
+Return<EvsResult> EvsCamera::setMaxFramesInFlight(uint32_t bufferCount) {
+ ALOGD("setMaxFramesInFlight");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // If we've been displaced by another owner of the camera, then we can't do anything else
+ if (mStreamState == DEAD) {
+ ALOGE("ignoring setMaxFramesInFlight call when camera has been lost.");
+ return EvsResult::OWNERSHIP_LOST;
+ }
+
+ // We cannot function without at least one video buffer to send data
+ if (bufferCount < 1) {
+ ALOGE("Ignoring setMaxFramesInFlight with less than one buffer requested");
+ return EvsResult::INVALID_ARG;
+ }
+
+ // Update our internal state
+ if (setAvailableFrames_Locked(bufferCount)) {
+ return EvsResult::OK;
+ } else {
+ return EvsResult::BUFFER_NOT_AVAILABLE;
+ }
+}
+
+
+Return<EvsResult> EvsCamera::startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& stream) {
+ ALOGD("startVideoStream");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // If we've been displaced by another owner of the camera, then we can't do anything else
+ if (mStreamState == DEAD) {
+ ALOGE("ignoring startVideoStream call when camera has been lost.");
+ return EvsResult::OWNERSHIP_LOST;
+ }
+ if (mStreamState != STOPPED) {
+ ALOGE("ignoring startVideoStream call when a stream is already running.");
+ return EvsResult::STREAM_ALREADY_RUNNING;
+ }
+
+ // If the client never indicated otherwise, configure ourselves for a single streaming buffer
+ if (mFramesAllowed < 1) {
+ if (!setAvailableFrames_Locked(1)) {
+ ALOGE("Failed to start stream because we couldn't get a graphics buffer");
+ return EvsResult::BUFFER_NOT_AVAILABLE;
+ }
+ }
+
+ // Record the user's callback for use when we have a frame ready
+ mStream = IEvsCameraStream_1_1::castFrom(stream).withDefault(nullptr);
+ if (mStream == nullptr) {
+ ALOGE("Default implementation does not support v1.0 IEvsCameraStream");
+ return EvsResult::INVALID_ARG;
+ }
+
+ // Start the frame generation thread
+ mStreamState = RUNNING;
+ mCaptureThread = std::thread([this](){ generateFrames(); });
+
+ return EvsResult::OK;
+}
+
+
+Return<void> EvsCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
+ std::lock_guard <std::mutex> lock(mAccessLock);
+ returnBuffer(buffer.bufferId, buffer.memHandle);
+
+ return Void();
+}
+
+
+Return<void> EvsCamera::stopVideoStream() {
+ ALOGD("stopVideoStream");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ if (mStreamState == RUNNING) {
+ // Tell the GenerateFrames loop we want it to stop
+ mStreamState = STOPPING;
+
+ // Block outside the mutex until the "stop" flag has been acknowledged
+ // We won't send any more frames, but the client might still get some already in flight
+ ALOGD("Waiting for stream thread to end...");
+ lock.unlock();
+ mCaptureThread.join();
+ lock.lock();
+
+ mStreamState = STOPPED;
+ mStream = nullptr;
+ ALOGD("Stream marked STOPPED.");
+ }
+
+ return Void();
+}
+
+
+Return<int32_t> EvsCamera::getExtendedInfo(uint32_t opaqueIdentifier) {
+ ALOGD("getExtendedInfo");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // For any single digit value, return the index itself as a test value
+ if (opaqueIdentifier <= 9) {
+ return opaqueIdentifier;
+ }
+
+ // Return zero by default as required by the spec
+ return 0;
+}
+
+
+Return<EvsResult> EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int32_t /*opaqueValue*/) {
+ ALOGD("setExtendedInfo");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // If we've been displaced by another owner of the camera, then we can't do anything else
+ if (mStreamState == DEAD) {
+ ALOGE("ignoring setExtendedInfo call when camera has been lost.");
+ return EvsResult::OWNERSHIP_LOST;
+ }
+
+ // We don't store any device specific information in this implementation
+ return EvsResult::INVALID_ARG;
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+Return<void> EvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) {
+ ALOGD("getCameraInfo_1_1");
+
+ // Send back our self description
+ _hidl_cb(mDescription);
+ return Void();
+}
+
+
+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);
+
+ for (auto&& buffer : buffers) {
+ returnBuffer(buffer.bufferId, buffer.buffer.nativeHandle);
+ }
+
+ return EvsResult::OK;
+}
+
+
+Return<EvsResult> EvsCamera::pauseVideoStream() {
+ // Default implementation does not support this.
+ return EvsResult::UNDERLYING_SERVICE_ERROR;
+}
+
+
+Return<EvsResult> EvsCamera::resumeVideoStream() {
+ // Default implementation does not support this.
+ return EvsResult::UNDERLYING_SERVICE_ERROR;
+}
+
+
+Return<EvsResult> EvsCamera::setMaster() {
+ // Default implementation does not expect multiple subscribers and therefore
+ // return a success code always.
+ return EvsResult::OK;
+}
+
+Return<EvsResult> EvsCamera::forceMaster(const sp<IEvsDisplay>& ) {
+ // Default implementation does not expect multiple subscribers and therefore
+ // return a success code always.
+ return EvsResult::OK;
+}
+
+
+Return<EvsResult> EvsCamera::unsetMaster() {
+ // Default implementation does not expect multiple subscribers and therefore
+ // return a success code always.
+ return EvsResult::OK;
+}
+
+
+Return<void> EvsCamera::getParameterList(getParameterList_cb _hidl_cb) {
+ hidl_vec<CameraParam> hidlCtrls;
+ hidlCtrls.resize(mCameraInfo->controls.size());
+ unsigned idx = 0;
+ for (auto& [cid, cfg] : mCameraInfo->controls) {
+ hidlCtrls[idx++] = cid;
+ }
+
+ _hidl_cb(hidlCtrls);
+ return Void();
+}
+
+
+Return<void> EvsCamera::getIntParameterRange(CameraParam id,
+ getIntParameterRange_cb _hidl_cb) {
+ auto range = mCameraInfo->controls[id];
+ _hidl_cb(get<0>(range), get<1>(range), get<2>(range));
+ return Void();
+}
+
+
+Return<void> EvsCamera::setIntParameter(CameraParam id, int32_t value,
+ setIntParameter_cb _hidl_cb) {
+ // Default implementation does not support this.
+ (void)id;
+ (void)value;
+ _hidl_cb(EvsResult::INVALID_ARG, 0);
+ return Void();
+}
+
+
+Return<void> EvsCamera::getIntParameter(CameraParam id,
+ getIntParameter_cb _hidl_cb) {
+ // Default implementation does not support this.
+ (void)id;
+ _hidl_cb(EvsResult::INVALID_ARG, 0);
+ return Void();
+}
+
+
+bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) {
+ if (bufferCount < 1) {
+ ALOGE("Ignoring request to set buffer count to zero");
+ return false;
+ }
+ if (bufferCount > MAX_BUFFERS_IN_FLIGHT) {
+ ALOGE("Rejecting buffer request in excess of internal limit");
+ return false;
+ }
+
+ // Is an increase required?
+ if (mFramesAllowed < bufferCount) {
+ // An increase is required
+ unsigned needed = bufferCount - mFramesAllowed;
+ ALOGI("Allocating %d buffers for camera frames", needed);
+
+ unsigned added = increaseAvailableFrames_Locked(needed);
+ if (added != needed) {
+ // If we didn't add all the frames we needed, then roll back to the previous state
+ ALOGE("Rolling back to previous frame queue size");
+ decreaseAvailableFrames_Locked(added);
+ return false;
+ }
+ } else if (mFramesAllowed > bufferCount) {
+ // A decrease is required
+ unsigned framesToRelease = mFramesAllowed - bufferCount;
+ ALOGI("Returning %d camera frame buffers", framesToRelease);
+
+ unsigned released = decreaseAvailableFrames_Locked(framesToRelease);
+ if (released != framesToRelease) {
+ // This shouldn't happen with a properly behaving client because the client
+ // should only make this call after returning sufficient outstanding buffers
+ // to allow a clean resize.
+ ALOGE("Buffer queue shrink failed -- too many buffers currently in use?");
+ }
+ }
+
+ return true;
+}
+
+
+unsigned EvsCamera::increaseAvailableFrames_Locked(unsigned numToAdd) {
+ // Acquire the graphics buffer allocator
+ GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
+
+ unsigned added = 0;
+
+ while (added < numToAdd) {
+ buffer_handle_t memHandle = nullptr;
+ status_t result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage,
+ &memHandle, &mStride, 0, "EvsCamera");
+ if (result != NO_ERROR) {
+ ALOGE("Error %d allocating %d x %d graphics buffer", result, mWidth, mHeight);
+ break;
+ }
+ if (!memHandle) {
+ ALOGE("We didn't get a buffer handle back from the allocator");
+ break;
+ }
+
+ // Find a place to store the new buffer
+ bool stored = false;
+ for (auto&& rec : mBuffers) {
+ if (rec.handle == nullptr) {
+ // Use this existing entry
+ rec.handle = memHandle;
+ rec.inUse = false;
+ stored = true;
+ break;
+ }
+ }
+ if (!stored) {
+ // Add a BufferRecord wrapping this handle to our set of available buffers
+ mBuffers.emplace_back(memHandle);
+ }
+
+ mFramesAllowed++;
+ added++;
+ }
+
+ return added;
+}
+
+
+unsigned EvsCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) {
+ // Acquire the graphics buffer allocator
+ GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
+
+ unsigned removed = 0;
+
+ for (auto&& rec : mBuffers) {
+ // Is this record not in use, but holding a buffer that we can free?
+ if ((rec.inUse == false) && (rec.handle != nullptr)) {
+ // Release buffer and update the record so we can recognize it as "empty"
+ alloc.free(rec.handle);
+ rec.handle = nullptr;
+
+ mFramesAllowed--;
+ removed++;
+
+ if (removed == numToRemove) {
+ break;
+ }
+ }
+ }
+
+ return removed;
+}
+
+
+// This is the asynchronous frame generation thread that runs in parallel with the
+// main serving thread. There is one for each active camera instance.
+void EvsCamera::generateFrames() {
+ ALOGD("Frame generation loop started");
+
+ unsigned idx;
+
+ while (true) {
+ bool timeForFrame = false;
+ nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // Lock scope for updating shared state
+ {
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mStreamState != RUNNING) {
+ // Break out of our main thread loop
+ break;
+ }
+
+ // Are we allowed to issue another buffer?
+ if (mFramesInUse >= mFramesAllowed) {
+ // Can't do anything right now -- skip this frame
+ ALOGW("Skipped a frame because too many are in flight\n");
+ } else {
+ // Identify an available buffer to fill
+ for (idx = 0; idx < mBuffers.size(); idx++) {
+ if (!mBuffers[idx].inUse) {
+ if (mBuffers[idx].handle != nullptr) {
+ // Found an available record, so stop looking
+ break;
+ }
+ }
+ }
+ if (idx >= mBuffers.size()) {
+ // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
+ ALOGE("Failed to find an available buffer slot\n");
+ } else {
+ // We're going to make the frame busy
+ mBuffers[idx].inUse = true;
+ mFramesInUse++;
+ timeForFrame = true;
+ }
+ }
+ }
+
+ if (timeForFrame) {
+ // Assemble the buffer description we'll transmit below
+ BufferDesc_1_1 newBuffer = {};
+ AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<AHardwareBuffer_Desc *>(&newBuffer.buffer.description);
+ pDesc->width = mWidth;
+ pDesc->height = mHeight;
+ pDesc->layers = 1;
+ pDesc->format = mFormat;
+ pDesc->usage = mUsage;
+ pDesc->stride = mStride;
+ newBuffer.buffer.nativeHandle = mBuffers[idx].handle;
+ newBuffer.pixelSize = sizeof(uint32_t);
+ newBuffer.bufferId = idx;
+ 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
+ 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);
+ } else {
+ // This can happen if the client dies and is likely unrecoverable.
+ // To avoid consuming resources generating failing calls, we stop sending
+ // frames. Note, however, that the stream remains in the "STREAMING" state
+ // until cleaned up on the main thread.
+ ALOGE("Frame delivery call failed in the transport layer.");
+
+ // Since we didn't actually deliver it, mark the frame as available
+ std::lock_guard<std::mutex> lock(mAccessLock);
+ mBuffers[idx].inUse = false;
+ mFramesInUse--;
+
+ break;
+ }
+ }
+
+ // We arbitrarily choose to generate frames at 12 fps to ensure we pass the 10fps test requirement
+ static const int kTargetFrameRate = 12;
+ static const nsecs_t kTargetFrameTimeUs = 1000*1000 / kTargetFrameRate;
+ const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ const nsecs_t workTimeUs = (now - startTime) / 1000;
+ const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs;
+ if (sleepDurationUs > 0) {
+ usleep(sleepDurationUs);
+ }
+ }
+
+ // If we've been asked to stop, send an event to signal the actual end of stream
+ EvsEventDesc event;
+ event.aType = EvsEventType::STREAM_STOPPED;
+ auto result = mStream->notify(event);
+ if (!result.isOk()) {
+ ALOGE("Error delivering end of stream marker");
+ }
+
+ return;
+}
+
+
+void EvsCamera::fillTestFrame(const BufferDesc_1_1& buff) {
+ // Lock our output buffer for writing
+ uint32_t *pixels = nullptr;
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&buff.buffer.description);
+ GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+ mapper.lock(buff.buffer.nativeHandle,
+ GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+ android::Rect(pDesc->width, pDesc->height),
+ (void **) &pixels);
+
+ // If we failed to lock the pixel buffer, we're about to crash, but log it first
+ if (!pixels) {
+ ALOGE("Camera failed to gain access to image buffer for writing");
+ }
+
+ // Fill in the test pixels
+ for (unsigned row = 0; row < pDesc->height; row++) {
+ for (unsigned col = 0; col < pDesc->width; col++) {
+ // Index into the row to check the pixel at this column.
+ // We expect 0xFF in the LSB channel, a vertical gradient in the
+ // second channel, a horitzontal gradient in the third channel, and
+ // 0xFF in the MSB.
+ // The exception is the very first 32 bits which is used for the
+ // time varying frame signature to avoid getting fooled by a static image.
+ uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB
+ ((row & 0xFF) << 8) | // vertical gradient
+ ((col & 0xFF) << 16); // horizontal gradient
+ if ((row | col) == 0) {
+ static uint32_t sFrameTicker = 0;
+ expectedPixel = (sFrameTicker) & 0xFF;
+ sFrameTicker++;
+ }
+ pixels[col] = expectedPixel;
+ }
+ // Point to the next row
+ // NOTE: stride retrieved from gralloc is in units of pixels
+ pixels = pixels + pDesc->stride;
+ }
+
+ // Release our output buffer
+ mapper.unlock(buff.buffer.nativeHandle);
+}
+
+
+void EvsCamera::fillTestFrame(const BufferDesc_1_0& buff) {
+ BufferDesc_1_1 newBufDesc = {};
+ AHardwareBuffer_Desc desc = {
+ buff.width, // width
+ buff.height, // height
+ 1, // layers, always 1 for EVS
+ buff.format, // One of AHardwareBuffer_Format
+ buff.usage, // Combination of AHardwareBuffer_UsageFlags
+ buff.stride, // Row stride in pixels
+ 0, // Reserved
+ 0 // Reserved
+ };
+ memcpy(&desc, &newBufDesc.buffer.description, sizeof(desc));
+ newBufDesc.buffer.nativeHandle = buff.memHandle;
+ newBufDesc.pixelSize = buff.pixelSize;
+ newBufDesc.bufferId = buff.bufferId;
+
+ return fillTestFrame(newBufDesc);
+}
+
+
+void EvsCamera::returnBuffer(const uint32_t bufferId, const buffer_handle_t memHandle) {
+ std::lock_guard <std::mutex> lock(mAccessLock);
+
+ if (memHandle == nullptr) {
+ ALOGE("ignoring doneWithFrame called with null handle");
+ } else if (bufferId >= mBuffers.size()) {
+ ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)",
+ bufferId, mBuffers.size()-1);
+ } else if (!mBuffers[bufferId].inUse) {
+ ALOGE("ignoring doneWithFrame called on frame %d which is already free",
+ bufferId);
+ } else {
+ // Mark the frame as available
+ mBuffers[bufferId].inUse = false;
+ mFramesInUse--;
+
+ // If this frame's index is high in the array, try to move it down
+ // to improve locality after mFramesAllowed has been reduced.
+ if (bufferId >= mFramesAllowed) {
+ // Find an empty slot lower in the array (which should always exist in this case)
+ for (auto&& rec : mBuffers) {
+ if (rec.handle == nullptr) {
+ rec.handle = mBuffers[bufferId].handle;
+ mBuffers[bufferId].handle = nullptr;
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+sp<EvsCamera> EvsCamera::Create(const char *deviceName) {
+ unique_ptr<ConfigManager::CameraInfo> nullCamInfo = nullptr;
+
+ return Create(deviceName, nullCamInfo);
+}
+
+
+sp<EvsCamera> EvsCamera::Create(const char *deviceName,
+ unique_ptr<ConfigManager::CameraInfo> &camInfo,
+ const Stream *streamCfg) {
+ sp<EvsCamera> evsCamera = new EvsCamera(deviceName, camInfo);
+ if (evsCamera == nullptr) {
+ return nullptr;
+ }
+
+ /* default implementation does not use a given configuration */
+ (void)streamCfg;
+
+ /* Use the first resolution from the list for the testing */
+ auto it = camInfo->streamConfigurations.begin();
+ evsCamera->mWidth = it->second[1];
+ evsCamera->mHeight = it->second[2];
+ evsCamera->mDescription.v1.vendorFlags = 0xFFFFFFFF; // Arbitrary test value
+
+ evsCamera->mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ evsCamera->mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
+ GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
+
+ return evsCamera;
+}
+
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h
new file mode 100644
index 0000000..72a1b57
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERA_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERA_H
+
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <ui/GraphicBuffer.h>
+
+#include <thread>
+
+#include "ConfigManager.h"
+
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
+using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+// From EvsEnumerator.h
+class EvsEnumerator;
+
+
+class EvsCamera : public IEvsCamera {
+public:
+ // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+ Return<void> getCameraInfo(getCameraInfo_cb _hidl_cb) override;
+ Return<EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
+ Return<EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& stream) override;
+ Return<void> stopVideoStream() override;
+ Return<void> doneWithFrame(const BufferDesc_1_0& buffer) override;
+
+ Return<int32_t> getExtendedInfo(uint32_t opaqueIdentifier) override;
+ Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
+
+ // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+ Return<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 hidl_vec<BufferDesc_1_1>& buffer) override;
+ Return<EvsResult> setMaster() override;
+ Return<EvsResult> forceMaster(const sp<IEvsDisplay>& display) override;
+ Return<EvsResult> unsetMaster() override;
+ Return<void> getParameterList(getParameterList_cb _hidl_cb) override;
+ Return<void> getIntParameterRange(CameraParam id,
+ getIntParameterRange_cb _hidl_cb) override;
+ Return<void> setIntParameter(CameraParam id, int32_t value,
+ setIntParameter_cb _hidl_cb) override;
+ Return<void> getIntParameter(CameraParam id,
+ getIntParameter_cb _hidl_cb) override;
+
+ static sp<EvsCamera> Create(const char *deviceName);
+ static sp<EvsCamera> Create(const char *deviceName,
+ unique_ptr<ConfigManager::CameraInfo> &camInfo,
+ const Stream *streamCfg = nullptr);
+ EvsCamera(const EvsCamera&) = delete;
+ EvsCamera& operator=(const EvsCamera&) = delete;
+
+ virtual ~EvsCamera() override;
+ void forceShutdown(); // This gets called if another caller "steals" ownership of the camera
+
+ const CameraDesc& getDesc() { return mDescription; };
+
+ static const char kCameraName_Backup[];
+
+private:
+ EvsCamera(const char *id,
+ unique_ptr<ConfigManager::CameraInfo> &camInfo);
+ // These three functions are expected to be called while mAccessLock is held
+ //
+ bool setAvailableFrames_Locked(unsigned bufferCount);
+ unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
+ unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
+
+ void generateFrames();
+ void fillTestFrame(const BufferDesc_1_0& buff);
+ void fillTestFrame(const BufferDesc_1_1& buff);
+ void returnBuffer(const uint32_t bufferId, const buffer_handle_t memHandle);
+
+ sp<EvsEnumerator> mEnumerator; // The enumerator object that created this camera
+
+ CameraDesc mDescription = {}; // The properties of this camera
+
+ std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+ uint32_t mWidth = 0; // Horizontal pixel count in the buffers
+ uint32_t mHeight = 0; // Vertical pixel count in the buffers
+ uint32_t mFormat = 0; // Values from android_pixel_format_t
+ uint64_t mUsage = 0; // Values from from Gralloc.h
+ uint32_t mStride = 0; // Bytes per line in the buffers
+
+ sp<IEvsCameraStream_1_1> mStream = nullptr; // The callback used to deliver each frame
+
+ struct BufferRecord {
+ buffer_handle_t handle;
+ bool inUse;
+
+ explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false) {};
+ };
+
+ std::vector <BufferRecord> mBuffers; // Graphics buffers to transfer images
+ unsigned mFramesAllowed; // How many buffers are we currently using
+ unsigned mFramesInUse; // How many buffers are currently outstanding
+
+ enum StreamStateValues {
+ STOPPED,
+ RUNNING,
+ STOPPING,
+ DEAD,
+ };
+ StreamStateValues mStreamState;
+
+ // Synchronization necessary to deconflict mCaptureThread from the main service thread
+ std::mutex mAccessLock;
+
+ // Static camera module information
+ unique_ptr<ConfigManager::CameraInfo> &mCameraInfo;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERA_H
diff --git a/automotive/evs/1.1/default/EvsDisplay.cpp b/automotive/evs/1.1/default/EvsDisplay.cpp
new file mode 100644
index 0000000..74c099a
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsDisplay.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.automotive.evs@1.1-service"
+
+#include "EvsDisplay.h"
+
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+EvsDisplay::EvsDisplay() {
+ ALOGD("EvsDisplay instantiated");
+
+ // Set up our self description
+ // NOTE: These are arbitrary values chosen for testing
+ mInfo.displayId = "Mock Display";
+ mInfo.vendorFlags = 3870;
+
+ // Assemble the buffer description we'll use for our render target
+ mBuffer.width = 320;
+ mBuffer.height = 240;
+ mBuffer.format = HAL_PIXEL_FORMAT_RGBA_8888;
+ mBuffer.usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
+ mBuffer.bufferId = 0x3870; // Arbitrary magic number for self recognition
+ mBuffer.pixelSize = 4;
+}
+
+
+EvsDisplay::~EvsDisplay() {
+ ALOGD("EvsDisplay being destroyed");
+ forceShutdown();
+}
+
+
+/**
+ * This gets called if another caller "steals" ownership of the display
+ */
+void EvsDisplay::forceShutdown()
+{
+ ALOGD("EvsDisplay forceShutdown");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // If the buffer isn't being held by a remote client, release it now as an
+ // optimization to release the resources more quickly than the destructor might
+ // get called.
+ if (mBuffer.memHandle) {
+ // Report if we're going away while a buffer is outstanding
+ if (mFrameBusy) {
+ ALOGE("EvsDisplay going down while client is holding a buffer");
+ }
+
+ // Drop the graphics buffer we've been using
+ GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ alloc.free(mBuffer.memHandle);
+ mBuffer.memHandle = nullptr;
+ }
+
+ // Put this object into an unrecoverable error state since somebody else
+ // is going to own the display now.
+ mRequestedState = DisplayState::DEAD;
+}
+
+
+/**
+ * Returns basic information about the EVS display provided by the system.
+ * See the description of the DisplayDesc structure for details.
+ */
+Return<void> EvsDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb) {
+ ALOGD("getDisplayInfo");
+
+ // Send back our self description
+ _hidl_cb(mInfo);
+ return Void();
+}
+
+
+/**
+ * Clients may set the display state to express their desired state.
+ * The HAL implementation must gracefully accept a request for any state
+ * while in any other state, although the response may be to ignore the request.
+ * The display is defined to start in the NOT_VISIBLE state upon initialization.
+ * The client is then expected to request the VISIBLE_ON_NEXT_FRAME state, and
+ * then begin providing video. When the display is no longer required, the client
+ * is expected to request the NOT_VISIBLE state after passing the last video frame.
+ */
+Return<EvsResult> EvsDisplay::setDisplayState(DisplayState state) {
+ ALOGD("setDisplayState");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mRequestedState == DisplayState::DEAD) {
+ // This object no longer owns the display -- it's been superceeded!
+ return EvsResult::OWNERSHIP_LOST;
+ }
+
+ // Ensure we recognize the requested state so we don't go off the rails
+ if (state < DisplayState::NUM_STATES) {
+ // Record the requested state
+ mRequestedState = state;
+ return EvsResult::OK;
+ }
+ else {
+ // Turn off the display if asked for an unrecognized state
+ mRequestedState = DisplayState::NOT_VISIBLE;
+ return EvsResult::INVALID_ARG;
+ }
+}
+
+
+/**
+ * The HAL implementation should report the actual current state, which might
+ * transiently differ from the most recently requested state. Note, however, that
+ * the logic responsible for changing display states should generally live above
+ * the device layer, making it undesirable for the HAL implementation to
+ * spontaneously change display states.
+ */
+Return<DisplayState> EvsDisplay::getDisplayState() {
+ ALOGD("getDisplayState");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ return mRequestedState;
+}
+
+
+/**
+ * This call returns a handle to a frame buffer associated with the display.
+ * This buffer may be locked and written to by software and/or GL. This buffer
+ * must be returned via a call to returnTargetBufferForDisplay() even if the
+ * display is no longer visible.
+ */
+// TODO: We need to know if/when our client dies so we can get the buffer back! (blocked b/31632518)
+Return<void> EvsDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb) {
+ ALOGD("getTargetBuffer");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mRequestedState == DisplayState::DEAD) {
+ ALOGE("Rejecting buffer request from object that lost ownership of the display.");
+ BufferDesc_1_0 nullBuff = {};
+ _hidl_cb(nullBuff);
+ return Void();
+ }
+
+ // If we don't already have a buffer, allocate one now
+ if (!mBuffer.memHandle) {
+ // Allocate the buffer that will hold our displayable image
+ buffer_handle_t handle = nullptr;
+ GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ status_t result = alloc.allocate(
+ mBuffer.width, mBuffer.height, mBuffer.format, 1, mBuffer.usage,
+ &handle, &mBuffer.stride, 0, "EvsDisplay");
+ if (result != NO_ERROR) {
+ ALOGE("Error %d allocating %d x %d graphics buffer",
+ result, mBuffer.width, mBuffer.height);
+ BufferDesc_1_0 nullBuff = {};
+ _hidl_cb(nullBuff);
+ return Void();
+ }
+ if (!handle) {
+ ALOGE("We didn't get a buffer handle back from the allocator");
+ BufferDesc_1_0 nullBuff = {};
+ _hidl_cb(nullBuff);
+ return Void();
+ }
+
+ mBuffer.memHandle = handle;
+ mFrameBusy = false;
+ ALOGD("Allocated new buffer %p with stride %u",
+ mBuffer.memHandle.getNativeHandle(), mBuffer.stride);
+ }
+
+ // Do we have a frame available?
+ if (mFrameBusy) {
+ // This means either we have a 2nd client trying to compete for buffers
+ // (an unsupported mode of operation) or else the client hasn't returned
+ // a previously issued buffer yet (they're behaving badly).
+ // NOTE: We have to make the callback even if we have nothing to provide
+ ALOGE("getTargetBuffer called while no buffers available.");
+ BufferDesc_1_0 nullBuff = {};
+ _hidl_cb(nullBuff);
+ return Void();
+ } else {
+ // Mark our buffer as busy
+ mFrameBusy = true;
+
+ // Send the buffer to the client
+ ALOGD("Providing display buffer handle %p as id %d",
+ mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId);
+ _hidl_cb(mBuffer);
+ return Void();
+ }
+}
+
+
+/**
+ * This call tells the display that the buffer is ready for display.
+ * The buffer is no longer valid for use by the client after this call.
+ */
+Return<EvsResult> EvsDisplay::returnTargetBufferForDisplayImpl(const uint32_t bufferId, const buffer_handle_t memHandle) {
+ ALOGD("returnTargetBufferForDisplay %p", memHandle);
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // Nobody should call us with a null handle
+ if (!memHandle) {
+ ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n");
+ return EvsResult::INVALID_ARG;
+ }
+ if (bufferId != mBuffer.bufferId) {
+ ALOGE ("Got an unrecognized frame returned.\n");
+ return EvsResult::INVALID_ARG;
+ }
+ if (!mFrameBusy) {
+ ALOGE ("A frame was returned with no outstanding frames.\n");
+ return EvsResult::BUFFER_NOT_AVAILABLE;
+ }
+
+ mFrameBusy = false;
+
+ // If we've been displaced by another owner of the display, then we can't do anything else
+ if (mRequestedState == DisplayState::DEAD) {
+ return EvsResult::OWNERSHIP_LOST;
+ }
+
+ // If we were waiting for a new frame, this is it!
+ if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) {
+ mRequestedState = DisplayState::VISIBLE;
+ }
+
+ // Validate we're in an expected state
+ if (mRequestedState != DisplayState::VISIBLE) {
+ // We shouldn't get frames back when we're not visible.
+ ALOGE ("Got an unexpected frame returned while not visible - ignoring.\n");
+ } else {
+ // This is where the buffer would be made visible.
+ // For now we simply validate it has the data we expect in it by reading it back
+
+ // Lock our display buffer for reading
+ uint32_t* pixels = nullptr;
+ GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+ mapper.lock(mBuffer.memHandle,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
+ android::Rect(mBuffer.width, mBuffer.height),
+ (void **)&pixels);
+
+ // If we failed to lock the pixel buffer, we're about to crash, but log it first
+ if (!pixels) {
+ ALOGE("Display failed to gain access to image buffer for reading");
+ }
+
+ // Check the test pixels
+ bool frameLooksGood = true;
+ for (unsigned row = 0; row < mBuffer.height; row++) {
+ for (unsigned col = 0; col < mBuffer.width; col++) {
+ // Index into the row to check the pixel at this column.
+ // We expect 0xFF in the LSB channel, a vertical gradient in the
+ // second channel, a horitzontal gradient in the third channel, and
+ // 0xFF in the MSB.
+ // The exception is the very first 32 bits which is used for the
+ // time varying frame signature to avoid getting fooled by a static image.
+ uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB
+ ((row & 0xFF) << 8) | // vertical gradient
+ ((col & 0xFF) << 16); // horizontal gradient
+ if ((row | col) == 0) {
+ // we'll check the "uniqueness" of the frame signature below
+ continue;
+ }
+ // Walk across this row (we'll step rows below)
+ uint32_t receivedPixel = pixels[col];
+ if (receivedPixel != expectedPixel) {
+ ALOGE("Pixel check mismatch in frame buffer");
+ frameLooksGood = false;
+ break;
+ }
+ }
+
+ if (!frameLooksGood) {
+ break;
+ }
+
+ // Point to the next row (NOTE: gralloc reports stride in units of pixels)
+ pixels = pixels + mBuffer.stride;
+ }
+
+ // Ensure we don't see the same buffer twice without it being rewritten
+ static uint32_t prevSignature = ~0;
+ uint32_t signature = pixels[0] & 0xFF;
+ if (prevSignature == signature) {
+ frameLooksGood = false;
+ ALOGE("Duplicate, likely stale frame buffer detected");
+ }
+
+
+ // Release our output buffer
+ mapper.unlock(mBuffer.memHandle);
+
+ if (!frameLooksGood) {
+ return EvsResult::UNDERLYING_SERVICE_ERROR;
+ }
+ }
+
+ return EvsResult::OK;
+}
+
+
+Return<EvsResult> EvsDisplay::returnTargetBufferForDisplay(const BufferDesc_1_0& buffer) {
+ return returnTargetBufferForDisplayImpl(buffer.bufferId, buffer.memHandle);
+}
+
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/evs/1.1/default/EvsDisplay.h b/automotive/evs/1.1/default/EvsDisplay.h
new file mode 100644
index 0000000..2a56535
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsDisplay.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H
+
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <ui/GraphicBuffer.h>
+
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
+using ::android::hardware::automotive::evs::V1_0::DisplayState;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+class EvsDisplay : public IEvsDisplay {
+public:
+ // Methods from ::android::hardware::automotive::evs::V1_0::IEvsDisplay follow.
+ Return<void> getDisplayInfo(getDisplayInfo_cb _hidl_cb) override;
+ Return<EvsResult> setDisplayState(DisplayState state) override;
+ Return<DisplayState> getDisplayState() override;
+ Return<void> getTargetBuffer(getTargetBuffer_cb _hidl_cb) override;
+ Return<EvsResult> returnTargetBufferForDisplay(const BufferDesc_1_0& buffer) override;
+
+
+ // Implementation details
+ EvsDisplay();
+ virtual ~EvsDisplay() override;
+
+ void forceShutdown(); // This gets called if another caller "steals" ownership of the display
+ Return<EvsResult> returnTargetBufferForDisplayImpl(const uint32_t bufferId,
+ const buffer_handle_t memHandle);
+
+private:
+ DisplayDesc mInfo = {};
+ BufferDesc_1_0 mBuffer = {}; // A graphics buffer into which we'll store images
+
+ bool mFrameBusy = false; // A flag telling us our buffer is in use
+ DisplayState mRequestedState = DisplayState::NOT_VISIBLE;
+
+ std::mutex mAccessLock;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
new file mode 100644
index 0000000..a010729
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.automotive.evs@1.1-service"
+
+#include "EvsEnumerator.h"
+#include "EvsCamera.h"
+#include "EvsDisplay.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+// NOTE: All members values are static so that all clients operate on the same state
+// That is to say, this is effectively a singleton despite the fact that HIDL
+// constructs a new instance for each client.
+std::list<EvsEnumerator::CameraRecord> EvsEnumerator::sCameraList;
+wp<EvsDisplay> EvsEnumerator::sActiveDisplay;
+unique_ptr<ConfigManager> EvsEnumerator::sConfigManager;
+
+
+EvsEnumerator::EvsEnumerator() {
+ ALOGD("EvsEnumerator created");
+
+ // Add sample camera data to our list of cameras
+ // In a real driver, this would be expected to can the available hardware
+ sConfigManager =
+ ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml");
+ for (auto v : sConfigManager->getCameraList()) {
+ sCameraList.emplace_back(v.c_str());
+ }
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
+Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) {
+ ALOGD("getCameraList");
+
+ const unsigned numCameras = sCameraList.size();
+
+ // Build up a packed array of CameraDesc for return
+ // NOTE: Only has to live until the callback returns
+ std::vector<CameraDesc_1_0> descriptions;
+ descriptions.reserve(numCameras);
+ for (const auto& cam : sCameraList) {
+ descriptions.push_back( cam.desc.v1 );
+ }
+
+ // Encapsulate our camera descriptions in the HIDL vec type
+ hidl_vec<CameraDesc_1_0> hidlCameras(descriptions);
+
+ // Send back the results
+ ALOGD("reporting %zu cameras available", hidlCameras.size());
+ _hidl_cb(hidlCameras);
+
+ // HIDL convention says we return Void if we sent our result back via callback
+ return Void();
+}
+
+
+Return<sp<IEvsCamera_1_0>> EvsEnumerator::openCamera(const hidl_string& cameraId) {
+ ALOGD("openCamera");
+
+ // Find the named camera
+ CameraRecord *pRecord = nullptr;
+ for (auto &&cam : sCameraList) {
+ if (cam.desc.v1.cameraId == cameraId) {
+ // Found a match!
+ pRecord = &cam;
+ break;
+ }
+ }
+
+ // Is this a recognized camera id?
+ if (!pRecord) {
+ ALOGE("Requested camera %s not found", cameraId.c_str());
+ return nullptr;
+ }
+
+ // Has this camera already been instantiated by another caller?
+ sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+ if (pActiveCamera != nullptr) {
+ ALOGW("Killing previous camera because of new caller");
+ closeCamera(pActiveCamera);
+ }
+
+ // Construct a camera instance for the caller
+ if (sConfigManager == nullptr) {
+ pActiveCamera = EvsCamera::Create(cameraId.c_str());
+ } else {
+ pActiveCamera = EvsCamera::Create(cameraId.c_str(),
+ sConfigManager->getCameraInfo(cameraId));
+ }
+ pRecord->activeInstance = pActiveCamera;
+ if (pActiveCamera == nullptr) {
+ ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
+ }
+
+ return pActiveCamera;
+}
+
+
+Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera_1_0>& pCamera) {
+ ALOGD("closeCamera");
+
+ auto pCamera_1_1 = IEvsCamera_1_1::castFrom(pCamera).withDefault(nullptr);
+ if (pCamera_1_1 == nullptr) {
+ ALOGE("Ignoring call to closeCamera with null camera ptr");
+ return Void();
+ }
+
+ // Get the camera id so we can find it in our list
+ std::string cameraId;
+ pCamera_1_1->getCameraInfo_1_1([&cameraId](CameraDesc desc) {
+ cameraId = desc.v1.cameraId;
+ }
+ );
+
+ // Find the named camera
+ CameraRecord *pRecord = nullptr;
+ for (auto &&cam : sCameraList) {
+ if (cam.desc.v1.cameraId == cameraId) {
+ // Found a match!
+ pRecord = &cam;
+ break;
+ }
+ }
+
+ // Is the display being destroyed actually the one we think is active?
+ if (!pRecord) {
+ ALOGE("Asked to close a camera who's name isn't recognized");
+ } else {
+ sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+
+ if (pActiveCamera == nullptr) {
+ ALOGE("Somehow a camera is being destroyed when the enumerator didn't know one existed");
+ } else if (pActiveCamera != pCamera_1_1) {
+ // This can happen if the camera was aggressively reopened, orphaning this previous instance
+ ALOGW("Ignoring close of previously orphaned camera - why did a client steal?");
+ } else {
+ // Drop the active camera
+ pActiveCamera->forceShutdown();
+ pRecord->activeInstance = nullptr;
+ }
+ }
+
+ return Void();
+}
+
+
+Return<sp<IEvsDisplay>> EvsEnumerator::openDisplay() {
+ ALOGD("openDisplay");
+
+ // If we already have a display active, then we need to shut it down so we can
+ // give exclusive access to the new caller.
+ sp<EvsDisplay> pActiveDisplay = sActiveDisplay.promote();
+ if (pActiveDisplay != nullptr) {
+ ALOGW("Killing previous display because of new caller");
+ closeDisplay(pActiveDisplay);
+ }
+
+ // Create a new display interface and return it
+ pActiveDisplay = new EvsDisplay();
+ sActiveDisplay = pActiveDisplay;
+
+ ALOGD("Returning new EvsDisplay object %p", pActiveDisplay.get());
+ return pActiveDisplay;
+}
+
+
+Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay>& pDisplay) {
+ ALOGD("closeDisplay");
+
+ // Do we still have a display object we think should be active?
+ sp<EvsDisplay> pActiveDisplay = sActiveDisplay.promote();
+ if (pActiveDisplay == nullptr) {
+ ALOGE("Somehow a display is being destroyed when the enumerator didn't know one existed");
+ } else if (sActiveDisplay != pDisplay) {
+ ALOGW("Ignoring close of previously orphaned display - why did a client steal?");
+ } else {
+ // Drop the active display
+ pActiveDisplay->forceShutdown();
+ sActiveDisplay = nullptr;
+ }
+
+ return Void();
+}
+
+
+Return<DisplayState> EvsEnumerator::getDisplayState() {
+ ALOGD("getDisplayState");
+
+ // Do we still have a display object we think should be active?
+ sp<IEvsDisplay> pActiveDisplay = sActiveDisplay.promote();
+ if (pActiveDisplay != nullptr) {
+ return pActiveDisplay->getDisplayState();
+ } else {
+ return DisplayState::NOT_OPEN;
+ }
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+Return<void> EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) {
+ ALOGD("getCameraList");
+
+ const unsigned numCameras = sCameraList.size();
+
+ // Build up a packed array of CameraDesc for return
+ // NOTE: Only has to live until the callback returns
+ std::vector<CameraDesc_1_1> descriptions;
+ descriptions.reserve(numCameras);
+ for (const auto& cam : sCameraList) {
+ descriptions.push_back( cam.desc );
+ }
+
+ // Encapsulate our camera descriptions in the HIDL vec type
+ hidl_vec<CameraDesc_1_1> hidlCameras(descriptions);
+
+ // Send back the results
+ ALOGD("reporting %zu cameras available", hidlCameras.size());
+ _hidl_cb(hidlCameras);
+
+ // HIDL convention says we return Void if we sent our result back via callback
+ return Void();
+}
+
+Return<sp<IEvsCamera_1_1>>
+EvsEnumerator::openCamera_1_1(const hidl_string& cameraId,
+ const Stream& streamCfg) {
+ // Find the named camera
+ CameraRecord *pRecord = nullptr;
+ for (auto &&cam : sCameraList) {
+ if (cam.desc.v1.cameraId == cameraId) {
+ // Found a match!
+ pRecord = &cam;
+ break;
+ }
+ }
+
+ // Is this a recognized camera id?
+ if (!pRecord) {
+ ALOGE("Requested camera %s not found", cameraId.c_str());
+ return nullptr;
+ }
+
+ // Has this camera already been instantiated by another caller?
+ sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+ if (pActiveCamera != nullptr) {
+ ALOGW("Killing previous camera because of new caller");
+ closeCamera(pActiveCamera);
+ }
+
+ // Construct a camera instance for the caller
+ if (sConfigManager == nullptr) {
+ pActiveCamera = EvsCamera::Create(cameraId.c_str());
+ } else {
+ pActiveCamera = EvsCamera::Create(cameraId.c_str(),
+ sConfigManager->getCameraInfo(cameraId),
+ &streamCfg);
+ }
+
+ pRecord->activeInstance = pActiveCamera;
+ if (pActiveCamera == nullptr) {
+ ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
+ }
+
+ return pActiveCamera;
+}
+
+
+EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) {
+ // Find the named camera
+ CameraRecord *pRecord = nullptr;
+ for (auto &&cam : sCameraList) {
+ if (cam.desc.v1.cameraId == cameraId) {
+ // Found a match!
+ pRecord = &cam;
+ break;
+ }
+ }
+
+ return pRecord;
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h
new file mode 100644
index 0000000..475ec76
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsEnumerator.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
+
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+
+#include <list>
+
+#include "ConfigManager.h"
+
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using ::android::hardware::automotive::evs::V1_0::DisplayState;
+using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+class EvsCamera; // from EvsCamera.h
+class EvsDisplay; // from EvsDisplay.h
+
+
+class EvsEnumerator : public IEvsEnumerator {
+public:
+ // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
+ Return<void> getCameraList(getCameraList_cb _hidl_cb) override;
+ Return<sp<IEvsCamera_1_0>> openCamera(const hidl_string& cameraId) override;
+ Return<void> closeCamera(const ::android::sp<IEvsCamera_1_0>& carCamera) override;
+ Return<sp<IEvsDisplay>> openDisplay() override;
+ Return<void> closeDisplay(const ::android::sp<IEvsDisplay>& display) override;
+ Return<DisplayState> getDisplayState() override;
+
+ // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+ Return<void> getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override;
+ Return<sp<IEvsCamera_1_1>> openCamera_1_1(const hidl_string& cameraId,
+ const Stream& streamCfg) override;
+
+ // Implementation details
+ EvsEnumerator();
+
+private:
+ // NOTE: All members values are static so that all clients operate on the same state
+ // That is to say, this is effectively a singleton despite the fact that HIDL
+ // constructs a new instance for each client.
+ struct CameraRecord {
+ CameraDesc_1_1 desc;
+ wp<EvsCamera> activeInstance;
+
+ CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; }
+ };
+
+ static CameraRecord* findCameraById(const std::string& cameraId);
+
+ static std::list<CameraRecord> sCameraList;
+
+ // Weak pointer. Object destructs if client dies.
+ static wp<EvsDisplay> sActiveDisplay;
+
+ static unique_ptr<ConfigManager> sConfigManager;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
diff --git a/automotive/evs/1.1/default/ServiceNames.h b/automotive/evs/1.1/default/ServiceNames.h
new file mode 100644
index 0000000..1178da5
--- /dev/null
+++ b/automotive/evs/1.1/default/ServiceNames.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const static char kEnumeratorServiceName[] = "EvsEnumeratorHw";
diff --git a/automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc b/automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc
new file mode 100644
index 0000000..284b3fd
--- /dev/null
+++ b/automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc
@@ -0,0 +1,5 @@
+service vendor.evs-hal-mock /vendor/bin/hw/android.hardware.automotive.evs@1.1-service
+ class hal
+ user automotive_evs
+ group automotive_evs
+ disabled
diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
new file mode 100644
index 0000000..a79e7c2
--- /dev/null
+++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
@@ -0,0 +1,91 @@
+<?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.
+-->
+
+<!-- Exterior View System Example Configuration
+
+ Android Automotive axes are used to define coordinates.
+ See https://source.android.com/devices/sensors/sensor-types#auto_axes
+
+ Use evs_configuration.dtd with xmllint tool, to validate XML configuration file
+-->
+
+<configuration>
+ <!-- system configuration -->
+ <system>
+ <!-- number of cameras available to EVS -->
+ <num_cameras value='1'/>
+ </system>
+
+ <!-- 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>
+ <!-- list of supported controls -->
+ <supported_controls>
+ <control name='BRIGHTNESS' min='0' max='255'/>
+ <control name='CONTRAST' min='0' max='255'/>
+ </supported_controls>
+
+ <stream id='0' width='640' height='360' format='RGBA_8888' framerate='30'/>
+ </caps>
+
+ <!-- list of parameters -->
+ <characteristics>
+ <!-- Camera intrinsic calibration matrix. See
+ https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+ -->
+ <parameter
+ name='LENS_INTRINSIC_CALIBRATION'
+ type='float'
+ size='5'
+ value='0.0,0.0,0.0,0.0,0.0'
+ />
+ </characteristics>
+ </device>
+ </camera>
+ <display>
+ <device id='display0' position='driver'>
+ <caps>
+ <!-- list of supported inpu stream configurations -->
+ <stream id='0' width='1280' height='720' format='RGBA_8888' framerate='30'/>
+ </caps>
+ </device>
+ </display>
+</configuration>
+
diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp
new file mode 100644
index 0000000..5135864
--- /dev/null
+++ b/automotive/evs/1.1/default/service.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.automotive.evs@1.1-service"
+
+#include <unistd.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "ServiceNames.h"
+#include "EvsEnumerator.h"
+#include "EvsDisplay.h"
+
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::automotive::evs::V1_1::IEvsEnumerator;
+using android::hardware::automotive::evs::V1_0::IEvsDisplay;
+
+// The namespace in which all our implementation code lives
+using namespace android::hardware::automotive::evs::V1_1::implementation;
+using namespace android;
+
+
+int main() {
+ ALOGI("EVS Hardware Enumerator service is starting");
+ android::sp<IEvsEnumerator> service = new EvsEnumerator();
+
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ // Register our service -- if somebody is already registered by our name,
+ // they will be killed (their thread pool will throw an exception).
+ status_t status = service->registerAsService(kEnumeratorServiceName);
+ if (status == OK) {
+ ALOGD("%s is ready.", kEnumeratorServiceName);
+ joinRpcThreadpool();
+ } else {
+ ALOGE("Could not register service %s (%d).", kEnumeratorServiceName, status);
+ }
+
+ // In normal operation, we don't expect the thread pool to exit
+ ALOGE("EVS Hardware Enumerator is shutting down");
+ return 1;
+}
diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal
new file mode 100644
index 0000000..f88d223
--- /dev/null
+++ b/automotive/evs/1.1/types.hal
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.evs@1.1;
+
+import @1.0::CameraDesc;
+import @1.0::DisplayDesc;
+import @1.0::DisplayState;
+import @1.0::EvsResult;
+import android.hardware.graphics.common@1.2::HardwareBuffer;
+import android.hardware.camera.device@3.2::CameraMetadata;
+
+/**
+ * Structure describing the basic properties of an EVS camera, extended from its
+ * v1.0 declaration.
+ *
+ * The HAL is responsible for filling out this structure for each
+ * EVS camera in the system.
+ */
+struct CameraDesc {
+ @1.0::CameraDesc v1;
+ /**
+ * Store camera metadata such as lens characteristics.
+ */
+ CameraMetadata metadata;
+};
+
+/**
+ * Structure representing an image buffer through our APIs
+ *
+ * In addition to the handle to the graphics memory, we need to retain
+ * the properties of the buffer for easy reference and reconstruction of
+ * an ANativeWindowBuffer object on the remote side of API calls.
+ * (Not least because OpenGL expect an ANativeWindowBuffer* for us as a
+ * texture via eglCreateImageKHR().
+ */
+struct BufferDesc {
+ /**
+ * HIDL counterpart of `AHardwareBuffer_Desc`. Please see
+ * hardware/interfaces/graphics/common/1.2/types.hal for more details.
+ */
+ HardwareBuffer buffer;
+ /**
+ * The size of a pixel in the units of bytes
+ */
+ uint32_t pixelSize;
+ /**
+ * Opaque value from driver
+ */
+ uint32_t bufferId;
+ /**
+ * Unique identifier of the physical camera device that produces this buffer.
+ */
+ string deviceId;
+ /**
+ * Time that this buffer is being filled.
+ */
+ int64_t timestamp;
+};
+
+/**
+ * Types of informative streaming events
+ */
+enum EvsEventType : uint32_t {
+ /**
+ * Video stream is started
+ */
+ STREAM_STARTED = 0,
+ /**
+ * Video stream is stopped
+ */
+ STREAM_STOPPED,
+ /**
+ * Video frame is dropped
+ */
+ FRAME_DROPPED,
+ /**
+ * Timeout happens
+ */
+ TIMEOUT,
+ /**
+ * Camera parameter is changed; payload contains a changed parameter ID and
+ * its value
+ */
+ PARAMETER_CHANGED,
+ /**
+ * Master role has become available
+ */
+ MASTER_RELEASED,
+};
+
+/**
+ * Structure that describes informative events occurred during EVS is streaming
+ */
+struct EvsEventDesc {
+ /**
+ * Type of an informative event
+ */
+ EvsEventType aType;
+ /**
+ * Device identifier
+ */
+ string deviceId;
+ /**
+ * Possible additional information
+ */
+ uint32_t[4] payload;
+};
+
+/**
+ * EVS Camera Parameter
+ */
+enum CameraParam : uint32_t {
+ /**
+ * The brightness of image frames
+ */
+ BRIGHTNESS,
+ /**
+ * The contrast of image frames
+ */
+ CONTRAST,
+ /**
+ * Automatic gain/exposure control
+ */
+ AUTOGAIN,
+ /**
+ * Gain control
+ */
+ GAIN,
+ /**
+ * Automatic Whitebalance
+ */
+ AUTO_WHITE_BALANCE,
+ /**
+ * Manual white balance setting as a color temperature in Kelvin.
+ */
+ WHITE_BALANCE_TEMPERATURE,
+ /**
+ * Image sharpness adjustment
+ */
+ SHARPNESS,
+ /**
+ * Auto Exposure Control modes; auto, manual, shutter priority, or
+ * aperture priority.
+ */
+ AUTO_EXPOSURE,
+ /**
+ * Manual exposure time of the camera
+ */
+ ABSOLUTE_EXPOSURE,
+ /**
+ * Set the focal point of the camera to the specified position. This
+ * parameter may not be effective when auto focus is enabled.
+ */
+ ABSOLUTE_FOCUS,
+ /**
+ * Enables continuous automatic focus adjustments.
+ */
+ AUTO_FOCUS,
+ /**
+ * Specify the objective lens focal length as an absolute value.
+ */
+ ABSOLUTE_ZOOM,
+};
diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..4753933
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalEvsV1_1TargetTest",
+ srcs: [
+ "FrameHandler.cpp",
+ "VtsHalEvsV1_1TargetTest.cpp",
+ ],
+ defaults: ["VtsHalTargetTestDefaults"],
+ shared_libs: [
+ "libui",
+ "libcamera_metadata",
+ ],
+ static_libs: [
+ "android.hardware.automotive.evs@1.0",
+ "android.hardware.automotive.evs@1.1",
+ "android.hardware.automotive.evs@common-default-lib",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.camera.device@3.2",
+ ],
+ test_suites: ["general-tests"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
new file mode 100644
index 0000000..ebf488a
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalEvsTest"
+
+#include "FrameHandler.h"
+#include "FormatConvert.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <chrono>
+
+#include <android/log.h>
+#include <cutils/native_handle.h>
+#include <ui/GraphicBuffer.h>
+
+using namespace std::chrono_literals;
+
+FrameHandler::FrameHandler(android::sp <IEvsCamera> pCamera, CameraDesc cameraInfo,
+ android::sp <IEvsDisplay> pDisplay,
+ BufferControlFlag mode) :
+ mCamera(pCamera),
+ mCameraInfo(cameraInfo),
+ mDisplay(pDisplay),
+ mReturnMode(mode) {
+ // Nothing but member initialization here...
+}
+
+
+void FrameHandler::shutdown()
+{
+ // Make sure we're not still streaming
+ blockingStopStream();
+
+ // At this point, the receiver thread is no longer running, so we can safely drop
+ // our remote object references so they can be freed
+ mCamera = nullptr;
+ mDisplay = nullptr;
+}
+
+
+bool FrameHandler::startStream() {
+ // Tell the camera to start streaming
+ Return<EvsResult> result = mCamera->startVideoStream(this);
+ if (result != EvsResult::OK) {
+ return false;
+ }
+
+ // Mark ourselves as running
+ mLock.lock();
+ mRunning = true;
+ mLock.unlock();
+
+ return true;
+}
+
+
+void FrameHandler::asyncStopStream() {
+ // Tell the camera to stop streaming.
+ // This will result in a null frame being delivered when the stream actually stops.
+ mCamera->stopVideoStream();
+}
+
+
+void FrameHandler::blockingStopStream() {
+ // Tell the stream to stop
+ asyncStopStream();
+
+ // Wait until the stream has actually stopped
+ std::unique_lock<std::mutex> lock(mEventLock);
+ if (mRunning) {
+ mEventSignal.wait(lock, [this]() { return !mRunning; });
+ }
+}
+
+
+bool FrameHandler::returnHeldBuffer() {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ // Return the oldest buffer we're holding
+ if (mHeldBuffers.empty()) {
+ // No buffers are currently held
+ return false;
+ }
+
+ hidl_vec<BufferDesc_1_1> buffers = mHeldBuffers.front();
+ mHeldBuffers.pop();
+ mCamera->doneWithFrame_1_1(buffers);
+
+ return true;
+}
+
+
+bool FrameHandler::isRunning() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return mRunning;
+}
+
+
+void FrameHandler::waitForFrameCount(unsigned frameCount) {
+ // Wait until we've seen at least the requested number of frames (could be more)
+ std::unique_lock<std::mutex> lock(mLock);
+ mFrameSignal.wait(lock, [this, frameCount](){
+ return mFramesReceived >= frameCount;
+ });
+}
+
+
+void FrameHandler::getFramesCounters(unsigned* received, unsigned* displayed) {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ if (received) {
+ *received = mFramesReceived;
+ }
+ if (displayed) {
+ *displayed = mFramesDisplayed;
+ }
+}
+
+
+Return<void> FrameHandler::deliverFrame(const BufferDesc_1_0& bufferArg) {
+ ALOGW("A frame delivered via v1.0 method is rejected.");
+ mCamera->doneWithFrame(bufferArg);
+ return Void();
+}
+
+
+Return<void> FrameHandler::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 *>(&buffer.buffer.description);
+ ALOGD("Received a frame from the camera (%p)",
+ buffer.buffer.nativeHandle.getNativeHandle());
+
+ // Store a dimension of a received frame.
+ mFrameWidth = pDesc->width;
+ mFrameHeight = pDesc->height;
+
+ // If we were given an opened display at construction time, then send the received
+ // image back down the camera.
+ bool displayed = false;
+ if (mDisplay.get()) {
+ // Get the output buffer we'll use to display the imagery
+ BufferDesc_1_0 tgtBuffer = {};
+ mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
+ tgtBuffer = buff;
+ }
+ );
+
+ if (tgtBuffer.memHandle == nullptr) {
+ printf("Didn't get target buffer - frame lost\n");
+ ALOGE("Didn't get requested output buffer -- skipping this frame.");
+ } else {
+ // Copy the contents of the of buffer.memHandle into tgtBuffer
+ copyBufferContents(tgtBuffer, buffer);
+
+ // Send the target buffer back for display
+ Return<EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
+ if (!result.isOk()) {
+ printf("HIDL error on display buffer (%s)- frame lost\n",
+ result.description().c_str());
+ ALOGE("Error making the remote function call. HIDL said %s",
+ result.description().c_str());
+ } else if (result != EvsResult::OK) {
+ printf("Display reported error - frame lost\n");
+ ALOGE("We encountered error %d when returning a buffer to the display!",
+ (EvsResult) result);
+ } else {
+ // Everything looks good!
+ // Keep track so tests or watch dogs can monitor progress
+ 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(buffers);
+ break;
+ case eNoAutoReturn:
+ // Hang onto the buffer handles for now -- the client will return it explicitly later
+ mHeldBuffers.push(buffers);
+ break;
+ }
+
+ ALOGD("Frame handling complete");
+
+ return Void();
+}
+
+
+Return<void> FrameHandler::notify(const EvsEventDesc& event) {
+ // Local flag we use to keep track of when the stream is stopping
+ 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;
+ } else if (mLatestEventDesc.aType == EvsEventType::PARAMETER_CHANGED) {
+ ALOGD("Camera parameter 0x%X is changed to 0x%X",
+ mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]);
+ } else {
+ ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
+ }
+ lock.unlock();
+ mEventSignal.notify_one();
+
+ return Void();
+}
+
+
+bool FrameHandler::copyBufferContents(const BufferDesc_1_0& tgtBuffer,
+ const BufferDesc_1_1& srcBuffer) {
+ bool success = true;
+ const AHardwareBuffer_Desc* pSrcDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc *>(&srcBuffer.buffer.description);
+
+ // Make sure we don't run off the end of either buffer
+ const unsigned width = std::min(tgtBuffer.width,
+ pSrcDesc->width);
+ const unsigned height = std::min(tgtBuffer.height,
+ pSrcDesc->height);
+
+ sp<android::GraphicBuffer> tgt = new android::GraphicBuffer(tgtBuffer.memHandle,
+ android::GraphicBuffer::CLONE_HANDLE,
+ tgtBuffer.width,
+ tgtBuffer.height,
+ tgtBuffer.format,
+ 1,
+ tgtBuffer.usage,
+ tgtBuffer.stride);
+ sp<android::GraphicBuffer> src = new android::GraphicBuffer(srcBuffer.buffer.nativeHandle,
+ android::GraphicBuffer::CLONE_HANDLE,
+ pSrcDesc->width,
+ pSrcDesc->height,
+ pSrcDesc->format,
+ pSrcDesc->layers,
+ pSrcDesc->usage,
+ pSrcDesc->stride);
+
+ // Lock our source buffer for reading (current expectation are for this to be NV21 format)
+ uint8_t* srcPixels = nullptr;
+ src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
+
+ // Lock our target buffer for writing (should be either RGBA8888 or BGRA8888 format)
+ uint32_t* tgtPixels = nullptr;
+ tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
+
+ if (srcPixels && tgtPixels) {
+ using namespace ::android::hardware::automotive::evs::common;
+ if (tgtBuffer.format == HAL_PIXEL_FORMAT_RGBA_8888) {
+ if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21
+ Utils::copyNV21toRGB32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
+ } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
+ Utils::copyYV12toRGB32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
+ } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
+ Utils::copyYUYVtoRGB32(width, height,
+ srcPixels, pSrcDesc->stride,
+ tgtPixels, tgtBuffer.stride);
+ } else if (pSrcDesc->format == tgtBuffer.format) { // 32bit RGBA
+ Utils::copyMatchedInterleavedFormats(width, height,
+ srcPixels, pSrcDesc->stride,
+ tgtPixels, tgtBuffer.stride,
+ tgtBuffer.pixelSize);
+ } else {
+ ALOGE("Camera buffer format is not supported");
+ success = false;
+ }
+ } else if (tgtBuffer.format == HAL_PIXEL_FORMAT_BGRA_8888) {
+ if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21
+ Utils::copyNV21toBGR32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
+ } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
+ Utils::copyYV12toBGR32(width, height,
+ srcPixels,
+ tgtPixels, tgtBuffer.stride);
+ } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
+ Utils::copyYUYVtoBGR32(width, height,
+ srcPixels, pSrcDesc->stride,
+ tgtPixels, tgtBuffer.stride);
+ } else if (pSrcDesc->format == tgtBuffer.format) { // 32bit RGBA
+ Utils::copyMatchedInterleavedFormats(width, height,
+ srcPixels, pSrcDesc->stride,
+ tgtPixels, tgtBuffer.stride,
+ tgtBuffer.pixelSize);
+ } else {
+ ALOGE("Camera buffer format is not supported");
+ success = false;
+ }
+ } else {
+ // We always expect 32 bit RGB for the display output for now. Is there a need for 565?
+ ALOGE("Diplay buffer is always expected to be 32bit RGBA");
+ success = false;
+ }
+ } else {
+ ALOGE("Failed to lock buffer contents for contents transfer");
+ success = false;
+ }
+
+ if (srcPixels) {
+ src->unlock();
+ }
+ if (tgtPixels) {
+ tgt->unlock();
+ }
+
+ return success;
+}
+
+void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) {
+ if (width) {
+ *width = mFrameWidth;
+ }
+
+ if (height) {
+ *height = mFrameHeight;
+ }
+}
+
+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(mEventLock);
+ auto now = std::chrono::system_clock::now();
+ 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;
+ }
+ );
+
+ if (!result) {
+ ALOGW("A timer is expired before a target event has happened.");
+ break;
+ }
+ }
+
+ return found;
+}
+
+const char *FrameHandler::eventToString(const EvsEventType aType) {
+ switch (aType) {
+ case EvsEventType::STREAM_STARTED:
+ return "STREAM_STARTED";
+ case EvsEventType::STREAM_STOPPED:
+ return "STREAM_STOPPED";
+ case EvsEventType::FRAME_DROPPED:
+ return "FRAME_DROPPED";
+ case EvsEventType::TIMEOUT:
+ return "TIMEOUT";
+ case EvsEventType::PARAMETER_CHANGED:
+ return "PARAMETER_CHANGED";
+ case EvsEventType::MASTER_RELEASED:
+ return "MASTER_RELEASED";
+ default:
+ return "Unknown";
+ }
+}
+
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h
new file mode 100644
index 0000000..21e85fe
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EVS_VTS_FRAMEHANDLER_H
+#define EVS_VTS_FRAMEHANDLER_H
+
+#include <queue>
+
+#include <FrameHandler.h>
+
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
+using ::android::sp;
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+
+
+/*
+ * FrameHandler:
+ * This class can be used to receive camera imagery from an IEvsCamera implementation. Given an
+ * IEvsDisplay instance at startup, it will forward the received imagery to the display,
+ * providing a trivial implementation of a rear vew camera type application.
+ * Note that the video frames are delivered on a background thread, while the control interface
+ * is actuated from the applications foreground thread.
+ */
+class FrameHandler : public IEvsCameraStream {
+public:
+ enum BufferControlFlag {
+ eAutoReturn,
+ eNoAutoReturn,
+ };
+
+ FrameHandler(android::sp <IEvsCamera> pCamera, CameraDesc cameraInfo,
+ android::sp <IEvsDisplay> pDisplay = nullptr,
+ BufferControlFlag mode = eAutoReturn);
+ virtual ~FrameHandler() {
+ if (mCamera != nullptr) {
+ /* shutdown a camera explicitly */
+ shutdown();
+ }
+ }
+
+ void shutdown();
+
+ bool startStream();
+ void asyncStopStream();
+ void blockingStopStream();
+
+ bool returnHeldBuffer();
+
+ bool isRunning();
+
+ void waitForFrameCount(unsigned frameCount);
+ bool waitForEvent(const EvsEventDesc& aTargetEvent,
+ EvsEventDesc& aReceivedEvent,
+ bool ignorePayload = false);
+ void getFramesCounters(unsigned* received, unsigned* displayed);
+ void getFrameDimension(unsigned* width, unsigned* height);
+
+private:
+ // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream
+ Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
+
+ // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
+ 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);
+ const char *eventToString(const EvsEventType aType);
+
+ // Values initialized as startup
+ android::sp <IEvsCamera> mCamera;
+ CameraDesc mCameraInfo;
+ android::sp <IEvsDisplay> mDisplay;
+ BufferControlFlag mReturnMode;
+
+ // Since we get frames delivered to us asynchronously via the IEvsCameraStream interface,
+ // we need to protect all member variables that may be modified while we're streaming
+ // (ie: those below)
+ std::mutex mLock;
+ std::mutex mEventLock;
+ std::condition_variable mEventSignal;
+ std::condition_variable mFrameSignal;
+ std::queue<hidl_vec<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;
+ EvsEventDesc mLatestEventDesc;
+};
+
+
+#endif //EVS_VTS_FRAMEHANDLER_H
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
new file mode 100644
index 0000000..4fc4e4c
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -0,0 +1,2194 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalEvsTest"
+
+
+// Note: We have't got a great way to indicate which target
+// should be tested, so we'll leave the interface served by the
+// default (mock) EVS driver here for easy reference. All
+// actual EVS drivers should serve on the EvsEnumeratorHw name,
+// however, so the code is checked in that way.
+//const static char kEnumeratorName[] = "EvsEnumeratorHw-Mock";
+const static char kEnumeratorName[] = "EvsEnumeratorHw";
+
+
+// These values are called out in the EVS design doc (as of Mar 8, 2017)
+static const int kMaxStreamStartMilliseconds = 500;
+static const int kMinimumFramesPerSecond = 10;
+
+static const int kSecondsToMilliseconds = 1000;
+static const int kMillisecondsToMicroseconds = 1000;
+static const float kNanoToMilliseconds = 0.000001f;
+static const float kNanoToSeconds = 0.000000001f;
+
+
+#include "FrameHandler.h"
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <thread>
+#include <unordered_set>
+
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/ProcessState.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include <android/log.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <system/camera_metadata.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::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;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+
+/*
+ * Plese note that this is different from what is defined in
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+const size_t kStreamCfgSz = 5;
+typedef struct {
+ int32_t width;
+ int32_t height;
+ int32_t format;
+ int32_t direction;
+ int32_t framerate;
+} RawStreamConfig;
+
+
+// Test environment for Evs HIDL HAL.
+class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static EvsHidlEnvironment* Instance() {
+ static EvsHidlEnvironment* instance = new EvsHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<IEvsEnumerator>(); }
+
+ private:
+ EvsHidlEnvironment() {}
+};
+
+// The main test class for EVS
+class EvsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+public:
+ virtual void SetUp() override {
+ // Make sure we can connect to the enumerator
+ string service_name =
+ EvsHidlEnvironment::Instance()->getServiceName<IEvsEnumerator>(kEnumeratorName);
+ pEnumerator = getService<IEvsEnumerator>(service_name);
+ ASSERT_NE(pEnumerator.get(), nullptr);
+
+ mIsHwModule = !service_name.compare(kEnumeratorName);
+ }
+
+ virtual void TearDown() override {
+ // 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() {
+ // SetUp() must run first!
+ assert(pEnumerator != nullptr);
+
+ // Get the camera list
+ pEnumerator->getCameraList_1_1(
+ [this](hidl_vec <CameraDesc> cameraList) {
+ ALOGI("Camera list callback received %zu cameras",
+ cameraList.size());
+ cameraInfo.reserve(cameraList.size());
+ for (auto&& cam: cameraList) {
+ ALOGI("Found camera %s", cam.v1.cameraId.c_str());
+ cameraInfo.push_back(cam);
+ }
+ }
+ );
+
+ // We insist on at least one camera for EVS to pass any camera tests
+ ASSERT_GE(cameraInfo.size(), 1u);
+ }
+
+ 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.
+};
+
+
+// Test cases, their implementations, and corresponding requirements are
+// documented at go/aae-evs-public-api-test.
+
+/*
+ * CameraOpenClean:
+ * Opens each camera reported by the enumerator and then explicitly closes it via a
+ * call to closeCamera. Then repeats the test to ensure all cameras can be reopened.
+ */
+TEST_F(EvsHidlTest, CameraOpenClean) {
+ ALOGI("Starting CameraOpenClean test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
+ // 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());
+ EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+ }
+ );
+
+ // Explicitly close the camera so resources are released right away
+ pEnumerator->closeCamera(pCam);
+ }
+ }
+}
+
+
+/*
+ * CameraOpenAggressive:
+ * Opens each camera reported by the enumerator twice in a row without an intervening closeCamera
+ * call. This ensures that the intended "aggressive open" behavior works. This is necessary for
+ * the system to be tolerant of shutdown/restart race conditions.
+ */
+TEST_F(EvsHidlTest, CameraOpenAggressive) {
+ ALOGI("Starting CameraOpenAggressive test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
+ // 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());
+ EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+ }
+ );
+
+ sp<IEvsCamera_1_1> pCam2 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+ .withDefault(nullptr);
+ 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.
+ EXPECT_EQ(EvsResult::OWNERSHIP_LOST, EvsResult(result));
+ } else {
+ // default implementation supports multiple clients.
+ EXPECT_EQ(EvsResult::OK, EvsResult(result));
+ }
+
+ // Close the superceded camera
+ pEnumerator->closeCamera(pCam);
+
+ // Verify that the second camera instance self-identifies correctly
+ pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) {
+ ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+ EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+ }
+ );
+
+ // Close the second camera instance
+ pEnumerator->closeCamera(pCam2);
+ }
+
+ // Sleep here to ensure the destructor cleanup has time to run so we don't break follow on tests
+ sleep(1); // I hate that this is an arbitrary time to wait. :( b/36122635
+}
+
+
+/*
+ * CameraStreamPerformance:
+ * Measure and qualify the stream start up time and streaming frame rate of each reported camera
+ */
+TEST_F(EvsHidlTest, CameraStreamPerformance) {
+ ALOGI("Starting CameraStreamPerformance test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
+ // 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,
+ FrameHandler::eAutoReturn);
+
+ // Start the camera's video stream
+ nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ bool startResult = frameHandler->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Ensure the first frame arrived within the expected time
+ frameHandler->waitForFrameCount(1);
+ nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t timeToFirstFrame = systemTime(SYSTEM_TIME_MONOTONIC) - start;
+
+ // 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;
+ frameHandler->getFrameDimension(&width, &height);
+ EXPECT_GE(width, height);
+
+ // Wait a bit, then ensure we get at least the required minimum number of frames
+ sleep(5);
+ nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // 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
+ nsecs_t runTime = end - firstFrame;
+ float framesPerSecond = framesReceived / (runTime * kNanoToSeconds);
+ printf("Measured camera rate %3.2f fps\n", framesPerSecond);
+ ALOGI("Measured camera rate %3.2f fps", framesPerSecond);
+ EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond);
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam);
+ }
+}
+
+
+/*
+ * CameraStreamBuffering:
+ * Ensure the camera implementation behaves properly when the client holds onto buffers for more
+ * than one frame time. The camera must cleanly skip frames until the client is ready again.
+ */
+TEST_F(EvsHidlTest, CameraStreamBuffering) {
+ ALOGI("Starting CameraStreamBuffering test");
+
+ // Arbitrary constant (should be > 1 and less than crazy)
+ static const unsigned int kBuffersToHold = 6;
+
+ // Get the camera list
+ loadCameraList();
+
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
+ // 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);
+
+ // Now ask for exactly two buffers in flight as we'll test behavior in that case
+ Return<EvsResult> goodResult = pCam->setMaxFramesInFlight(kBuffersToHold);
+ EXPECT_EQ(EvsResult::OK, goodResult);
+
+
+ // Set up a frame receiver object which will fire up its own thread.
+ sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+ nullptr,
+ FrameHandler::eNoAutoReturn);
+
+ // Start the camera's video stream
+ bool startResult = frameHandler->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Check that the video stream stalls once we've gotten exactly the number of buffers
+ // we requested since we told the frameHandler not to return them.
+ sleep(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";
+
+
+ // Give back one buffer
+ bool didReturnBuffer = frameHandler->returnHeldBuffer();
+ EXPECT_TRUE(didReturnBuffer);
+
+ // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one
+ // filled since we require 10fps minimum -- but give a 10% allowance just in case.
+ usleep(110 * kMillisecondsToMicroseconds);
+ frameHandler->getFramesCounters(&framesReceived, nullptr);
+ EXPECT_EQ(kBuffersToHold+1, framesReceived) << "Stream should've resumed";
+
+ // Even when the camera pointer goes out of scope, the FrameHandler object will
+ // keep the stream alive unless we tell it to shutdown.
+ // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+ // we have to break that cycle in order for either of them to get cleaned up.
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam);
+ }
+}
+
+
+/*
+ * CameraToDisplayRoundTrip:
+ * End to end test of data flowing from the camera to the display. Each delivered frame of camera
+ * imagery is simply copied to the display buffer and presented on screen. This is the one test
+ * which a human could observe to see the operation of the system on the physical display.
+ */
+TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) {
+ ALOGI("Starting CameraToDisplayRoundTrip test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
+ // Request exclusive access to the EVS display
+ sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+ ASSERT_NE(pDisplay, nullptr);
+
+ // 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,
+ FrameHandler::eAutoReturn);
+
+
+ // Activate the display
+ pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+
+ // Start the camera's video stream
+ bool startResult = frameHandler->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Wait a while to let the data flow
+ static const int kSecondsToWait = 5;
+ const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds -
+ kMaxStreamStartMilliseconds;
+ const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond /
+ kSecondsToMilliseconds;
+ sleep(kSecondsToWait);
+ unsigned framesReceived = 0;
+ unsigned framesDisplayed = 0;
+ frameHandler->getFramesCounters(&framesReceived, &framesDisplayed);
+ EXPECT_EQ(framesReceived, framesDisplayed);
+ EXPECT_GE(framesDisplayed, minimumFramesExpected);
+
+ // Turn off the display (yes, before the stream stops -- it should be handled)
+ pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
+
+ // Shut down the streamer
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam);
+ }
+
+ // Explicitly release the display
+ pEnumerator->closeDisplay(pDisplay);
+}
+
+
+/*
+ * MultiCameraStream:
+ * Verify that each client can start and stop video streams on the same
+ * underlying camera.
+ */
+TEST_F(EvsHidlTest, MultiCameraStream) {
+ ALOGI("Starting MultiCameraStream test");
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
+ // 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,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandler0, nullptr);
+
+ sp<FrameHandler> frameHandler1 = new FrameHandler(pCam1, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandler1, nullptr);
+
+ // Start the camera's video stream via client 0
+ bool startResult = false;
+ startResult = frameHandler0->startStream() &&
+ frameHandler1->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Ensure the stream starts
+ frameHandler0->waitForFrameCount(1);
+ frameHandler1->waitForFrameCount(1);
+
+ nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // Wait a bit, then ensure both clients get at least the required minimum number of frames
+ sleep(5);
+ nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+ unsigned framesReceived0 = 0, framesReceived1 = 0;
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+ framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for
+ framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for
+ nsecs_t runTime = end - firstFrame;
+ float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
+ float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
+ ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
+ EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
+ EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
+
+ // Shutdown one client
+ frameHandler0->shutdown();
+
+ // Read frame counters again
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+
+ // Wait a bit again
+ sleep(5);
+ unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0;
+ frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr);
+ EXPECT_EQ(framesReceived0, framesReceivedAfterStop0);
+ EXPECT_LT(framesReceived1, framesReceivedAfterStop1);
+
+ // Shutdown another
+ frameHandler1->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam0);
+ pEnumerator->closeCamera(pCam1);
+
+ // 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);
+ }
+}
+
+
+/*
+ * CameraParameter:
+ * Verify that a client can adjust a camera parameter.
+ */
+TEST_F(EvsHidlTest, CameraParameter) {
+ ALOGI("Starting CameraParameter test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
+ // 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) {
+ cmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ cmds.push_back(cmd);
+ }
+ }
+ );
+
+ if (cmds.size() < 1) {
+ continue;
+ }
+
+ // Set up per-client frame receiver objects which will fire up its own thread
+ sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandler, nullptr);
+
+ // Start the camera's video stream
+ bool startResult = frameHandler->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Ensure the stream starts
+ frameHandler->waitForFrameCount(1);
+
+ result = pCam->setMaster();
+ ASSERT_EQ(EvsResult::OK, result);
+
+ for (auto &cmd : cmds) {
+ // Get a valid parameter value range
+ int32_t minVal, maxVal, step;
+ pCam->getIntParameterRange(
+ cmd,
+ [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+ minVal = val0;
+ maxVal = val1;
+ step = val2;
+ }
+ );
+
+ EvsResult result = EvsResult::OK;
+ if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ std::vector<int32_t> values;
+ pCam->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);
+ }
+ }
+
+ // Try to program a parameter with a random value [minVal, maxVal]
+ int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
+ std::vector<int32_t> values;
+
+ // Rounding down
+ val0 = val0 - (val0 % step);
+ pCam->setIntParameter(cmd, val0,
+ [&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);
+
+ values.clear();
+ pCam->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.";
+ }
+ }
+
+ result = pCam->unsetMaster();
+ ASSERT_EQ(EvsResult::OK, result);
+
+ // Shutdown
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam);
+ }
+}
+
+
+/*
+ * CameraMasterRelease
+ * Verify that non-master client gets notified when the master client either
+ * terminates or releases a role.
+ */
+TEST_F(EvsHidlTest, CameraMasterRelease) {
+ ALOGI("Starting CameraMasterRelease test");
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
+ // 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,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandlerMaster, nullptr);
+ sp<FrameHandler> frameHandlerNonMaster =
+ new FrameHandler(pCamNonMaster, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandlerNonMaster, nullptr);
+
+ // Set one client as the master
+ EvsResult result = pCamMaster->setMaster();
+ ASSERT_TRUE(result == EvsResult::OK);
+
+ // Try to set another client as the master.
+ result = pCamNonMaster->setMaster();
+ ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+
+ // Start the camera's video stream via a master client.
+ bool startResult = frameHandlerMaster->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Ensure the stream starts
+ frameHandlerMaster->waitForFrameCount(1);
+
+ // Start the camera's video stream via another client
+ startResult = frameHandlerNonMaster->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Ensure the stream starts
+ frameHandlerNonMaster->waitForFrameCount(1);
+
+ // Non-master client expects to receive a master role relesed
+ // notification.
+ 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();
+
+ // Join a listening thread.
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Verify change notifications.
+ ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+ static_cast<EvsEventType>(aNotification.aType));
+
+ // Non-master becomes a master.
+ result = pCamNonMaster->setMaster();
+ ASSERT_TRUE(result == EvsResult::OK);
+
+ // Previous master client fails to become a master.
+ 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();
+
+ // Join a listening thread.
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Verify change notifications.
+ ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+ static_cast<EvsEventType>(aNotification.aType));
+
+ // Closing streams.
+ frameHandlerMaster->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCamMaster);
+ pEnumerator->closeCamera(pCamNonMaster);
+ }
+}
+
+
+/*
+ * MultiCameraParameter:
+ * Verify that master and non-master clients behave as expected when they try to adjust
+ * camera parameters.
+ */
+TEST_F(EvsHidlTest, MultiCameraParameter) {
+ ALOGI("Starting MultiCameraParameter test");
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
+ // 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) {
+ camMasterCmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ camMasterCmds.push_back(cmd);
+ }
+ }
+ );
+
+ pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec<CameraParam> cmdList) {
+ camNonMasterCmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ camNonMasterCmds.push_back(cmd);
+ }
+ }
+ );
+
+ if (camMasterCmds.size() < 1 ||
+ camNonMasterCmds.size() < 1) {
+ // Skip a camera device if it does not support any parameter.
+ continue;
+ }
+
+ // Set up per-client frame receiver objects which will fire up its own thread
+ sp<FrameHandler> frameHandlerMaster =
+ new FrameHandler(pCamMaster, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandlerMaster, nullptr);
+ sp<FrameHandler> frameHandlerNonMaster =
+ new FrameHandler(pCamNonMaster, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandlerNonMaster, nullptr);
+
+ // Set one client as the master
+ EvsResult result = pCamMaster->setMaster();
+ ASSERT_EQ(EvsResult::OK, result);
+
+ // Try to set another client as the master.
+ result = pCamNonMaster->setMaster();
+ ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
+
+ // Start the camera's video stream via a master client.
+ bool startResult = frameHandlerMaster->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Ensure the stream starts
+ frameHandlerMaster->waitForFrameCount(1);
+
+ // Start the camera's video stream via another client
+ startResult = frameHandlerNonMaster->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Ensure the stream starts
+ frameHandlerNonMaster->waitForFrameCount(1);
+
+ int32_t val0 = 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;
+ pCamMaster->getIntParameterRange(
+ cmd,
+ [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+ minVal = val0;
+ maxVal = val1;
+ step = val2;
+ }
+ );
+
+ EvsResult result = EvsResult::OK;
+ if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ values.clear();
+ pCamMaster->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);
+ }
+ }
+
+ // Calculate a parameter value to program.
+ val0 = minVal + (std::rand() % (maxVal - minVal));
+ 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, &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(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);
+ 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, &values](auto status, auto effectiveValues) {
+ result = status;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
+ });
+ ASSERT_EQ(EvsResult::INVALID_ARG, result);
+
+ // Non-master client attemps to be a master
+ result = pCamNonMaster->setMaster();
+ 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, &values](auto status, auto effectiveValues) {
+ result = status;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
+ });
+ ASSERT_EQ(EvsResult::INVALID_ARG, result);
+
+ // Non-master client becomes a master
+ result = pCamNonMaster->setMaster();
+ ASSERT_EQ(EvsResult::OK, result);
+
+ // Try to adjust a parameter via new master client
+ for (auto &cmd : camNonMasterCmds) {
+ // Get a valid parameter value range
+ int32_t minVal, maxVal, step;
+ pCamNonMaster->getIntParameterRange(
+ cmd,
+ [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+ minVal = val0;
+ maxVal = val1;
+ step = val2;
+ }
+ );
+
+ EvsResult result = EvsResult::OK;
+ values.clear();
+ if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+ // Try to turn off auto-focus
+ values.clear();
+ pCamNonMaster->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);
+ }
+ }
+
+ // Calculate a parameter value to program. This is being rounding down.
+ val0 = minVal + (std::rand() % (maxVal - minVal));
+ 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, &values](auto status, auto effectiveValues) {
+ result = status;
+ if (status == EvsResult::OK) {
+ for (auto &&v : effectiveValues) {
+ values.push_back(v);
+ }
+ }
+ });
+ ASSERT_EQ(EvsResult::OK, result);
+
+ // 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
+ 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]));
+ }
+ }
+
+ // New master retires from a master role
+ result = pCamNonMaster->unsetMaster();
+ ASSERT_EQ(EvsResult::OK, result);
+
+ // Shutdown
+ frameHandlerMaster->shutdown();
+ frameHandlerNonMaster->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCamMaster);
+ pEnumerator->closeCamera(pCamNonMaster);
+ }
+}
+
+
+/*
+ * HighPriorityCameraClient:
+ * EVS client, which owns the display, is priortized and therefore can take over
+ * a master role from other EVS clients without the display.
+ */
+TEST_F(EvsHidlTest, HighPriorityCameraClient) {
+ ALOGI("Starting HighPriorityCameraClient test");
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Using null stream configuration makes EVS uses the default resolution and
+ // output format.
+ Stream nullCfg = {};
+
+ // Request exclusive access to the EVS display
+ sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+ ASSERT_NE(pDisplay, nullptr);
+
+ // 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;
+ pCam0->getParameterList([&cam0Cmds](hidl_vec<CameraParam> cmdList) {
+ cam0Cmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ cam0Cmds.push_back(cmd);
+ }
+ }
+ );
+
+ pCam1->getParameterList([&cam1Cmds](hidl_vec<CameraParam> cmdList) {
+ cam1Cmds.reserve(cmdList.size());
+ for (auto &&cmd : cmdList) {
+ cam1Cmds.push_back(cmd);
+ }
+ }
+ );
+ if (cam0Cmds.size() < 1 || cam1Cmds.size() < 1) {
+ // Cannot execute this test.
+ return;
+ }
+
+ // Set up a frame receiver object which will fire up its own thread.
+ sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
+ pDisplay,
+ FrameHandler::eAutoReturn);
+ sp<FrameHandler> frameHandler1 = new FrameHandler(pCam1, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+
+ // Activate the display
+ pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+
+ // Start the camera's video stream
+ ASSERT_TRUE(frameHandler0->startStream());
+ ASSERT_TRUE(frameHandler1->startStream());
+
+ // Ensure the stream starts
+ frameHandler0->waitForFrameCount(1);
+ frameHandler1->waitForFrameCount(1);
+
+ // Client 1 becomes a master and programs a parameter.
+ EvsResult result = EvsResult::OK;
+ // Get a valid parameter value range
+ int32_t minVal, maxVal, step;
+ pCam1->getIntParameterRange(
+ cam1Cmds[0],
+ [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+ minVal = val0;
+ maxVal = val1;
+ step = val2;
+ }
+ );
+
+ // 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, &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(val0, v);
+ }
+
+ // Join a listener
+ if (listener.joinable()) {
+ listener.join();
+ }
+
+ // Verify a change notification
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::PARAMETER_CHANGED);
+ ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+ cam1Cmds[0]);
+ 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));
+
+ // 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));
+
+ // 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
+ values.clear();
+ pCam0->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);
+ }
+
+ 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, &values](auto status, auto effectiveValues) {
+ result = status;
+ 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
+ ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+ EvsEventType::PARAMETER_CHANGED);
+ ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+ cam0Cmds[0]);
+ 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);
+
+ // Shut down the streamer
+ frameHandler0->shutdown();
+ frameHandler1->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam0);
+ pEnumerator->closeCamera(pCam1);
+ }
+
+ // Explicitly release the display
+ pEnumerator->closeDisplay(pDisplay);
+}
+
+
+/*
+ * CameraUseStreamConfigToDisplay:
+ * End to end test of data flowing from the camera to the display. Similar to
+ * CameraToDisplayRoundTrip test case but this case retrieves available stream
+ * configurations from EVS and uses one of them to start a video stream.
+ */
+TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) {
+ ALOGI("Starting CameraUseStreamConfigToDisplay test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Request exclusive access to the EVS display
+ sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+ ASSERT_NE(pDisplay, nullptr);
+
+ // Test each reported camera
+ for (auto&& cam: cameraInfo) {
+ activeCameras.clear();
+ // choose a configuration that has a frame rate faster than minReqFps.
+ Stream targetCfg = {};
+ const int32_t minReqFps = 15;
+ int32_t maxArea = 0;
+ camera_metadata_entry_t streamCfgs;
+ bool foundCfg = false;
+ if (!find_camera_metadata_entry(
+ reinterpret_cast<camera_metadata_t *>(cam.metadata.data()),
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ &streamCfgs)) {
+ // Stream configurations are found in metadata
+ RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+ for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+ if (ptr->width * ptr->height > maxArea &&
+ ptr->framerate >= minReqFps) {
+ targetCfg.width = ptr->width;
+ targetCfg.height = ptr->height;
+
+ maxArea = ptr->width * ptr->height;
+ foundCfg = true;
+ }
+ }
+ ++ptr;
+ }
+ }
+ targetCfg.format =
+ static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+ if (!foundCfg) {
+ // Current EVS camera does not provide stream configurations in the
+ // metadata.
+ continue;
+ }
+
+ sp<IEvsCamera_1_1> pCam =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+ .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,
+ FrameHandler::eAutoReturn);
+
+
+ // Activate the display
+ pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+
+ // Start the camera's video stream
+ bool startResult = frameHandler->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Wait a while to let the data flow
+ static const int kSecondsToWait = 5;
+ const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds -
+ kMaxStreamStartMilliseconds;
+ const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond /
+ kSecondsToMilliseconds;
+ sleep(kSecondsToWait);
+ unsigned framesReceived = 0;
+ unsigned framesDisplayed = 0;
+ frameHandler->getFramesCounters(&framesReceived, &framesDisplayed);
+ EXPECT_EQ(framesReceived, framesDisplayed);
+ EXPECT_GE(framesDisplayed, minimumFramesExpected);
+
+ // Turn off the display (yes, before the stream stops -- it should be handled)
+ pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
+
+ // Shut down the streamer
+ frameHandler->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam);
+ }
+
+ // Explicitly release the display
+ pEnumerator->closeDisplay(pDisplay);
+}
+
+
+/*
+ * MultiCameraStreamUseConfig:
+ * Verify that each client can start and stop video streams on the same
+ * underlying camera with same configuration.
+ */
+TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) {
+ ALOGI("Starting MultiCameraStream test");
+
+ if (mIsHwModule) {
+ // This test is not for HW module implementation.
+ return;
+ }
+
+ // Get the camera list
+ loadCameraList();
+
+ // Test each reported camera
+ for (auto&& cam: cameraInfo) {
+ activeCameras.clear();
+ // choose a configuration that has a frame rate faster than minReqFps.
+ Stream targetCfg = {};
+ const int32_t minReqFps = 15;
+ int32_t maxArea = 0;
+ camera_metadata_entry_t streamCfgs;
+ bool foundCfg = false;
+ if (!find_camera_metadata_entry(
+ reinterpret_cast<camera_metadata_t *>(cam.metadata.data()),
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ &streamCfgs)) {
+ // Stream configurations are found in metadata
+ RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+ for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+ if (ptr->width * ptr->height > maxArea &&
+ ptr->framerate >= minReqFps) {
+ targetCfg.width = ptr->width;
+ targetCfg.height = ptr->height;
+
+ maxArea = ptr->width * ptr->height;
+ foundCfg = true;
+ }
+ }
+ ++ptr;
+ }
+ }
+ targetCfg.format =
+ static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+ if (!foundCfg) {
+ ALOGI("Device %s does not provide a list of supported stream configurations, skipped",
+ cam.v1.cameraId.c_str());
+
+ continue;
+ }
+
+ // Create the first camera client with a selected stream configuration.
+ sp<IEvsCamera_1_1> pCam0 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+ .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;
+ targetCfg.id += 1; // EVS manager sees only the stream id.
+ sp<IEvsCamera_1_1> pCam1 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+ .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 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam1, nullptr);
+
+ // Set up per-client frame receiver objects which will fire up its own thread
+ sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandler0, nullptr);
+
+ sp<FrameHandler> frameHandler1 = new FrameHandler(pCam1, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+ ASSERT_NE(frameHandler1, nullptr);
+
+ // Start the camera's video stream via client 0
+ bool startResult = false;
+ startResult = frameHandler0->startStream() &&
+ frameHandler1->startStream();
+ ASSERT_TRUE(startResult);
+
+ // Ensure the stream starts
+ frameHandler0->waitForFrameCount(1);
+ frameHandler1->waitForFrameCount(1);
+
+ nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // Wait a bit, then ensure both clients get at least the required minimum number of frames
+ sleep(5);
+ nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+ unsigned framesReceived0 = 0, framesReceived1 = 0;
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+ framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for
+ framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for
+ nsecs_t runTime = end - firstFrame;
+ float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
+ float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
+ ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
+ EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
+ EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
+
+ // Shutdown one client
+ frameHandler0->shutdown();
+
+ // Read frame counters again
+ frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+
+ // Wait a bit again
+ sleep(5);
+ unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0;
+ frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr);
+ frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr);
+ EXPECT_EQ(framesReceived0, framesReceivedAfterStop0);
+ EXPECT_LT(framesReceived1, framesReceivedAfterStop1);
+
+ // Shutdown another
+ frameHandler1->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam0);
+ pEnumerator->closeCamera(pCam1);
+ }
+}
+
+
+/*
+ * 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);
+ EvsHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/automotive/evs/common/utils/default/Android.bp b/automotive/evs/common/utils/default/Android.bp
new file mode 100644
index 0000000..776ef81
--- /dev/null
+++ b/automotive/evs/common/utils/default/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_library_static {
+ host_supported: true,
+ name: "android.hardware.automotive.evs@common-default-lib",
+ vendor_available: true,
+ relative_install_path: "hw",
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+ srcs: [
+ "FormatConvert.cpp"
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ ],
+}
diff --git a/automotive/evs/common/utils/default/FormatConvert.cpp b/automotive/evs/common/utils/default/FormatConvert.cpp
new file mode 100644
index 0000000..d4c7da0
--- /dev/null
+++ b/automotive/evs/common/utils/default/FormatConvert.cpp
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsHalEvsTest"
+
+#include "FormatConvert.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace common {
+
+// Round up to the nearest multiple of the given alignment value
+template<unsigned alignment>
+int Utils::align(int value) {
+ static_assert((alignment && !(alignment & (alignment - 1))),
+ "alignment must be a power of 2");
+
+ unsigned mask = alignment - 1;
+ return (value + mask) & ~mask;
+}
+
+
+// Limit the given value to the provided range. :)
+inline float Utils::clamp(float v, float min, float max) {
+ if (v < min) return min;
+ if (v > max) return max;
+ return v;
+}
+
+
+uint32_t Utils::yuvToRgbx(const unsigned char Y,
+ const unsigned char Uin,
+ const unsigned char Vin,
+ bool bgrxFormat) {
+ // Don't use this if you want to see the best performance. :)
+ // Better to do this in a pixel shader if we really have to, but on actual
+ // embedded hardware we expect to be able to texture directly from the YUV data
+ float U = Uin - 128.0f;
+ float V = Vin - 128.0f;
+
+ float Rf = Y + 1.140f*V;
+ float Gf = Y - 0.395f*U - 0.581f*V;
+ float Bf = Y + 2.032f*U;
+ unsigned char R = (unsigned char)clamp(Rf, 0.0f, 255.0f);
+ unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f);
+ unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f);
+
+ if (!bgrxFormat) {
+ return (R ) |
+ (G << 8) |
+ (B << 16) |
+ 0xFF000000; // Fill the alpha channel with ones
+ } else {
+ return (R << 16) |
+ (G << 8) |
+ (B ) |
+ 0xFF000000; // Fill the alpha channel with ones
+ }
+}
+
+
+void Utils::copyNV21toRGB32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels,
+ bool bgrxFormat)
+{
+ // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+ // U/V array. It assumes an even width and height for the overall image, and a horizontal
+ // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+ unsigned strideLum = align<16>(width);
+ unsigned sizeY = strideLum * height;
+ unsigned strideColor = strideLum; // 1/2 the samples, but two interleaved channels
+ unsigned offsetUV = sizeY;
+
+ uint8_t* srcY = src;
+ uint8_t* srcUV = src+offsetUV;
+
+ for (unsigned r = 0; r < height; r++) {
+ // Note that we're walking the same UV row twice for even/odd luminance rows
+ uint8_t* rowY = srcY + r*strideLum;
+ uint8_t* rowUV = srcUV + (r/2 * strideColor);
+
+ uint32_t* rowDest = dst + r*dstStridePixels;
+
+ for (unsigned c = 0; c < width; c++) {
+ unsigned uCol = (c & ~1); // uCol is always even and repeats 1:2 with Y values
+ unsigned vCol = uCol | 1; // vCol is always odd
+ rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol], bgrxFormat);
+ }
+ }
+}
+
+
+void Utils::copyYV12toRGB32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels,
+ bool bgrxFormat)
+{
+ // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
+ // by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image,
+ // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
+ // and V arrays.
+ unsigned strideLum = align<16>(width);
+ unsigned sizeY = strideLum * height;
+ unsigned strideColor = align<16>(strideLum/2);
+ unsigned sizeColor = strideColor * height/2;
+ unsigned offsetU = sizeY;
+ unsigned offsetV = sizeY + sizeColor;
+
+ uint8_t* srcY = src;
+ uint8_t* srcU = src+offsetU;
+ uint8_t* srcV = src+offsetV;
+
+ for (unsigned r = 0; r < height; r++) {
+ // Note that we're walking the same U and V rows twice for even/odd luminance rows
+ uint8_t* rowY = srcY + r*strideLum;
+ uint8_t* rowU = srcU + (r/2 * strideColor);
+ uint8_t* rowV = srcV + (r/2 * strideColor);
+
+ uint32_t* rowDest = dst + r*dstStridePixels;
+
+ for (unsigned c = 0; c < width; c++) {
+ rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c], bgrxFormat);
+ }
+ }
+}
+
+
+void Utils::copyYUYVtoRGB32(unsigned width, unsigned height,
+ uint8_t* src, unsigned srcStridePixels,
+ uint32_t* dst, unsigned dstStridePixels,
+ bool bgrxFormat)
+{
+ uint32_t* srcWords = (uint32_t*)src;
+
+ const int srcRowPadding32 = srcStridePixels/2 - width/2; // 2 bytes per pixel, 4 bytes per word
+ const int dstRowPadding32 = dstStridePixels - width; // 4 bytes per pixel, 4 bytes per word
+
+ for (unsigned r = 0; r < height; r++) {
+ for (unsigned c = 0; c < width/2; c++) {
+ // Note: we're walking two pixels at a time here (even/odd)
+ uint32_t srcPixel = *srcWords++;
+
+ uint8_t Y1 = (srcPixel) & 0xFF;
+ uint8_t U = (srcPixel >> 8) & 0xFF;
+ uint8_t Y2 = (srcPixel >> 16) & 0xFF;
+ uint8_t V = (srcPixel >> 24) & 0xFF;
+
+ // On the RGB output, we're writing one pixel at a time
+ *(dst+0) = yuvToRgbx(Y1, U, V, bgrxFormat);
+ *(dst+1) = yuvToRgbx(Y2, U, V, bgrxFormat);
+ dst += 2;
+ }
+
+ // Skip over any extra data or end of row alignment padding
+ srcWords += srcRowPadding32;
+ dst += dstRowPadding32;
+ }
+}
+
+
+void Utils::copyNV21toBGR32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels)
+{
+ return copyNV21toRGB32(width, height, src, dst, dstStridePixels, true);
+}
+
+
+void Utils::copyYV12toBGR32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels)
+{
+ return copyYV12toRGB32(width, height, src, dst, dstStridePixels, true);
+}
+
+
+void Utils::copyYUYVtoBGR32(unsigned width, unsigned height,
+ uint8_t* src, unsigned srcStridePixels,
+ uint32_t* dst, unsigned dstStridePixels)
+{
+ return copyYUYVtoRGB32(width, height, src, srcStridePixels, dst, dstStridePixels, true);
+}
+
+
+void Utils::copyMatchedInterleavedFormats(unsigned width, unsigned height,
+ void* src, unsigned srcStridePixels,
+ void* dst, unsigned dstStridePixels,
+ unsigned pixelSize) {
+ for (unsigned row = 0; row < height; row++) {
+ // Copy the entire row of pixel data
+ memcpy(dst, src, width * pixelSize);
+
+ // Advance to the next row (keeping in mind that stride here is in units of pixels)
+ src = (uint8_t*)src + srcStridePixels * pixelSize;
+ dst = (uint8_t*)dst + dstStridePixels * pixelSize;
+ }
+}
+
+} // namespace common
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
diff --git a/automotive/evs/common/utils/default/include/FormatConvert.h b/automotive/evs/common/utils/default/include/FormatConvert.h
new file mode 100644
index 0000000..2bb8955
--- /dev/null
+++ b/automotive/evs/common/utils/default/include/FormatConvert.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EVS_VTS_FORMATCONVERT_H
+#define EVS_VTS_FORMATCONVERT_H
+
+#include <queue>
+#include <stdint.h>
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace common {
+
+class Utils {
+public:
+ // Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx/BGRx
+ // values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+ // U/V array. It assumes an even width and height for the overall image, and a horizontal
+ // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+ static void copyNV21toRGB32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels,
+ bool bgrxFormat = false);
+
+ static void copyNV21toBGR32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels);
+
+
+ // Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx/BGRx values.
+ // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
+ // by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image,
+ // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
+ // and V arrays.
+ static void copyYV12toRGB32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels,
+ bool bgrxFormat = false);
+
+ static void copyYV12toBGR32(unsigned width, unsigned height,
+ uint8_t* src,
+ uint32_t* dst, unsigned dstStridePixels);
+
+ // Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx/BGRx
+ // values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+ // U/V array. It assumes an even width and height for the overall image, and a horizontal
+ // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+ static void copyYUYVtoRGB32(unsigned width, unsigned height,
+ uint8_t* src, unsigned srcStrideBytes,
+ uint32_t* dst, unsigned dstStrideBytes,
+ bool bgrxFormat = false);
+
+ static void copyYUYVtoBGR32(unsigned width, unsigned height,
+ uint8_t* src, unsigned srcStrideBytes,
+ uint32_t* dst, unsigned dstStrideBytes);
+
+
+ // Given an simple rectangular image buffer with an integer number of bytes per pixel,
+ // copy the pixel values into a new rectangular buffer (potentially with a different stride).
+ // This is typically used to copy RGBx data into an RGBx output buffer.
+ static void copyMatchedInterleavedFormats(unsigned width, unsigned height,
+ void* src, unsigned srcStridePixels,
+ void* dst, unsigned dstStridePixels,
+ unsigned pixelSize);
+
+private:
+ template<unsigned alignment>
+ static int align(int value);
+
+ static inline float clamp(float v, float min, float max);
+ static uint32_t yuvToRgbx(const unsigned char Y,
+ const unsigned char Uin,
+ const unsigned char Vin,
+ bool bgrxFormat = false);
+};
+
+} // namespace common
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // EVS_VTS_FORMATCONVERT_H
diff --git a/automotive/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
new file mode 100644
index 0000000..face235
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/Android.bp
@@ -0,0 +1,18 @@
+aidl_interface {
+ name: "android.hardware.automotive.occupant_awareness",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/automotive/occupant_awareness/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ },
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl
new file mode 100644
index 0000000..8597ddb
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.occupant_awareness;
+
+@VintfStability
+@Backing(type="byte")
+enum ConfidenceLevel {
+ /**
+ * No prediction could be made.
+ */
+ NONE,
+ /**
+ * Best-guess, low-confidence prediction. Predictions exceeding this threshold are adequate
+ * for non-critical applications.
+ */
+ LOW,
+ /**
+ * High-confidence prediction. Predictions exceeding this threshold are adequate for
+ * applications that require reliable predictions.
+ */
+ HIGH,
+ /**
+ * Highest confidence rate achievable.
+ */
+ MAX,
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl
new file mode 100644
index 0000000..f5cc9d5
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl
@@ -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.
+ */
+
+package android.hardware.automotive.occupant_awareness;
+
+import android.hardware.automotive.occupant_awareness.ConfidenceLevel;
+
+@VintfStability
+parcelable DriverMonitoringDetection {
+ /*
+ * Confidence of the computed attention data.
+ */
+ ConfidenceLevel confidenceScore;
+ /*
+ * Is the driver currently looking on-road?
+ */
+ boolean isLookingOnRoad;
+ /*
+ * Duration the driver has been looking on or off road, in milliseconds.
+ */
+ long gazeDurationMillis;
+}
+
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/GazeDetection.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/GazeDetection.aidl
new file mode 100644
index 0000000..fc36e13
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/GazeDetection.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.occupant_awareness;
+
+import android.hardware.automotive.occupant_awareness.VehicleRegion;
+import android.hardware.automotive.occupant_awareness.ConfidenceLevel;
+
+@VintfStability
+parcelable GazeDetection {
+ /*
+ * Confidence level for the gaze detection.
+ */
+ ConfidenceLevel gazeConfidence;
+ /*
+ * Head position, in millimeters. The vehicle coordinate system is specified in the cabin space
+ * configuration. headPosition is double[3] array.
+ */
+ double[] headPosition;
+ /*
+ * Unit vector for the head pose direction. The vehicle coordinate system is specified in the
+ * cabin space configuration. headAngleUnitVector is double[3] array.
+ */
+ double[] headAngleUnitVector;
+ /*
+ * Unit vector for the gaze direction. The vehicle coordinate system is specified in the cabin
+ * space configuration. gazeAngleUnitVector is double[3] array.
+ */
+ double[] gazeAngleUnitVector;
+ /*
+ * Current gaze target.
+ */
+ VehicleRegion gazeTarget;
+ /*
+ * Custom gaze target string. This only need to be populated when gazeTarget is CUSTOM_TARGET.
+ * Vendors should use "com.vendor_name.target_name" format to avoid name collision with other
+ * vendors.
+ */
+ String customGazeTarget;
+ /*
+ * Duration that the subject has been looking at the current gaze target in milliseconds.
+ */
+ long timeOnTargetMillis;
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl
new file mode 100644
index 0000000..1df0bda
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl
@@ -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.
+ */
+
+package android.hardware.automotive.occupant_awareness;
+
+import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus;
+import android.hardware.automotive.occupant_awareness.Role;
+import android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback;
+import android.hardware.automotive.occupant_awareness.OccupantDetections;
+
+@VintfStability
+interface IOccupantAwareness {
+ /*
+ * System not able to generate any occupancy awareness.
+ */
+ const int CAP_NONE = 0;
+ /*
+ * System is able to detect the presence of humans.
+ */
+ const int CAP_PRESENCE_DETECTION = 1 << 0;
+ /*
+ * System is able to detect the gaze of humans.
+ */
+ const int CAP_GAZE_DETECTION = 1 << 1;
+ /*
+ * System is able to compute the attention details of humans.
+ */
+ const int CAP_DRIVER_MONITORING_DETECTION = 1 << 2;
+
+ /**
+ * Starts the occupant awareness detection system. This is a non-blocking function call.
+ * Once system is ready, state will be modified. State update can be inrquired using callback
+ * or getState() function.
+ * @return status is the current system state.
+ */
+ OccupantAwarenessStatus startDetection();
+
+ /**
+ * Stops the occupant awareness detection system. This is a non-blocking function call.
+ * Once system is reset, state will be modified. State update can be inrquired using callback
+ * or getState() function.
+ * @return status is the current system state.
+ */
+ OccupantAwarenessStatus stopDetection();
+
+ /**
+ * Returns list of Awareness Capability supported for the given type of occupants.
+ *
+ * @param out Bitwise OR of supported capabilities (CAP_* mask).
+ */
+ int getCapabilityForRole(in Role occupantRole);
+
+ /**
+ * Inquires the current state of the occupant awareness system.
+ * @param occupantRole specifies the role of occupants of interest.
+ * @param detectionCapability specifies a single detection capability (CAP_* ) of interest.
+ *
+ * @return status is the current system state.
+ */
+ OccupantAwarenessStatus getState(in Role occupantRole, in int detectionCapability);
+
+ /**
+ * Registers a callback for data streaming. Only single callback is supported. setCallback()
+ * should replace existing callback with new callback.
+ * @return: returns ok if successful.
+ */
+ void setCallback(in IOccupantAwarenessClientCallback callback);
+
+ /**
+ * Returns the most recent set of detections.
+ * @param OccupantDetections output detections.
+ * @return returns ok if successful.
+ */
+ void getLatestDetection(out OccupantDetections detections);
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl
new file mode 100644
index 0000000..69f7b0b
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.occupant_awareness;
+
+import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus;
+import android.hardware.automotive.occupant_awareness.OccupantDetections;
+
+@VintfStability
+interface IOccupantAwarenessClientCallback {
+ /**
+ * A callback invoked when the system status changes.
+ *
+ * @param detectionFlags The detection subsystem(s) whose status has changed.
+ * @param status The new system status.
+ */
+ oneway void onSystemStatusChanged(in int detectionFlags, in OccupantAwarenessStatus status);
+
+ /**
+ * A callback invoked when a new set of detections are available.
+ *
+ * @param detections Occupant detections.
+ */
+ oneway void onDetectionEvent(in OccupantDetections detections);
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl
new file mode 100644
index 0000000..6a3453d
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.occupant_awareness;
+
+@VintfStability
+@Backing(type="byte")
+enum OccupantAwarenessStatus {
+ /*
+ * System is online and ready to serve requests.
+ */
+ READY = 0,
+ /**
+ * Detection is not supported in this vehicle due to a permanent lack of capabilities. Clients
+ * need not retry.
+ */
+ NOT_SUPPORTED = 1,
+ /*
+ * The system has not yet been initialized. No requests can be served until the
+ * initialization process completes. This state does not indicate any error and
+ * clients should retry later.
+ */
+ NOT_INITIALIZED = 2,
+ /*
+ * A permanent failure has occurred. No detections will be provided.
+ */
+ FAILURE = 3,
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl
new file mode 100644
index 0000000..47ca35a
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl
@@ -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.
+ */
+
+package android.hardware.automotive.occupant_awareness;
+
+import android.hardware.automotive.occupant_awareness.Role;
+import android.hardware.automotive.occupant_awareness.PresenceDetection;
+import android.hardware.automotive.occupant_awareness.GazeDetection;
+import android.hardware.automotive.occupant_awareness.DriverMonitoringDetection;
+
+/*
+ * A complete detection for a single occupant in the vehicle. Includes data about the subject's
+ * presence in the vehicle, gaze and attention.
+ */
+ @VintfStability
+parcelable OccupantDetection {
+ /*
+ * Role of the occupant (e.g., driver, passenger).
+ */
+ Role role;
+ /*
+ * Occupant presence state for a single occupant.
+ * If the vector is empty, no data could be generated.
+ */
+ PresenceDetection[] presenceData;
+ /*
+ * Gaze data for a single occupant.
+ * If the vector is empty, no data could be generated.
+ */
+ GazeDetection[] gazeData;
+ /*
+ * Attention data for a single occupant.
+ * If the vector is empty, no data could be generated.
+ */
+ DriverMonitoringDetection[] attentionData;
+}
+
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl
new file mode 100644
index 0000000..e8f6621
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetections.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.automotive.occupant_awareness;
+
+import android.hardware.automotive.occupant_awareness.OccupantDetection;
+
+@VintfStability
+parcelable OccupantDetections {
+ /**
+ * Timestamp that the underlying source image was captured, in milliseconds since Jan 1, 1970
+ * (Unix time).
+ */
+ long timeStampMillis;
+ /**
+ * A vector of detections for all occupants in the vehicle. One OccupantDetection will be
+ * generated per detected face.
+ */
+ OccupantDetection[] detections;
+}
+
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl
new file mode 100644
index 0000000..a018106
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.occupant_awareness;
+
+@VintfStability
+parcelable PresenceDetection {
+ /*
+ * Boolean representing whether an occupant was detected.
+ */
+ boolean isOccupantDetected;
+ /**
+ * Duration that a particular occupant has been continuously
+ * detected, in milliseconds. Will be zero duration if the occupant is not
+ * currently detected.
+ */
+ long detectionDurationMillis;
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/Role.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/Role.aidl
new file mode 100644
index 0000000..42e86ad
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/Role.aidl
@@ -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.
+ */
+
+package android.hardware.automotive.occupant_awareness;
+
+@VintfStability
+@Backing(type="int")
+enum Role {
+ /*
+ * All valid role(s) must have at least 1 bit set.
+ */
+ INVALID = 0,
+ /*
+ * System could not determine role for this occupant.
+ */
+ UNKNOWN = 1 << 0,
+ /*
+ * Occupants that the system detects as front seat passengers.
+ */
+ FRONT_PASSENGER = 1 << 1,
+ /*
+ * Occupants that the system detects as driver(s).
+ */
+ DRIVER = 1 << 2,
+ /*
+ * Occupants on left seat of row 2.
+ */
+ ROW_2_PASSENGER_LEFT = 1 << 3,
+ /*
+ * Occupants on center seat of row 2.
+ */
+ ROW_2_PASSENGER_CENTER = 1 << 4,
+ /*
+ * Occupants on right seat of row 2.
+ */
+ ROW_2_PASSENGER_RIGHT = 1 << 5,
+ /*
+ * Occupants on left seat of row 3.
+ */
+ ROW_3_PASSENGER_LEFT = 1 << 6,
+ /*
+ * Occupants on center seat of row 3.
+ */
+ ROW_3_PASSENGER_CENTER = 1 << 7,
+ /*
+ * Occupants on right seat of row 3.
+ */
+ ROW_3_PASSENGER_RIGHT = 1 << 8,
+
+ /*
+ * Occupants that the system detects as front seat occupant.
+ * FRONT_OCCUPANTS = DRIVER | FRONT_PASSENGER
+ */
+ FRONT_OCCUPANTS = 1 << 1 | 1 << 2,
+ /*
+ * Occupants of row 2.
+ * ROW_2_OCCUPANTS = ROW_2_PASSENGER_LEFT | ROW_2_PASSENGER_CENTER | ROW_2_PASSENGER_RIGHT
+ */
+ ROW_2_OCCUPANTS = 1 << 3 | 1 << 4 | 1 << 5,
+ /*
+ * Occupants of row 3.
+ * ROW_3_OCCUPANTS = ROW_3_PASSENGER_LEFT | ROW_3_PASSENGER_CENTER | ROW_3_PASSENGER_RIGHT
+ */
+ ROW_3_OCCUPANTS = 1 << 6 | 1 << 7 | 1 << 8,
+ /*
+ * All the occupants in the vehicle.
+ * ALL_OCCUPANTS = UNKNOWN | FRONT_OCCUPANTS | ROW_2_OCCUPANTS | ROW_3_OCCUPANTS
+ */
+ ALL_OCCUPANTS = 0x1FF,
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl
new file mode 100644
index 0000000..9ee9d52
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.occupant_awareness;
+
+@VintfStability
+@Backing(type="int")
+enum VehicleRegion {
+ /*
+ * List of targets in the car.
+ */
+ UNKNOWN = 0,
+ INSTRUMENT_CLUSTER = 1,
+ REAR_VIEW_MIRROR = 2,
+ LEFT_SIDE_MIRROR = 3,
+ RIGHT_SIDE_MIRROR = 4,
+ FORWARD_ROADWAY = 5,
+ LEFT_ROADWAY = 6,
+ RIGHT_ROADWAY = 7,
+ HEAD_UNIT_DISPLAY = 8,
+ /*
+ * Vendors can use this value along with customGazeTarget string to uniquely identify their
+ * custom region.
+ */
+ CUSTOM_TARGET = 200,
+}
diff --git a/automotive/occupant_awareness/aidl/default/Android.bp b/automotive/occupant_awareness/aidl/default/Android.bp
new file mode 100644
index 0000000..1b2fba2
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/default/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",
+ init_rc: ["android.hardware.automotive.occupant_awareness@1.0-service.rc"],
+ relative_install_path: "hw",
+ vendor: true,
+ srcs: [
+ "service.cpp",
+ "OccupantAwareness.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libutils",
+ "android.hardware.automotive.occupant_awareness-ndk_platform",
+ ],
+}
diff --git a/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp b/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp
new file mode 100644
index 0000000..a156075
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 "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;
+
+ScopedAStatus OccupantAwareness::startDetection(OccupantAwarenessStatus* status) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mStatus != OccupantAwarenessStatus::NOT_SUPPORTED) {
+ mStatus = OccupantAwarenessStatus::NOT_SUPPORTED;
+ if (mCallback) {
+ mCallback->onSystemStatusChanged(kAllCapabilities,
+ OccupantAwarenessStatus::NOT_SUPPORTED);
+ }
+ }
+ *status = mStatus;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::stopDetection(OccupantAwarenessStatus* status) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mStatus != OccupantAwarenessStatus::NOT_INITIALIZED) {
+ mStatus = OccupantAwarenessStatus::NOT_INITIALIZED;
+ if (mCallback) {
+ mCallback->onSystemStatusChanged(kAllCapabilities,
+ OccupantAwarenessStatus::NOT_INITIALIZED);
+ }
+ }
+ *status = mStatus;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::getCapabilityForRole(Role occupantRole, int32_t* capabilities) {
+ if (!isValidRole(occupantRole)) {
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
+
+ // No awareness capability for default HAL.
+ *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);
+ }
+
+ 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) {
+ // No detection generated for default hal.
+ (void)detections;
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+}
+
+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 != 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;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace occupant_awareness
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/occupant_awareness/aidl/default/OccupantAwareness.h b/automotive/occupant_awareness/aidl/default/OccupantAwareness.h
new file mode 100644
index 0000000..ac51aa4
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/default/OccupantAwareness.h
@@ -0,0 +1,67 @@
+/*
+ * 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>
+#include <aidl/android/hardware/automotive/occupant_awareness/BnOccupantAwarenessClientCallback.h>
+#include <utils/StrongPointer.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 default HAL mimics a system which has no Occupant awareness capability. The hal does not
+ * do any useful work, and returns appropriate failure code / status.
+ **/
+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);
+
+ std::mutex mMutex;
+ std::shared_ptr<IOccupantAwarenessClientCallback> mCallback = nullptr;
+ OccupantAwarenessStatus mStatus = OccupantAwarenessStatus::NOT_INITIALIZED;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace occupant_awareness
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/occupant_awareness/aidl/default/android.hardware.automotive.occupant_awareness@1.0-service.rc b/automotive/occupant_awareness/aidl/default/android.hardware.automotive.occupant_awareness@1.0-service.rc
new file mode 100644
index 0000000..35d5bca
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/default/android.hardware.automotive.occupant_awareness@1.0-service.rc
@@ -0,0 +1,4 @@
+service hal_occupant_awareness_default /vendor/bin/hw/android.hardware.automotive.occupant_awareness@1.0-service
+ class hal
+ user system
+ group system
diff --git a/automotive/occupant_awareness/aidl/default/service.cpp b/automotive/occupant_awareness/aidl/default/service.cpp
new file mode 100644
index 0000000..44960fb
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/default/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"
+
+#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/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 ed09859..a94a37e 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -58,9 +58,11 @@
defaults: ["vhal_v2_0_defaults"],
srcs: [
"impl/vhal_v2_0/CommConn.cpp",
+ "impl/vhal_v2_0/EmulatedVehicleConnector.cpp",
"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",
@@ -80,6 +82,20 @@
],
}
+// VHal virtualization utils
+cc_library_static {
+ name: "android.hardware.automotive.vehicle@2.0-virtualization-utils",
+ vendor: true,
+ defaults: ["vhal_v2_0_defaults"],
+ srcs: [
+ "impl/vhal_v2_0/virtualization/Utils.cpp",
+ ],
+ export_include_dirs: ["impl"],
+ shared_libs: [
+ "libbase",
+ ],
+}
+
cc_test {
name: "android.hardware.automotive.vehicle@2.0-manager-unit-tests",
vendor: true,
@@ -97,6 +113,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"],
@@ -116,3 +147,59 @@
"libqemu_pipe",
],
}
+
+cc_binary {
+ name: "android.hardware.automotive.vehicle@2.0-virtualization-service",
+ defaults: ["vhal_v2_0_defaults"],
+ init_rc: ["android.hardware.automotive.vehicle@2.0-virtualization-service.rc"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp",
+ "VirtualizedVehicleService.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libjsoncpp",
+ "libprotobuf-cpp-full",
+ "libgrpc++",
+ ],
+ static_libs: [
+ "android.hardware.automotive.vehicle@2.0-manager-lib",
+ "android.hardware.automotive.vehicle@2.0-default-impl-lib",
+ "android.hardware.automotive.vehicle@2.0-grpc",
+ "android.hardware.automotive.vehicle@2.0-virtualization-utils",
+ "libqemu_pipe",
+ ],
+ cflags: [
+ "-Wno-unused-parameter"
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.automotive.vehicle@2.0-virtualization-grpc-server",
+ init_rc: ["android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc"],
+ defaults: ["vhal_v2_0_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp",
+ "VirtualizationGrpcServer.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libjsoncpp",
+ "libprotobuf-cpp-full",
+ "libgrpc++",
+ ],
+ static_libs: [
+ "android.hardware.automotive.vehicle@2.0-manager-lib",
+ "android.hardware.automotive.vehicle@2.0-default-impl-lib",
+ "android.hardware.automotive.vehicle@2.0-grpc",
+ "android.hardware.automotive.vehicle@2.0-virtualization-utils",
+ ],
+ cflags: [
+ "-Wno-unused-parameter"
+ ],
+}
diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp
index d1fd555..127eb98 100644
--- a/automotive/vehicle/2.0/default/VehicleService.cpp
+++ b/automotive/vehicle/2.0/default/VehicleService.cpp
@@ -20,8 +20,9 @@
#include <iostream>
-#include <vhal_v2_0/VehicleHalManager.h>
+#include <vhal_v2_0/EmulatedVehicleConnector.h>
#include <vhal_v2_0/EmulatedVehicleHal.h>
+#include <vhal_v2_0/VehicleHalManager.h>
using namespace android;
using namespace android::hardware;
@@ -29,9 +30,11 @@
int main(int /* argc */, char* /* argv */ []) {
auto store = std::make_unique<VehiclePropertyStore>();
- auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get());
+ auto connector = impl::makeEmulatedPassthroughConnector();
+ auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get());
auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
auto service = std::make_unique<VehicleHalManager>(hal.get());
+ connector->setValuePool(hal->getValuePool());
configureRpcThreadpool(4, true /* callerWillJoin */);
diff --git a/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp b/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp
new file mode 100644
index 0000000..cca65d9
--- /dev/null
+++ b/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp
@@ -0,0 +1,49 @@
+#include <android-base/logging.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include "vhal_v2_0/virtualization/GrpcVehicleServer.h"
+#include "vhal_v2_0/virtualization/Utils.h"
+
+int main(int argc, char* argv[]) {
+ namespace vhal_impl = android::hardware::automotive::vehicle::V2_0::impl;
+
+ vhal_impl::VsockServerInfo serverInfo;
+
+ // unique values to identify the options
+ constexpr int OPT_VHAL_SERVER_CID = 1001;
+ constexpr int OPT_VHAL_SERVER_PORT_NUMBER = 1002;
+
+ struct option longOptions[] = {
+ {"server_cid", 1, 0, OPT_VHAL_SERVER_CID},
+ {"server_port", 1, 0, OPT_VHAL_SERVER_PORT_NUMBER},
+ {nullptr, 0, nullptr, 0},
+ };
+
+ int optValue;
+ while ((optValue = getopt_long_only(argc, argv, ":", longOptions, 0)) != -1) {
+ switch (optValue) {
+ case OPT_VHAL_SERVER_CID:
+ serverInfo.serverCid = std::atoi(optarg);
+ LOG(DEBUG) << "Vehicle HAL server CID: " << serverInfo.serverCid;
+ break;
+ case OPT_VHAL_SERVER_PORT_NUMBER:
+ serverInfo.serverPort = std::atoi(optarg);
+ LOG(DEBUG) << "Vehicle HAL server port: " << serverInfo.serverPort;
+ break;
+ default:
+ // ignore other options
+ break;
+ }
+ }
+
+ if (serverInfo.serverCid == 0 || serverInfo.serverPort == 0) {
+ LOG(FATAL) << "Invalid server information, CID: " << serverInfo.serverCid
+ << "; port: " << serverInfo.serverPort;
+ // Will abort after logging
+ }
+
+ auto server = vhal_impl::makeGrpcVehicleServer(vhal_impl::getVsockUri(serverInfo));
+ server->Start();
+ return 0;
+}
diff --git a/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp b/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp
new file mode 100644
index 0000000..1de81ae
--- /dev/null
+++ b/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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 <hidl/HidlTransportSupport.h>
+
+#include <vhal_v2_0/EmulatedVehicleConnector.h>
+#include <vhal_v2_0/EmulatedVehicleHal.h>
+#include <vhal_v2_0/VehicleHalManager.h>
+#include <vhal_v2_0/virtualization/GrpcVehicleClient.h>
+#include <vhal_v2_0/virtualization/Utils.h>
+
+using namespace android;
+using namespace android::hardware;
+using namespace android::hardware::automotive::vehicle::V2_0;
+
+int main(int argc, char* argv[]) {
+ constexpr const char* VHAL_SERVER_CID_PROPERTY_KEY = "ro.vendor.vehiclehal.server.cid";
+ constexpr const char* VHAL_SERVER_PORT_PROPERTY_KEY = "ro.vendor.vehiclehal.server.port";
+
+ auto property_get_uint = [](const char* key, unsigned int default_value) {
+ auto value = property_get_int64(key, default_value);
+ if (value < 0 || value > UINT_MAX) {
+ LOG(DEBUG) << key << ": " << value << " is out of bound, using default value '"
+ << default_value << "' instead";
+ return default_value;
+ }
+ return static_cast<unsigned int>(value);
+ };
+
+ impl::VsockServerInfo serverInfo{property_get_uint(VHAL_SERVER_CID_PROPERTY_KEY, 0),
+ property_get_uint(VHAL_SERVER_PORT_PROPERTY_KEY, 0)};
+
+ if (serverInfo.serverCid == 0 || serverInfo.serverPort == 0) {
+ LOG(FATAL) << "Invalid server information, CID: " << serverInfo.serverCid
+ << "; port: " << serverInfo.serverPort;
+ // Will abort after logging
+ }
+
+ auto store = std::make_unique<VehiclePropertyStore>();
+ auto connector = impl::makeGrpcVehicleClient(impl::getVsockUri(serverInfo));
+ auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get());
+ auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
+ auto service = std::make_unique<VehicleHalManager>(hal.get());
+
+ configureRpcThreadpool(4, true /* callerWillJoin */);
+
+ LOG(INFO) << "Registering as service...";
+ status_t status = service->registerAsService();
+
+ if (status != OK) {
+ LOG(ERROR) << "Unable to register vehicle service (" << status << ")";
+ return 1;
+ }
+
+ LOG(INFO) << "Ready";
+ joinRpcThreadpool();
+
+ return 1;
+}
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc
new file mode 100644
index 0000000..29147ad
--- /dev/null
+++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc
@@ -0,0 +1,10 @@
+# It is an interim state to run GRPC server as an Android service.
+# Eventually it will run outside of Android (e.g., AGL),
+# so the command line arguments are expected, though not conventionally used in Android
+service vendor.vehicle-hal-2.0-server \
+ /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server \
+ -server_cid ${ro.vendor.vehiclehal.server.cid:-0} \
+ -server_port ${ro.vendor.vehiclehal.server.port:-0}
+ class hal
+ user vehicle_network
+ group system inet
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc
new file mode 100644
index 0000000..234de59
--- /dev/null
+++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc
@@ -0,0 +1,4 @@
+service vendor.vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-virtualization-service
+ class hal
+ user vehicle_network
+ group system inet
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
new file mode 100644
index 0000000..d40f122
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
@@ -0,0 +1,149 @@
+/*
+ * 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_VehicleConnector_H_
+#define android_hardware_automotive_vehicle_V2_0_VehicleConnector_H_
+
+#include <vector>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+/**
+ * This file defines the interface of client/server pair for HAL-vehicle
+ * communication. Vehicle HAL may use this interface to talk to the vehicle
+ * regardless of the underlying communication channels.
+ */
+
+/**
+ * Vehicle HAL talks to the vehicle through a client, instead of accessing
+ * the car bus directly, to give us more flexibility on the implementation.
+ * Android OS do not need direct access to the vehicle, and the communication
+ * channel is also customizable.
+ *
+ * Client lives on the Android (HAL) side to talk to the vehicle
+ */
+class IVehicleClient {
+ public:
+ IVehicleClient() = default;
+
+ IVehicleClient(const IVehicleClient&) = delete;
+
+ IVehicleClient& operator=(const IVehicleClient&) = delete;
+
+ IVehicleClient(IVehicleClient&&) = default;
+
+ virtual ~IVehicleClient() = default;
+
+ // Get configuration of all properties from server
+ virtual std::vector<VehiclePropConfig> getAllPropertyConfig() const = 0;
+
+ // Send the set property request to server
+ // 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
+ // 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;
+};
+
+/**
+ * Server lives on the vehicle side to talk to Android HAL
+ */
+class IVehicleServer {
+ public:
+ IVehicleServer() = default;
+
+ IVehicleServer(const IVehicleServer&) = delete;
+
+ IVehicleServer& operator=(const IVehicleServer&) = delete;
+
+ IVehicleServer(IVehicleServer&&) = default;
+
+ virtual ~IVehicleServer() = default;
+
+ // Receive the get property configuration request from HAL.
+ // Return a list of all property config
+ virtual std::vector<VehiclePropConfig> onGetAllPropertyConfig() const = 0;
+
+ // Receive the set property request from HAL.
+ // Process the setting and return the status code
+ // 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
+ // 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;
+};
+
+/**
+ * If Android has direct access to the vehicle, then the client and
+ * the server may act in passthrough mode to avoid extra IPC
+ *
+ * Template is used here for spliting the logic of operating Android objects (VehicleClientType),
+ * talking to cars (VehicleServerType) and the commucation between client and server (passthrough
+ * mode in this case), so that we can easily combine different parts together without duplicating
+ * codes (for example, in Google VHAL, the server talks to the fake car in the same way no matter
+ * if it is on top of passthrough connector or VSOCK or any other communication channels between
+ * client and server)
+ *
+ * The alternative may be factoring the common logic of every operations for both client and
+ * server. Which is not always the case. Making sure different non-template connectors calling
+ * the same method is hard, especially when the engineer maintaining the code may not be aware
+ * of it when making changes. Template is a clean and easy way to solve this problem in this
+ * case.
+ */
+template <typename VehicleClientType, typename VehicleServerType>
+class IPassThroughConnector : public VehicleClientType, public VehicleServerType {
+ static_assert(std::is_base_of_v<IVehicleClient, VehicleClientType>);
+ static_assert(std::is_base_of_v<IVehicleServer, VehicleServerType>);
+
+ public:
+ std::vector<VehiclePropConfig> getAllPropertyConfig() const override {
+ return this->onGetAllPropertyConfig();
+ }
+
+ StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override {
+ return this->onSetProperty(value, updateStatus);
+ }
+
+ void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override {
+ return this->onPropertyValue(value, updateStatus);
+ }
+
+ // To be implemented:
+ // virtual std::vector<VehiclePropConfig> onGetAllPropertyConfig() = 0;
+ // virtual void onPropertyValue(const VehiclePropValue& value) = 0;
+ // virtual StatusCode onSetProperty(const VehiclePropValue& value) = 0;
+};
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_VehicleConnector_H_
diff --git a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
index 94ace45..24b777c 100644
--- a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
@@ -50,12 +50,18 @@
VehiclePropValue* valueToUpdate = const_cast<VehiclePropValue*>(getValueOrNullLocked(recId));
if (valueToUpdate == nullptr) {
mPropertyValues.insert({ recId, propValue });
- } else {
- valueToUpdate->timestamp = propValue.timestamp;
- valueToUpdate->value = propValue.value;
- if (updateStatus) {
- valueToUpdate->status = propValue.status;
- }
+ return true;
+ }
+
+ // propValue is outdated and drops it.
+ if (valueToUpdate->timestamp > propValue.timestamp) {
+ return false;
+ }
+ // update the propertyValue.
+ valueToUpdate->timestamp = propValue.timestamp;
+ valueToUpdate->value = propValue.value;
+ if (updateStatus) {
+ valueToUpdate->status = propValue.status;
}
return true;
}
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/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 3070171..bf85da2 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -85,6 +85,34 @@
0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
/**
+ * This property is used for test purpose to set properties' value from vehicle.
+ * For example: Mocking hard button press triggering a HVAC fan speed change.
+ * Android set kSetPropertyFromVehcileForTest with an array of integer {HVAC_FAN_SPEED, value of
+ * fan speed} and a long value indicates the timestamp of the events .
+ * It only works with integer type properties.
+ */
+const int32_t kSetIntPropertyFromVehcileForTest =
+ 0x1112 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
+ * This property is used for test purpose to set properties' value from vehicle.
+ * It only works with float type properties.
+ */
+const int32_t kSetFloatPropertyFromVehcileForTest =
+ 0x1113 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
+ * This property is used for test purpose to set properties' value from vehicle.
+ * It only works with boolean type properties.
+ */
+const int32_t kSetBooleanPropertyFromVehcileForTest =
+ 0x1114 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+
+/**
+ * This property is used for test purpose. End to end tests use this property to test set and get
+ * method for MIXED type properties.
+ */
+const int32_t kMixedTypePropertyForTest =
+ 0x1111 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
* FakeDataCommand enum defines the supported command type for kGenerateFakeDataControllingProperty.
* All those commands can be send independently with each other. And each will override the one sent
* previously.
@@ -167,7 +195,6 @@
.prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.floatValues = {15000.0f}}},
@@ -177,14 +204,13 @@
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
},
- .initialValue = {.int32Values = {1}}},
+ .initialValue = {.int32Values = {(int)FuelType::FUEL_TYPE_UNLEADED}}},
{.config =
{
.prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.floatValues = {150000.0f}}},
@@ -194,14 +220,13 @@
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
},
- .initialValue = {.int32Values = {1}}},
+ .initialValue = {.int32Values = {(int)EvConnectorType::IEC_TYPE_1_AC}}},
{.config =
{
.prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {SEAT_1_LEFT}}},
@@ -210,7 +235,6 @@
.prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}},
@@ -219,7 +243,6 @@
.prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}},
@@ -232,6 +255,13 @@
.initialValue = {.stringValue = "Toy Vehicle"}},
{.config =
{
+ .prop = toInt(VehicleProperty::INFO_EXTERIOR_DIMENSIONS),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = {.floatValues = {1776, 4950, 2008, 2140, 2984, 1665, 1667, 11800}}},
+ {.config =
+ {
.prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
@@ -265,10 +295,29 @@
{
.prop = toInt(VehicleProperty::PERF_ODOMETER),
.access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0f,
+ .maxSampleRate = 10.0f,
},
.initialValue = {.floatValues = {0.0f}}},
-
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::PERF_STEERING_ANGLE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0f,
+ .maxSampleRate = 10.0f,
+ },
+ .initialValue = {.floatValues = {0.0f}}},
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::PERF_REAR_STEERING_ANGLE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0f,
+ .maxSampleRate = 10.0f,
+ },
+ .initialValue = {.floatValues = {0.0f}}},
{
.config =
{
@@ -285,8 +334,9 @@
{
.prop = toInt(VehicleProperty::FUEL_LEVEL),
.access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0f,
+ .maxSampleRate = 100.0f,
},
.initialValue = {.floatValues = {15000.0f}}},
@@ -295,7 +345,6 @@
.prop = toInt(VehicleProperty::FUEL_DOOR_OPEN),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {0}}},
@@ -303,8 +352,9 @@
{
.prop = toInt(VehicleProperty::EV_BATTERY_LEVEL),
.access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0f,
+ .maxSampleRate = 100.0f,
},
.initialValue = {.floatValues = {150000.0f}}},
@@ -313,7 +363,6 @@
.prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {0}}},
@@ -322,7 +371,6 @@
.prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {0}}},
@@ -330,17 +378,17 @@
{
.prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE),
.access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 10.0f,
},
.initialValue = {.floatValues = {0.0f}}},
{.config =
{
.prop = toInt(VehicleProperty::RANGE_REMAINING),
- .access = VehiclePropertyAccess::READ,
+ .access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
.minSampleRate = 1.0f,
.maxSampleRate = 2.0f,
},
@@ -374,7 +422,7 @@
.minSampleRate = 1.0f,
.maxSampleRate = 2.0f,
},
- .initialValue = {.floatValues = {200}}}, // units in kPa
+ .initialValue = {.floatValues = {200.0f}}}, // units in kPa
{.config =
{
@@ -397,7 +445,6 @@
.prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {0}}},
@@ -430,6 +477,17 @@
.areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
.initialValue = {.int32Values = {0}} // Will be used for all areas.
},
+ {
+ .config = {.prop = toInt(VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs =
+ {VehicleAreaConfig{
+ .areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)},
+ VehicleAreaConfig{
+ .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
+ .initialValue = {.int32Values = {0}} // Will be used for all areas.
+ },
{.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
.access = VehiclePropertyAccess::READ_WRITE,
@@ -558,14 +616,10 @@
},
.initialValue = {.floatValues = {25.0f}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS},
- },
+ {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS}},
.initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}},
{.config =
@@ -573,8 +627,8 @@
.prop = toInt(VehicleProperty::DISTANCE_DISPLAY_UNITS),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
.configArray = {(int)VehicleUnit::KILOMETER, (int)VehicleUnit::MILE},
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}
},
.initialValue = {.int32Values = {(int)VehicleUnit::MILE}}},
@@ -596,6 +650,14 @@
{.config =
{
+ .prop = toInt(VehicleProperty::TURN_SIGNAL_STATE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {toInt(VehicleTurnSignal::NONE)}}},
+
+ {.config =
+ {
.prop = toInt(VehicleProperty::IGNITION_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -626,6 +688,50 @@
.prop = kGenerateFakeDataControllingProperty,
.access = VehiclePropertyAccess::WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {1, 0, 0, 2, 0, 0, 0, 0, 0},
+ },
+ },
+
+ {
+ .config =
+ {
+ .prop = kSetIntPropertyFromVehcileForTest,
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {0, 0, 0, 2, 1, 0, 0, 0, 0},
+ },
+ },
+
+ {
+ .config =
+ {
+ .prop = kSetFloatPropertyFromVehcileForTest,
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {0, 0, 1, 0, 1, 0, 1, 0, 0},
+ },
+ },
+
+ {
+ .config =
+ {
+ .prop = kSetBooleanPropertyFromVehcileForTest,
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {0, 1, 1, 0, 1, 0, 0, 0, 0},
+ },
+ },
+
+ {
+ .config = {.prop = kMixedTypePropertyForTest,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {1, 1, 0, 2, 0, 0, 1, 0, 0}},
+ .initialValue =
+ {
+ .int32Values = {1 /* indicate TRUE boolean value */, 2, 3},
+ .floatValues = {4.5f},
+ .stringValue = "MIXED property",
},
},
@@ -757,7 +863,6 @@
.prop = toInt(VehicleProperty::HEADLIGHTS_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_STATE_ON}}},
@@ -766,7 +871,6 @@
.prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_STATE_ON}}},
@@ -775,7 +879,6 @@
.prop = toInt(VehicleProperty::FOG_LIGHTS_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_STATE_ON}}},
@@ -784,7 +887,6 @@
.prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_STATE_ON}}},
@@ -793,7 +895,6 @@
.prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
@@ -802,7 +903,6 @@
.prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
@@ -811,7 +911,6 @@
.prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
@@ -820,7 +919,6 @@
.prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
@@ -874,6 +972,24 @@
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE},
.initialValue = {.stringValue = "Vendor String Property"}},
+
+ {.config =
+ {
+ .prop = toInt(VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray =
+ {kMixedTypePropertyForTest,
+ (int)VehicleVendorPermission::PERMISSION_GET_VENDOR_CATEGORY_INFO,
+ (int)VehicleVendorPermission::PERMISSION_SET_VENDOR_CATEGORY_INFO,
+ VENDOR_EXTENSION_INT_PROPERTY,
+ (int)VehicleVendorPermission::PERMISSION_GET_VENDOR_CATEGORY_SEAT,
+ (int)VehicleVendorPermission::PERMISSION_NOT_ACCESSIBLE,
+ VENDOR_EXTENSION_FLOAT_PROPERTY,
+ (int)VehicleVendorPermission::PERMISSION_DEFAULT,
+ (int)VehicleVendorPermission::PERMISSION_DEFAULT},
+ },
+ .initialValue = {.int32Values = {1}}},
};
} // impl
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
new file mode 100644
index 0000000..222fe5e
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
@@ -0,0 +1,287 @@
+/*
+ * 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 <utils/SystemClock.h>
+
+#include "DefaultConfig.h"
+#include "EmulatedVehicleConnector.h"
+#include "JsonFakeValueGenerator.h"
+#include "LinearFakeValueGenerator.h"
+#include "Obd2SensorStore.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
+ if (!mPropCallback) {
+ LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
+ return;
+ }
+ return mPropCallback(value, updateStatus);
+}
+
+void EmulatedVehicleClient::registerPropertyValueCallback(PropertyCallBackType&& callback) {
+ if (mPropCallback) {
+ LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!";
+ return;
+ }
+ mPropCallback = std::move(callback);
+}
+
+GeneratorHub* EmulatedVehicleServer::getGenerator() {
+ return &mGeneratorHub;
+}
+
+VehiclePropValuePool* EmulatedVehicleServer::getValuePool() const {
+ if (!mValuePool) {
+ LOG(WARNING) << __func__ << ": Value pool not set!";
+ }
+ return mValuePool;
+}
+
+void EmulatedVehicleServer::setValuePool(VehiclePropValuePool* valuePool) {
+ if (!valuePool) {
+ LOG(WARNING) << __func__ << ": Setting value pool to nullptr!";
+ }
+ mValuePool = valuePool;
+}
+
+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, updateStatus);
+ }
+}
+
+std::vector<VehiclePropConfig> EmulatedVehicleServer::onGetAllPropertyConfig() const {
+ std::vector<VehiclePropConfig> vehiclePropConfigs;
+ constexpr size_t numOfVehiclePropConfigs =
+ sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]);
+ vehiclePropConfigs.reserve(numOfVehiclePropConfigs);
+ for (auto& it : kVehicleProperties) {
+ vehiclePropConfigs.emplace_back(it.config);
+ }
+ return vehiclePropConfigs;
+}
+
+StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
+ constexpr bool updateStatus = true;
+
+ LOG(INFO) << __func__;
+ const auto& v = request.value;
+ if (!v.int32Values.size()) {
+ LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values";
+ return StatusCode::INVALID_ARG;
+ }
+
+ FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
+
+ switch (command) {
+ case FakeDataCommand::StartLinear: {
+ LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear";
+ if (v.int32Values.size() < 2) {
+ LOG(ERROR) << __func__ << ": expected property ID in int32Values";
+ return StatusCode::INVALID_ARG;
+ }
+ if (!v.int64Values.size()) {
+ LOG(ERROR) << __func__ << ": interval is not provided in int64Values";
+ return StatusCode::INVALID_ARG;
+ }
+ if (v.floatValues.size() < 3) {
+ LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: "
+ << v.floatValues.size();
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t cookie = v.int32Values[1];
+ getGenerator()->registerGenerator(cookie,
+ std::make_unique<LinearFakeValueGenerator>(request));
+ break;
+ }
+ case FakeDataCommand::StartJson: {
+ LOG(INFO) << __func__ << ", FakeDataCommand::StartJson";
+ if (v.stringValue.empty()) {
+ LOG(ERROR) << __func__ << ": path to JSON file is missing";
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t cookie = std::hash<std::string>()(v.stringValue);
+ getGenerator()->registerGenerator(cookie,
+ std::make_unique<JsonFakeValueGenerator>(request));
+ break;
+ }
+ case FakeDataCommand::StopLinear: {
+ LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear";
+ if (v.int32Values.size() < 2) {
+ LOG(ERROR) << __func__ << ": expected property ID in int32Values";
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t cookie = v.int32Values[1];
+ getGenerator()->unregisterGenerator(cookie);
+ break;
+ }
+ case FakeDataCommand::StopJson: {
+ LOG(INFO) << __func__ << ", FakeDataCommand::StopJson";
+ if (v.stringValue.empty()) {
+ LOG(ERROR) << __func__ << ": path to JSON file is missing";
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t cookie = std::hash<std::string>()(v.stringValue);
+ getGenerator()->unregisterGenerator(cookie);
+ break;
+ }
+ case FakeDataCommand::KeyPress: {
+ LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress";
+ int32_t keyCode = request.value.int32Values[2];
+ int32_t display = request.value.int32Values[3];
+ // Send back to HAL
+ onPropertyValueFromCar(
+ *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
+ updateStatus);
+ onPropertyValueFromCar(
+ *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
+ updateStatus);
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command);
+ return StatusCode::INVALID_ARG;
+ }
+ }
+ return StatusCode::OK;
+}
+
+VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createApPowerStateReq(
+ VehicleApPowerStateReq state, int32_t param) {
+ auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
+ req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
+ req->areaId = 0;
+ req->timestamp = elapsedRealtimeNano();
+ req->status = VehiclePropertyStatus::AVAILABLE;
+ req->value.int32Values[0] = toInt(state);
+ req->value.int32Values[1] = param;
+ return req;
+}
+
+VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createHwInputKeyProp(
+ VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
+ auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
+ keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
+ keyEvent->areaId = 0;
+ keyEvent->timestamp = elapsedRealtimeNano();
+ keyEvent->status = VehiclePropertyStatus::AVAILABLE;
+ keyEvent->value.int32Values[0] = toInt(action);
+ keyEvent->value.int32Values[1] = keyCode;
+ keyEvent->value.int32Values[2] = targetDisplay;
+ return keyEvent;
+}
+
+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):
+ case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
+ case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
+ // CPMS is in WAIT_FOR_VHAL state, simply move to ON
+ // Send back to HAL
+ // 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),
+ true /* updateStatus */);
+ break;
+ case toInt(VehicleApPowerStateReport::ON):
+ case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
+ case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
+ // Do nothing
+ break;
+ default:
+ // Unknown state
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ // In the real vhal, the value will be sent to Car ECU.
+ // We just pretend it is done here and send back to HAL
+ auto updatedPropValue = getValuePool()->obtain(value);
+ updatedPropValue->timestamp = elapsedRealtimeNano();
+
+ onPropertyValueFromCar(*updatedPropValue, updateStatus);
+ return StatusCode::OK;
+}
+
+EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() {
+ return std::make_unique<EmulatedPassthroughConnector>();
+}
+
+} // 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/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
new file mode 100644
index 0000000..5fc6493
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
@@ -0,0 +1,98 @@
+/*
+ * 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_EmulatedVehicleConnector_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_
+
+#include <vhal_v2_0/VehicleConnector.h>
+#include <vhal_v2_0/VehicleHal.h>
+
+#include "GeneratorHub.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+// Extension of the client/server interfaces for emulated vehicle
+
+class EmulatedVehicleClient : public IVehicleClient {
+ public:
+ // Type of callback function for handling the new property values
+ using PropertyCallBackType = std::function<void(const VehiclePropValue&, bool updateStatus)>;
+
+ // Method from IVehicleClient
+ void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override;
+
+ void registerPropertyValueCallback(PropertyCallBackType&& callback);
+
+ private:
+ PropertyCallBackType mPropCallback;
+};
+
+class EmulatedVehicleServer : public IVehicleServer {
+ public:
+ // Methods from IVehicleServer
+
+ std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;
+
+ StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;
+
+ // Set the Property Value Pool used in this server
+ void setValuePool(VehiclePropValuePool* valuePool);
+
+ private:
+ GeneratorHub* getGenerator();
+
+ VehiclePropValuePool* getValuePool() const;
+
+ void onFakeValueGenerated(const VehiclePropValue& value);
+
+ StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
+
+ VehicleHal::VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
+
+ VehicleHal::VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action,
+ int32_t keyCode, int32_t targetDisplay);
+
+ // private data members
+
+ GeneratorHub mGeneratorHub{
+ std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)};
+
+ VehiclePropValuePool* mValuePool{nullptr};
+};
+
+// Helper functions
+
+using EmulatedPassthroughConnector =
+ IPassThroughConnector<EmulatedVehicleClient, EmulatedVehicleServer>;
+using EmulatedPassthroughConnectorPtr = std::unique_ptr<EmulatedPassthroughConnector>;
+
+EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector();
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_
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 e1da030..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
@@ -87,17 +87,20 @@
return sensorStore;
}
-EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
+EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore,
+ EmulatedVehicleClient* client)
: mPropStore(propStore),
mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
mRecurrentTimer(
std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
- mGeneratorHub(
- std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1)) {
+ mVehicleClient(client) {
initStaticConfig();
for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
mPropStore->registerProperty(kVehicleProperties[i].config);
}
+ mVehicleClient->registerPropertyValueCallback(std::bind(&EmulatedVehicleHal::onPropertyValue,
+ this, std::placeholders::_1,
+ std::placeholders::_2));
}
VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
@@ -129,10 +132,15 @@
}
StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
- static constexpr bool shouldUpdateStatus = false;
+ constexpr bool updateStatus = false;
if (propValue.prop == kGenerateFakeDataControllingProperty) {
- StatusCode status = handleGenerateFakeDataRequest(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;
}
@@ -156,29 +164,6 @@
// Placeholder for future implementation of VMS property in the default hal. For
// now, just returns OK; otherwise, hal clients crash with property not supported.
return StatusCode::OK;
- case AP_POWER_STATE_REPORT:
- switch (propValue.value.int32Values[0]) {
- case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
- case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
- case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
- // CPMS is in WAIT_FOR_VHAL state, simply move to ON
- doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::ON, 0));
- break;
- case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
- case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
- // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
- doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0));
- break;
- case toInt(VehicleApPowerStateReport::ON):
- case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
- case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
- // Do nothing
- break;
- default:
- // Unknown state
- break;
- }
- break;
}
}
@@ -198,12 +183,16 @@
return StatusCode::NOT_AVAILABLE;
}
- if (!mPropStore->writeValue(propValue, shouldUpdateStatus)) {
- return StatusCode::INVALID_ARG;
- }
+ /**
+ * After checking all conditions, such as the property is available, a real vhal will
+ * sent the events to Car ECU to take actions.
+ */
- getEmulatorOrDie()->doSetValueFromClient(propValue);
- doHalEvent(getValuePool()->obtain(propValue));
+ // Send the value to the vehicle server, the server will talk to the (real or emulated) car
+ auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus);
+ if (setValueStatus != StatusCode::OK) {
+ return setValueStatus;
+ }
return StatusCode::OK;
}
@@ -291,7 +280,6 @@
}
if (v.get()) {
- v->timestamp = elapsedRealtimeNano();
doHalEvent(std::move(v));
}
}
@@ -324,144 +312,20 @@
}
bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
- static constexpr bool shouldUpdateStatus = true;
-
- if (propValue.prop == kGenerateFakeDataControllingProperty) {
- StatusCode status = handleGenerateFakeDataRequest(propValue);
- if (status != StatusCode::OK) {
- return false;
- }
- }
-
- if (mPropStore->writeValue(propValue, shouldUpdateStatus)) {
- doHalEvent(getValuePool()->obtain(propValue));
- return true;
- } else {
- return false;
- }
+ constexpr bool updateStatus = true;
+ return mVehicleClient->setProperty(propValue, updateStatus) == StatusCode::OK;
}
std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const {
return mPropStore->readAllValues();
}
-StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
- ALOGI("%s", __func__);
- const auto& v = request.value;
- if (!v.int32Values.size()) {
- ALOGE("%s: expected at least \"command\" field in int32Values", __func__);
- return StatusCode::INVALID_ARG;
- }
-
- FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
-
- switch (command) {
- case FakeDataCommand::StartLinear: {
- ALOGI("%s, FakeDataCommand::StartLinear", __func__);
- if (v.int32Values.size() < 2) {
- ALOGE("%s: expected property ID in int32Values", __func__);
- return StatusCode::INVALID_ARG;
- }
- if (!v.int64Values.size()) {
- ALOGE("%s: interval is not provided in int64Values", __func__);
- return StatusCode::INVALID_ARG;
- }
- if (v.floatValues.size() < 3) {
- ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__,
- v.floatValues.size());
- return StatusCode::INVALID_ARG;
- }
- int32_t cookie = v.int32Values[1];
- mGeneratorHub.registerGenerator(cookie,
- std::make_unique<LinearFakeValueGenerator>(request));
- break;
- }
- case FakeDataCommand::StartJson: {
- ALOGI("%s, FakeDataCommand::StartJson", __func__);
- if (v.stringValue.empty()) {
- ALOGE("%s: path to JSON file is missing", __func__);
- return StatusCode::INVALID_ARG;
- }
- int32_t cookie = std::hash<std::string>()(v.stringValue);
- mGeneratorHub.registerGenerator(cookie,
- std::make_unique<JsonFakeValueGenerator>(request));
- break;
- }
- case FakeDataCommand::StopLinear: {
- ALOGI("%s, FakeDataCommand::StopLinear", __func__);
- if (v.int32Values.size() < 2) {
- ALOGE("%s: expected property ID in int32Values", __func__);
- return StatusCode::INVALID_ARG;
- }
- int32_t cookie = v.int32Values[1];
- mGeneratorHub.unregisterGenerator(cookie);
- break;
- }
- case FakeDataCommand::StopJson: {
- ALOGI("%s, FakeDataCommand::StopJson", __func__);
- if (v.stringValue.empty()) {
- ALOGE("%s: path to JSON file is missing", __func__);
- return StatusCode::INVALID_ARG;
- }
- int32_t cookie = std::hash<std::string>()(v.stringValue);
- mGeneratorHub.unregisterGenerator(cookie);
- break;
- }
- case FakeDataCommand::KeyPress: {
- ALOGI("%s, FakeDataCommand::KeyPress", __func__);
- int32_t keyCode = request.value.int32Values[2];
- int32_t display = request.value.int32Values[3];
- doHalEvent(
- createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display));
- doHalEvent(createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
- break;
- }
- default: {
- ALOGE("%s: unexpected command: %d", __func__, command);
- return StatusCode::INVALID_ARG;
- }
- }
- return StatusCode::OK;
-}
-
-VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createApPowerStateReq(
- VehicleApPowerStateReq state, int32_t param) {
- auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
- req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
- req->areaId = 0;
- req->timestamp = elapsedRealtimeNano();
- req->status = VehiclePropertyStatus::AVAILABLE;
- req->value.int32Values[0] = toInt(state);
- req->value.int32Values[1] = param;
- return req;
-}
-
-VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp(
- VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
- auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
- keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
- keyEvent->areaId = 0;
- keyEvent->timestamp = elapsedRealtimeNano();
- keyEvent->status = VehiclePropertyStatus::AVAILABLE;
- keyEvent->value.int32Values[0] = toInt(action);
- keyEvent->value.int32Values[1] = keyCode;
- keyEvent->value.int32Values[2] = targetDisplay;
- return keyEvent;
-}
-
-void EmulatedVehicleHal::onFakeValueGenerated(const VehiclePropValue& value) {
- ALOGD("%s: %s", __func__, toString(value).c_str());
- static constexpr bool shouldUpdateStatus = false;
-
+void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
- if (updatedPropValue) {
- updatedPropValue->timestamp = elapsedRealtimeNano();
- updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
- mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
- auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode;
- if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
- doHalEvent(std::move(updatedPropValue));
- }
+
+ 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 78895e3..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
@@ -30,6 +30,7 @@
#include "vhal_v2_0/VehiclePropertyStore.h"
#include "DefaultConfig.h"
+#include "EmulatedVehicleConnector.h"
#include "GeneratorHub.h"
#include "VehicleEmulator.h"
@@ -44,7 +45,8 @@
/** Implementation of VehicleHal that connected to emulator instead of real vehicle network. */
class EmulatedVehicleHal : public EmulatedVehicleHalIface {
public:
- EmulatedVehicleHal(VehiclePropertyStore* propStore);
+ EmulatedVehicleHal(VehiclePropertyStore* propStore,
+ EmulatedVehicleClient* client);
~EmulatedVehicleHal() = default;
// Methods from VehicleHal
@@ -66,10 +68,7 @@
}
StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
- void onFakeValueGenerated(const VehiclePropValue& value);
- VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
- VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode,
- int32_t targetDisplay);
+ void onPropertyValue(const VehiclePropValue& value, bool updateStatus);
void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
bool isContinuousProperty(int32_t propId) const;
@@ -85,7 +84,7 @@
VehiclePropertyStore* mPropStore;
std::unordered_set<int32_t> mHvacPowerProps;
RecurrentTimer mRecurrentTimer;
- GeneratorHub mGeneratorHub;
+ EmulatedVehicleClient* mVehicleClient;
};
} // impl
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 9eb8894..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);
@@ -92,7 +92,10 @@
}
ALOGI("%s: Listening for connections on port %d", __FUNCTION__, DEBUG_SOCKET);
- ::listen(mListenFd, 1);
+ if (::listen(mListenFd, 1) == -1) {
+ ALOGE("%s: Error on listening: errno: %d: %s", __FUNCTION__, errno, strerror(errno));
+ return false;
+ }
return true;
}
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/Android.bp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
index 6754843..2eedecd 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
@@ -29,3 +29,64 @@
],
srcs: ["VehicleHalProto.proto"]
}
+
+cc_library_static {
+ name: "android.hardware.automotive.vehicle@2.0-grpc",
+ vendor: true,
+ include_dirs: [
+ "external/protobuf/src",
+ ],
+ generated_headers: [
+ "DefaultVehicleHalProtoStub_h",
+ ],
+ export_generated_headers: [
+ "DefaultVehicleHalProtoStub_h",
+ ],
+ generated_sources: [
+ "DefaultVehicleHalProtoStub_cc",
+ ],
+ shared_libs: [
+ "libgrpc++_unsecure",
+ ],
+ cflags: [
+ "-Wno-unused-parameter"
+ ],
+}
+
+genrule {
+ name: "DefaultVehicleHalProtoStub_h",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ "VehicleHalProto.proto",
+ "VehicleServer.proto",
+ ],
+ out: [
+ "VehicleHalProto.pb.h",
+ "VehicleHalProto.grpc.pb.h",
+ "VehicleServer.pb.h",
+ "VehicleServer.grpc.pb.h",
+ ],
+}
+
+genrule {
+ name: "DefaultVehicleHalProtoStub_cc",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ "VehicleHalProto.proto",
+ "VehicleServer.proto",
+ ],
+ out: [
+ "VehicleHalProto.pb.cc",
+ "VehicleHalProto.grpc.pb.cc",
+ "VehicleServer.pb.cc",
+ "VehicleServer.grpc.pb.cc",
+ ],
+}
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 2ef64fb..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
@@ -15,9 +15,8 @@
*/
syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
-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
new file mode 100644
index 0000000..6f71d65
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
@@ -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.
+ */
+
+syntax = "proto3";
+
+package vhal_proto;
+
+import "google/protobuf/empty.proto";
+import "VehicleHalProto.proto";
+
+// correspond to StatusCode defined in types.hal
+enum VehicleHalStatusCode {
+ OK = 0;
+ TRY_AGAIN = 1;
+ INVALID_ARG = 2;
+ NOT_AVAILABLE = 3;
+ ACCESS_DENIED = 4;
+ INTERNAL_ERROR = 5;
+}
+
+message VehicleHalCallStatus {
+ VehicleHalStatusCode status_code = 1;
+}
+
+message WrappedVehiclePropValue {
+ VehiclePropValue value = 1;
+ // An indicator on whether we should update the status of the property
+ // - true: if the value is generated by (emulated/real) car, or;
+ // if the value is injected to 'fake' a on car event (for debugging purpose)
+ // - false: if the value is set by VHal (public interface), since Android
+ // cannot change status of property on a real car
+ bool update_status = 2;
+}
+
+service VehicleServer {
+ rpc GetAllPropertyConfig(google.protobuf.Empty) returns (stream VehiclePropConfig) {}
+
+ // Change the property value of the vehicle
+ rpc SetProperty(WrappedVehiclePropValue) returns (VehicleHalCallStatus) {}
+
+ // Start a vehicle property value stream
+ rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream WrappedVehiclePropValue) {}
+}
+
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/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp
new file mode 100644
index 0000000..e329c5b
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "GrpcVehicleClient.h"
+
+#include <condition_variable>
+#include <mutex>
+
+#include <android-base/logging.h>
+#include <grpc++/grpc++.h>
+
+#include "VehicleServer.grpc.pb.h"
+#include "VehicleServer.pb.h"
+#include "vhal_v2_0/ProtoMessageConverter.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
+ // TODO(chenhaosjtuacm): get secured credentials here
+ return ::grpc::InsecureChannelCredentials();
+}
+
+class GrpcVehicleClientImpl : public EmulatedVehicleClient {
+ public:
+ GrpcVehicleClientImpl(const std::string& addr)
+ : mServiceAddr(addr),
+ mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())),
+ mGrpcStub(vhal_proto::VehicleServer::NewStub(mGrpcChannel)) {
+ StartValuePollingThread();
+ }
+
+ ~GrpcVehicleClientImpl() {
+ mShuttingDownFlag.store(true);
+ mShutdownCV.notify_all();
+ if (mPollingThread.joinable()) {
+ mPollingThread.join();
+ }
+ }
+
+ // methods from IVehicleClient
+
+ std::vector<VehiclePropConfig> getAllPropertyConfig() const override;
+
+ StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override;
+
+ private:
+ void StartValuePollingThread();
+
+ // private data members
+
+ std::string mServiceAddr;
+ std::shared_ptr<::grpc::Channel> mGrpcChannel;
+ std::unique_ptr<vhal_proto::VehicleServer::Stub> mGrpcStub;
+ std::thread mPollingThread;
+
+ std::mutex mShutdownMutex;
+ std::condition_variable mShutdownCV;
+ std::atomic<bool> mShuttingDownFlag{false};
+};
+
+std::unique_ptr<EmulatedVehicleClient> makeGrpcVehicleClient(const std::string& addr) {
+ return std::make_unique<GrpcVehicleClientImpl>(addr);
+}
+
+std::vector<VehiclePropConfig> GrpcVehicleClientImpl::getAllPropertyConfig() const {
+ std::vector<VehiclePropConfig> configs;
+ ::grpc::ClientContext context;
+ auto config_stream = mGrpcStub->GetAllPropertyConfig(&context, ::google::protobuf::Empty());
+ vhal_proto::VehiclePropConfig protoConfig;
+ while (config_stream->Read(&protoConfig)) {
+ VehiclePropConfig config;
+ proto_msg_converter::fromProto(&config, protoConfig);
+ configs.emplace_back(std::move(config));
+ }
+ auto grpc_status = config_stream->Finish();
+ if (!grpc_status.ok()) {
+ LOG(ERROR) << __func__
+ << ": GRPC GetAllPropertyConfig Failed: " << grpc_status.error_message();
+ configs.clear();
+ }
+
+ return configs;
+}
+
+StatusCode GrpcVehicleClientImpl::setProperty(const VehiclePropValue& value, bool updateStatus) {
+ ::grpc::ClientContext context;
+ vhal_proto::WrappedVehiclePropValue wrappedProtoValue;
+ vhal_proto::VehicleHalCallStatus vhal_status;
+ proto_msg_converter::toProto(wrappedProtoValue.mutable_value(), value);
+ wrappedProtoValue.set_update_status(updateStatus);
+
+ auto grpc_status = mGrpcStub->SetProperty(&context, wrappedProtoValue, &vhal_status);
+ if (!grpc_status.ok()) {
+ LOG(ERROR) << __func__ << ": GRPC SetProperty Failed: " << grpc_status.error_message();
+ return StatusCode::INTERNAL_ERROR;
+ }
+
+ return static_cast<StatusCode>(vhal_status.status_code());
+}
+
+void GrpcVehicleClientImpl::StartValuePollingThread() {
+ mPollingThread = std::thread([this]() {
+ while (!mShuttingDownFlag.load()) {
+ ::grpc::ClientContext context;
+
+ std::atomic<bool> rpc_ok{true};
+ std::thread shuttingdown_watcher([this, &rpc_ok, &context]() {
+ std::unique_lock<std::mutex> shutdownLock(mShutdownMutex);
+ mShutdownCV.wait(shutdownLock, [this, &rpc_ok]() {
+ return !rpc_ok.load() || mShuttingDownFlag.load();
+ });
+ context.TryCancel();
+ });
+
+ auto value_stream =
+ mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty());
+ vhal_proto::WrappedVehiclePropValue wrappedProtoValue;
+ while (!mShuttingDownFlag.load() && value_stream->Read(&wrappedProtoValue)) {
+ VehiclePropValue value;
+ proto_msg_converter::fromProto(&value, wrappedProtoValue.value());
+ onPropertyValue(value, wrappedProtoValue.update_status());
+ }
+
+ rpc_ok.store(false);
+ mShutdownCV.notify_all();
+ shuttingdown_watcher.join();
+
+ auto grpc_status = value_stream->Finish();
+ // never reach here until connection lost
+ LOG(ERROR) << __func__
+ << ": GRPC Value Streaming Failed: " << grpc_status.error_message();
+
+ // try to reconnect
+ }
+ });
+}
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h
new file mode 100644
index 0000000..14eae7f
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_
+
+#include "vhal_v2_0/EmulatedVehicleConnector.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+std::unique_ptr<EmulatedVehicleClient> makeGrpcVehicleClient(const std::string& addr);
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp
new file mode 100644
index 0000000..e30b3be
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "GrpcVehicleServer.h"
+
+#include <condition_variable>
+#include <mutex>
+#include <shared_mutex>
+
+#include <android-base/logging.h>
+#include <grpc++/grpc++.h>
+
+#include "VehicleServer.grpc.pb.h"
+#include "VehicleServer.pb.h"
+#include "vhal_v2_0/ProtoMessageConverter.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+class GrpcVehicleServerImpl : public GrpcVehicleServer, public vhal_proto::VehicleServer::Service {
+ public:
+ GrpcVehicleServerImpl(const std::string& addr) : mServiceAddr(addr) {
+ setValuePool(&mValueObjectPool);
+ }
+
+ // method from GrpcVehicleServer
+ void Start() override;
+
+ // method from IVehicleServer
+ void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override;
+
+ // methods from vhal_proto::VehicleServer::Service
+
+ ::grpc::Status GetAllPropertyConfig(
+ ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::grpc::ServerWriter<vhal_proto::VehiclePropConfig>* stream) override;
+
+ ::grpc::Status SetProperty(::grpc::ServerContext* context,
+ const vhal_proto::WrappedVehiclePropValue* wrappedPropValue,
+ vhal_proto::VehicleHalCallStatus* status) override;
+
+ ::grpc::Status StartPropertyValuesStream(
+ ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::grpc::ServerWriter<vhal_proto::WrappedVehiclePropValue>* stream) override;
+
+ private:
+ // We keep long-lasting connection for streaming the prop values.
+ // For us, each connection can be represented as a function to send the new value, and
+ // an ID to identify this connection
+ struct ConnectionDescriptor {
+ using ValueWriterType = std::function<bool(const vhal_proto::WrappedVehiclePropValue&)>;
+
+ ConnectionDescriptor(ValueWriterType&& value_writer)
+ : mValueWriter(std::move(value_writer)),
+ mConnectionID(CONNECTION_ID_COUNTER.fetch_add(1)) {}
+
+ ConnectionDescriptor(const ConnectionDescriptor&) = delete;
+
+ ConnectionDescriptor& operator=(const ConnectionDescriptor&) = delete;
+
+ // This move constructor is NOT THREAD-SAFE, which means it cannot be moved
+ // while using. Since the connection descriptors are pretected by mConnectionMutex
+ // then we are fine here
+ ConnectionDescriptor(ConnectionDescriptor&& cd)
+ : mValueWriter(std::move(cd.mValueWriter)),
+ mConnectionID(cd.mConnectionID),
+ mIsAlive(cd.mIsAlive.load()) {
+ cd.mIsAlive.store(false);
+ }
+
+ ValueWriterType mValueWriter;
+ uint64_t mConnectionID;
+ std::atomic<bool> mIsAlive{true};
+
+ static std::atomic<uint64_t> CONNECTION_ID_COUNTER;
+ };
+
+ std::string mServiceAddr;
+ VehiclePropValuePool mValueObjectPool;
+ mutable std::shared_mutex mConnectionMutex;
+ mutable std::shared_mutex mWriterMutex;
+ std::list<ConnectionDescriptor> mValueStreamingConnections;
+};
+
+std::atomic<uint64_t> GrpcVehicleServerImpl::ConnectionDescriptor::CONNECTION_ID_COUNTER = 0;
+
+static std::shared_ptr<::grpc::ServerCredentials> getServerCredentials() {
+ // TODO(chenhaosjtuacm): get secured credentials here
+ return ::grpc::InsecureServerCredentials();
+}
+
+GrpcVehicleServerPtr makeGrpcVehicleServer(const std::string& addr) {
+ return std::make_unique<GrpcVehicleServerImpl>(addr);
+}
+
+void GrpcVehicleServerImpl::Start() {
+ ::grpc::ServerBuilder builder;
+ builder.RegisterService(this);
+ builder.AddListeningPort(mServiceAddr, getServerCredentials());
+ std::unique_ptr<::grpc::Server> server(builder.BuildAndStart());
+
+ server->Wait();
+}
+
+void GrpcVehicleServerImpl::onPropertyValueFromCar(const VehiclePropValue& value,
+ bool updateStatus) {
+ vhal_proto::WrappedVehiclePropValue wrappedPropValue;
+ proto_msg_converter::toProto(wrappedPropValue.mutable_value(), value);
+ wrappedPropValue.set_update_status(updateStatus);
+ std::shared_lock read_lock(mConnectionMutex);
+
+ bool has_terminated_connections = 0;
+
+ for (auto& connection : mValueStreamingConnections) {
+ auto writeOK = connection.mValueWriter(wrappedPropValue);
+ if (!writeOK) {
+ LOG(ERROR) << __func__ << ": Server Write failed, connection lost. ID: "
+ << connection.mConnectionID;
+ has_terminated_connections = true;
+ connection.mIsAlive.store(false);
+ }
+ }
+
+ if (!has_terminated_connections) {
+ return;
+ }
+
+ read_lock.unlock();
+
+ std::unique_lock write_lock(mConnectionMutex);
+
+ for (auto itr = mValueStreamingConnections.begin(); itr != mValueStreamingConnections.end();) {
+ if (!itr->mIsAlive.load()) {
+ itr = mValueStreamingConnections.erase(itr);
+ } else {
+ ++itr;
+ }
+ }
+}
+
+::grpc::Status GrpcVehicleServerImpl::GetAllPropertyConfig(
+ ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::grpc::ServerWriter<vhal_proto::VehiclePropConfig>* stream) {
+ auto configs = onGetAllPropertyConfig();
+ for (auto& config : configs) {
+ vhal_proto::VehiclePropConfig protoConfig;
+ proto_msg_converter::toProto(&protoConfig, config);
+ if (!stream->Write(protoConfig)) {
+ return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost.");
+ }
+ }
+
+ return ::grpc::Status::OK;
+}
+
+::grpc::Status GrpcVehicleServerImpl::SetProperty(
+ ::grpc::ServerContext* context, const vhal_proto::WrappedVehiclePropValue* wrappedPropValue,
+ vhal_proto::VehicleHalCallStatus* status) {
+ VehiclePropValue value;
+ proto_msg_converter::fromProto(&value, wrappedPropValue->value());
+
+ auto set_status = static_cast<int32_t>(onSetProperty(value, wrappedPropValue->update_status()));
+ if (!vhal_proto::VehicleHalStatusCode_IsValid(set_status)) {
+ return ::grpc::Status(::grpc::StatusCode::INTERNAL, "Unknown status code");
+ }
+
+ status->set_status_code(static_cast<vhal_proto::VehicleHalStatusCode>(set_status));
+
+ return ::grpc::Status::OK;
+}
+
+::grpc::Status GrpcVehicleServerImpl::StartPropertyValuesStream(
+ ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::grpc::ServerWriter<vhal_proto::WrappedVehiclePropValue>* stream) {
+ std::mutex terminateMutex;
+ std::condition_variable terminateCV;
+ std::unique_lock<std::mutex> terminateLock(terminateMutex);
+ bool terminated{false};
+
+ auto callBack = [stream, &terminateMutex, &terminateCV, &terminated,
+ this](const vhal_proto::WrappedVehiclePropValue& value) {
+ std::unique_lock lock(mWriterMutex);
+ if (!stream->Write(value)) {
+ std::unique_lock<std::mutex> terminateLock(terminateMutex);
+ terminated = true;
+ terminateLock.unlock();
+ terminateCV.notify_all();
+ return false;
+ }
+ return true;
+ };
+
+ // Register connection
+ std::unique_lock lock(mConnectionMutex);
+ auto& conn = mValueStreamingConnections.emplace_back(std::move(callBack));
+ lock.unlock();
+
+ // Never stop until connection lost
+ terminateCV.wait(terminateLock, [&terminated]() { return terminated; });
+
+ LOG(ERROR) << __func__ << ": Stream lost, ID : " << conn.mConnectionID;
+
+ return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost.");
+}
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h
new file mode 100644
index 0000000..32f4eb2
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_
+
+#include "vhal_v2_0/EmulatedVehicleConnector.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+// Connect to the Vehicle Client via GRPC
+class GrpcVehicleServer : public EmulatedVehicleServer {
+ public:
+ // Start listening incoming calls, should never return if working normally
+ virtual void Start() = 0;
+};
+
+using GrpcVehicleServerPtr = std::unique_ptr<GrpcVehicleServer>;
+
+GrpcVehicleServerPtr makeGrpcVehicleServer(const std::string& addr);
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp
new file mode 100644
index 0000000..41d4827
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Utils.h"
+
+#include <sstream>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace impl {
+
+std::string getVsockUri(const VsockServerInfo& serverInfo) {
+ std::stringstream uri_stream;
+ uri_stream << "vsock:" << serverInfo.serverCid << ":" << serverInfo.serverPort;
+ return uri_stream.str();
+}
+
+} // namespace impl
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h
new file mode 100644
index 0000000..6b1049c
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_
+
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace impl {
+
+struct VsockServerInfo {
+ unsigned int serverCid{0};
+ unsigned int serverPort{0};
+};
+
+std::string getVsockUri(const VsockServerInfo& serverInfo);
+
+} // namespace impl
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 0f20dd1..6145ea2 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -35,6 +35,21 @@
/**
* Any combination of scalar or vector types. The exact format must be
* provided in the description of the property.
+ *
+ * For vendor MIXED type properties, configArray needs to be formatted in this
+ * structure.
+ * configArray[0], 1 indicates the property has a String value
+ * configArray[1], 1 indicates the property has a Boolean value .
+ * configArray[2], 1 indicates the property has an Integer value.
+ * configArray[3], the number indicates the size of Integer[] in the property.
+ * configArray[4], 1 indicates the property has a Long value.
+ * configArray[5], the number indicates the size of Long[] in the property.
+ * configArray[6], 1 indicates the property has a Float value.
+ * configArray[7], the number indicates the size of Float[] in the property.
+ * configArray[8], the number indicates the size of byte[] in the property.
+ * For example:
+ * {@code configArray = {1, 1, 1, 3, 0, 0, 0, 0, 0}} indicates the property has
+ * a String value, a Boolean value, an Integer value and an array with 3 integers.
*/
MIXED = 0x00e00000,
@@ -283,6 +298,28 @@
| VehicleArea:SEAT),
/**
+ * Exterior dimensions of vehicle.
+ *
+ * int32Values[0] = height
+ * int32Values[1] = length
+ * int32Values[2] = width
+ * int32Values[3] = width including mirrors
+ * int32Values[4] = wheel base
+ * int32Values[5] = track width front
+ * int32Values[6] = track width rear
+ * int32Values[7] = curb to curb turning radius
+ *
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:MILLIMETER
+ */
+ INFO_EXTERIOR_DIMENSIONS = (
+ 0x010B
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /**
* Current odometer value of the vehicle
*
* @change_mode VehiclePropertyChangeMode:CONTINUOUS
@@ -325,7 +362,7 @@
| VehicleArea:GLOBAL),
/**
- * Steering angle of the vehicle
+ * Front bicycle model steering angle for vehicle
*
* Angle is in degrees. Left is negative.
*
@@ -340,6 +377,21 @@
| VehicleArea:GLOBAL),
/**
+ * Rear bicycle model steering angle for vehicle
+ *
+ * Angle is in degrees. Left is negative.
+ *
+ * @change_mode VehiclePropertyChangeMode:CONTINUOUS
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:DEGREES
+ */
+ PERF_REAR_STEERING_ANGLE = (
+ 0x0210
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:GLOBAL),
+
+ /**
* Temperature of engine coolant
*
* @change_mode VehiclePropertyChangeMode:CONTINUOUS
@@ -799,7 +851,7 @@
| VehicleArea:SEAT),
/**
- * On/off defrost for designated window
+ * Fan-based defrost for designated window.
*
* @change_mode VehiclePropertyChangeMode:ON_CHANGE
* @access VehiclePropertyAccess:READ_WRITE
@@ -1076,6 +1128,7 @@
*
* @change_mode VehiclePropertyChangeMode:STATIC
* @access VehiclePropertyAccess:READ
+ * @data_enum VehicleHvacFanDirection
*/
HVAC_FAN_DIRECTION_AVAILABLE = (
0x0511
@@ -1118,6 +1171,18 @@
| VehiclePropertyType:INT32
| VehicleArea:SEAT),
+ /**
+ * Electric defrosters' status
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_ELECTRIC_DEFROSTER_ON = (
+ 0x0514
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:WINDOW),
+
/**
* Distance units for display
*
@@ -2321,6 +2386,116 @@
| VehiclePropertyType:INT32
| VehicleArea:SEAT),
+ /**
+ * Support customize permissions for vendor properties
+ *
+ * Implement this property if vehicle hal support customize vendor permissions feature.
+ * VehiclePropConfig.configArray is used to indicate vendor properties and permissions
+ * which selected for this vendor property. The permission must be one of enum in
+ * VehicleVendorPermission.
+ * The configArray is set as follows:
+ * configArray[n] = propId : property ID for the vendor property
+ * configArray[n+1] = one of enums in VehicleVendorPermission. It indicates the permission
+ * for reading value of the property.
+ * configArray[n+2] = one of enums in VehicleVendorPermission. It indicates the permission
+ * for writing value of the property.
+ *
+ * For example:
+ * configArray = {
+ * vendor_prop_1, PERMISSION_VENDOR_SEAT_READ, PERMISSION_VENDOR_SEAT_WRITE,
+ * vendor_prop_2, PERMISSION_VENDOR_INFO, PERMISSION_NOT_ACCESSIBLE,
+ * }
+ * If vendor properties are not in this array, they will have the default vendor permission.
+ * If vendor chose PERMISSION_NOT_ACCESSIBLE, android will not have access to the property. In
+ * the example, Android can not write value for vendor_prop_2.
+ *
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ */
+ SUPPORT_CUSTOMIZE_VENDOR_PERMISSION = (
+ 0x0F05
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:GLOBAL),
+
+ /**
+ * Allow disabling optional featurs from vhal.
+ *
+ * This property reports optional features that should be disabled.
+ * All allowed optional features for the system is declared in Car service overlay,
+ * config_allowed_optional_car_features.
+ * This property allows disabling features defined in the overlay. Without this property,
+ * all the features declared in the overlay will be enabled.
+ *
+ * Value read should include all features disabled with ',' separation.
+ * ex) "com.android.car.user.CarUserNoticeService,storage_monitoring"
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ */
+ DISABLED_OPTIONAL_FEATURES = (
+ 0x0F06
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:STRING
+ | VehicleArea:GLOBAL),
+
+};
+
+/**
+ * Used by SUPPORT_CUSTOMIZE_VENDOR_PERMISSION to indicate the permission of vendor properties.
+ */
+enum VehicleVendorPermission : int32_t {
+ PERMISSION_DEFAULT = 0x00000000,
+
+ // permissions for the property related with window
+ PERMISSION_SET_VENDOR_CATEGORY_WINDOW= 0X00000001,
+ PERMISSION_GET_VENDOR_CATEGORY_WINDOW = 0x00000002,
+ // permissions for the property related with door
+ PERMISSION_SET_VENDOR_CATEGORY_DOOR = 0x00000003,
+ PERMISSION_GET_VENDOR_CATEGORY_DOOR = 0x00000004,
+ // permissions for the property related with seat
+ PERMISSION_SET_VENDOR_CATEGORY_SEAT = 0x00000005,
+ PERMISSION_GET_VENDOR_CATEGORY_SEAT = 0x00000006,
+ // permissions for the property related with mirror
+ PERMISSION_SET_VENDOR_CATEGORY_MIRROR= 0x00000007,
+ PERMISSION_GET_VENDOR_CATEGORY_MIRROR = 0x00000008,
+
+ // permissions for the property related with car's information
+ PERMISSION_SET_VENDOR_CATEGORY_INFO = 0x00000009,
+ PERMISSION_GET_VENDOR_CATEGORY_INFO = 0x0000000A,
+ // permissions for the property related with car's engine
+ PERMISSION_SET_VENDOR_CATEGORY_ENGINE= 0x0000000B,
+ PERMISSION_GET_VENDOR_CATEGORY_ENGINE = 0x0000000C,
+ // permissions for the property related with car's HVAC
+ PERMISSION_SET_VENDOR_CATEGORY_HVAC = 0x0000000D,
+ PERMISSION_GET_VENDOR_CATEGORY_HVAC = 0x0000000E,
+ // permissions for the property related with car's light
+ PERMISSION_SET_VENDOR_CATEGORY_LIGHT = 0x0000000F,
+ PERMISSION_GET_VENDOR_CATEGORY_LIGHT = 0x00000010,
+
+ // permissions reserved for other vendor permission
+ PERMISSION_SET_VENDOR_CATEGORY_1 = 0x00010000,
+ PERMISSION_GET_VENDOR_CATEGORY_1 = 0x00011000,
+ PERMISSION_SET_VENDOR_CATEGORY_2 = 0x00020000,
+ PERMISSION_GET_VENDOR_CATEGORY_2 = 0x00021000,
+ PERMISSION_SET_VENDOR_CATEGORY_3 = 0x00030000,
+ PERMISSION_GET_VENDOR_CATEGORY_3 = 0x00031000,
+ PERMISSION_SET_VENDOR_CATEGORY_4 = 0x00040000,
+ PERMISSION_GET_VENDOR_CATEGORY_4 = 0x00041000,
+ PERMISSION_SET_VENDOR_CATEGORY_5 = 0x00050000,
+ PERMISSION_GET_VENDOR_CATEGORY_5 = 0x00051000,
+ PERMISSION_SET_VENDOR_CATEGORY_6 = 0x00060000,
+ PERMISSION_GET_VENDOR_CATEGORY_6 = 0x00061000,
+ PERMISSION_SET_VENDOR_CATEGORY_7 = 0x00070000,
+ PERMISSION_GET_VENDOR_CATEGORY_7 = 0x00071000,
+ PERMISSION_SET_VENDOR_CATEGORY_8 = 0x00080000,
+ PERMISSION_GET_VENDOR_CATEGORY_8 = 0x00081000,
+ PERMISSION_SET_VENDOR_CATEGORY_9 = 0x00090000,
+ PERMISSION_GET_VENDOR_CATEGORY_9 = 0x00091000,
+ PERMISSION_SET_VENDOR_CATEGORY_10 = 0x000A0000,
+ PERMISSION_GET_VENDOR_CATEGORY_10 = 0x000A1000,
+
+ // Indicate not available for android to access.
+ PERMISSION_NOT_ACCESSIBLE = 0xF0000000
};
/**
@@ -2458,9 +2633,19 @@
* Bit flags for fan direction
*/
enum VehicleHvacFanDirection : int32_t {
+ UNKNOWN = 0x0,
+
FACE = 0x1,
FLOOR = 0x2,
+ /**
+ * FACE_AND_FLOOR = FACE | FLOOR
+ */
+ FACE_AND_FLOOR = 0x3,
DEFROST = 0x4,
+ /**
+ * DEFROST_AND_FLOOR = DEFROST | FLOOR
+ */
+ DEFROST_AND_FLOOR = 0x06,
};
enum VehicleOilLevel : int32_t {
@@ -2499,7 +2684,7 @@
* power controller must change power state to this state to shutdown
* system.
*
- * int32Values[1] : one of enum_vehicle_ap_power_state_shutdown_param_type
+ * int32Values[1] : one of VehicleApPowerStateShutdownParam
*
* SHUTDOWN_PRPARE may be requested from either WAIT_FOR_VHAL or ON states.
*/
@@ -2531,6 +2716,11 @@
/** AP can only shutdown with postponing allowed. */
SHUTDOWN_ONLY = 3,
+
+ /**
+ * AP may enter deep sleep, but must either sleep or shut down immediately.
+ * Postponing is not allowed. */
+ SLEEP_IMMEDIATELY = 4,
};
enum VehicleApPowerStateReport : int32_t {
@@ -2723,6 +2913,8 @@
* Various gears which can be selected by user and chosen in system.
*/
enum VehicleGear : int32_t {
+ GEAR_UNKNOWN = 0x0000,
+
GEAR_NEUTRAL = 0x0001,
GEAR_REVERSE = 0x0002,
GEAR_PARK = 0x0004,
@@ -3541,4 +3733,3 @@
enum VmsPublisherInformationIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex {
PUBLISHER_ID = 1,
};
-
diff --git a/biometrics/face/1.1/Android.bp b/biometrics/face/1.1/Android.bp
new file mode 100644
index 0000000..2206597
--- /dev/null
+++ b/biometrics/face/1.1/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.biometrics.face@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "IBiometricsFace.hal",
+ ],
+ interfaces: [
+ "android.hardware.biometrics.face@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/biometrics/face/1.1/IBiometricsFace.hal b/biometrics/face/1.1/IBiometricsFace.hal
new file mode 100644
index 0000000..84e7443
--- /dev/null
+++ b/biometrics/face/1.1/IBiometricsFace.hal
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.face@1.1;
+
+import @1.0::IBiometricsFace;
+import @1.0::Status;
+import @1.0::Feature;
+
+/**
+ * The HAL interface for biometric face authentication.
+ */
+interface IBiometricsFace extends @1.0::IBiometricsFace {
+ /**
+ * Enrolls a user's face for a remote client, for example Android Auto.
+ *
+ * The HAL implementation is responsible for creating a secure communication
+ * channel and receiving the enrollment images from a mobile device with
+ * face authentication hardware.
+ *
+ * Note that the Hardware Authentication Token must be valid for the
+ * duration of enrollment and thus should be explicitly invalidated by a
+ * call to revokeChallenge() when enrollment is complete, to reduce the
+ * window of opportunity to re-use the challenge and HAT. For example,
+ * Settings calls generateChallenge() once to allow the user to enroll one
+ * or more faces or toggle secure settings without having to re-enter the
+ * PIN/pattern/password. Once the user completes the operation, Settings
+ * invokes revokeChallenge() to close the transaction. If the HAT is expired,
+ * the implementation must invoke onError with UNABLE_TO_PROCESS.
+ *
+ * Requirements for using this API:
+ * - Mobile devices MUST NOT delegate enrollment to another device by calling
+ * this API. This feature is intended only to allow enrollment on devices
+ * where it is impossible to enroll locally on the device.
+ * - The path MUST be protected by a secret key with rollback protection.
+ * - Synchronizing between devices MUST be accomplished by having both
+ * devices agree on a secret PIN entered by the user (similar to BT
+ * pairing procedure) and use a salted version of that PIN plus other secret
+ * to encrypt traffic.
+ * - All communication to/from the remote device MUST be encrypted and signed
+ * to prevent image injection and other man-in-the-middle type attacks.
+ * - generateChallenge() and revokeChallenge() MUST be implemented on both
+ * remote and local host (e.g. hash the result of the remote host with a
+ * local secret before responding to the API call) and any transmission of
+ * the challenge between hosts MUST be signed to prevent man-in-the-middle
+ * attacks.
+ * - In the event of a lost connection, the result of the last
+ * generateChallenge() MUST be invalidated and the process started over.
+ * - Both the remote and local host MUST honor the timeout and invalidate the
+ * challenge.
+ *
+ * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+ * method.
+ *
+ * @param hat A valid Hardware Authentication Token, generated as a result
+ * of a generateChallenge() challenge being wrapped by the gatekeeper
+ * after a successful strong authentication request.
+ * @param timeoutSec A timeout in seconds, after which this enroll
+ * attempt is cancelled. Note that the framework can continue
+ * enrollment by calling this again with a valid HAT. This timeout is
+ * expected to be used to limit power usage if the device becomes idle
+ * during enrollment. The implementation is expected to send
+ * ERROR_TIMEOUT if this happens.
+ * @param disabledFeatures A list of features to be disabled during
+ * enrollment. Note that all features are enabled by default.
+ * @return status The status of this method call.
+ */
+ enrollRemotely(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures)
+ generates (Status status);
+
+ /**
+ * Enrolls a user's face.
+ *
+ * Note that the Hardware Authentication Token must be valid for the
+ * duration of enrollment and thus should be explicitly invalidated by a
+ * call to revokeChallenge() when enrollment is complete, to reduce the
+ * window of opportunity to re-use the challenge and HAT. For example,
+ * Settings calls generateChallenge() once to allow the user to enroll one
+ * or more faces or toggle secure settings without having to re-enter the
+ * PIN/pattern/password. Once the user completes the operation, Settings
+ * invokes revokeChallenge() to close the transaction. If the HAT is expired,
+ * the implementation must invoke onError with UNABLE_TO_PROCESS.
+ *
+ * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+ * method.
+ *
+ * @param hat A valid Hardware Authentication Token, generated as a result
+ * of a generateChallenge() challenge being wrapped by the gatekeeper
+ * after a successful strong authentication request.
+ * @param timeoutSec A timeout in seconds, after which this enroll
+ * attempt is cancelled. Note that the framework can continue
+ * enrollment by calling this again with a valid HAT. This timeout is
+ * expected to be used to limit power usage if the device becomes idle
+ * during enrollment. The implementation is expected to send
+ * ERROR_TIMEOUT if this happens.
+ * @param disabledFeatures A list of features to be disabled during
+ * enrollment. Note that all features are enabled by default.
+ * @param windowId optional ID of a camera preview window for a
+ * single-camera device. Must be null if not used.
+ * @return status The status of this method call.
+ */
+ enroll_1_1(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures,
+ handle windowId) generates (Status status);
+};
diff --git a/biometrics/face/1.1/default/Android.bp b/biometrics/face/1.1/default/Android.bp
new file mode 100644
index 0000000..360071f
--- /dev/null
+++ b/biometrics/face/1.1/default/Android.bp
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_binary {
+ name: "android.hardware.biometrics.face@1.1-service.example",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ init_rc: ["android.hardware.biometrics.face@1.1-service.rc"],
+ vintf_fragments: ["manifest_face_default.xml"],
+ relative_install_path: "hw",
+ proprietary: true,
+ srcs: [
+ "BiometricsFace.cpp",
+ "service.cpp",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "libutils",
+ "liblog",
+ "android.hardware.biometrics.face@1.0",
+ "android.hardware.biometrics.face@1.1",
+ ],
+}
diff --git a/biometrics/face/1.1/default/BiometricsFace.cpp b/biometrics/face/1.1/default/BiometricsFace.cpp
new file mode 100644
index 0000000..2143880
--- /dev/null
+++ b/biometrics/face/1.1/default/BiometricsFace.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BiometricsFace.h"
+
+namespace android::hardware::biometrics::face::implementation {
+using android::hardware::biometrics::face::V1_0::FaceError;
+using android::hardware::biometrics::face::V1_0::OptionalUint64;
+
+// Arbitrary value.
+constexpr uint64_t kDeviceId = 123;
+// Arbitrary value.
+constexpr uint64_t kAuthenticatorId = 987;
+// Arbitrary value.
+constexpr uint64_t kLockoutDuration = 555;
+
+BiometricsFace::BiometricsFace() : mRandom(std::mt19937::default_seed) {}
+
+// Methods from IBiometricsFace follow.
+Return<void> BiometricsFace::setCallback(const sp<IBiometricsFaceClientCallback>& clientCallback,
+ setCallback_cb _hidl_cb) {
+ mClientCallback = clientCallback;
+ _hidl_cb({Status::OK, kDeviceId});
+ return Void();
+}
+
+Return<Status> BiometricsFace::setActiveUser(int32_t userId, const hidl_string& storePath) {
+ if (userId < 0 || storePath.empty() || std::string(storePath).find("/data") != 0) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ mUserId = userId;
+ mClientCallback->onLockoutChanged(kLockoutDuration);
+ return Status::OK;
+}
+
+Return<void> BiometricsFace::generateChallenge(uint32_t /* challengeTimeoutSec */,
+ generateChallenge_cb _hidl_cb) {
+ std::uniform_int_distribution<uint64_t> dist;
+ _hidl_cb({Status::OK, dist(mRandom)});
+ return Void();
+}
+
+Return<Status> BiometricsFace::enroll(const hidl_vec<uint8_t>& /* hat */, uint32_t /* timeoutSec */,
+ const hidl_vec<Feature>& /* disabledFeatures */) {
+ // hat can never be valid in this implementation.
+ mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::revokeChallenge() {
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::setFeature(Feature /* feature */, bool /* enabled */,
+ const hidl_vec<uint8_t>& /* hat */,
+ uint32_t /* faceId */) {
+ // hat can never be valid in this implementation.
+ return Status::ILLEGAL_ARGUMENT;
+}
+
+Return<void> BiometricsFace::getFeature(Feature /* feature */, uint32_t /* faceId */,
+ getFeature_cb _hidl_cb) {
+ // hat can never be valid in this implementation.
+ _hidl_cb({Status::ILLEGAL_ARGUMENT, false});
+ return Void();
+}
+
+Return<void> BiometricsFace::getAuthenticatorId(getAuthenticatorId_cb _hidl_cb) {
+ _hidl_cb({Status::OK, kAuthenticatorId});
+ return Void();
+}
+
+Return<Status> BiometricsFace::cancel() {
+ mClientCallback->onError(kDeviceId, mUserId, FaceError::CANCELED, 0 /* vendorCode */);
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::enumerate() {
+ mClientCallback->onEnumerate(kDeviceId, {}, mUserId);
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::remove(uint32_t /* faceId */) {
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::authenticate(uint64_t /* operationId */) {
+ mClientCallback->onError(kDeviceId, mUserId, FaceError::HW_UNAVAILABLE, 0 /* vendorCode */);
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::userActivity() {
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::resetLockout(const hidl_vec<uint8_t>& /* hat */) {
+ return Status::OK;
+}
+
+// Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow.
+Return<Status> BiometricsFace::enroll_1_1(const hidl_vec<uint8_t>& /* hat */,
+ uint32_t /* timeoutSec */,
+ const hidl_vec<Feature>& /* disabledFeatures */,
+ const hidl_handle& /* windowId */) {
+ mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ return Status::OK;
+}
+
+Return<Status> BiometricsFace::enrollRemotely(const hidl_vec<uint8_t>& /* hat */,
+ uint32_t /* timeoutSec */,
+ const hidl_vec<Feature>& /* disabledFeatures */) {
+ mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ return Status::OK;
+}
+
+} // namespace android::hardware::biometrics::face::implementation
diff --git a/biometrics/face/1.1/default/BiometricsFace.h b/biometrics/face/1.1/default/BiometricsFace.h
new file mode 100644
index 0000000..5ce5771
--- /dev/null
+++ b/biometrics/face/1.1/default/BiometricsFace.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <random>
+
+namespace android::hardware::biometrics::face::implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::biometrics::face::V1_0::Feature;
+using ::android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
+using ::android::hardware::biometrics::face::V1_0::Status;
+
+class BiometricsFace : public V1_1::IBiometricsFace {
+ public:
+ BiometricsFace();
+
+ // Methods from ::android::hardware::biometrics::face::V1_0::IBiometricsFace follow.
+ Return<void> setCallback(const sp<IBiometricsFaceClientCallback>& clientCallback,
+ setCallback_cb _hidl_cb) override;
+
+ Return<Status> setActiveUser(int32_t userId, const hidl_string& storePath) override;
+
+ Return<void> generateChallenge(uint32_t challengeTimeoutSec,
+ generateChallenge_cb _hidl_cb) override;
+
+ Return<Status> enroll(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+ const hidl_vec<Feature>& disabledFeatures) override;
+
+ Return<Status> revokeChallenge() override;
+
+ Return<Status> setFeature(Feature feature, bool enabled, const hidl_vec<uint8_t>& hat,
+ uint32_t faceId) override;
+
+ Return<void> getFeature(Feature feature, uint32_t faceId, getFeature_cb _hidl_cb) override;
+
+ Return<void> getAuthenticatorId(getAuthenticatorId_cb _hidl_cb) override;
+
+ Return<Status> cancel() override;
+
+ Return<Status> enumerate() override;
+
+ Return<Status> remove(uint32_t faceId) override;
+
+ Return<Status> authenticate(uint64_t operationId) override;
+
+ Return<Status> userActivity() override;
+
+ Return<Status> resetLockout(const hidl_vec<uint8_t>& hat) override;
+
+ // Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow.
+ Return<Status> enroll_1_1(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+ const hidl_vec<Feature>& disabledFeatures,
+ const hidl_handle& windowId) override;
+
+ Return<Status> enrollRemotely(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+ const hidl_vec<Feature>& disabledFeatures) override;
+
+ private:
+ std::mt19937 mRandom;
+ int32_t mUserId;
+ sp<IBiometricsFaceClientCallback> mClientCallback;
+};
+
+} // namespace android::hardware::biometrics::face::implementation
diff --git a/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc b/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
new file mode 100644
index 0000000..687e2d8
--- /dev/null
+++ b/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
@@ -0,0 +1,10 @@
+service vendor.face-hal-1-1-default /vendor/bin/hw/android.hardware.biometrics.face@1.1-service.example
+ # "class hal" causes a race condition on some devices due to files created
+ # in /data. As a workaround, postpone startup until later in boot once
+ # /data is mounted.
+ class late_start
+ user system
+ group system
+ writepid /dev/cpuset/foreground/tasks
+ capabilities SYS_NICE
+ rlimit rtprio 10 10
diff --git a/biometrics/face/1.1/default/manifest_face_default.xml b/biometrics/face/1.1/default/manifest_face_default.xml
new file mode 100644
index 0000000..ec71d9c
--- /dev/null
+++ b/biometrics/face/1.1/default/manifest_face_default.xml
@@ -0,0 +1,11 @@
+<manifest version="2.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.biometrics.face</name>
+ <transport>hwbinder</transport>
+ <version>1.1</version>
+ <interface>
+ <name>IBiometricsFace</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/biometrics/face/1.1/default/service.cpp b/biometrics/face/1.1/default/service.cpp
new file mode 100644
index 0000000..344bdb9
--- /dev/null
+++ b/biometrics/face/1.1/default/service.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.biometrics.face@1.1-service"
+
+#include <android/hardware/biometrics/face/1.0/types.h>
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
+#include <android/log.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include "BiometricsFace.h"
+
+using android::sp;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::biometrics::face::implementation::BiometricsFace;
+using android::hardware::biometrics::face::V1_1::IBiometricsFace;
+
+int main() {
+ ALOGI("BiometricsFace HAL is being started.");
+
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+ android::sp<IBiometricsFace> face = new BiometricsFace();
+ const android::status_t status = face->registerAsService();
+
+ if (status != android::OK) {
+ ALOGE("Error starting the BiometricsFace HAL.");
+ return 1;
+ }
+
+ ALOGI("BiometricsFace HAL has started successfully.");
+ joinRpcThreadpool();
+
+ ALOGI("BiometricsFace HAL is terminating.");
+ return 1; // should never get here
+}
diff --git a/biometrics/face/1.1/vts/functional/Android.bp b/biometrics/face/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..ccbb399
--- /dev/null
+++ b/biometrics/face/1.1/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+ name: "VtsHalBiometricsFaceV1_1TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalBiometricsFaceV1_1TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.biometrics.face@1.0",
+ "android.hardware.biometrics.face@1.1",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
new file mode 100644
index 0000000..6ada442
--- /dev/null
+++ b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "biometrics_face_hidl_hal_test"
+
+#include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <chrono>
+#include <cstdint>
+#include <random>
+
+using android::sp;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo;
+using android::hardware::biometrics::face::V1_0::FaceError;
+using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
+using android::hardware::biometrics::face::V1_0::OptionalUint64;
+using android::hardware::biometrics::face::V1_0::Status;
+using android::hardware::biometrics::face::V1_1::IBiometricsFace;
+
+namespace {
+
+// Arbitrary, nonexistent userId
+constexpr uint32_t kUserId = 9;
+constexpr uint32_t kTimeoutSec = 3;
+constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
+constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata";
+constexpr char kCallbackNameOnError[] = "onError";
+
+// Callback arguments that need to be captured for the tests.
+struct FaceCallbackArgs {
+ // The error passed to the last onError() callback.
+ FaceError error;
+
+ // The userId passed to the last callback.
+ int32_t userId;
+};
+
+// Test callback class for the BiometricsFace HAL.
+// The HAL will call these callback methods to notify about completed operations
+// or encountered errors.
+class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase<FaceCallbackArgs>,
+ public IBiometricsFaceClientCallback {
+ public:
+ Return<void> onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override { return Void(); }
+
+ Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
+ return Void();
+ }
+
+ Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
+ return Void();
+ }
+
+ Return<void> onError(uint64_t, int32_t userId, FaceError error, int32_t) override {
+ FaceCallbackArgs args = {};
+ args.error = error;
+ args.userId = userId;
+ NotifyFromCallback(kCallbackNameOnError, args);
+ return Void();
+ }
+
+ Return<void> onRemoved(uint64_t, const hidl_vec<uint32_t>&, int32_t) override { return Void(); }
+
+ Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
+ return Void();
+ }
+
+ Return<void> onLockoutChanged(uint64_t) override { return Void(); }
+};
+
+// Test class for the BiometricsFace HAL.
+class FaceHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ mService = IBiometricsFace::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ mCallback = new FaceCallback();
+ mCallback->SetWaitTimeoutDefault(kTimeout);
+ Return<void> ret1 = mService->setCallback(mCallback, [](const OptionalUint64& res) {
+ ASSERT_EQ(Status::OK, res.status);
+ // Makes sure the "deviceId" represented by "res.value" is not 0.
+ // 0 would mean the HIDL is not available.
+ ASSERT_NE(0UL, res.value);
+ });
+ ASSERT_TRUE(ret1.isOk());
+ Return<Status> ret2 = mService->setActiveUser(kUserId, kFacedataDir);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret2));
+ }
+
+ void TearDown() override {}
+
+ sp<IBiometricsFace> mService;
+ sp<FaceCallback> mCallback;
+};
+
+// enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FaceHidlTest, Enroll2_2ZeroHatTest) {
+ // Filling HAT with zeros
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; i++) {
+ token[i] = 0;
+ }
+
+ hidl_handle windowId = nullptr;
+ Return<Status> ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid HAT should fail.
+TEST_P(FaceHidlTest, Enroll2_2GarbageHatTest) {
+ // Filling HAT with pseudorandom invalid data.
+ // Using default seed to make the test reproducible.
+ std::mt19937 gen(std::mt19937::default_seed);
+ std::uniform_int_distribution<uint8_t> dist;
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; ++i) {
+ token[i] = dist(gen);
+ }
+
+ hidl_handle windowId = nullptr;
+ Return<Status> ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FaceHidlTest, EnrollRemotelyZeroHatTest) {
+ // Filling HAT with zeros
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; i++) {
+ token[i] = 0;
+ }
+
+ Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid HAT should fail.
+TEST_P(FaceHidlTest, EnrollRemotelyGarbageHatTest) {
+ // Filling HAT with pseudorandom invalid data.
+ // Using default seed to make the test reproducible.
+ std::mt19937 gen(std::mt19937::default_seed);
+ std::uniform_int_distribution<uint8_t> dist;
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; ++i) {
+ token[i] = dist(gen);
+ }
+
+ Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+} // anonymous namespace
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, FaceHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBiometricsFace::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/biometrics/fingerprint/2.2/Android.bp b/biometrics/fingerprint/2.2/Android.bp
new file mode 100644
index 0000000..6c769ac
--- /dev/null
+++ b/biometrics/fingerprint/2.2/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.biometrics.fingerprint@2.2",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IBiometricsFingerprint.hal",
+ "IBiometricsFingerprintClientCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.biometrics.fingerprint@2.1",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal
new file mode 100644
index 0000000..0651034
--- /dev/null
+++ b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint@2.2;
+
+import @2.1::IBiometricsFingerprint;
+import @2.1::RequestStatus;
+
+interface IBiometricsFingerprint extends @2.1::IBiometricsFingerprint {
+ /**
+ * Fingerprint enroll request:
+ * Switches the HAL state machine to collect and store a new fingerprint
+ * template. Switches back as soon as enroll is complete, signalled by
+ * (fingerprintMsg.type == FINGERPRINT_TEMPLATE_ENROLLING &&
+ * fingerprintMsg.data.enroll.samplesRemaining == 0)
+ * or after timeoutSec seconds.
+ * The fingerprint template must be assigned to the group gid.
+ *
+ * @param hat a valid Hardware Authentication Token (HAT), generated
+ * as a result of a preEnroll() call.
+ * @param gid a framework defined fingerprint set (group) id.
+ * @param timeoutSec a timeout in seconds.
+ * @param windowId optional ID of an illumination window for optical under
+ * display fingerprint sensors. Must contain a null pointer if not used.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ *
+ * A notify() function may be called with a more detailed error structure.
+ */
+ enroll_2_2(vec<uint8_t> hat, uint32_t gid, uint32_t timeoutSec, handle windowId)
+ generates (RequestStatus debugErrno);
+
+ /**
+ * Authenticates an operation identified by operationId
+ *
+ * @param operationId operation id.
+ * @param gid fingerprint group id.
+ * @param windowId optional ID of an illumination window for optical under
+ * display fingerprint sensors. Must contain a null pointer if not used.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ */
+ authenticate_2_2(uint64_t operationId, uint32_t gid, handle windowId)
+ generates (RequestStatus debugErrno);
+};
diff --git a/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal b/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal
new file mode 100644
index 0000000..14c2b12
--- /dev/null
+++ b/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint@2.2;
+
+import @2.1::IBiometricsFingerprintClientCallback;
+
+/*
+ * This HAL interface communicates asynchronous results from the
+ * fingerprint driver in response to user actions on the fingerprint sensor
+ */
+interface IBiometricsFingerprintClientCallback extends @2.1::IBiometricsFingerprintClientCallback {
+ /**
+ * Sent when a fingerprint image is acquired by the sensor
+ * @param deviceId the instance of this fingerprint device
+ * @param acquiredInfo a message about the quality of the acquired image
+ * @param vendorCode a vendor-specific message about the quality of the image. Only
+ * valid when acquiredInfo == ACQUIRED_VENDOR
+ */
+ oneway onAcquired_2_2(uint64_t deviceId, FingerprintAcquiredInfo acquiredInfo,
+ int32_t vendorCode);
+};
diff --git a/biometrics/fingerprint/2.2/types.hal b/biometrics/fingerprint/2.2/types.hal
new file mode 100644
index 0000000..2c1d3f3
--- /dev/null
+++ b/biometrics/fingerprint/2.2/types.hal
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint@2.2;
+
+import @2.1::FingerprintAcquiredInfo;
+
+/**
+ * Fingerprint acquisition info is meant as feedback for the current operation.
+ * Anything but START and ACQUIRED_GOOD must be shown to the user as feedback on
+ * how to take action on the current operation. For example,
+ * ACQUIRED_IMAGER_DIRTY may be used to tell the user to clean the sensor if it
+ * is detected to be dirty.
+ * If this causes the current operation to fail, an additional ERROR_CANCELED
+ * must be sent to stop the operation in progress (e.g. enrollment).
+ * In general, these messages will result in a "Try again" message.
+ */
+enum FingerprintAcquiredInfo : @2.1::FingerprintAcquiredInfo {
+ /**
+ * This message represents the earliest message sent at the beginning of the
+ * authentication pipeline. It is expected to be used to measure latency. For
+ * example, in a camera-based authentication system it's expected to be sent
+ * prior to camera initialization. Note this should be sent whenever
+ * authentication is restarted (see IBiometricsFace#userActivity).
+ * The framework will measure latency based on the time between the last START
+ * message and the onAuthenticated callback.
+ */
+ START = 7,
+};
diff --git a/biometrics/fingerprint/2.2/vts/functional/Android.bp b/biometrics/fingerprint/2.2/vts/functional/Android.bp
new file mode 100644
index 0000000..496570c
--- /dev/null
+++ b/biometrics/fingerprint/2.2/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+ name: "VtsHalBiometricsFingerprintV2_2TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalBiometricsFingerprintV2_2TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.biometrics.fingerprint@2.1",
+ "android.hardware.biometrics.fingerprint@2.2",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
new file mode 100644
index 0000000..50bd4ab
--- /dev/null
+++ b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "fingerprint_hidl_hal_test"
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/properties.h>
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h>
+#include <android/hardware/biometrics/fingerprint/2.2/IBiometricsFingerprint.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+
+#include <cinttypes>
+#include <random>
+
+using android::sp;
+using android::base::GetUintProperty;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::biometrics::fingerprint::V2_1::FingerprintAcquiredInfo;
+using android::hardware::biometrics::fingerprint::V2_1::FingerprintError;
+using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
+using android::hardware::biometrics::fingerprint::V2_1::RequestStatus;
+using android::hardware::biometrics::fingerprint::V2_2::IBiometricsFingerprint;
+
+namespace {
+
+constexpr uint32_t kTimeoutSec = 3;
+constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
+constexpr uint32_t kGroupId = 99;
+constexpr char kCallbackNameOnError[] = "onError";
+
+// Callback arguments that need to be captured for the tests.
+struct FingerprintCallbackArgs {
+ // The error passed to the last onError() callback.
+ FingerprintError error;
+
+ // The deviceId passed to the last callback.
+ uint64_t deviceId;
+};
+
+// Test callback class for the BiometricsFingerprint HAL.
+// The HAL will call these callback methods to notify about completed operations
+// or encountered errors.
+class FingerprintCallback : public ::testing::VtsHalHidlTargetCallbackBase<FingerprintCallbackArgs>,
+ public IBiometricsFingerprintClientCallback {
+ public:
+ Return<void> onEnrollResult(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+
+ Return<void> onAcquired(uint64_t, FingerprintAcquiredInfo, int32_t) override { return Void(); }
+
+ Return<void> onAuthenticated(uint64_t, uint32_t, uint32_t, const hidl_vec<uint8_t>&) override {
+ return Void();
+ }
+
+ Return<void> onError(uint64_t deviceId, FingerprintError error, int32_t) override {
+ FingerprintCallbackArgs args = {};
+ args.error = error;
+ args.deviceId = deviceId;
+ NotifyFromCallback(kCallbackNameOnError, args);
+ return Void();
+ }
+
+ Return<void> onRemoved(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+
+ Return<void> onEnumerate(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+};
+
+class FingerprintHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ mService = IBiometricsFingerprint::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ mCallback = new FingerprintCallback();
+ mCallback->SetWaitTimeoutDefault(kTimeout);
+ Return<uint64_t> ret1 = mService->setNotify(mCallback);
+ ASSERT_NE(0UL, static_cast<uint64_t>(ret1));
+
+ /*
+ * Devices shipped from now on will instead store
+ * fingerprint data under /data/vendor_de/<user-id>/fpdata.
+ * Support for /data/vendor_de and /data/vendor_ce has been added to vold.
+ */
+
+ auto api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+ if (api_level == 0) {
+ api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
+ }
+ ASSERT_NE(api_level, 0);
+
+ // 27 is the API number for O-MR1
+ string tmpDir;
+ if (api_level <= 27) {
+ tmpDir = "/data/system/users/0/fpdata/";
+ } else {
+ tmpDir = "/data/vendor_de/0/fpdata/";
+ }
+
+ Return<RequestStatus> res = mService->setActiveGroup(kGroupId, tmpDir);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ }
+
+ sp<IBiometricsFingerprint> mService;
+ sp<FingerprintCallback> mCallback;
+};
+
+// Enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FingerprintHidlTest, EnrollZeroHatTest) {
+ // Filling HAT with zeros
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; i++) {
+ token[i] = 0;
+ }
+
+ hidl_handle windowId = nullptr;
+ Return<RequestStatus> ret = mService->enroll_2_2(token, kGroupId, kTimeoutSec, windowId);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(ret));
+
+ // At least one call to onError should occur
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ ASSERT_NE(FingerprintError::ERROR_NO_ERROR, res.args->error);
+}
+
+// Enroll with an invalid (null) HAT should fail.
+TEST_P(FingerprintHidlTest, EnrollGarbageHatTest) {
+ // Filling HAT with pseudorandom invalid data.
+ // Using default seed to make the test reproducible.
+ std::mt19937 gen(std::mt19937::default_seed);
+ std::uniform_int_distribution<uint8_t> dist;
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; ++i) {
+ token[i] = dist(gen);
+ }
+
+ hidl_handle windowId = nullptr;
+ Return<RequestStatus> ret = mService->enroll_2_2(token, kGroupId, kTimeoutSec, windowId);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(ret));
+
+ // At least one call to onError should occur
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ ASSERT_NE(FingerprintError::ERROR_NO_ERROR, res.args->error);
+}
+
+} // anonymous namespace
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, FingerprintHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ IBiometricsFingerprint::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp
index 3e5c6d7..f4390b2 100644
--- a/camera/common/1.0/default/Android.bp
+++ b/camera/common/1.0/default/Android.bp
@@ -21,6 +21,7 @@
"libcamera_metadata",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"libexif",
],
include_dirs: ["system/media/private/camera/include"],
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index b8c40e9..ac32c95 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -27,7 +27,9 @@
using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error;
using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error;
+using MapperErrorV4 = android::hardware::graphics::mapper::V4_0::Error;
using IMapperV3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapperV4 = android::hardware::graphics::mapper::V4_0::IMapper;
HandleImporter::HandleImporter() : mInitialized(false) {}
@@ -36,6 +38,12 @@
return;
}
+ mMapperV4 = IMapperV4::getService();
+ if (mMapperV4 != nullptr) {
+ mInitialized = true;
+ return;
+ }
+
mMapperV3 = IMapperV3::getService();
if (mMapperV3 != nullptr) {
mInitialized = true;
@@ -53,6 +61,7 @@
}
void HandleImporter::cleanup() {
+ mMapperV4.clear();
mMapperV3.clear();
mMapperV2.clear();
mInitialized = false;
@@ -151,6 +160,10 @@
initializeLocked();
}
+ if (mMapperV4 != nullptr) {
+ return importBufferInternal<IMapperV4, MapperErrorV4>(mMapperV4, handle);
+ }
+
if (mMapperV3 != nullptr) {
return importBufferInternal<IMapperV3, MapperErrorV3>(mMapperV3, handle);
}
@@ -159,7 +172,7 @@
return importBufferInternal<IMapper, MapperErrorV2>(mMapperV2, handle);
}
- ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+ ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
return false;
}
@@ -169,12 +182,17 @@
}
Mutex::Autolock lock(mLock);
- if (mMapperV3 == nullptr && mMapperV2 == nullptr) {
- ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+ if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
+ ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
return;
}
- if (mMapperV3 != nullptr) {
+ if (mMapperV4 != nullptr) {
+ auto ret = mMapperV4->freeBuffer(const_cast<native_handle_t*>(handle));
+ if (!ret.isOk()) {
+ ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
+ }
+ } else if (mMapperV3 != nullptr) {
auto ret = mMapperV3->freeBuffer(const_cast<native_handle_t*>(handle));
if (!ret.isOk()) {
ALOGE("%s: mapper freeBuffer failed: %s",
@@ -222,14 +240,26 @@
initializeLocked();
}
- if (mMapperV3 == nullptr && mMapperV2 == nullptr) {
- ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+ if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
+ ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
return ret;
}
hidl_handle acquireFenceHandle;
auto buffer = const_cast<native_handle_t*>(buf);
- if (mMapperV3 != nullptr) {
+ if (mMapperV4 != nullptr) {
+ IMapperV4::Rect accessRegion{0, 0, static_cast<int>(size), 1};
+ // No need to use bytesPerPixel and bytesPerStride because we are using
+ // an 1-D buffer and accressRegion.
+ mMapperV4->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpPtr) {
+ if (tmpError == MapperErrorV4::NONE) {
+ ret = tmpPtr;
+ } else {
+ ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+ }
+ });
+ } else if (mMapperV3 != nullptr) {
IMapperV3::Rect accessRegion { 0, 0, static_cast<int>(size), 1 };
// No need to use bytesPerPixel and bytesPerStride because we are using
// an 1-D buffer and accressRegion.
@@ -269,6 +299,16 @@
initializeLocked();
}
+ if (mMapperV4 != nullptr) {
+ // No device currently supports IMapper 4.0 so it is safe to just return an error code here.
+ //
+ // This will be supported by a combination of lock and BufferMetadata getters. We are going
+ // to refactor all the IAllocator/IMapper versioning code into a shared library. We will
+ // then add the IMapper 4.0 lockYCbCr support then.
+ ALOGE("%s: MapperV4 doesn't support lockYCbCr directly!", __FUNCTION__);
+ return {};
+ }
+
if (mMapperV3 != nullptr) {
return lockYCbCrInternal<IMapperV3, MapperErrorV3>(
mMapperV3, buf, cpuUsage, accessRegion);
@@ -279,11 +319,14 @@
mMapperV2, buf, cpuUsage, accessRegion);
}
- ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+ ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
return {};
}
int HandleImporter::unlock(buffer_handle_t& buf) {
+ if (mMapperV4 != nullptr) {
+ return unlockInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf);
+ }
if (mMapperV3 != nullptr) {
return unlockInternal<IMapperV3, MapperErrorV3>(mMapperV3, buf);
}
@@ -291,7 +334,7 @@
return unlockInternal<IMapper, MapperErrorV2>(mMapperV2, buf);
}
- ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+ ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
return -1;
}
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h
index a93d455..fc2bbd1 100644
--- a/camera/common/1.0/default/include/HandleImporter.h
+++ b/camera/common/1.0/default/include/HandleImporter.h
@@ -17,10 +17,11 @@
#ifndef CAMERA_COMMON_1_0_HANDLEIMPORTED_H
#define CAMERA_COMMON_1_0_HANDLEIMPORTED_H
-#include <utils/Mutex.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
#include <cutils/native_handle.h>
+#include <utils/Mutex.h>
using android::hardware::graphics::mapper::V2_0::IMapper;
using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
@@ -70,6 +71,7 @@
bool mInitialized;
sp<IMapper> mMapperV2;
sp<graphics::mapper::V3_0::IMapper> mMapperV3;
+ sp<graphics::mapper::V4_0::IMapper> mMapperV4;
};
} // namespace helper
diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp
index 97d0b5f..e6e6485 100644
--- a/camera/device/1.0/default/Android.bp
+++ b/camera/device/1.0/default/Android.bp
@@ -14,6 +14,7 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hardware.graphics.common@1.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
index e4d9e85..878878d 100644
--- a/camera/device/3.2/default/Android.bp
+++ b/camera/device/3.2/default/Android.bp
@@ -13,6 +13,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"liblog",
"libhardware",
"libcamera_metadata",
diff --git a/camera/device/3.3/default/Android.bp b/camera/device/3.3/default/Android.bp
index d964f3d..7d51434 100644
--- a/camera/device/3.3/default/Android.bp
+++ b/camera/device/3.3/default/Android.bp
@@ -15,6 +15,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"liblog",
"libhardware",
"libcamera_metadata",
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
index 71a9e77..59e8329 100644
--- a/camera/device/3.4/default/Android.bp
+++ b/camera/device/3.4/default/Android.bp
@@ -48,6 +48,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"liblog",
"libhardware",
"libcamera_metadata",
@@ -84,6 +85,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"liblog",
"libhardware",
"libcamera_metadata",
diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp
index 43362fd..1c307ee 100644
--- a/camera/device/3.5/default/Android.bp
+++ b/camera/device/3.5/default/Android.bp
@@ -49,6 +49,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"liblog",
"libhardware",
"libcamera_metadata",
@@ -81,7 +82,8 @@
"android.hardware.camera.device@3.5",
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"liblog",
"libhardware",
"libcamera_metadata",
diff --git a/camera/device/3.5/types.hal b/camera/device/3.5/types.hal
index 6d861e2..38493b4 100644
--- a/camera/device/3.5/types.hal
+++ b/camera/device/3.5/types.hal
@@ -23,7 +23,8 @@
/**
* If the result metadata cannot be produced for a physical camera device part of a logical
* multi-camera, then HAL must invoke the notification callback and pass a message with ERROR_RESULT
- * code and errorStreamId that contains the stream id associated with that physical device.
+ * code and errorStreamId that contains the stream id associated with that physical device. Such
+ * callback must be made before the final processCaptureResult() call for the corresponding request.
* The behavior during absent result metadata remains unchanged for a logical or a non-logical
* camera device and the errorStreamId must be set to -1.
*/
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.3/types.hal b/camera/metadata/3.3/types.hal
index ca0c9d6..0d89681 100644
--- a/camera/metadata/3.3/types.hal
+++ b/camera/metadata/3.3/types.hal
@@ -71,8 +71,10 @@
/** android.lens.poseReference [static, enum, public]
*
- * <p>The origin for ANDROID_LENS_POSE_TRANSLATION.</p>
+ * <p>The origin for ANDROID_LENS_POSE_TRANSLATION, and the accuracy of
+ * ANDROID_LENS_POSE_TRANSLATION and ANDROID_LENS_POSE_ROTATION.</p>
*
+ * @see ANDROID_LENS_POSE_ROTATION
* @see ANDROID_LENS_POSE_TRANSLATION
*/
ANDROID_LENS_POSE_REFERENCE = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_LENS_END,
diff --git a/camera/metadata/3.5/Android.bp b/camera/metadata/3.5/Android.bp
new file mode 100644
index 0000000..224c369
--- /dev/null
+++ b/camera/metadata/3.5/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.camera.metadata@3.5",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ ],
+ interfaces: [
+ "android.hardware.camera.metadata@3.2",
+ "android.hardware.camera.metadata@3.3",
+ "android.hardware.camera.metadata@3.4",
+ ],
+ gen_java: true,
+}
diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal
new file mode 100644
index 0000000..4e2252c
--- /dev/null
+++ b/camera/metadata/3.5/types.hal
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata@3.5;
+
+import android.hardware.camera.metadata@3.2;
+import android.hardware.camera.metadata@3.3;
+import android.hardware.camera.metadata@3.4;
+
+// No new metadata sections added in this revision
+
+/**
+ * Main enumeration for defining camera metadata tags added in this revision
+ *
+ * <p>Partial documentation is included for each tag; for complete documentation, reference
+ * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
+ */
+enum CameraMetadataTag : @3.4::CameraMetadataTag {
+ /** android.control.availableBokehMaxSizes [static, int32[], ndk_public]
+ *
+ * <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_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]
+ *
+ * <p>Whether bokeh mode is enabled for a particular capture request.</p>
+ */
+ 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,
+
+ /** android.scaler.availableRotateAndCropModes [static, byte[], public]
+ *
+ * <p>List of rotate-and-crop modes for ANDROID_SCALER_ROTATE_AND_CROP that are supported by this camera device.</p>
+ *
+ * @see ANDROID_SCALER_ROTATE_AND_CROP
+ */
+ ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_SCALER_END_3_4,
+
+ /** android.scaler.rotateAndCrop [dynamic, enum, public]
+ *
+ * <p>Whether a rotation-and-crop operation is applied to processed
+ * outputs from the camera.</p>
+ */
+ ANDROID_SCALER_ROTATE_AND_CROP,
+
+ ANDROID_SCALER_END_3_5,
+
+};
+
+/*
+ * Enumeration definitions for the various entries that need them
+ */
+
+/** android.control.bokehMode enumeration values
+ * @see ANDROID_CONTROL_BOKEH_MODE
+ */
+enum CameraMetadataEnumAndroidControlBokehMode : uint32_t {
+ ANDROID_CONTROL_BOKEH_MODE_OFF,
+ ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE,
+ ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS,
+};
+
+/** android.lens.poseReference enumeration values added since v3.3
+ * @see ANDROID_LENS_POSE_REFERENCE
+ */
+enum CameraMetadataEnumAndroidLensPoseReference :
+ @3.3::CameraMetadataEnumAndroidLensPoseReference {
+ ANDROID_LENS_POSE_REFERENCE_UNDEFINED,
+};
+
+/** android.request.availableCapabilities enumeration values added since v3.4
+ * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
+ */
+enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
+ @3.4::CameraMetadataEnumAndroidRequestAvailableCapabilities {
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING,
+};
+
+/** android.scaler.rotateAndCrop enumeration values
+ * @see ANDROID_SCALER_ROTATE_AND_CROP
+ */
+enum CameraMetadataEnumAndroidScalerRotateAndCrop : uint32_t {
+ ANDROID_SCALER_ROTATE_AND_CROP_NONE,
+ ANDROID_SCALER_ROTATE_AND_CROP_90,
+ ANDROID_SCALER_ROTATE_AND_CROP_180,
+ ANDROID_SCALER_ROTATE_AND_CROP_270,
+ ANDROID_SCALER_ROTATE_AND_CROP_AUTO,
+};
diff --git a/camera/provider/2.4/ICameraProvider.hal b/camera/provider/2.4/ICameraProvider.hal
index 74c3ff1..105629d 100644
--- a/camera/provider/2.4/ICameraProvider.hal
+++ b/camera/provider/2.4/ICameraProvider.hal
@@ -115,7 +115,7 @@
* INTERNAL_ERROR:
* A camera ID list cannot be created. This may be due to
* a failure to initialize the camera subsystem, for example.
- * @return cameraDeviceServiceNames The vector of internal camera device
+ * @return cameraDeviceNames The vector of internal camera device
* names known to this provider.
*/
getCameraIdList()
diff --git a/camera/provider/2.4/ICameraProviderCallback.hal b/camera/provider/2.4/ICameraProviderCallback.hal
index 63dd3c5..8822305 100644
--- a/camera/provider/2.4/ICameraProviderCallback.hal
+++ b/camera/provider/2.4/ICameraProviderCallback.hal
@@ -39,7 +39,7 @@
* are already present, as soon as the callbacks are available through
* setCallback.
*
- * @param cameraDeviceServiceName The name of the camera device that has a
+ * @param cameraDeviceName The name of the camera device that has a
* new status.
* @param newStatus The new status that device is in.
*
@@ -57,7 +57,7 @@
* android.flash.info.available is reported as true via the
* ICameraDevice::getCameraCharacteristics call.
*
- * @param cameraDeviceServiceName The name of the camera device that has a
+ * @param cameraDeviceName The name of the camera device that has a
* new status.
* @param newStatus The new status that device is in.
*
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index 95e27fd..9203b8d 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -13,6 +13,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"camera.device@1.0-impl",
@@ -51,6 +52,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"camera.device@3.3-impl",
@@ -93,6 +95,8 @@
"android.hardware.camera.provider@2.4-external",
"android.hardware.camera.provider@2.4-legacy",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"camera.device@1.0-impl",
@@ -137,6 +141,8 @@
"android.hardware.camera.device@3.5",
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libbinder",
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 2c3ed37..15f5c9a 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -41,14 +41,12 @@
"android.hardware.camera.metadata@3.4",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.allocator@3.0",
+ "android.hardware.camera.provider@2.6",
"android.hardware.graphics.common@1.0",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
"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 a5369e7..b4092ca 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -20,51 +20,52 @@
#include <chrono>
#include <mutex>
#include <regex>
+#include <string>
#include <unordered_map>
#include <unordered_set>
#include <condition_variable>
#include <inttypes.h>
-#include <android/hardware/camera/device/1.0/ICameraDevice.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <android/hardware/camera/device/3.5/ICameraDevice.h>
-#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
-#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
-#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
-#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
-#include <android/hardware/camera/metadata/3.4/types.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
-#include <binder/MemoryHeapBase.h>
#include <CameraMetadata.h>
#include <CameraParameters.h>
+#include <android/hardware/camera/device/1.0/ICameraDevice.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.5/ICameraDevice.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+#include <android/hardware/camera/metadata/3.4/types.h>
+#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
+#include <android/hardware/camera/provider/2.6/ICameraProvider.h>
+#include <android/hardware/camera/provider/2.6/ICameraProviderCallback.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
#include <cutils/properties.h>
#include <fmq/MessageQueue.h>
#include <grallocusage/GrallocUsageConversion.h>
+#include <gtest/gtest.h>
#include <gui/BufferItemConsumer.h>
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
#include <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>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/2.0/types.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#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;
@@ -286,27 +287,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) {}
@@ -547,18 +527,19 @@
}
// 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;
ASSERT_TRUE(parseProviderName(service_name, &mProviderType, &id));
- castProvider(mProvider, &mProvider2_5);
+ castProvider(mProvider, &mProvider2_5, &mProvider2_6);
notifyDeviceState(provider::V2_5::DeviceState::NORMAL);
}
virtual void TearDown() override {}
@@ -622,7 +603,7 @@
Return<void> returnStreamBuffers(const hidl_vec<StreamBuffer>& buffers) override;
- void setCurrentStreamConfig(const hidl_vec<V3_2::Stream>& streams,
+ void setCurrentStreamConfig(const hidl_vec<V3_4::Stream>& streams,
const hidl_vec<V3_2::HalStream>& halStreams);
void waitForBuffersReturned();
@@ -639,7 +620,7 @@
/* members for requestStreamBuffers() and returnStreamBuffers()*/
std::mutex mLock; // protecting members below
bool mUseHalBufManager = false;
- hidl_vec<V3_2::Stream> mStreams;
+ hidl_vec<V3_4::Stream> mStreams;
hidl_vec<V3_2::HalStream> mHalStreams;
uint64_t mNextBufferId = 1;
using OutstandingBuffers = std::unordered_map<uint64_t, hidl_handle>;
@@ -730,8 +711,9 @@
sp<ICameraDeviceSession> *session /*out*/,
camera_metadata_t **staticMeta /*out*/,
::android::sp<ICameraDevice> *device = nullptr/*out*/);
- void castProvider(const sp<provider::V2_4::ICameraProvider> &provider,
- sp<provider::V2_5::ICameraProvider> *provider2_5 /*out*/);
+ void castProvider(const sp<provider::V2_4::ICameraProvider>& provider,
+ sp<provider::V2_5::ICameraProvider>* provider2_5 /*out*/,
+ sp<provider::V2_6::ICameraProvider>* provider2_6 /*out*/);
void castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
@@ -776,6 +758,8 @@
const CameraMetadata& chars, int deviceVersion,
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(
@@ -797,9 +781,11 @@
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(camera_metadata_t *staticMeta,
+ static Status getAvailableOutputStreams(const camera_metadata_t *staticMeta,
std::vector<AvailableStream> &outputStreams,
const AvailableStream *threshold = nullptr);
static Status getJpegBufferSize(camera_metadata_t *staticMeta,
@@ -865,6 +851,8 @@
int32_t partialResultCount;
// For buffer drop errors, the stream ID for the stream that lost a buffer.
+ // For physical sub-camera result errors, the Id of the physical stream
+ // for the physical sub-camera.
// Otherwise -1.
int32_t errorStreamId;
@@ -878,6 +866,8 @@
// return from HAL but framework.
::android::Vector<StreamBuffer> resultOutputBuffers;
+ std::unordered_set<std::string> expectedPhysicalResults;
+
InFlightRequest() :
shutterTimestamp(0),
errorCodeValid(false),
@@ -907,6 +897,24 @@
partialResultCount(0),
errorStreamId(-1),
hasInputBuffer(hasInput) {}
+
+ InFlightRequest(ssize_t numBuffers, bool hasInput,
+ bool partialResults, uint32_t partialCount,
+ const std::unordered_set<std::string>& extraPhysicalResult,
+ std::shared_ptr<ResultMetadataQueue> queue = nullptr) :
+ shutterTimestamp(0),
+ errorCodeValid(false),
+ errorCode(ErrorCode::ERROR_BUFFER),
+ usePartialResult(partialResults),
+ numPartialResults(partialCount),
+ resultQueue(queue),
+ haveResultMetadata(false),
+ numBuffersLeft(numBuffers),
+ frameNumber(0),
+ partialResultCount(0),
+ errorStreamId(-1),
+ hasInputBuffer(hasInput),
+ expectedPhysicalResults(extraPhysicalResult) {}
};
// Map from frame number to the in-flight request state
@@ -932,6 +940,7 @@
// Camera provider service
sp<ICameraProvider> mProvider;
sp<::android::hardware::camera::provider::V2_5::ICameraProvider> mProvider2_5;
+ sp<::android::hardware::camera::provider::V2_6::ICameraProvider> mProvider2_6;
// Camera provider type.
std::string mProviderType;
@@ -1124,6 +1133,13 @@
return notify;
}
+ if (physicalCameraMetadata.size() != request->expectedPhysicalResults.size()) {
+ ALOGE("%s: Frame %d: Returned physical metadata count %zu "
+ "must be equal to expected count %zu", __func__, frameNumber,
+ physicalCameraMetadata.size(), request->expectedPhysicalResults.size());
+ ADD_FAILURE();
+ return notify;
+ }
std::vector<::android::hardware::camera::device::V3_2::CameraMetadata> physResultMetadata;
physResultMetadata.resize(physicalCameraMetadata.size());
for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
@@ -1251,11 +1267,11 @@
}
void CameraHidlTest::DeviceCb::setCurrentStreamConfig(
- const hidl_vec<V3_2::Stream>& streams, const hidl_vec<V3_2::HalStream>& halStreams) {
+ const hidl_vec<V3_4::Stream>& streams, const hidl_vec<V3_2::HalStream>& halStreams) {
ASSERT_EQ(streams.size(), halStreams.size());
ASSERT_NE(streams.size(), 0);
for (size_t i = 0; i < streams.size(); i++) {
- ASSERT_EQ(streams[i].id, halStreams[i].id);
+ ASSERT_EQ(streams[i].v3_2.id, halStreams[i].id);
}
std::lock_guard<std::mutex> l(mLock);
mUseHalBufManager = true;
@@ -1293,16 +1309,6 @@
std::lock_guard<std::mutex> l(mParent->mLock);
for (size_t i = 0; i < messages.size(); i++) {
- ssize_t idx = mParent->mInflightMap.indexOfKey(
- messages[i].msg.shutter.frameNumber);
- if (::android::NAME_NOT_FOUND == idx) {
- ALOGE("%s: Unexpected frame number! received: %u",
- __func__, messages[i].msg.shutter.frameNumber);
- ADD_FAILURE();
- break;
- }
- InFlightRequest *r = mParent->mInflightMap.editValueAt(idx);
-
switch(messages[i].type) {
case MsgType::ERROR:
if (ErrorCode::ERROR_DEVICE == messages[i].msg.error.errorCode) {
@@ -1310,13 +1316,59 @@
__func__);
ADD_FAILURE();
} else {
- r->errorCodeValid = true;
- r->errorCode = messages[i].msg.error.errorCode;
- r->errorStreamId = messages[i].msg.error.errorStreamId;
+ ssize_t idx = mParent->mInflightMap.indexOfKey(
+ messages[i].msg.error.frameNumber);
+ if (::android::NAME_NOT_FOUND == idx) {
+ ALOGE("%s: Unexpected error frame number! received: %u",
+ __func__, messages[i].msg.error.frameNumber);
+ ADD_FAILURE();
+ break;
+ }
+ InFlightRequest *r = mParent->mInflightMap.editValueAt(idx);
+
+ if (ErrorCode::ERROR_RESULT == messages[i].msg.error.errorCode &&
+ messages[i].msg.error.errorStreamId != -1) {
+ if (r->haveResultMetadata) {
+ ALOGE("%s: Camera must report physical camera result error before "
+ "the final capture result!", __func__);
+ ADD_FAILURE();
+ } else {
+ for (size_t j = 0; j < mStreams.size(); j++) {
+ if (mStreams[j].v3_2.id == messages[i].msg.error.errorStreamId) {
+ hidl_string physicalCameraId = mStreams[j].physicalCameraId;
+ bool idExpected = r->expectedPhysicalResults.find(
+ physicalCameraId) != r->expectedPhysicalResults.end();
+ if (!idExpected) {
+ ALOGE("%s: ERROR_RESULT's error stream's physicalCameraId "
+ "%s must be expected", __func__,
+ physicalCameraId.c_str());
+ ADD_FAILURE();
+ } else {
+ r->expectedPhysicalResults.erase(physicalCameraId);
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ r->errorCodeValid = true;
+ r->errorCode = messages[i].msg.error.errorCode;
+ r->errorStreamId = messages[i].msg.error.errorStreamId;
+ }
}
break;
case MsgType::SHUTTER:
+ {
+ ssize_t idx = mParent->mInflightMap.indexOfKey(messages[i].msg.shutter.frameNumber);
+ if (::android::NAME_NOT_FOUND == idx) {
+ ALOGE("%s: Unexpected shutter frame number! received: %u",
+ __func__, messages[i].msg.shutter.frameNumber);
+ ADD_FAILURE();
+ break;
+ }
+ InFlightRequest *r = mParent->mInflightMap.editValueAt(idx);
r->shutterTimestamp = messages[i].msg.shutter.timestamp;
+ }
break;
default:
ALOGE("%s: Unsupported notify message %d", __func__,
@@ -1357,7 +1409,7 @@
for (size_t i = 0; i < bufReqs.size(); i++) {
bool found = false;
for (size_t idx = 0; idx < mStreams.size(); idx++) {
- if (bufReqs[i].streamId == mStreams[idx].id) {
+ if (bufReqs[i].streamId == mStreams[idx].v3_2.id) {
found = true;
indexes[i] = idx;
break;
@@ -1381,7 +1433,7 @@
const auto& halStream = mHalStreams[idx];
const V3_5::BufferRequest& bufReq = bufReqs[i];
if (mOutstandingBufferIds[idx].size() + bufReq.numBuffersRequested > halStream.maxBuffers) {
- bufRets[i].streamId = stream.id;
+ bufRets[i].streamId = stream.v3_2.id;
bufRets[i].val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
allStreamOk = false;
continue;
@@ -1390,17 +1442,17 @@
hidl_vec<StreamBuffer> tmpRetBuffers(bufReq.numBuffersRequested);
for (size_t j = 0; j < bufReq.numBuffersRequested; j++) {
hidl_handle buffer_handle;
- mParent->allocateGraphicBuffer(stream.width, stream.height,
+ mParent->allocateGraphicBuffer(stream.v3_2.width, stream.v3_2.height,
android_convertGralloc1To0Usage(
halStream.producerUsage, halStream.consumerUsage),
halStream.overrideFormat, &buffer_handle);
- tmpRetBuffers[j] = {stream.id, mNextBufferId, buffer_handle, BufferStatus::OK,
+ tmpRetBuffers[j] = {stream.v3_2.id, mNextBufferId, buffer_handle, BufferStatus::OK,
nullptr, nullptr};
mOutstandingBufferIds[idx].insert(std::make_pair(mNextBufferId++, buffer_handle));
}
atLeastOneStreamOk = true;
- bufRets[i].streamId = stream.id;
+ bufRets[i].streamId = stream.v3_2.id;
bufRets[i].val.buffers(std::move(tmpRetBuffers));
}
@@ -1426,11 +1478,11 @@
ADD_FAILURE();
}
- std::lock_guard<std::mutex> l(mLock);
+ std::unique_lock<std::mutex> l(mLock);
for (const auto& buf : buffers) {
bool found = false;
for (size_t idx = 0; idx < mOutstandingBufferIds.size(); idx++) {
- if (mStreams[idx].id == buf.streamId &&
+ if (mStreams[idx].v3_2.id == buf.streamId &&
mOutstandingBufferIds[idx].count(buf.bufferId) == 1) {
mOutstandingBufferIds[idx].erase(buf.bufferId);
// TODO: check do we need to close/delete native handle or assume we have enough
@@ -1446,6 +1498,10 @@
ALOGE("%s: unknown buffer ID %" PRIu64, __FUNCTION__, buf.bufferId);
ADD_FAILURE();
}
+ if (!hasOutstandingBuffersLocked()) {
+ l.unlock();
+ mFlushedCondition.notify_one();
+ }
return Void();
}
@@ -1506,7 +1562,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);
@@ -1531,7 +1587,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);
@@ -1548,7 +1604,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);
@@ -1561,7 +1617,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());
@@ -1579,7 +1635,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,
@@ -1597,6 +1653,33 @@
return Void();
}
};
+
+ struct ProviderCb2_6
+ : public ::android::hardware::camera::provider::V2_6::ICameraProviderCallback {
+ virtual Return<void> cameraDeviceStatusChange(const hidl_string& cameraDeviceName,
+ CameraDeviceStatus newStatus) override {
+ ALOGI("camera device status callback name %s, status %d", cameraDeviceName.c_str(),
+ (int)newStatus);
+ return Void();
+ }
+
+ virtual Return<void> torchModeStatusChange(const hidl_string& cameraDeviceName,
+ TorchModeStatus newStatus) override {
+ ALOGI("Torch mode status callback name %s, status %d", cameraDeviceName.c_str(),
+ (int)newStatus);
+ return Void();
+ }
+
+ virtual Return<void> physicalCameraDeviceStatusChange(
+ const hidl_string& cameraDeviceName, const hidl_string& physicalCameraDeviceName,
+ CameraDeviceStatus newStatus) override {
+ ALOGI("physical camera device status callback name %s, physical camera name %s,"
+ " status %d",
+ cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(), (int)newStatus);
+ return Void();
+ }
+ };
+
sp<ProviderCb> cb = new ProviderCb;
auto status = mProvider->setCallback(cb);
ASSERT_TRUE(status.isOk());
@@ -1604,10 +1687,20 @@
status = mProvider->setCallback(nullptr);
ASSERT_TRUE(status.isOk());
ASSERT_EQ(Status::OK, status);
+
+ if (mProvider2_6.get() != nullptr) {
+ sp<ProviderCb2_6> cb = new ProviderCb2_6;
+ auto status = mProvider2_6->setCallback(cb);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_EQ(Status::OK, status);
+ status = mProvider2_6->setCallback(nullptr);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_EQ(Status::OK, status);
+ }
}
// Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device
-TEST_F(CameraHidlTest, getCameraDeviceInterface) {
+TEST_P(CameraHidlTest, getCameraDeviceInterface) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
for (const auto& name : cameraDeviceNames) {
@@ -1649,7 +1742,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) {
@@ -1719,7 +1812,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) {
@@ -1767,7 +1860,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) {
@@ -1787,7 +1880,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) {
@@ -1812,7 +1905,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) {
@@ -1837,7 +1930,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) {
@@ -1867,7 +1960,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) {
@@ -1916,7 +2009,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) {
@@ -1936,7 +2029,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) {
@@ -1963,7 +2056,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) {
@@ -1986,7 +2079,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) {
@@ -2064,7 +2157,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) {
@@ -2088,7 +2181,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,
@@ -2149,7 +2242,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) {
@@ -2195,7 +2288,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) {
@@ -2250,7 +2343,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) {
@@ -2298,7 +2391,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) {
@@ -2390,7 +2483,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) {
@@ -2456,7 +2549,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;
@@ -2594,7 +2687,7 @@
}
// Check dump functionality.
-TEST_F(CameraHidlTest, dumpState) {
+TEST_P(CameraHidlTest, dumpState) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
Return<void> ret;
@@ -2659,7 +2752,7 @@
}
// Open, dumpStates, then close
-TEST_F(CameraHidlTest, openClose) {
+TEST_P(CameraHidlTest, openClose) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
Return<void> ret;
@@ -2752,7 +2845,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) {
@@ -2809,13 +2902,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());
}
@@ -2842,7 +2929,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;
@@ -2950,7 +3037,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;
@@ -3146,7 +3233,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;
@@ -3312,7 +3399,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,
@@ -3431,7 +3518,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;
@@ -3554,7 +3641,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) {
@@ -3759,7 +3846,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;
@@ -3880,7 +3967,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)};
@@ -4048,7 +4135,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)};
@@ -4117,7 +4204,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);
@@ -4157,7 +4244,7 @@
ASSERT_TRUE(resultQueueRet.isOk());
InFlightRequest inflightReq = {static_cast<ssize_t> (halStreamConfig.streams.size()), false,
- supportsPartialResults, partialResultCount, resultQueue};
+ supportsPartialResults, partialResultCount, physicalIds, resultQueue};
std::vector<hidl_handle> graphicBuffers;
graphicBuffers.reserve(halStreamConfig.streams.size());
@@ -4236,7 +4323,7 @@
request.v3_2.outputBuffers[0].buffer = nullptr;
mInflightMap.clear();
inflightReq = {static_cast<ssize_t> (physicalIds.size()), false,
- supportsPartialResults, partialResultCount, resultQueue};
+ supportsPartialResults, partialResultCount, physicalIds, resultQueue};
mInflightMap.add(request.v3_2.frameNumber, &inflightReq);
}
@@ -4295,7 +4382,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)};
@@ -4453,7 +4540,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,
@@ -4528,7 +4615,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,
@@ -4593,7 +4680,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,
@@ -4736,7 +4823,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,
@@ -4781,7 +4868,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);
@@ -4789,7 +4876,7 @@
// Retrieve all valid output stream resolutions from the camera
// static characteristics.
-Status CameraHidlTest::getAvailableOutputStreams(camera_metadata_t *staticMeta,
+Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t *staticMeta,
std::vector<AvailableStream> &outputStreams,
const AvailableStream *threshold) {
AvailableStream depthPreviewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -5315,10 +5402,10 @@
ASSERT_EQ(physicalIds.size(), halConfig.streams.size());
*halStreamConfig = halConfig;
if (*useHalBufManager) {
- hidl_vec<V3_2::Stream> streams(physicalIds.size());
+ hidl_vec<V3_4::Stream> streams(physicalIds.size());
hidl_vec<V3_2::HalStream> halStreams(physicalIds.size());
for (size_t i = 0; i < physicalIds.size(); i++) {
- streams[i] = streams3_4[i].v3_2;
+ streams[i] = streams3_4[i];
halStreams[i] = halConfig.streams[i].v3_3.v3_2;
}
cb->setCurrentStreamConfig(streams, halStreams);
@@ -5493,9 +5580,9 @@
halStreamConfig->streams.resize(1);
halStreamConfig->streams[0] = halConfig.streams[0].v3_3.v3_2;
if (*useHalBufManager) {
- hidl_vec<V3_2::Stream> streams(1);
+ hidl_vec<V3_4::Stream> streams(1);
hidl_vec<V3_2::HalStream> halStreams(1);
- streams[0] = stream3_2;
+ streams[0] = config3_4.streams[0];
halStreams[0] = halConfig.streams[0].v3_3.v3_2;
cb->setCurrentStreamConfig(streams, halStreams);
}
@@ -5550,12 +5637,19 @@
}
//Cast camera provider to corresponding version if available
-void CameraHidlTest::castProvider(const sp<ICameraProvider> &provider,
- sp<provider::V2_5::ICameraProvider> *provider2_5 /*out*/) {
+void CameraHidlTest::castProvider(const sp<ICameraProvider>& provider,
+ sp<provider::V2_5::ICameraProvider>* provider2_5 /*out*/,
+ sp<provider::V2_6::ICameraProvider>* provider2_6 /*out*/) {
ASSERT_NE(nullptr, provider2_5);
- auto castResult = provider::V2_5::ICameraProvider::castFrom(provider);
- if (castResult.isOk()) {
- *provider2_5 = castResult;
+ auto castResult2_5 = provider::V2_5::ICameraProvider::castFrom(provider);
+ if (castResult2_5.isOk()) {
+ *provider2_5 = castResult2_5;
+ }
+
+ ASSERT_NE(nullptr, provider2_6);
+ auto castResult2_6 = provider::V2_6::ICameraProvider::castFrom(provider);
+ if (castResult2_6.isOk()) {
+ *provider2_6 = castResult2_6;
}
}
@@ -5623,6 +5717,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;
@@ -5630,15 +5729,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;
}
@@ -5654,6 +5775,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());
@@ -5673,8 +5800,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,
@@ -5772,6 +5898,216 @@
ADD_FAILURE() << "Get Heic maxJpegAppSegmentsCount failed!";
}
}
+
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_LENS_POSE_REFERENCE, &entry);
+ if (0 == retcode && entry.count > 0) {
+ uint8_t poseReference = entry.data.u8[0];
+ ASSERT_TRUE(poseReference <= ANDROID_LENS_POSE_REFERENCE_UNDEFINED &&
+ poseReference >= ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA);
+ }
+
+ verifyBokehCharacteristics(metadata);
+ verifyZoomCharacteristics(metadata);
+}
+
+void CameraHidlTest::verifyBokehCharacteristics(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_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+ bool hasBokehRequestKey = false;
+ if ((0 == retcode) && (entry.count > 0)) {
+ hasBokehRequestKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+ ANDROID_CONTROL_BOKEH_MODE) != 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 hasBokehResultKey = false;
+ if ((0 == retcode) && (entry.count > 0)) {
+ hasBokehResultKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+ ANDROID_CONTROL_BOKEH_MODE) != 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 hasBokehMaxSizesKey = false;
+ bool hasBokehZoomRatioRangesKey = false;
+ if ((0 == retcode) && (entry.count > 0)) {
+ 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_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 && !hasBokehMaxSizesKey &&
+ !hasBokehZoomRatioRangesKey && !hasBokehMaxSizes && !hasBokehZoomRatioRanges;
+ if (noBokeh) {
+ return;
+ }
+ bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehMaxSizesKey &&
+ hasBokehZoomRatioRangesKey && hasBokehMaxSizes && hasBokehZoomRatioRanges;
+ ASSERT_TRUE(hasBokeh);
+
+ // Must have OFF, and must have one of STILL_CAPTURE and CONTINUOUS.
+ // 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, 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;
+ ASSERT_TRUE(maxWidth == 0 && maxHeight == 0);
+ 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;
+ break;
+ }
+
+ 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) ||
+ stream.format == static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED))
+ && stream.width == maxWidth && stream.height == maxHeight) {
+ sizeSupported = true;
+ break;
+ }
+ }
+ 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,
@@ -6144,68 +6480,15 @@
PixelFormat format, hidl_handle *buffer_handle /*out*/) {
ASSERT_NE(buffer_handle, nullptr);
- sp<android::hardware::graphics::allocator::V2_0::IAllocator> allocator =
- android::hardware::graphics::allocator::V2_0::IAllocator::getService();
- sp<android::hardware::graphics::allocator::V3_0::IAllocator> allocatorV3 =
- android::hardware::graphics::allocator::V3_0::IAllocator::getService();
+ buffer_handle_t buffer;
+ uint32_t stride;
- sp<android::hardware::graphics::mapper::V3_0::IMapper> mapperV3 =
- android::hardware::graphics::mapper::V3_0::IMapper::getService();
- sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
- android::hardware::graphics::mapper::V2_0::IMapper::getService();
- ::android::hardware::hidl_vec<uint32_t> descriptor;
- if (mapperV3 != nullptr && allocatorV3 != nullptr) {
- android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo descriptorInfo {};
- descriptorInfo.width = width;
- descriptorInfo.height = height;
- descriptorInfo.layerCount = 1;
- descriptorInfo.format =
- static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
- descriptorInfo.usage = usage;
+ 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);
- auto ret = mapperV3->createDescriptor(
- descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V3_0::Error err,
- ::android::hardware::hidl_vec<uint32_t> desc) {
- ASSERT_EQ(err, android::hardware::graphics::mapper::V3_0::Error::NONE);
- descriptor = desc;
- });
- ASSERT_TRUE(ret.isOk());
-
- ret = allocatorV3->allocate(descriptor, 1u,
- [&](android::hardware::graphics::mapper::V3_0::Error err, uint32_t /*stride*/,
- const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>& buffers) {
- ASSERT_EQ(android::hardware::graphics::mapper::V3_0::Error::NONE, err);
- ASSERT_EQ(buffers.size(), 1u);
- *buffer_handle = buffers[0];
- });
- ASSERT_TRUE(ret.isOk());
- } else {
- ASSERT_NE(mapper.get(), nullptr);
- ASSERT_NE(allocator.get(), nullptr);
- android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo {};
- descriptorInfo.width = width;
- descriptorInfo.height = height;
- descriptorInfo.layerCount = 1;
- descriptorInfo.format = format;
- descriptorInfo.usage = usage;
-
- auto ret = mapper->createDescriptor(
- descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V2_0::Error err,
- ::android::hardware::hidl_vec<uint32_t> desc) {
- ASSERT_EQ(err, android::hardware::graphics::mapper::V2_0::Error::NONE);
- descriptor = desc;
- });
- ASSERT_TRUE(ret.isOk());
-
- ret = allocator->allocate(descriptor, 1u,
- [&](android::hardware::graphics::mapper::V2_0::Error err, uint32_t /*stride*/,
- const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>& buffers) {
- ASSERT_EQ(android::hardware::graphics::mapper::V2_0::Error::NONE, err);
- ASSERT_EQ(buffers.size(), 1u);
- *buffer_handle = buffers[0];
- });
- ASSERT_TRUE(ret.isOk());
- }
+ buffer_handle->setTo(const_cast<native_handle_t*>(buffer), true /*shouldOwn*/);
}
void CameraHidlTest::verifyRecommendedConfigs(const CameraMetadata& chars) {
@@ -6325,11 +6608,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/camera/provider/2.6/Android.bp b/camera/provider/2.6/Android.bp
new file mode 100644
index 0000000..e69819c
--- /dev/null
+++ b/camera/provider/2.6/Android.bp
@@ -0,0 +1,26 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.camera.provider@2.6",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "ICameraProvider.hal",
+ "ICameraProviderCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.camera.common@1.0",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
+ "android.hardware.camera.device@3.4",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.camera.provider@2.5",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal
new file mode 100644
index 0000000..0948db6
--- /dev/null
+++ b/camera/provider/2.6/ICameraProvider.hal
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.provider@2.6;
+
+import @2.5::ICameraProvider;
+import android.hardware.camera.common@1.0::Status;
+import android.hardware.camera.device@3.4::StreamConfiguration;
+
+/**
+ * Camera provider HAL
+ *
+ * @2.6::adds support for the getConcurrentStreamingCameraIds() and
+ * isConcurrentStreamCombinationSupported()
+ * @2.6::ICameraProviderCallback to receive physical camera availability
+ * callbacks for logical multi-cameras.
+ */
+interface ICameraProvider extends @2.5::ICameraProvider {
+ /**
+ * getConcurrentStreamingCameraIds
+ *
+ * Get a vector of combinations of camera device ids that are able to
+ * configure streams concurrently. Each camera device advertised in a
+ * combination MUST at the very least support the following streams while
+ * streaming concurrently with the other camera ids in the combination.
+ *
+ * Target 1 Target 2
+ * ---------------------------------------------
+ * | Type | Size | Type | Size |
+ * ---------------------------------------------
+ * | YUV | 1280 X 720 | |
+ * ---------------------------------------------
+ * | PRIV | 1280 X 720 | |
+ * ---------------------------------------------
+ * | YUV | 1280 X 720 | YUV |1280 X 720|
+ * ---------------------------------------------
+ * | PRIV | 1280 X 720 | PRIV |1280 X 720|
+ * ---------------------------------------------
+ * | PRIV | 1280 X 720 | YUV |1280 X 720|
+ * ---------------------------------------------
+
+ * @return status Status code for the operation
+ * @return cameraIds a list of camera id combinations that support
+ * concurrent stream configurations with the minimum guarantees
+ * specified.
+ */
+ getConcurrentStreamingCameraIds() generates (Status status, vec<vec<string>> cameraIds);
+
+ /**
+ * isConcurrentStreamCombinationSupported:
+ *
+ * Check for device support of specific camera stream combinations while
+ * streaming concurrently with other devices.
+ *
+ * The per device streamList must contain at least one output-capable stream, and may
+ * not contain more than one input-capable stream.
+ * In contrast to regular stream configuration the framework does not create
+ * or initialize any actual streams. This means that Hal must not use or
+ * consider the stream "id" value.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Preconditions:
+ *
+ * The framework can call this method at any time before, during and
+ * after active session configuration per device. This means that calls must not
+ * impact the performance of pending camera requests in any way. In
+ * particular there must not be any glitches or delays during normal
+ * camera streaming.
+ *
+ * The framework must not call this method with any combination of camera
+ * ids that is not a subset of the camera ids advertised by getConcurrentStreamingCameraIds of
+ * the same provider.
+ *
+ * Performance requirements:
+ * This call is expected to be significantly faster than stream
+ * configuration. In general HW and SW camera settings must not be
+ * changed and there must not be a user-visible impact on camera performance.
+ *
+ * @param configs a vector of camera ids and their corresponding stream
+ * configurations that need to be queried for support.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On successful stream combination query.
+ * METHOD_NOT_SUPPORTED:
+ * The camera provider does not support stream combination query.
+ * INTERNAL_ERROR:
+ * The stream combination query cannot complete due to internal
+ * error.
+ * @return true in case the stream combination is supported, false otherwise.
+ *
+ *
+ */
+ isConcurrentStreamCombinationSupported(vec<CameraIdAndStreamCombination> configs)
+ generates (Status status, bool queryStatus);
+};
diff --git a/camera/provider/2.6/ICameraProviderCallback.hal b/camera/provider/2.6/ICameraProviderCallback.hal
new file mode 100644
index 0000000..42c1092
--- /dev/null
+++ b/camera/provider/2.6/ICameraProviderCallback.hal
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.provider@2.6;
+
+import android.hardware.camera.common@1.0::types;
+import android.hardware.camera.provider@2.4::ICameraProviderCallback;
+
+/**
+ * Callback functions for a camera provider HAL to use to inform the camera
+ * service of changes to the camera subsystem.
+ *
+ * Version 2.6 adds support for physical camera device status callback for
+ * multi-camera.
+ */
+interface ICameraProviderCallback extends @2.4::ICameraProviderCallback {
+
+ /**
+ * cameraPhysicalDeviceStatusChange:
+ *
+ * Callback to the camera service to indicate that the state of a physical
+ * camera device of a logical multi-camera has changed.
+ *
+ * On camera service startup, when ICameraProvider::setCallback is invoked,
+ * the camera service must assume that all physical devices backing internal
+ * multi-camera devices are in the CAMERA_DEVICE_STATUS_PRESENT state.
+ *
+ * The provider must call this method to inform the camera service of any
+ * initially NOT_PRESENT physical devices, as soon as the callbacks are available
+ * through setCallback.
+ *
+ * @param cameraDeviceName The name of the logical multi-camera whose
+ * physical camera has a new status.
+ * @param physicalCameraDeviceName The name of the physical camera device
+ * that has a new status.
+ * @param newStatus The new status that device is in.
+ *
+ */
+ physicalCameraDeviceStatusChange(string cameraDeviceName,
+ string physicalCameraDeviceName, CameraDeviceStatus newStatus);
+};
diff --git a/camera/provider/2.6/types.hal b/camera/provider/2.6/types.hal
new file mode 100644
index 0000000..24c62aa
--- /dev/null
+++ b/camera/provider/2.6/types.hal
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.provider@2.6;
+
+import android.hardware.camera.device@3.4::StreamConfiguration;
+
+/**
+ * CameraIdAndStreamCombination:
+ * Pairs the cameraId and the StreamConfiguration to be
+ * tested with other concurrent camera id and StreamConfigurations
+ */
+struct CameraIdAndStreamCombination {
+ string cameraId;
+
+ @3.4::StreamConfiguration streamConfiguration;
+};
diff --git a/cas/1.0/vts/functional/Android.bp b/cas/1.0/vts/functional/Android.bp
index 622baa5..ab39c0e 100644
--- a/cas/1.0/vts/functional/Android.bp
+++ b/cas/1.0/vts/functional/Android.bp
@@ -29,6 +29,6 @@
shared_libs: [
"libbinder",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
index 14b8bbd..0f16de5 100644
--- a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
+++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
@@ -16,8 +16,6 @@
#define LOG_TAG "mediacas_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/cas/1.0/ICas.h>
#include <android/hardware/cas/1.0/ICasListener.h>
@@ -27,8 +25,11 @@
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <android/hardware/cas/native/1.0/types.h>
#include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
#include <hidl/Status.h>
#include <hidlmemory/FrameworkUtils.h>
#include <utils/Condition.h>
@@ -208,29 +209,16 @@
EXPECT_TRUE(mEventData == eventData);
}
-// Test environment for Cas HIDL HAL.
-class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static CasHidlEnvironment* Instance() {
- static CasHidlEnvironment* instance = new CasHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
-};
-
-class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class MediaCasHidlTest : public testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override {
- mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
- CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+ mService = IMediaCasService::getService(GetParam());
ASSERT_NE(mService, nullptr);
}
- sp<IMediaCasService> mService;
+ sp<IMediaCasService> mService = nullptr;
- protected:
+ protected:
static void description(const std::string& description) {
RecordProperty("description", description);
}
@@ -325,7 +313,7 @@
return ::testing::AssertionFailure();
}
- uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->pointer()));
+ uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->unsecurePointer()));
memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer));
// hidlMemory is not to be passed out of scope!
@@ -419,7 +407,7 @@
return ::testing::AssertionResult(returnVoid.isOk());
}
-TEST_F(MediaCasHidlTest, EnumeratePlugins) {
+TEST_P(MediaCasHidlTest, EnumeratePlugins) {
description("Test enumerate plugins");
hidl_vec<HidlCasPluginDescriptor> descriptors;
EXPECT_TRUE(mService
@@ -440,7 +428,7 @@
}
}
-TEST_F(MediaCasHidlTest, TestInvalidSystemIdFails) {
+TEST_P(MediaCasHidlTest, TestInvalidSystemIdFails) {
description("Test failure for invalid system ID");
sp<MediaCasListener> casListener = new MediaCasListener();
@@ -458,7 +446,7 @@
EXPECT_EQ(descramblerBase, nullptr);
}
-TEST_F(MediaCasHidlTest, TestClearKeyPluginInstalled) {
+TEST_P(MediaCasHidlTest, TestClearKeyPluginInstalled) {
description("Test if ClearKey plugin is installed");
hidl_vec<HidlCasPluginDescriptor> descriptors;
EXPECT_TRUE(mService
@@ -480,7 +468,7 @@
ASSERT_TRUE(false) << "ClearKey plugin not installed";
}
-TEST_F(MediaCasHidlTest, TestClearKeyApis) {
+TEST_P(MediaCasHidlTest, TestClearKeyApis) {
description("Test that valid call sequences succeed");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -568,7 +556,7 @@
EXPECT_EQ(Status::OK, descrambleStatus);
ASSERT_NE(nullptr, dataMemory.get());
- uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->pointer()));
+ uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->unsecurePointer()));
int compareResult =
memcmp(static_cast<const void*>(opBuffer), static_cast<const void*>(kOutRefBinaryBuffer),
@@ -584,7 +572,7 @@
EXPECT_EQ(Status::OK, returnStatus);
}
-TEST_F(MediaCasHidlTest, TestClearKeySessionClosedAfterRelease) {
+TEST_P(MediaCasHidlTest, TestClearKeySessionClosedAfterRelease) {
description("Test that all sessions are closed after a MediaCas object is released");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -611,7 +599,7 @@
EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus);
}
-TEST_F(MediaCasHidlTest, TestClearKeyErrors) {
+TEST_P(MediaCasHidlTest, TestClearKeyErrors) {
description("Test that invalid call sequences fail with expected error codes");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -700,7 +688,7 @@
EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("bad"));
}
-TEST_F(MediaCasHidlTest, TestClearKeyOobFails) {
+TEST_P(MediaCasHidlTest, TestClearKeyOobFails) {
description("Test that oob descramble request fails with expected error");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -849,11 +837,7 @@
} // anonymous namespace
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- CasHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, MediaCasHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/cas/1.1/vts/functional/Android.bp b/cas/1.1/vts/functional/Android.bp
index 8afd19a..9e8eb52 100644
--- a/cas/1.1/vts/functional/Android.bp
+++ b/cas/1.1/vts/functional/Android.bp
@@ -30,6 +30,6 @@
shared_libs: [
"libbinder",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
index 88f1fb0..7e5a61a 100644
--- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
+++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
@@ -27,8 +27,11 @@
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <android/hardware/cas/native/1.0/types.h>
#include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
#include <hidl/Status.h>
#include <hidlmemory/FrameworkUtils.h>
#include <utils/Condition.h>
@@ -251,27 +254,14 @@
EXPECT_TRUE(mEventData == eventData);
}
-// Test environment for Cas HIDL HAL.
-class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static CasHidlEnvironment* Instance() {
- static CasHidlEnvironment* instance = new CasHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
-};
-
-class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class MediaCasHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
- CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+ mService = IMediaCasService::getService(GetParam());
ASSERT_NE(mService, nullptr);
}
- sp<IMediaCasService> mService;
+ sp<IMediaCasService> mService = nullptr;
protected:
static void description(const std::string& description) {
@@ -366,7 +356,7 @@
return ::testing::AssertionFailure();
}
- uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->pointer()));
+ uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->unsecurePointer()));
memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer));
// hidlMemory is not to be passed out of scope!
@@ -453,7 +443,7 @@
return ::testing::AssertionResult(returnVoid.isOk());
}
-TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) {
+TEST_P(MediaCasHidlTest, TestClearKeyApisWithSession) {
description("Test that valid call sequences with SessionEvent send and receive");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -543,7 +533,7 @@
EXPECT_EQ(Status::OK, descrambleStatus);
ASSERT_NE(nullptr, dataMemory.get());
- uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->pointer()));
+ uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->unsecurePointer()));
int compareResult =
memcmp(static_cast<const void*>(opBuffer),
@@ -561,11 +551,7 @@
} // anonymous namespace
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- CasHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, MediaCasHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/cas/1.2/types.hal b/cas/1.2/types.hal
index 40c06cf..06199cd 100644
--- a/cas/1.2/types.hal
+++ b/cas/1.2/types.hal
@@ -45,6 +45,10 @@
* ERROR_CAS_BLACKOUT is used to report geographical blackout.
*/
ERROR_CAS_BLACKOUT,
+ /**
+ * ERROR_CAS_REBOOTING is used to report CAS is during rebooting.
+ */
+ ERROR_CAS_REBOOTING,
};
/**
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 fb6ae0e..b9d3001 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -47,6 +47,13 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.automotive.occupant_awareness</name>
+ <interface>
+ <name>IOccupantAwareness</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.automotive.vehicle</name>
<version>2.0</version>
@@ -57,7 +64,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.biometrics.face</name>
- <version>1.0</version>
+ <version>1.0-1</version>
<interface>
<name>IBiometricsFace</name>
<instance>default</instance>
@@ -113,7 +120,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.camera.provider</name>
- <version>2.4-5</version>
+ <version>2.4-6</version>
<interface>
<name>ICameraProvider</name>
<regex-instance>[^/]+/[0-9]+</regex-instance>
@@ -121,7 +128,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.cas</name>
- <version>1.1</version>
+ <version>1.1-2</version>
<interface>
<name>IMediaCasService</name>
<instance>default</instance>
@@ -153,7 +160,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.drm</name>
- <version>1.0-2</version>
+ <version>1.0-3</version>
<interface>
<name>ICryptoFactory</name>
<regex-instance>.*</regex-instance>
@@ -165,7 +172,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.dumpstate</name>
- <version>1.0</version>
+ <version>1.1</version>
<interface>
<name>IDumpstateDevice</name>
<instance>default</instance>
@@ -187,7 +194,7 @@
- test DeviceManifestTest#GnssHalVersionCompatibility.
-->
<version>1.1</version>
- <version>2.0</version>
+ <version>2.0-1</version>
<interface>
<name>IGnss</name>
<instance>default</instance>
@@ -195,8 +202,10 @@
</hal>
<hal format="hidl" optional="false">
<name>android.hardware.graphics.allocator</name>
+ <!-- TODO(b/136016160): deprecating 2.0. New devices should not use this -->
<version>2.0</version>
<version>3.0</version>
+ <version>4.0</version>
<interface>
<name>IAllocator</name>
<instance>default</instance>
@@ -204,7 +213,7 @@
</hal>
<hal format="hidl" optional="false">
<name>android.hardware.graphics.composer</name>
- <version>2.1-3</version>
+ <version>2.1-4</version>
<interface>
<name>IComposer</name>
<instance>default</instance>
@@ -212,8 +221,10 @@
</hal>
<hal format="hidl" optional="false">
<name>android.hardware.graphics.mapper</name>
+ <!-- TODO(b/136016160): deprecating 2.1. New devices should not use this -->
<version>2.1</version>
<version>3.0</version>
+ <version>4.0</version>
<interface>
<name>IMapper</name>
<instance>default</instance>
@@ -276,9 +287,16 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.light</name>
+ <interface>
+ <name>ILights</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.media.c2</name>
- <version>1.0</version>
+ <version>1.0-1</version>
<interface>
<name>IComponentStore</name>
<regex-instance>default[0-9]*</regex-instance>
@@ -378,6 +396,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-2</version>
@@ -398,7 +423,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>
@@ -455,7 +480,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.usb.gadget</name>
- <version>1.0</version>
+ <version>1.0-1</version>
<interface>
<name>IUsbGadget</name>
<instance>default</instance>
@@ -494,7 +519,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.wifi</name>
- <version>1.0-3</version>
+ <version>1.0-4</version>
<interface>
<name>IWifi</name>
<instance>default</instance>
@@ -502,7 +527,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>
@@ -510,7 +535,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.wifi.supplicant</name>
- <version>1.0-2</version>
+ <version>1.0-3</version>
<interface>
<name>ISupplicant</name>
<instance>default</instance>
diff --git a/current.txt b/current.txt
index 00b01f3..75975f2 100644
--- a/current.txt
+++ b/current.txt
@@ -451,9 +451,9 @@
443659bb9e27221e5da0d16c7a0ecb2dc3a9a03acc8a0b2196b47c50735e2d2e android.hardware.audio.effect@5.0::IVirtualizerEffect
78fed26a781cdca1b3bcb37520bff705d7764ee81db9cfd37014953c7ad2596e android.hardware.audio.effect@5.0::IVisualizerEffect
6385b6accab8a544e2ee54ba7bf5aa55dff6153bcedd80fdaae16fe9e0be7050 android.hardware.audio.effect@5.0::types
+95aa2f59e29e2f84d8e84320ace9b6682b426a16e897b4bd241375cbee0e07f3 android.hardware.biometrics.face@1.0::types
e18ff318f3fc43db37f554696dc4e551abb9b119bde53950f73e28ce33a97a40 android.hardware.biometrics.face@1.0::IBiometricsFace
b6e55d7795bbafd011fb95a3b6d3954bf66c349e14cf107f3b72032ce3ceb448 android.hardware.biometrics.face@1.0::IBiometricsFaceClientCallback
-95aa2f59e29e2f84d8e84320ace9b6682b426a16e897b4bd241375cbee0e07f3 android.hardware.biometrics.face@1.0::types
ecedc58dbcdb13503c19c0ab160ac1dd0530bb1471164149282dd1463c684185 android.hardware.bluetooth.audio@2.0::IBluetoothAudioPort
fb9c40e4deab40be5476477078fe3d8a4a4495fd9deef4321878d169d675c633 android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvider
f7431f3e3e4e3387fc6f27a6cf423eddcd824a395dc4349d302c995ab44a9895 android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory
@@ -578,6 +578,18 @@
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
+a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types
+9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback
+bceee81ec1b59324abd05932b5620fda5a6589597c9cb3953ba7f3ea02cccd3e android.hardware.camera.provider@2.4::ICameraProvider
+2ce820dc4f3c6d85721b65150ed2157c6e2e2055f866fb6c6ba4790f14408d66 android.hardware.camera.provider@2.4::ICameraProviderCallback
b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
8eac60e1f724d141c71c69f06d4544acb720a55dfbbcd97fa01bb3d25ee4e2f5 android.hardware.neuralnetworks@1.0::types
@@ -591,14 +603,14 @@
# HALs released in Android R
e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types
-4540d12fe1cea996f21bd1712d4ae0906dcbd58177dac494efc605b004902d43 android.hardware.audio@6.0::IDevice
+dd3e9280be60a5e042331c1046d13938e2cc323dc4b267cc74d544bf62fc0314 android.hardware.audio@6.0::IDevice
2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory
bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice
-7318b521ea12fdd4b6e3f381085c71784c810d1ec7a8d701ec2250f3f86712e4 android.hardware.audio@6.0::IStream
+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
-b495a43bd6ff0c34a391824b0ba1a3f3f34b4a869690611a9a0afc404d75aa84 android.hardware.audio.common@6.0::types
+43a3303378f5b9852c2da9ac2c1d440965aab7ba02a800229e7b3c84e2167e06 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
@@ -614,10 +626,30 @@
5237c42d3913ef569f07bec802568084b615155d05a7951e75085da54856508c android.hardware.audio.effect@6.0::IPresetReverbEffect
282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect
0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect
+7e8e1c3d0173c5d503dd01cecff8e3864478557ca6b9e8cc2291598b1a4aea62 android.hardware.biometrics.face@1.1::IBiometricsFace
+ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types
+6828bbf18dc5d0f00c73341a10c8e4d574346c1abb1c2ed682ba5e9f8a3240d9 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint
+82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback
79e115c8f8970b8b914bafc66df5425e065fda4dcda97222966ef12451d2a1cc android.hardware.bluetooth@1.1::IBluetoothHci
40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks
07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
+c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas
+9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener
+f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService
+4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types
+66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory
+994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory
+881aa8720fb1d69aa9843bfab69d810ab7654a61d2f5ab5e2626cbf240f24eaf android.hardware.dumpstate@1.1::types
+13b33f623521ded51a6c0f7ea5b77e97066d0aa1e38a83c2873f08ad67294f89 android.hardware.dumpstate@1.1::IDumpstateDevice
+769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types
+88371e0edf69a1f72bfc45ecb2335e9b145e87339d3eecc92664a1fb200213ba android.hardware.gnss@2.1::IGnss
+ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback
+ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration
+5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement
+d7bf37660a0946de9599dcbae997b077ee3e604fc2044534d40d3da04297a5d3 android.hardware.gnss@2.1::IGnssMeasurementCallback
+6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections
+a3f439b782a6a92aaf3c0250f3526e94e8bf8844c3d578f0815e21b12c431346 android.hardware.gnss.measurement_corrections@1.1::types
ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types
@@ -627,28 +659,32 @@
6e1e28a96c90ba78d47257faea3f3bb4e6360affbbfa5822f0dc31211f9266ff android.hardware.identity@1.0::IWritableIdentityCredential
27ae3724053940462114228872b3ffaf0b8e6177d5ba97f5a76339d12b8a99dd android.hardware.keymaster@4.1::IKeymasterDevice
adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation
-ac429fca0da4ce91218768ec31b64ded88251f8a26d8c4f27c06abdc5b1926d9 android.hardware.keymaster@4.1::types
-9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice
-258825966435b3ed08832055bb736d81516013e405f161d9ccde9a90cfcdde83 android.hardware.neuralnetworks@1.3::IPreparedModel
-94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-f3c1e7298da628a755b452cd3325e8d0fe867a2debb873069baab6a27434a72d android.hardware.neuralnetworks@1.3::types
+ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardware.keymaster@4.1::types
+df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
+a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
+65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer
+d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardware.neuralnetworks@1.3::IDevice
+4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback
+29e26e83399b69c7998b787bd30426dd5baa2da350effca76bbee1ba877355c9 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
+384fd9fd6e4d43ea11d407e52ea81da5242c3c5f4b458b8707d8feb652a13e36 android.hardware.neuralnetworks@1.3::IPreparedModel
+0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback
+5f1a4e0c29fc686ed476f9f04eed35e4405d21288cb2746b978d6891de5cc37d android.hardware.neuralnetworks@1.3::types
3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
+c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
+11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types
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
-##
-# BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present
-##
-275a01e456f3c988ac9736d26ceaf3e95fb7b3c333a8a7fe983de6bae39df58a android.hardware.radio@1.5::types
-7a0a3382cca78d13a55e856b14b7fb025987f52c2adeab5747cd584391cd3cc7 android.hardware.radio@1.5::IRadio
-20d52e66fd548f89bcb98cda42749a591ce8f439a2a7148617adac0c967ad937 android.hardware.radio@1.5::IRadioIndication
-c7b4a0debd3bb8815a463d11194487c7eef81bca584f558d7ba74c34b18d7e3f android.hardware.radio@1.5::IRadioResponse
-55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types
-b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig
+8aed0a8e03e7a67bfdfb78ad7529a9ae95bea36e6060473b204c89d772522126 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
+def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
+62cf050c593c1ec34b49178b5bdde72dd9b80d9bad3eb184e4f0cd564d28678c android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
+98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types
+50e22cd55ad5499e68e81541bbc67bd10e59c1b9f3ff8cc7ba70dcb0d2918381 android.hardware.radio@1.5::types
+8cc3306e8cd755d04521d1611b217b9d13a2a76d2af57cbea8f875333b3363f7 android.hardware.radio@1.5::IRadio
+e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication
+7b77721a7716e163f5cc5f2830ed5616b953fcf0e5406f69de0fde5ce95e4184 android.hardware.radio@1.5::IRadioResponse
+2fd107f3de1b7e36825e241a88dfae8edf3a77c166cb746f00ddf6440ab78db1 android.hardware.radio.config@1.3::types
+a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig
742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
-7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse
-##
-# END Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present
-##
+0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse
+51d1c8d285e0456da2a3fdfbf4700c6277165d5e83219894d651c8ea0e39aa8b android.hardware.soundtrigger@2.3::types
+12d7533ff0754f45bf59ab300799074570a99a676545652c2c23abc73cb4515d android.hardware.soundtrigger@2.3::ISoundTriggerHw
+7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget
diff --git a/drm/1.3/Android.bp b/drm/1.3/Android.bp
new file mode 100644
index 0000000..b0ffcb9
--- /dev/null
+++ b/drm/1.3/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.drm@1.3",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "IDrmFactory.hal",
+ "ICryptoFactory.hal",
+ ],
+ interfaces: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "android.hardware.drm@1.2",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/drm/1.3/ICryptoFactory.hal b/drm/1.3/ICryptoFactory.hal
new file mode 100644
index 0000000..d7864eb
--- /dev/null
+++ b/drm/1.3/ICryptoFactory.hal
@@ -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.
+ */
+package android.hardware.drm@1.3;
+
+import @1.2::ICryptoFactory;
+
+/**
+ * ICryptoFactory is the main entry point for interacting with a vendor's
+ * crypto HAL to create crypto plugins. Crypto plugins create crypto sessions
+ * which are used by a codec to decrypt protected video content.
+ *
+ * The 1.3 factory must always create 1.2 ICryptoPlugin interfaces, which are
+ * returned via the 1.0 createPlugin method.
+ *
+ * The ICryptoFactory hal is required because all top-level interfaces
+ * have to be updated in a minor uprev.
+ */
+interface ICryptoFactory extends @1.2::ICryptoFactory {
+};
diff --git a/drm/1.3/IDrmFactory.hal b/drm/1.3/IDrmFactory.hal
new file mode 100644
index 0000000..5208028
--- /dev/null
+++ b/drm/1.3/IDrmFactory.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.drm@1.3;
+
+import @1.2::IDrmFactory;
+
+/**
+ * IDrmFactory is the main entry point for interacting with a vendor's
+ * drm HAL to create drm plugin instances. A drm plugin instance
+ * creates drm sessions which are used to obtain keys for a crypto
+ * session so it can decrypt protected video content.
+ *
+ * The 1.3 factory must always create 1.2 IDrmPlugin interfaces, which are
+ * returned via the 1.0 createPlugin method.
+ */
+
+interface IDrmFactory extends @1.2::IDrmFactory {
+ /**
+ * Return vector of uuids identifying crypto schemes supported by this HAL.
+ *
+ * @return schemes Vector of uuids for which isCryptoSchemeSupported is true;
+ * each uuid can be used as input to createPlugin.
+ */
+ getSupportedCryptoSchemes() generates(vec<uint8_t[16]> schemes);
+};
diff --git a/drm/TEST_MAPPING b/drm/TEST_MAPPING
new file mode 100644
index 0000000..cff6819
--- /dev/null
+++ b/drm/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+ "imports": [
+ // gts and cts filters
+ {
+ "path": "frameworks/av/drm/libmediadrm"
+ }
+ ]
+}
diff --git a/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp b/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
index 96b13c5..343d4c9 100644
--- a/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
+++ b/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
@@ -78,6 +78,7 @@
ASSERT_EQ(1, read(fds[0], &buff, 1)) << "dumped nothing";
native_handle_close(handle);
+ native_handle_delete(handle);
}
// Positive test: make sure dumpstateBoard() doesn't crash with two FDs.
@@ -96,6 +97,7 @@
ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
native_handle_close(handle);
+ native_handle_delete(handle);
}
INSTANTIATE_TEST_SUITE_P(
diff --git a/dumpstate/1.1/Android.bp b/dumpstate/1.1/Android.bp
new file mode 100644
index 0000000..2aa8c82
--- /dev/null
+++ b/dumpstate/1.1/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.dumpstate@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IDumpstateDevice.hal",
+ ],
+ interfaces: [
+ "android.hardware.dumpstate@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/dumpstate/1.1/IDumpstateDevice.hal b/dumpstate/1.1/IDumpstateDevice.hal
new file mode 100644
index 0000000..24831b3
--- /dev/null
+++ b/dumpstate/1.1/IDumpstateDevice.hal
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.dumpstate@1.1;
+
+import @1.0::IDumpstateDevice;
+
+interface IDumpstateDevice extends @1.0::IDumpstateDevice {
+ /**
+ * Extension of dumpstateBoard which also accepts a mode parameter to limit dumped data.
+ *
+ * For an example of when this is relevant, consider a bug report being generated with
+ * DumpstateMode::CONNECTIVITY - there is no reason to include camera or USB logs in this type
+ * of report.
+ *
+ * The 1.0 version of #dumpstateBoard(handle) should just delegate to this new method and pass
+ * DumpstateMode::DEFAULT and a timeout of 30,000ms (30 seconds).
+ *
+ * @param h A native handle with one or two valid file descriptors. The first FD is for text
+ * output, the second (if present) is for binary output.
+ * @param mode A mode value to restrict dumped content.
+ * @param timeoutMillis An approximate "budget" for how much time this call has been allotted.
+ * If execution runs longer than this, the IDumpstateDevice service may be killed and only
+ * partial information will be included in the report.
+ */
+ dumpstateBoard_1_1(handle h, DumpstateMode mode, uint64_t timeoutMillis);
+
+ /**
+ * Turns device vendor logging on or off.
+ *
+ * The setting should be persistent across reboots. Underlying implementations may need to start
+ * vendor logging daemons, set system properties, or change logging masks, for example. Given
+ * that many vendor logs contain significant amounts of private information and may come with
+ * memory/storage/battery impacts, calling this method on a user build should only be done after
+ * user consent has been obtained, e.g. from a toggle in developer settings.
+ *
+ * @param enable Whether to enable or disable device vendor logging.
+ * @return success Whether or not the change took effect.
+ */
+ setDeviceLoggingEnabled(bool enable) generates (bool success);
+};
diff --git a/dumpstate/1.1/types.hal b/dumpstate/1.1/types.hal
new file mode 100644
index 0000000..a6f391a
--- /dev/null
+++ b/dumpstate/1.1/types.hal
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.dumpstate@1.1;
+
+/**
+ * Constants that define the type of bug report being taken to restrict content appropriately.
+ */
+enum DumpstateMode : uint32_t {
+ /**
+ * Takes a bug report without user interference.
+ */
+ FULL = 0,
+
+ /**
+ * Interactive bug report, i.e. triggered by the user.
+ */
+ INTERACTIVE = 1,
+
+ /**
+ * Remote bug report triggered by DevicePolicyManager, for example.
+ */
+ REMOTE = 2,
+
+ /**
+ * Bug report triggered on a wear device.
+ */
+ WEAR = 3,
+
+ /**
+ * Bug report limited to only connectivity info (cellular, wifi, and networking). Sometimes
+ * called "telephony" in legacy contexts.
+ *
+ * All reported information MUST directly relate to connectivity debugging or customer support
+ * and MUST NOT contain unrelated private information. This information MUST NOT identify
+ * user-installed packages (UIDs are OK, package names are not), and MUST NOT contain logs of
+ * user application traffic.
+ */
+ CONNECTIVITY = 4,
+
+ /**
+ * Bug report limited to only wifi info.
+ */
+ WIFI = 5,
+
+ /**
+ * Default mode.
+ */
+ DEFAULT = 6
+};
diff --git a/dumpstate/1.1/vts/functional/Android.bp b/dumpstate/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..5267706
--- /dev/null
+++ b/dumpstate/1.1/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalDumpstateV1_1TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalDumpstateV1_1TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.dumpstate@1.0",
+ "android.hardware.dumpstate@1.1",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
new file mode 100644
index 0000000..3b6051c
--- /dev/null
+++ b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "dumpstate_1_1_hidl_hal_test"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <vector>
+
+#include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
+#include <android/hardware/dumpstate/1.1/types.h>
+#include <cutils/native_handle.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::dumpstate::V1_1::DumpstateMode;
+using ::android::hardware::dumpstate::V1_1::IDumpstateDevice;
+
+class DumpstateHidl1_1Test : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ dumpstate = IDumpstateDevice::getService(GetParam());
+ ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance";
+ }
+
+ sp<IDumpstateDevice> dumpstate;
+};
+
+#define TEST_FOR_DUMPSTATE_MODE(name, body, mode) \
+ TEST_P(DumpstateHidl1_1Test, name##_##mode) { body(DumpstateMode::mode); }
+
+#define TEST_FOR_ALL_DUMPSTATE_MODES(name, body) \
+ TEST_FOR_DUMPSTATE_MODE(name, body, FULL); \
+ TEST_FOR_DUMPSTATE_MODE(name, body, INTERACTIVE); \
+ TEST_FOR_DUMPSTATE_MODE(name, body, REMOTE); \
+ TEST_FOR_DUMPSTATE_MODE(name, body, WEAR); \
+ TEST_FOR_DUMPSTATE_MODE(name, body, CONNECTIVITY); \
+ TEST_FOR_DUMPSTATE_MODE(name, body, WIFI); \
+ TEST_FOR_DUMPSTATE_MODE(name, body, DEFAULT);
+
+const uint64_t kDefaultTimeoutMillis = 30 * 1000; // 30 seconds
+
+// Negative test: make sure dumpstateBoard() doesn't crash when passed a null pointer.
+TEST_FOR_ALL_DUMPSTATE_MODES(TestNullHandle, [this](DumpstateMode mode) {
+ Return<void> status = dumpstate->dumpstateBoard_1_1(nullptr, mode, kDefaultTimeoutMillis);
+
+ ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+});
+
+// Negative test: make sure dumpstateBoard() ignores a handle with no FD.
+TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithNoFd, [this](DumpstateMode mode) {
+ native_handle_t* handle = native_handle_create(0, 0);
+ ASSERT_NE(handle, nullptr) << "Could not create native_handle";
+
+ Return<void> status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+
+ ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+
+ native_handle_close(handle);
+ native_handle_delete(handle);
+});
+
+// Positive test: make sure dumpstateBoard() writes something to the FD.
+TEST_FOR_ALL_DUMPSTATE_MODES(TestOk, [this](DumpstateMode mode) {
+ // Index 0 corresponds to the read end of the pipe; 1 to the write end.
+ int fds[2];
+ ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+ native_handle_t* handle = native_handle_create(1, 0);
+ ASSERT_NE(handle, nullptr) << "Could not create native_handle";
+ handle->data[0] = fds[1];
+
+ Return<void> status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+ ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+
+ // Check that at least one byte was written
+ char buff;
+ ASSERT_EQ(1, read(fds[0], &buff, 1)) << "dumped nothing";
+
+ native_handle_close(handle);
+ native_handle_delete(handle);
+});
+
+// Positive test: make sure dumpstateBoard() doesn't crash with two FDs.
+TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithTwoFds, [this](DumpstateMode mode) {
+ int fds1[2];
+ int fds2[2];
+ ASSERT_EQ(0, pipe2(fds1, O_NONBLOCK)) << errno;
+ ASSERT_EQ(0, pipe2(fds2, O_NONBLOCK)) << errno;
+
+ native_handle_t* handle = native_handle_create(2, 0);
+ ASSERT_NE(handle, nullptr) << "Could not create native_handle";
+ handle->data[0] = fds1[1];
+ handle->data[1] = fds2[1];
+
+ Return<void> status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+ ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+
+ native_handle_close(handle);
+ native_handle_delete(handle);
+});
+
+// Make sure dumpstateBoard_1_1 actually validates its arguments.
+TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Negative) {
+ int fds[2];
+ ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+ native_handle_t* handle = native_handle_create(1, 0);
+ ASSERT_NE(handle, nullptr) << "Could not create native_handle";
+ handle->data[0] = fds[1];
+
+ Return<void> status = dumpstate->dumpstateBoard_1_1(handle, static_cast<DumpstateMode>(-100),
+ kDefaultTimeoutMillis);
+ ASSERT_FALSE(status.isOk()) << "Status should not be ok with invalid mode param: "
+ << status.description();
+
+ native_handle_close(handle);
+ native_handle_delete(handle);
+}
+
+TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Undefined) {
+ int fds[2];
+ ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+ native_handle_t* handle = native_handle_create(1, 0);
+ ASSERT_NE(handle, nullptr) << "Could not create native_handle";
+ handle->data[0] = fds[1];
+
+ Return<void> status = dumpstate->dumpstateBoard_1_1(handle, static_cast<DumpstateMode>(9001),
+ kDefaultTimeoutMillis);
+ ASSERT_FALSE(status.isOk()) << "Status should not be ok with invalid mode param: "
+ << status.description();
+
+ native_handle_close(handle);
+ native_handle_delete(handle);
+}
+
+// Make sure toggling device logging doesn't crash.
+TEST_P(DumpstateHidl1_1Test, TestEnableDeviceLogging) {
+ Return<bool> status = dumpstate->setDeviceLoggingEnabled(true);
+
+ ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+}
+
+TEST_P(DumpstateHidl1_1Test, TestDisableDeviceLogging) {
+ Return<bool> status = dumpstate->setDeviceLoggingEnabled(false);
+
+ ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, DumpstateHidl1_1Test,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IDumpstateDevice::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/gnss/1.0/IGnssCallback.hal b/gnss/1.0/IGnssCallback.hal
index d62676f..311ab21 100644
--- a/gnss/1.0/IGnssCallback.hal
+++ b/gnss/1.0/IGnssCallback.hal
@@ -90,6 +90,7 @@
* - QZSS: 193-200
* - Galileo: 1-36
* - Beidou: 1-37
+ * - IRNSS: 1-14
*/
int16_t svid;
diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
index 1a80ecf..6183a1a 100644
--- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -22,6 +22,7 @@
#include <log/log.h>
#include <chrono>
+#include <cmath>
#include <condition_variable>
#include <mutex>
@@ -403,6 +404,34 @@
}
/*
+ * InjectSeedLocation:
+ * Injects a seed location and ensures the injected seed location is not fused in the resulting
+ * GNSS location.
+ */
+TEST_P(GnssHalTest, InjectSeedLocation) {
+ // An arbitrary position in North Pacific Ocean (where no VTS labs will ever likely be located).
+ const double seedLatDegrees = 32.312894;
+ const double seedLngDegrees = -172.954117;
+ const float seedAccuracyMeters = 150.0;
+
+ auto result = gnss_hal_->injectLocation(seedLatDegrees, seedLngDegrees, seedAccuracyMeters);
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ StartAndGetSingleLocation(false);
+
+ // Ensure we don't get a location anywhere within 111km (1 degree of lat or lng) of the seed
+ // location.
+ EXPECT_TRUE(std::abs(last_location_.latitudeDegrees - seedLatDegrees) > 1.0 ||
+ std::abs(last_location_.longitudeDegrees - seedLngDegrees) > 1.0);
+
+ StopAndClearLocations();
+
+ auto resultVoid = gnss_hal_->deleteAidingData(IGnss::GnssAidingData::DELETE_POSITION);
+ ASSERT_TRUE(resultVoid.isOk());
+}
+
+/*
* GetAllExtentions:
* Tries getting all optional extensions, and ensures a valid return
* null or actual extension, no crash.
diff --git a/gnss/1.1/default/Android.bp b/gnss/1.1/default/Android.bp
index 95bd7f3..9c498d5 100644
--- a/gnss/1.1/default/Android.bp
+++ b/gnss/1.1/default/Android.bp
@@ -14,6 +14,8 @@
"libhidlbase",
"libutils",
"liblog",
+ "android.hardware.gnss@2.1",
+ "android.hardware.gnss@2.0",
"android.hardware.gnss@1.1",
"android.hardware.gnss@1.0",
],
diff --git a/gnss/1.1/default/Gnss.cpp b/gnss/1.1/default/Gnss.cpp
index 4abe707..5043649 100644
--- a/gnss/1.1/default/Gnss.cpp
+++ b/gnss/1.1/default/Gnss.cpp
@@ -44,7 +44,7 @@
auto svStatus = this->getMockSvStatus();
this->reportSvStatus(svStatus);
- auto location = Utils::getMockLocation();
+ auto location = Utils::getMockLocationV1_0();
this->reportLocation(location);
std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
@@ -197,14 +197,14 @@
Return<GnssSvStatus> Gnss::getMockSvStatus() const {
std::unique_lock<std::recursive_mutex> lock(mGnssConfiguration->getMutex());
GnssSvInfo mockGnssSvInfoList[] = {
- Utils::getSvInfo(3, GnssConstellationType::GPS, 32.5, 59.1, 166.5),
- Utils::getSvInfo(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5),
- Utils::getSvInfo(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0),
- Utils::getSvInfo(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0),
- Utils::getSvInfo(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0),
- Utils::getSvInfo(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0),
- Utils::getSvInfo(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0),
- Utils::getSvInfo(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0)};
+ Utils::getMockSvInfoV1_0(3, GnssConstellationType::GPS, 32.5, 59.1, 166.5),
+ Utils::getMockSvInfoV1_0(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5),
+ Utils::getMockSvInfoV1_0(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0),
+ Utils::getMockSvInfoV1_0(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0),
+ Utils::getMockSvInfoV1_0(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0),
+ Utils::getMockSvInfoV1_0(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0),
+ Utils::getMockSvInfoV1_0(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0),
+ Utils::getMockSvInfoV1_0(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0)};
GnssSvStatus svStatus = {.numSvs = sizeof(mockGnssSvInfoList) / sizeof(GnssSvInfo)};
for (uint32_t i = 0; i < svStatus.numSvs; i++) {
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index cc34290..369a89d 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -29,6 +29,10 @@
],
shared_libs: [
"android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss.measurement_corrections@1.1",
],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
index ca9eef4..4a0a7f9 100644
--- a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
+++ b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
@@ -15,15 +15,15 @@
*/
#define LOG_TAG "VtsHalGnssV1_1TargetTest"
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "gnss_hal_test.h"
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- GnssHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+using android::hardware::gnss::V1_1::IGnss;
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GnssHalTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index e6e3c85..88fbff8 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "GnssHalTest"
#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
#include <gnss_hal_test.h>
@@ -28,18 +30,8 @@
using ::android::hardware::gnss::common::Utils;
-// Implementations for the main test class for GNSS HAL
-GnssHalTest::GnssHalTest()
- : info_called_count_(0),
- capabilities_called_count_(0),
- location_called_count_(0),
- name_called_count_(0),
- notify_count_(0) {}
-
void GnssHalTest::SetUp() {
- gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
- GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
- list_gnss_sv_status_.clear();
+ gnss_hal_ = IGnss::getService(GetParam());
ASSERT_NE(gnss_hal_, nullptr);
SetUpGnssCallback();
@@ -48,14 +40,15 @@
void GnssHalTest::TearDown() {
if (gnss_hal_ != nullptr) {
gnss_hal_->cleanup();
+ gnss_hal_ = nullptr;
}
- if (notify_count_ > 0) {
- ALOGW("%d unprocessed callbacks discarded", notify_count_);
- }
+
+ // Set to nullptr to destruct the callback event queues and warn of any unprocessed events.
+ gnss_cb_ = nullptr;
}
void GnssHalTest::SetUpGnssCallback() {
- gnss_cb_ = new GnssCallback(*this);
+ gnss_cb_ = new GnssCallback();
ASSERT_NE(gnss_cb_, nullptr);
auto result = gnss_hal_->setCallback_1_1(gnss_cb_);
@@ -69,13 +62,13 @@
/*
* All capabilities, name and systemInfo callbacks should trigger
*/
- EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
- EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
- EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+ EXPECT_TRUE(gnss_cb_->capabilities_cbq_.retrieve(gnss_cb_->last_capabilities_, TIMEOUT_SEC));
+ EXPECT_TRUE(gnss_cb_->info_cbq_.retrieve(gnss_cb_->last_info_, TIMEOUT_SEC));
+ EXPECT_TRUE(gnss_cb_->name_cbq_.retrieve(gnss_cb_->last_name_, TIMEOUT_SEC));
- EXPECT_EQ(capabilities_called_count_, 1);
- EXPECT_EQ(info_called_count_, 1);
- EXPECT_EQ(name_called_count_, 1);
+ EXPECT_EQ(gnss_cb_->capabilities_cbq_.calledCount(), 1);
+ EXPECT_EQ(gnss_cb_->info_cbq_.calledCount(), 1);
+ EXPECT_EQ(gnss_cb_->name_cbq_.calledCount(), 1);
}
void GnssHalTest::StopAndClearLocations() {
@@ -89,9 +82,9 @@
* the last reply for final startup messages to arrive (esp. system
* info.)
*/
- while (wait(TIMEOUT_SEC) == std::cv_status::no_timeout) {
+ while (gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, TIMEOUT_SEC)) {
}
- location_called_count_ = 0;
+ gnss_cb_->location_cbq_.reset();
}
void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) {
@@ -118,19 +111,22 @@
*/
const int kFirstGnssLocationTimeoutSeconds = 75;
- wait(kFirstGnssLocationTimeoutSeconds);
- EXPECT_EQ(location_called_count_, 1);
+ EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+ kFirstGnssLocationTimeoutSeconds));
+ int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+ EXPECT_EQ(locationCalledCount, 1);
- if (location_called_count_ > 0) {
+ if (locationCalledCount > 0) {
// don't require speed on first fix
- CheckLocation(last_location_, false);
+ CheckLocation(gnss_cb_->last_location_, false);
return true;
}
return false;
}
void GnssHalTest::CheckLocation(GnssLocation& location, bool check_speed) {
- bool check_more_accuracies = (info_called_count_ > 0 && last_info_.yearOfHw >= 2017);
+ const bool check_more_accuracies =
+ (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017);
Utils::checkLocation(location, check_speed, check_more_accuracies);
}
@@ -145,12 +141,14 @@
EXPECT_TRUE(StartAndCheckFirstLocation());
for (int i = 1; i < count; i++) {
- EXPECT_EQ(std::cv_status::no_timeout, wait(kLocationTimeoutSubsequentSec));
- EXPECT_EQ(location_called_count_, i + 1);
+ EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+ kLocationTimeoutSubsequentSec));
+ int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+ EXPECT_EQ(locationCalledCount, i + 1);
// Don't cause confusion by checking details if no location yet
- if (location_called_count_ > 0) {
+ if (locationCalledCount > 0) {
// Should be more than 1 location by now, but if not, still don't check first fix speed
- CheckLocation(last_location_, location_called_count_ > 1);
+ CheckLocation(gnss_cb_->last_location_, locationCalledCount > 1);
}
}
}
@@ -174,22 +172,33 @@
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 kLocationsToAwait = 3;
-
- StartAndCheckLocations(kLocationsToAwait);
+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.
- EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
- (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
+ int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+ EXPECT_GE(sv_status_cbq_size + 1, 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
+ // Find first non-GPS constellation to blacklist
GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
- for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+ for (int i = 0; i < sv_status_cbq_size; ++i) {
+ IGnssCallback::GnssSvStatus gnss_sv_status;
+ gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, 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) &&
@@ -207,66 +216,47 @@
if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
- // Proceed functionally to return something.
+ // Proceed functionally to blacklist something.
constellation_to_blacklist = GnssConstellationType::GLONASS;
}
return constellation_to_blacklist;
}
-void GnssHalTest::notify() {
- std::unique_lock<std::mutex> lock(mtx_);
- notify_count_++;
- cv_.notify_one();
-}
-
-std::cv_status GnssHalTest::wait(int timeout_seconds) {
- std::unique_lock<std::mutex> lock(mtx_);
-
- auto status = std::cv_status::no_timeout;
- while (notify_count_ == 0) {
- status = cv_.wait_for(lock, std::chrono::seconds(timeout_seconds));
- if (status == std::cv_status::timeout) return status;
- }
- notify_count_--;
- return status;
-}
+GnssHalTest::GnssCallback::GnssCallback()
+ : info_cbq_("system_info"),
+ name_cbq_("name"),
+ capabilities_cbq_("capabilities"),
+ location_cbq_("location"),
+ sv_status_cbq_("sv_status") {}
Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
const IGnssCallback::GnssSystemInfo& info) {
ALOGI("Info received, year %d", info.yearOfHw);
- parent_.info_called_count_++;
- parent_.last_info_ = info;
- parent_.notify();
+ info_cbq_.store(info);
return Void();
}
Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
ALOGI("Capabilities received %d", capabilities);
- parent_.capabilities_called_count_++;
- parent_.last_capabilities_ = capabilities;
- parent_.notify();
+ capabilities_cbq_.store(capabilities);
return Void();
}
Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
ALOGI("Name received: %s", name.c_str());
- parent_.name_called_count_++;
- parent_.last_name_ = name;
- parent_.notify();
+ name_cbq_.store(name);
return Void();
}
Return<void> GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation& location) {
ALOGI("Location received");
- parent_.location_called_count_++;
- parent_.last_location_ = location;
- parent_.notify();
+ location_cbq_.store(location);
return Void();
}
Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb(
const IGnssCallback::GnssSvStatus& svStatus) {
ALOGI("GnssSvStatus received");
- parent_.list_gnss_sv_status_.emplace_back(svStatus);
+ sv_status_cbq_.store(svStatus);
return Void();
}
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index 09ebadc..88b7723 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -19,18 +19,15 @@
#include <android/hardware/gnss/1.1/IGnss.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
-#include <condition_variable>
-#include <list>
-#include <mutex>
+#include <gtest/gtest.h>
+#include "GnssCallbackEventQueue.h"
using android::hardware::Return;
using android::hardware::Void;
using android::hardware::gnss::V1_0::GnssLocation;
+using android::hardware::gnss::common::GnssCallbackEventQueue;
using android::hardware::gnss::V1_0::GnssConstellationType;
using android::hardware::gnss::V1_0::GnssLocationFlags;
using android::hardware::gnss::V1_1::IGnss;
@@ -40,26 +37,9 @@
#define TIMEOUT_SEC 2 // for basic commands/responses
-// Test environment for GNSS HIDL HAL.
-class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static GnssHidlEnvironment* Instance() {
- static GnssHidlEnvironment* instance = new GnssHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IGnss>(); }
-
- private:
- GnssHidlEnvironment() {}
-};
-
// The main test class for GNSS HAL.
-class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
- GnssHalTest();
-
+class GnssHalTest : public testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override;
virtual void TearDown() override;
@@ -73,32 +53,40 @@
/* Callback class for data & Event. */
class GnssCallback : public IGnssCallback {
public:
- GnssHalTest& parent_;
+ IGnssCallback::GnssSystemInfo last_info_;
+ android::hardware::hidl_string last_name_;
+ uint32_t last_capabilities_;
+ GnssLocation last_location_;
- GnssCallback(GnssHalTest& parent) : parent_(parent){};
+ GnssCallbackEventQueue<IGnssCallback::GnssSystemInfo> info_cbq_;
+ GnssCallbackEventQueue<android::hardware::hidl_string> name_cbq_;
+ GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+ GnssCallbackEventQueue<GnssLocation> location_cbq_;
+ GnssCallbackEventQueue<IGnssCallback::GnssSvStatus> sv_status_cbq_;
- virtual ~GnssCallback() = default;
+ GnssCallback();
+ virtual ~GnssCallback() = default;
- // Dummy callback handlers
- Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue /* status */) override {
- return Void();
- }
- Return<void> gnssNmeaCb(int64_t /* timestamp */,
- const android::hardware::hidl_string& /* nmea */) override {
- return Void();
- }
- Return<void> gnssAcquireWakelockCb() override { return Void(); }
- Return<void> gnssReleaseWakelockCb() override { return Void(); }
- Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override {
- return Void();
- }
- Return<void> gnssRequestTimeCb() override { return Void(); }
- // Actual (test) callback handlers
- Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
- Return<void> gnssLocationCb(const GnssLocation& location) override;
- Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
- Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
- Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
+ // Dummy callback handlers
+ Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue /* status */) override {
+ return Void();
+ }
+ Return<void> gnssNmeaCb(int64_t /* timestamp */,
+ const android::hardware::hidl_string& /* nmea */) override {
+ return Void();
+ }
+ Return<void> gnssAcquireWakelockCb() override { return Void(); }
+ Return<void> gnssReleaseWakelockCb() override { return Void(); }
+ Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override {
+ return Void();
+ }
+ Return<void> gnssRequestTimeCb() override { return Void(); }
+ // Actual (test) callback handlers
+ Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
+ Return<void> gnssLocationCb(const GnssLocation& location) override;
+ Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
+ Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
+ Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
};
/*
@@ -160,29 +148,11 @@
* Note that location is not stopped in this method. The client should call
* StopAndClearLocations() after the call.
*/
- GnssConstellationType startLocationAndGetNonGpsConstellation();
+ GnssConstellationType startLocationAndGetNonGpsConstellation(
+ const int locations_to_await, const int gnss_sv_info_list_timeout);
sp<IGnss> gnss_hal_; // GNSS HAL to call into
- sp<IGnssCallback> gnss_cb_; // Primary callback interface
-
- /* Count of calls to set the following items, and the latest item (used by
- * test.)
- */
- int info_called_count_;
- IGnssCallback::GnssSystemInfo last_info_;
- uint32_t last_capabilities_;
- int capabilities_called_count_;
- int location_called_count_;
- GnssLocation last_location_;
- list<IGnssCallback::GnssSvStatus> list_gnss_sv_status_;
-
- int name_called_count_;
- android::hardware::hidl_string last_name_;
-
- private:
- std::mutex mtx_;
- std::condition_variable cv_;
- int notify_count_;
+ sp<GnssCallback> gnss_cb_; // Primary callback interface
};
#endif // GNSS_HAL_TEST_H_
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index 503e419..e0d8b54 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -18,9 +18,8 @@
#include <gnss_hal_test.h>
-#include <VtsHalHidlTargetTestBase.h>
-
#include <android/hardware/gnss/1.1/IGnssConfiguration.h>
+#include <gtest/gtest.h>
using android::hardware::hidl_vec;
@@ -39,18 +38,18 @@
*
* Empty test fixture to verify basic Setup & Teardown
*/
-TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
/*
* TestGnssMeasurementCallback:
* Gets the GnssMeasurementExtension and verify that it returns an actual extension.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
+TEST_P(GnssHalTest, TestGnssMeasurementCallback) {
auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
ASSERT_TRUE(gnssMeasurement_1_1.isOk());
auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
ASSERT_TRUE(gnssMeasurement_1_0.isOk());
- if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
+ if (gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
// At least one interface must be non-null.
@@ -65,7 +64,7 @@
* NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
* each received location.
*/
-TEST_F(GnssHalTest, GetLocationLowPower) {
+TEST_P(GnssHalTest, GetLocationLowPower) {
if (!IsGnssHalVersion_1_1()) {
ALOGI("Test GetLocationLowPower skipped. GNSS HAL version is greater than 1.1.");
return;
@@ -78,8 +77,10 @@
const bool kLowPowerMode = true;
// Warmup period - VTS doesn't have AGPS access via GnssLocationProvider
- StartAndCheckLocations(5);
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToCheck);
StopAndClearLocations();
+ gnss_cb_->location_cbq_.reset();
// Start of Low Power Mode test
SetPositionMode(kMinIntervalMsec, kLowPowerMode);
@@ -93,24 +94,26 @@
// Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and
// ensure that no location is received yet
- wait(kNoLocationPeriodSec);
+ gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec);
+ const int location_called_count = gnss_cb_->location_cbq_.calledCount();
// Tolerate (ignore) one extra location right after the first one
// to handle startup edge case scheduling limitations in some implementations
- if ((i == 1) && (location_called_count_ == 2)) {
- CheckLocation(last_location_, true);
+ if ((i == 1) && (location_called_count == 2)) {
+ CheckLocation(gnss_cb_->last_location_, true);
continue; // restart the quiet wait period after this too-fast location
}
- EXPECT_LE(location_called_count_, i);
- if (location_called_count_ != i) {
+ EXPECT_LE(location_called_count, i);
+ if (location_called_count != i) {
ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
- location_called_count_, i);
+ location_called_count, i);
}
- if (std::cv_status::no_timeout !=
- wait(kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
+ if (!gnss_cb_->location_cbq_.retrieve(
+ gnss_cb_->last_location_,
+ kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
ALOGW("GetLocationLowPower test - timeout awaiting location %d", i);
} else {
- CheckLocation(last_location_, true);
+ CheckLocation(gnss_cb_->last_location_, true);
}
}
@@ -127,7 +130,8 @@
*/
IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource(
- const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status, const int min_observations) {
+ const std::list<IGnssCallback::GnssSvStatus> list_gnss_sv_status,
+ const int min_observations) {
struct ComparableBlacklistedSource {
IGnssConfiguration::BlacklistedSource id;
@@ -213,7 +217,7 @@
* 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
* formerly strongest satellite
*/
-TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+TEST_P(GnssHalTest, BlacklistIndividualSatellites) {
if (!IsGnssHalVersion_1_1()) {
ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 1.1.");
return;
@@ -222,12 +226,15 @@
const int kLocationsToAwait = 3;
const int kRetriesToUnBlacklist = 10;
+ gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
+ int location_called_count = gnss_cb_->location_cbq_.calledCount();
// Tolerate 1 less sv status to handle edge cases in reporting.
- EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
- (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
+ int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+ EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size,
+ kLocationsToAwait, location_called_count);
/*
* Identify strongest SV seen at least kLocationsToAwait -1 times
@@ -235,8 +242,14 @@
* observability (one epoch RF null)
*/
+ const int kGnssSvStatusTimeout = 2;
+ std::list<IGnssCallback::GnssSvStatus> sv_status_list;
+ int count = gnss_cb_->sv_status_cbq_.retrieve(sv_status_list, sv_status_cbq_size,
+ kGnssSvStatusTimeout);
+ ASSERT_EQ(count, sv_status_cbq_size);
+
IGnssConfiguration::BlacklistedSource source_to_blacklist =
- FindStrongFrequentNonGpsSource(list_gnss_sv_status_, kLocationsToAwait - 1);
+ FindStrongFrequentNonGpsSource(sv_status_list, kLocationsToAwait - 1);
if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) {
// Cannot find a non-GPS satellite. Let the test pass.
@@ -260,21 +273,26 @@
EXPECT_TRUE(result);
// retry and ensure satellite not used
- list_gnss_sv_status_.clear();
+ gnss_cb_->sv_status_cbq_.reset();
+ gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// early exit if test is being run with insufficient signal
- if (location_called_count_ == 0) {
+ location_called_count = gnss_cb_->location_cbq_.calledCount();
+ if (location_called_count == 0) {
ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
}
- ASSERT_TRUE(location_called_count_ > 0);
+ ASSERT_TRUE(location_called_count > 0);
// Tolerate 1 less sv status to handle edge cases in reporting.
- EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
- (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
- for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+ sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+ EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size,
+ kLocationsToAwait, location_called_count);
+ for (int i = 0; i < sv_status_cbq_size; ++i) {
+ IGnssCallback::GnssSvStatus gnss_sv_status;
+ gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout);
for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
EXPECT_FALSE((gnss_sv.svid == source_to_blacklist.svid) &&
@@ -295,24 +313,28 @@
int unblacklist_loops_remaining = kRetriesToUnBlacklist;
while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) {
StopAndClearLocations();
- list_gnss_sv_status_.clear();
+ gnss_cb_->sv_status_cbq_.reset();
+ gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// early exit loop if test is being run with insufficient signal
- if (location_called_count_ == 0) {
+ location_called_count = gnss_cb_->location_cbq_.calledCount();
+ if (location_called_count == 0) {
ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
}
- ASSERT_TRUE(location_called_count_ > 0);
+ ASSERT_TRUE(location_called_count > 0);
// Tolerate 1 less sv status to handle edge cases in reporting.
- EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD(
- "Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
- ", tries remaining %d",
- (int)list_gnss_sv_status_.size(), kLocationsToAwait, unblacklist_loops_remaining);
+ sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+ EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
+ ", tries remaining %d",
+ sv_status_cbq_size, kLocationsToAwait, unblacklist_loops_remaining);
- for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+ for (int i = 0; i < sv_status_cbq_size; ++i) {
+ IGnssCallback::GnssSvStatus gnss_sv_status;
+ gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout);
for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
if ((gnss_sv.svid == source_to_blacklist.svid) &&
@@ -339,15 +361,18 @@
* GnssStatus does not use any constellation but GPS.
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
-TEST_F(GnssHalTest, BlacklistConstellationWithLocationOff) {
+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;
+ const int kGnssSvStatusTimeout = 2;
+
// Find first non-GPS constellation to blacklist
- GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
+ GnssConstellationType constellation_to_blacklist =
+ startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvStatusTimeout);
// Turns off location
StopAndClearLocations();
@@ -365,21 +390,25 @@
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);
// retry and ensure constellation not used
- list_gnss_sv_status_.clear();
+ gnss_cb_->sv_status_cbq_.reset();
- location_called_count_ = 0;
+ gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// Tolerate 1 less sv status to handle edge cases in reporting.
- EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+ 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 (const auto& gnss_sv_status : list_gnss_sv_status_) {
+ for (int i = 0; i < sv_status_cbq_size; ++i) {
+ IGnssCallback::GnssSvStatus gnss_sv_status;
+ gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout);
for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) &&
@@ -400,19 +429,23 @@
*
* 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 constellations, and turns off location.
+ * 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_F(GnssHalTest, BlacklistConstellationWithLocationOn) {
+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;
- GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
+ 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;
@@ -427,6 +460,7 @@
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);
@@ -435,16 +469,19 @@
StopAndClearLocations();
// retry and ensure constellation not used
- list_gnss_sv_status_.clear();
+ gnss_cb_->sv_status_cbq_.reset();
- location_called_count_ = 0;
+ gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// Tolerate 1 less sv status to handle edge cases in reporting.
- EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+ 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 (const auto& gnss_sv_status : list_gnss_sv_status_) {
+ for (int i = 0; i < sv_status_cbq_size; ++i) {
+ IGnssCallback::GnssSvStatus gnss_sv_status;
+ gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout);
for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) &&
@@ -465,9 +502,9 @@
*
* Ensure successfully injecting a location.
*/
-TEST_F(GnssHalTest, InjectBestLocation) {
+TEST_P(GnssHalTest, InjectBestLocation) {
StartAndCheckLocations(1);
- GnssLocation gnssLocation = last_location_;
+ GnssLocation gnssLocation = gnss_cb_->last_location_;
CheckLocation(gnssLocation, true);
auto result = gnss_hal_->injectBestLocation(gnssLocation);
@@ -484,10 +521,10 @@
* GnssDebugValuesSanityTest:
* Ensures that GnssDebug values make sense.
*/
-TEST_F(GnssHalTest, GnssDebugValuesSanityTest) {
+TEST_P(GnssHalTest, GnssDebugValuesSanityTest) {
auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
ASSERT_TRUE(gnssDebug.isOk());
- if (info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
+ if (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017) {
sp<IGnssDebug> iGnssDebug = gnssDebug;
EXPECT_NE(iGnssDebug, nullptr);
diff --git a/gnss/2.0/default/Android.bp b/gnss/2.0/default/Android.bp
index 3ba89da..37de55d 100644
--- a/gnss/2.0/default/Android.bp
+++ b/gnss/2.0/default/Android.bp
@@ -25,7 +25,7 @@
"AGnss.cpp",
"AGnssRil.cpp",
"Gnss.cpp",
- "GnssBatching.cpp",
+ "GnssBatching.cpp",
"GnssMeasurement.cpp",
"GnssMeasurementCorrections.cpp",
"GnssVisibilityControl.cpp",
@@ -35,9 +35,10 @@
"libhidlbase",
"libutils",
"liblog",
- "android.hardware.gnss@2.0",
"android.hardware.gnss.measurement_corrections@1.0",
"android.hardware.gnss.visibility_control@1.0",
+ "android.hardware.gnss@2.1",
+ "android.hardware.gnss@2.0",
"android.hardware.gnss@1.0",
"android.hardware.gnss@1.1",
],
diff --git a/gnss/2.0/default/Gnss.cpp b/gnss/2.0/default/Gnss.cpp
index 3d64fc3..09f2fc0 100644
--- a/gnss/2.0/default/Gnss.cpp
+++ b/gnss/2.0/default/Gnss.cpp
@@ -19,7 +19,6 @@
#include "Gnss.h"
#include <log/log.h>
-#include <utils/SystemClock.h>
#include "AGnss.h"
#include "AGnssRil.h"
@@ -47,24 +46,6 @@
sp<V2_0::IGnssCallback> Gnss::sGnssCallback_2_0 = nullptr;
sp<V1_1::IGnssCallback> Gnss::sGnssCallback_1_1 = nullptr;
-namespace {
-
-V2_0::GnssLocation getMockLocationV2_0() {
- const ElapsedRealtime timestamp = {
- .flags = ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
- ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
- .timestampNs = static_cast<uint64_t>(::android::elapsedRealtimeNano()),
- // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
- // In an actual implementation provide an estimate of the synchronization uncertainty
- // or don't set the field.
- .timeUncertaintyNs = 1000000};
-
- V2_0::GnssLocation location = {.v1_0 = Utils::getMockLocation(), .elapsedRealtime = timestamp};
- return location;
-}
-
-} // namespace
-
Gnss::Gnss() : mMinIntervalMs(1000) {}
Gnss::~Gnss() {
@@ -86,7 +67,7 @@
mIsActive = true;
mThread = std::thread([this]() {
while (mIsActive == true) {
- const auto location = getMockLocationV2_0();
+ const auto location = Utils::getMockLocationV2_0();
this->reportLocation(location);
std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
diff --git a/gnss/2.0/default/GnssMeasurement.cpp b/gnss/2.0/default/GnssMeasurement.cpp
index 1f95ff9..d778d50 100644
--- a/gnss/2.0/default/GnssMeasurement.cpp
+++ b/gnss/2.0/default/GnssMeasurement.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "GnssMeasurement"
#include "GnssMeasurement.h"
+#include "Utils.h"
#include <log/log.h>
#include <utils/SystemClock.h>
@@ -29,6 +30,7 @@
using GnssConstellationType = V2_0::GnssConstellationType;
using GnssMeasurementFlags = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags;
using GnssMeasurementState = V2_0::IGnssMeasurementCallback::GnssMeasurementState;
+using Utils = common::Utils;
sp<V2_0::IGnssMeasurementCallback> GnssMeasurement::sCallback = nullptr;
@@ -81,7 +83,7 @@
mIsActive = true;
mThread = std::thread([this]() {
while (mIsActive == true) {
- auto measurement = this->getMockMeasurement();
+ auto measurement = Utils::getMockMeasurementV2_0();
this->reportMeasurement(measurement);
std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
@@ -97,60 +99,6 @@
}
}
-GnssData GnssMeasurement::getMockMeasurement() {
- V1_0::IGnssMeasurementCallback::GnssMeasurement measurement_1_0 = {
- .flags = (uint32_t)GnssMeasurementFlags::HAS_CARRIER_FREQUENCY,
- .svid = (int16_t)6,
- .constellation = V1_0::GnssConstellationType::UNKNOWN,
- .timeOffsetNs = 0.0,
- .receivedSvTimeInNs = 8195997131077,
- .receivedSvTimeUncertaintyInNs = 15,
- .cN0DbHz = 30.0,
- .pseudorangeRateMps = -484.13739013671875,
- .pseudorangeRateUncertaintyMps = 1.0379999876022339,
- .accumulatedDeltaRangeState = (uint32_t)V1_0::IGnssMeasurementCallback::
- GnssAccumulatedDeltaRangeState::ADR_STATE_UNKNOWN,
- .accumulatedDeltaRangeM = 0.0,
- .accumulatedDeltaRangeUncertaintyM = 0.0,
- .carrierFrequencyHz = 1.59975e+09,
- .multipathIndicator =
- V1_0::IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN};
- V1_1::IGnssMeasurementCallback::GnssMeasurement measurement_1_1 = {.v1_0 = measurement_1_0};
- V2_0::IGnssMeasurementCallback::GnssMeasurement measurement_2_0 = {
- .v1_1 = measurement_1_1,
- .codeType = "C",
- .state = GnssMeasurementState::STATE_CODE_LOCK | GnssMeasurementState::STATE_BIT_SYNC |
- GnssMeasurementState::STATE_SUBFRAME_SYNC |
- GnssMeasurementState::STATE_TOW_DECODED |
- GnssMeasurementState::STATE_GLO_STRING_SYNC |
- GnssMeasurementState::STATE_GLO_TOD_DECODED,
- .constellation = GnssConstellationType::GLONASS,
- };
-
- hidl_vec<IGnssMeasurementCallback::GnssMeasurement> measurements(1);
- measurements[0] = measurement_2_0;
- V1_0::IGnssMeasurementCallback::GnssClock clock = {.timeNs = 2713545000000,
- .fullBiasNs = -1226701900521857520,
- .biasNs = 0.59689998626708984,
- .biasUncertaintyNs = 47514.989972114563,
- .driftNsps = -51.757811607455452,
- .driftUncertaintyNsps = 310.64968328491528,
- .hwClockDiscontinuityCount = 1};
-
- ElapsedRealtime timestamp = {
- .flags = ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
- ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
- .timestampNs = static_cast<uint64_t>(::android::elapsedRealtimeNano()),
- // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
- // In an actual implementation provide an estimate of the synchronization uncertainty
- // or don't set the field.
- .timeUncertaintyNs = 1000000};
-
- GnssData gnssData = {
- .measurements = measurements, .clock = clock, .elapsedRealtime = timestamp};
- return gnssData;
-}
-
void GnssMeasurement::reportMeasurement(const GnssData& data) {
ALOGD("reportMeasurement()");
std::unique_lock<std::mutex> lock(mMutex);
diff --git a/gnss/2.0/default/GnssMeasurement.h b/gnss/2.0/default/GnssMeasurement.h
index c24c00e..d8ffd59 100644
--- a/gnss/2.0/default/GnssMeasurement.h
+++ b/gnss/2.0/default/GnssMeasurement.h
@@ -59,7 +59,6 @@
private:
void start();
void stop();
- GnssData getMockMeasurement();
void reportMeasurement(const GnssData&);
static sp<IGnssMeasurementCallback> sCallback;
diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp
index 278d87b..da5289d 100644
--- a/gnss/2.0/vts/functional/Android.bp
+++ b/gnss/2.0/vts/functional/Android.bp
@@ -28,6 +28,8 @@
"android.hardware.gnss@1.0",
"android.hardware.gnss@1.1",
"android.hardware.gnss@2.0",
+ "android.hardware.gnss@2.1",
"android.hardware.gnss@common-vts-lib",
],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
index ae36c50..2c74fa3 100644
--- a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
+++ b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
@@ -15,15 +15,15 @@
*/
#define LOG_TAG "VtsHalGnssV2_0TargetTest"
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "gnss_hal_test.h"
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- GnssHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+using android::hardware::gnss::V2_0::IGnss;
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GnssHalTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp
index 14ae43c..b3a3203 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -16,16 +16,20 @@
#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"
+using ::android::hardware::hidl_string;
+
using ::android::hardware::gnss::common::Utils;
// Implementations for the main test class for GNSS HAL
void GnssHalTest::SetUp() {
- gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
- GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
+ gnss_hal_ = IGnss::getService(GetParam());
ASSERT_NE(gnss_hal_, nullptr);
SetUpGnssCallback();
@@ -98,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.
@@ -147,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 90a7866..55dc1bc 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.h
+++ b/gnss/2.0/vts/functional/gnss_hal_test.h
@@ -18,18 +18,15 @@
#define GNSS_HAL_TEST_H_
#include <android/hardware/gnss/2.0/IGnss.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include "GnssCallbackEventQueue.h"
-#include <condition_variable>
-#include <deque>
-#include <list>
-#include <mutex>
+#include <gtest/gtest.h>
using android::hardware::hidl_vec;
using android::hardware::Return;
using android::hardware::Void;
+using android::hardware::gnss::common::GnssCallbackEventQueue;
using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
using android::hardware::gnss::V1_0::GnssLocationFlags;
using android::hardware::gnss::V2_0::IGnss;
@@ -48,72 +45,13 @@
#define TIMEOUT_SEC 2 // for basic commands/responses
-// Test environment for GNSS HIDL HAL.
-class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static GnssHidlEnvironment* Instance() {
- static GnssHidlEnvironment* instance = new GnssHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IGnss>(); }
-
- private:
- GnssHidlEnvironment() {}
-};
-
// The main test class for GNSS HAL.
-class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class GnssHalTest : public testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override;
virtual void TearDown() override;
- /* Producer/consumer queue for storing/retrieving callback events from GNSS HAL */
- template <class T>
- class CallbackQueue {
- public:
- CallbackQueue(const std::string& name) : name_(name), called_count_(0){};
- ~CallbackQueue() { reset(); }
-
- /* Adds callback event to the end of the queue. */
- void store(const T& event);
-
- /*
- * Removes the callack event at the front of the queue, stores it in event parameter
- * and returns true. Returns false on timeout and event is not populated.
- */
- bool retrieve(T& event, int timeout_seconds);
-
- /*
- * Removes parameter count number of callack events at the front of the queue, stores
- * them in event_list parameter and returns the number of events retrieved. Waits up to
- * timeout_seconds to retrieve each event. If timeout occurs, it returns the number of
- * items retrieved which will be less than count.
- */
- int retrieve(list<T>& event_list, int count, int timeout_seconds);
-
- /* Returns the number of events pending to be retrieved from the callback event queue. */
- int size() const;
-
- /* Returns the number of callback events received since last reset(). */
- int calledCount() const;
-
- /* Clears the callback event queue and resets the calledCount() to 0. */
- void reset();
-
- private:
- CallbackQueue(const CallbackQueue&) = delete;
- CallbackQueue& operator=(const CallbackQueue&) = delete;
-
- std::string name_;
- int called_count_;
- mutable std::recursive_mutex mtx_;
- std::condition_variable_any cv_;
- std::deque<T> events_;
- };
-
/* Callback class for data & Event. */
class GnssCallback : public IGnssCallback_2_0 {
public:
@@ -122,11 +60,11 @@
uint32_t last_capabilities_;
GnssLocation_2_0 last_location_;
- CallbackQueue<IGnssCallback_1_0::GnssSystemInfo> info_cbq_;
- CallbackQueue<android::hardware::hidl_string> name_cbq_;
- CallbackQueue<uint32_t> capabilities_cbq_;
- CallbackQueue<GnssLocation_2_0> location_cbq_;
- CallbackQueue<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_list_cbq_;
+ GnssCallbackEventQueue<IGnssCallback_1_0::GnssSystemInfo> info_cbq_;
+ GnssCallbackEventQueue<android::hardware::hidl_string> name_cbq_;
+ GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+ GnssCallbackEventQueue<GnssLocation_2_0> location_cbq_;
+ GnssCallbackEventQueue<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_list_cbq_;
GnssCallback();
virtual ~GnssCallback() = default;
@@ -169,7 +107,7 @@
/* Callback class for GnssMeasurement. */
class GnssMeasurementCallback : public IGnssMeasurementCallback_2_0 {
public:
- CallbackQueue<IGnssMeasurementCallback_2_0::GnssData> measurement_cbq_;
+ GnssCallbackEventQueue<IGnssMeasurementCallback_2_0::GnssData> measurement_cbq_;
GnssMeasurementCallback() : measurement_cbq_("measurement"){};
virtual ~GnssMeasurementCallback() = default;
@@ -192,7 +130,7 @@
class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
public:
uint32_t last_capabilities_;
- CallbackQueue<uint32_t> capabilities_cbq_;
+ GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){};
virtual ~GnssMeasurementCorrectionsCallback() = default;
@@ -243,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
*/
@@ -252,61 +196,4 @@
sp<GnssCallback> gnss_cb_; // Primary callback interface
};
-template <class T>
-void GnssHalTest::CallbackQueue<T>::store(const T& event) {
- std::unique_lock<std::recursive_mutex> lock(mtx_);
- events_.push_back(event);
- ++called_count_;
- lock.unlock();
- cv_.notify_all();
-}
-
-template <class T>
-bool GnssHalTest::CallbackQueue<T>::retrieve(T& event, int timeout_seconds) {
- std::unique_lock<std::recursive_mutex> lock(mtx_);
- cv_.wait_for(lock, std::chrono::seconds(timeout_seconds), [&] { return !events_.empty(); });
- if (events_.empty()) {
- return false;
- }
- event = events_.front();
- events_.pop_front();
- return true;
-}
-
-template <class T>
-int GnssHalTest::CallbackQueue<T>::retrieve(list<T>& event_list, int count, int timeout_seconds) {
- for (int i = 0; i < count; ++i) {
- T event;
- if (!retrieve(event, timeout_seconds)) {
- return i;
- }
- event_list.push_back(event);
- }
-
- return count;
-}
-
-template <class T>
-int GnssHalTest::CallbackQueue<T>::size() const {
- std::unique_lock<std::recursive_mutex> lock(mtx_);
- return events_.size();
-}
-
-template <class T>
-int GnssHalTest::CallbackQueue<T>::calledCount() const {
- std::unique_lock<std::recursive_mutex> lock(mtx_);
- return called_count_;
-}
-
-template <class T>
-void GnssHalTest::CallbackQueue<T>::reset() {
- std::unique_lock<std::recursive_mutex> lock(mtx_);
- if (!events_.empty()) {
- ALOGW("%u unprocessed events discarded in callback queue %s", (unsigned int)events_.size(),
- name_.c_str());
- }
- events_.clear();
- called_count_ = 0;
-}
-
#endif // GNSS_HAL_TEST_H_
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index 39736cc..53f5b9e 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -16,10 +16,11 @@
#define LOG_TAG "GnssHalTestCases"
-#include <VtsHalHidlTargetTestBase.h>
#include <gnss_hal_test.h>
#include "Utils.h"
+#include <gtest/gtest.h>
+
using android::hardware::hidl_string;
using android::hardware::hidl_vec;
@@ -51,13 +52,13 @@
*
* Empty test fixture to verify basic Setup & Teardown
*/
-TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
/*
* TestGnssMeasurementExtension:
* Gets the GnssMeasurementExtension and verifies that it returns an actual extension.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementExtension) {
+TEST_P(GnssHalTest, TestGnssMeasurementExtension) {
auto gnssMeasurement_2_0 = gnss_hal_->getExtensionGnssMeasurement_2_0();
auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
@@ -80,7 +81,7 @@
* The GNSS HAL 2.0 implementation must support @2.0::IGnssConfiguration interface due to
* the deprecation of some methods in @1.0::IGnssConfiguration interface.
*/
-TEST_F(GnssHalTest, TestGnssConfigurationExtension) {
+TEST_P(GnssHalTest, TestGnssConfigurationExtension) {
auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0();
ASSERT_TRUE(gnssConfiguration.isOk());
sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration;
@@ -96,7 +97,7 @@
* TestGnssConfiguration_setSuplEs_Deprecation:
* Calls setSuplEs and verifies that it returns false.
*/
-TEST_F(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) {
+TEST_P(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) {
auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0();
ASSERT_TRUE(gnssConfiguration.isOk());
sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration;
@@ -111,7 +112,7 @@
* TestGnssConfiguration_setGpsLock_Deprecation:
* Calls setGpsLock and verifies that it returns false.
*/
-TEST_F(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) {
+TEST_P(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) {
auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0();
ASSERT_TRUE(gnssConfiguration.isOk());
sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration;
@@ -130,7 +131,7 @@
* @2.0::IAGnssRil interface due to the deprecation of framework network API methods needed
* to support the @1.0::IAGnssRil interface.
*/
-TEST_F(GnssHalTest, TestAGnssRilExtension) {
+TEST_P(GnssHalTest, TestAGnssRilExtension) {
auto agnssRil_2_0 = gnss_hal_->getExtensionAGnssRil_2_0();
ASSERT_TRUE(agnssRil_2_0.isOk());
sp<IAGnssRil_2_0> iAGnssRil_2_0 = agnssRil_2_0;
@@ -148,7 +149,7 @@
* 1. Updates GNSS HAL that a network has connected.
* 2. Updates GNSS HAL that network has disconnected.
*/
-TEST_F(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) {
+TEST_P(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) {
auto agnssRil = gnss_hal_->getExtensionAGnssRil_2_0();
ASSERT_TRUE(agnssRil.isOk());
sp<IAGnssRil_2_0> iAGnssRil = agnssRil;
@@ -180,7 +181,11 @@
* 2. constellation is valid.
* 3. state is valid.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementFields) {
+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();
@@ -234,7 +239,7 @@
* @2.0::IAGnss interface due to the deprecation of framework network API methods needed
* to support the @1.0::IAGnss interface.
*/
-TEST_F(GnssHalTest, TestAGnssExtension) {
+TEST_P(GnssHalTest, TestAGnssExtension) {
auto agnss_2_0 = gnss_hal_->getExtensionAGnss_2_0();
ASSERT_TRUE(agnss_2_0.isOk());
sp<IAGnss_2_0> iAGnss_2_0 = agnss_2_0;
@@ -258,7 +263,7 @@
* TestGnssNiExtension_Deprecation:
* Gets the @1.0::IGnssNi extension and verifies that it is a nullptr.
*/
-TEST_F(GnssHalTest, TestGnssNiExtension_Deprecation) {
+TEST_P(GnssHalTest, TestGnssNiExtension_Deprecation) {
// Verify IGnssNi 1.0 is not supported.
auto gnssNi = gnss_hal_->getExtensionGnssNi();
ASSERT_TRUE(!gnssNi.isOk() || ((sp<IGnssNi>)gnssNi) == nullptr);
@@ -269,7 +274,7 @@
* Gets the GnssVisibilityControlExtension and if it is not null, verifies that it supports
* the gnss.visibility_control@1.0::IGnssVisibilityControl interface by invoking a method.
*/
-TEST_F(GnssHalTest, TestGnssVisibilityControlExtension) {
+TEST_P(GnssHalTest, TestGnssVisibilityControlExtension) {
auto gnssVisibilityControl = gnss_hal_->getExtensionVisibilityControl();
ASSERT_TRUE(gnssVisibilityControl.isOk());
sp<IGnssVisibilityControl> iGnssVisibilityControl = gnssVisibilityControl;
@@ -290,7 +295,13 @@
* capabilities are reported and the mandatory LOS_SATS or the EXCESS_PATH_LENGTH
* capability flag is set.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) {
+TEST_P(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) {
+ if (!IsGnssHalVersion_2_0()) {
+ ALOGI("Test GnssMeasurementCorrectionsCapabilities skipped. GNSS HAL version is greater "
+ "than 2.0.");
+ return;
+ }
+
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) {
return;
}
@@ -318,7 +329,7 @@
* If measurement corrections capability is supported, verifies that it supports the
* gnss.measurement_corrections@1.0::IMeasurementCorrections interface by invoking a method.
*/
-TEST_F(GnssHalTest, TestGnssMeasurementCorrections) {
+TEST_P(GnssHalTest, TestGnssMeasurementCorrections) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) {
return;
}
@@ -348,7 +359,7 @@
* Sets a GnssMeasurementCallback, waits for a GnssData object, and verifies the flags in member
* elapsedRealitme are valid.
*/
-TEST_F(GnssHalTest, TestGnssDataElapsedRealtimeFlags) {
+TEST_P(GnssHalTest, TestGnssDataElapsedRealtimeFlags) {
const int kFirstGnssMeasurementTimeoutSeconds = 10;
auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0();
@@ -383,7 +394,7 @@
iGnssMeasurement->close();
}
-TEST_F(GnssHalTest, TestGnssLocationElapsedRealtime) {
+TEST_P(GnssHalTest, TestGnssLocationElapsedRealtime) {
StartAndCheckFirstLocation();
ASSERT_TRUE((int)gnss_cb_->last_location_.elapsedRealtime.flags <=
@@ -399,7 +410,7 @@
}
// This test only verify that injectBestLocation_2_0 does not crash.
-TEST_F(GnssHalTest, TestInjectBestLocation_2_0) {
+TEST_P(GnssHalTest, TestInjectBestLocation_2_0) {
StartAndCheckFirstLocation();
gnss_hal_->injectBestLocation_2_0(gnss_cb_->last_location_);
StopAndClearLocations();
@@ -410,7 +421,7 @@
* Gets the @2.0::IGnssBatching extension and verifies that it doesn't return an error. Support
* for this interface is optional.
*/
-TEST_F(GnssHalTest, TestGnssBatchingExtension) {
+TEST_P(GnssHalTest, TestGnssBatchingExtension) {
auto gnssBatching_2_0 = gnss_hal_->getExtensionGnssBatching_2_0();
ASSERT_TRUE(gnssBatching_2_0.isOk());
}
@@ -422,7 +433,7 @@
* NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
* each received location.
*/
-TEST_F(GnssHalTest, GetLocationLowPower) {
+TEST_P(GnssHalTest, GetLocationLowPower) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::LOW_POWER_MODE)) {
ALOGI("Test GetLocationLowPower skipped. LOW_POWER_MODE capability not supported.");
return;
@@ -453,18 +464,18 @@
// ensure that no location is received yet
gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec);
- const int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+ const int location_called_count = gnss_cb_->location_cbq_.calledCount();
// Tolerate (ignore) one extra location right after the first one
// to handle startup edge case scheduling limitations in some implementations
- if ((i == 1) && (locationCalledCount == 2)) {
+ if ((i == 1) && (location_called_count == 2)) {
CheckLocation(gnss_cb_->last_location_, true);
continue; // restart the quiet wait period after this too-fast location
}
- EXPECT_LE(locationCalledCount, i);
- if (locationCalledCount != i) {
- ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
- locationCalledCount, i);
+ EXPECT_LE(location_called_count, i);
+ if (location_called_count != i) {
+ ALOGW("GetLocationLowPower test - too many locations received. %d vs. %d expected ",
+ location_called_count, i);
}
if (!gnss_cb_->location_cbq_.retrieve(
@@ -513,7 +524,7 @@
* or a source with constellation == UNKNOWN if none are found sufficient times
*/
IGnssConfiguration_1_1::BlacklistedSource FindStrongFrequentNonGpsSource(
- const list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>>& sv_info_lists,
+ const std::list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>>& sv_info_lists,
const int min_observations) {
struct ComparableBlacklistedSource {
IGnssConfiguration_1_1::BlacklistedSource id;
@@ -599,7 +610,12 @@
* 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
* formerly strongest satellite
*/
-TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+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.");
@@ -626,7 +642,7 @@
*/
const int kGnssSvStatusTimeout = 2;
- list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_lists;
+ std::list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_lists;
int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, sv_info_list_cbq_size,
kGnssSvStatusTimeout);
ASSERT_EQ(count, sv_info_list_cbq_size);
@@ -744,7 +760,12 @@
* GnssStatus does not use any constellation but GPS.
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
-TEST_F(GnssHalTest, BlacklistConstellation) {
+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
new file mode 100644
index 0000000..7efc4a6
--- /dev/null
+++ b/gnss/2.1/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.gnss@2.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IGnss.hal",
+ "IGnssCallback.hal",
+ "IGnssMeasurement.hal",
+ "IGnssMeasurementCallback.hal",
+ "IGnssConfiguration.hal",
+ ],
+ interfaces: [
+ "android.hardware.gnss.measurement_corrections@1.1",
+ "android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss.visibility_control@1.0",
+ "android.hardware.gnss@1.0",
+ "android.hardware.gnss@1.1",
+ "android.hardware.gnss@2.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal
new file mode 100644
index 0000000..ce37647
--- /dev/null
+++ b/gnss/2.1/IGnss.hal
@@ -0,0 +1,76 @@
+/*
+ * 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 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections;
+import @2.0::IGnss;
+
+import IGnssCallback;
+import IGnssMeasurement;
+import IGnssConfiguration;
+
+/**
+ * Represents the standard GNSS (Global Navigation Satellite System) interface.
+ */
+interface IGnss extends @2.0::IGnss {
+ /**
+ * Opens the interface and provides the callback routines to the implementation of this
+ * interface.
+ *
+ * The framework calls this method to instruct the GPS engine to prepare for serving requests
+ * from the framework. The GNSS HAL implementation must respond to all GNSS requests from the
+ * framework upon successful return from this method until cleanup() method is called to
+ * close this interface.
+ *
+ * @param callback Callback interface for IGnss.
+ *
+ * @return success Returns true on success.
+ */
+ setCallback_2_1(IGnssCallback callback) generates (bool success);
+
+ /**
+ * This method returns the IGnssMeasurement interface.
+ *
+ * At least one of getExtensionGnssMeasurement(), getExtensionGnssMeasurement_1_1(),
+ * getExtensionGnssMeasurement_2_0(), and getExtensionGnssMeasurement_2_1() methods must return
+ * a non-null handle, and the other methods must return nullptr.
+ *
+ * @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);
+
+ /**
+ * This method returns the IMeasurementCorrections interface.
+ *
+ * Both getExtensionMeasurementCorrections and getExtensionMeasurementCorrections_1_1 must
+ * return non-null. Both methods can return the same V1.1 IMeasurementCorrections object.
+ *
+ * @return measurementCorrectionsIface Handle to the IMeasurementCorrections interface.
+ */
+ getExtensionMeasurementCorrections_1_1() generates (IMeasurementCorrections measurementCorrectionsIface);
+};
\ No newline at end of file
diff --git a/gnss/2.1/IGnssCallback.hal b/gnss/2.1/IGnssCallback.hal
new file mode 100644
index 0000000..da70742
--- /dev/null
+++ b/gnss/2.1/IGnssCallback.hal
@@ -0,0 +1,58 @@
+/*
+ * 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::IGnssCallback;
+
+/**
+ * This interface is required for the HAL to communicate certain information
+ * like status and location info back to the platform, the platform implements
+ * the interfaces and passes a handle to the HAL.
+ */
+interface IGnssCallback extends @2.0::IGnssCallback {
+
+ /** Extends a GnssSvInfo, adding a basebandCN0DbHz. */
+ struct GnssSvInfo {
+ /**
+ * GNSS satellite information for a single satellite and frequency.
+ */
+ @2.0::IGnssCallback.GnssSvInfo v2_0;
+
+ /**
+ * Baseband Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. It contains
+ * the measured C/N0 value for the signal measured at the baseband.
+ *
+ * This is typically a few dB weaker than the value estimated for C/N0 at the antenna port,
+ * which is reported in cN0DbHz.
+ *
+ * If a signal has separate components (e.g. Pilot and Data channels) and the receiver only
+ * processes one of the components, then the reported basebandCN0DbHz reflects only the
+ * component that is processed.
+ *
+ * This value is mandatory. Like cN0DbHz, it may be reported as 0 for satellites being
+ * reported that may be searched for, but not yet tracked.
+ */
+ double basebandCN0DbHz;
+ };
+
+ /**
+ * Callback for the HAL to pass a vector of GnssSvInfo back to the client.
+ *
+ * @param svInfoList SV info list information from HAL.
+ */
+ gnssSvStatusCb_2_1(vec<GnssSvInfo> svInfoList);
+};
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/IGnssMeasurement.hal b/gnss/2.1/IGnssMeasurement.hal
new file mode 100644
index 0000000..d2c76e6
--- /dev/null
+++ b/gnss/2.1/IGnssMeasurement.hal
@@ -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.gnss@2.1;
+
+import @1.0::IGnssMeasurement;
+import @1.1::IGnssMeasurement;
+import @2.0::IGnssMeasurement;
+import IGnssMeasurementCallback;
+
+/**
+ * Extended interface for GNSS Measurements support.
+ */
+interface IGnssMeasurement extends @2.0::IGnssMeasurement {
+
+ /**
+ * Initializes the interface and registers the callback routines with the HAL. After a
+ * successful call to 'setCallback_2_1' the HAL must begin to provide updates at an average
+ * output rate of 1Hz (occasional intra-measurement time offsets in the range from 0-2000msec
+ * can be tolerated.)
+ *
+ * @param callback Handle to GnssMeasurement callback interface.
+ * @param enableFullTracking If true, GNSS chipset must switch off duty cycling. In such mode
+ * no clock discontinuities are expected and, when supported, carrier phase should be
+ * continuous in good signal conditions. All non-blacklisted, healthy constellations,
+ * satellites and frequency bands that the chipset supports must be reported in this mode.
+ * The GNSS chipset is allowed to consume more power in this mode. If false, API must behave
+ * as in HAL V1_0, optimizing power via duty cycling, constellations and frequency limits,
+ * etc.
+ *
+ * @return initRet Returns SUCCESS if successful. Returns ERROR_ALREADY_INIT if a callback has
+ * already been registered without a corresponding call to 'close'. Returns ERROR_GENERIC
+ * for any other error. The HAL must not generate any other updates upon returning this
+ * error code.
+ */
+ setCallback_2_1(IGnssMeasurementCallback callback, bool enableFullTracking)
+ generates (GnssMeasurementStatus initRet);
+};
diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal
new file mode 100644
index 0000000..0385abd
--- /dev/null
+++ b/gnss/2.1/IGnssMeasurementCallback.hal
@@ -0,0 +1,182 @@
+/*
+ * 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 @1.0::IGnssMeasurementCallback;
+import @2.0::IGnssMeasurementCallback;
+import @2.0::ElapsedRealtime;
+import GnssSignalType;
+
+/** The callback interface to report measurements from the HAL. */
+interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback {
+
+ /**
+ * Flags to indicate what fields in GnssMeasurement are valid.
+ */
+ enum GnssMeasurementFlags : uint32_t {
+ /** A valid 'snr' is stored in the data structure. */
+ HAS_SNR = 1 << 0,
+ /** A valid 'carrier frequency' is stored in the data structure. */
+ HAS_CARRIER_FREQUENCY = 1 << 9,
+ /** A valid 'carrier cycles' is stored in the data structure. */
+ HAS_CARRIER_CYCLES = 1 << 10,
+ /** A valid 'carrier phase' is stored in the data structure. */
+ HAS_CARRIER_PHASE = 1 << 11,
+ /** A valid 'carrier phase uncertainty' is stored in the data structure. */
+ HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12,
+ /** A valid automatic gain control is stored in the data structure. */
+ HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13,
+ /** A valid receiver inter-signal bias is stored in the data structure. */
+ HAS_RECEIVER_ISB = 1 << 16,
+ /** A valid receiver inter-signal bias uncertainty is stored in the data structure. */
+ HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17,
+ /** A valid satellite inter-signal bias is stored in the data structure. */
+ HAS_SATELLITE_ISB = 1 << 18,
+ /** A valid satellite inter-signal bias uncertainty is stored in the data structure. */
+ HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19
+ };
+
+
+ /**
+ * Extends a GNSS Measurement, adding basebandCN0DbHz, GnssMeasurementFlags,
+ * receiverInterSignalBiasNs, receiverInterSignalBiasUncertaintyNs, satelliteInterSignalBiasNs
+ * and satelliteInterSignalBiasUncertaintyNs.
+ */
+ struct GnssMeasurement {
+ /**
+ * GNSS measurement information for a single satellite and frequency, as in the 2.0 version
+ * of the HAL.
+ *
+ * In this version of the HAL, the field 'flags' in the v2_0.v1_1.v1_0 struct is deprecated,
+ * and is no longer used by the framework. The GNSS measurement flags are instead reported
+ * in @2.1::IGnssMeasurementCallback.GnssMeasurement.flags.
+ *
+ */
+ @2.0::IGnssMeasurementCallback.GnssMeasurement v2_0;
+
+ /**
+ * A set of flags indicating the validity of the fields in this data
+ * structure.
+ *
+ * Fields for which there is no corresponding flag must be filled in
+ * with a valid value. For convenience, these are marked as mandatory.
+ *
+ * Others fields may have invalid information in them, if not marked as
+ * valid by the corresponding bit in flags.
+ */
+ bitfield<GnssMeasurementFlags> flags;
+
+ /**
+ * The receiver inter-signal bias (ISB) in nanoseconds.
+ *
+ * This value is the estimated receiver-side inter-system (different from the constellation
+ * in GnssClock.referenceSignalForIsb) bias and inter-frequency (different from the carrier
+ * frequency in GnssClock.referenceSignalForIsb) bias. The reported receiver ISB
+ * must include signal delays caused by
+ *
+ * - Receiver inter-constellation bias
+ * - Receiver inter-frequency bias
+ * - Receiver inter-code bias
+ *
+ * The value does not include the inter-frequency Ionospheric bias.
+ *
+ * The receiver ISB of GnssClock.referenceSignalForIsb is defined to be 0.0 nanoseconds.
+ */
+ double receiverInterSignalBiasNs;
+
+ /**
+ * 1-sigma uncertainty associated with the receiver inter-signal bias in nanoseconds.
+ */
+ double receiverInterSignalBiasUncertaintyNs;
+
+ /**
+ * The satellite inter-signal bias in nanoseconds.
+ *
+ * This value is the satellite-and-control-segment-side inter-system (different from the
+ * constellation in GnssClock.referenceSignalForIsb) bias and inter-frequency (different
+ * from the carrier frequency in GnssClock.referenceSignalForIsb) bias, including:
+ *
+ * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPT-UTC Time Offset (TauGps),
+ * BDS-GLO Time Offset (BGTO))
+ * - Group delay (e.g., Total Group Delay (TGD))
+ * - Satellite inter-signal bias, which includes satellite inter-frequency bias (GLO only),
+ * and satellite inter-code bias (e.g., Differential Code Bias (DCB)).
+ *
+ * The receiver ISB of GnssClock.referenceSignalForIsb is defined to be 0.0 nanoseconds.
+ */
+ double satelliteInterSignalBiasNs;
+
+ /**
+ * 1-sigma uncertainty associated with the satellite inter-signal bias in nanoseconds.
+ */
+ double satelliteInterSignalBiasUncertaintyNs;
+
+ /**
+ * Baseband Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. It contains
+ * the measured C/N0 value for the signal measured at the baseband.
+ *
+ * This is typically a few dB weaker than the value estimated for C/N0 at the antenna port,
+ * which is reported in cN0DbHz.
+ *
+ * If a signal has separate components (e.g. Pilot and Data channels) and the receiver only
+ * processes one of the components, then the reported basebandCN0DbHz reflects only the
+ * component that is processed.
+ *
+ * This value is mandatory.
+ */
+ double basebandCN0DbHz;
+ };
+
+ /**
+ * Extends a GNSS clock time, adding a referenceSignalTypeForIsb.
+ */
+ struct GnssClock {
+ /**
+ * GNSS clock time information, as in the 1.0 version of the HAL.
+ */
+ @1.0::IGnssMeasurementCallback.GnssClock v1_0;
+
+ /**
+ * Reference GNSS signal type for inter-signal bias.
+ */
+ GnssSignalType referenceSignalTypeForIsb;
+ };
+
+ /**
+ * Complete set of GNSS Measurement data, same as 2.0 with additional fields in measurements.
+ */
+ struct GnssData {
+ /** The full set of satellite measurement observations. */
+ vec<GnssMeasurement> measurements;
+
+ /** The GNSS clock time reading. */
+ GnssClock clock;
+
+ /**
+ * Timing information of the GNSS data synchronized with SystemClock.elapsedRealtimeNanos()
+ * clock.
+ */
+ ElapsedRealtime elapsedRealtime;
+ };
+
+ /**
+ * Callback for the hal to pass a GnssData structure back to the client.
+ *
+ * @param data Contains a reading of GNSS measurements.
+ */
+ gnssMeasurementCb_2_1(GnssData data);
+};
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
new file mode 100644
index 0000000..1f1078e
--- /dev/null
+++ b/gnss/2.1/default/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_binary {
+ name: "android.hardware.gnss@2.1-service",
+ init_rc: ["android.hardware.gnss@2.1-service.rc"],
+ relative_install_path: "hw",
+ vendor: true,
+ vintf_fragments: ["android.hardware.gnss@2.1-service.xml"],
+ srcs: [
+ "Gnss.cpp",
+ "GnssDebug.cpp",
+ "GnssMeasurement.cpp",
+ "GnssMeasurementCorrections.cpp",
+ "GnssConfiguration.cpp",
+ "service.cpp",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "libutils",
+ "liblog",
+ "android.hardware.gnss.measurement_corrections@1.1",
+ "android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss.visibility_control@1.0",
+ "android.hardware.gnss@2.1",
+ "android.hardware.gnss@1.0",
+ "android.hardware.gnss@1.1",
+ "android.hardware.gnss@2.0",
+ ],
+ static_libs: [
+ "android.hardware.gnss@common-default-lib",
+ ],
+}
diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp
new file mode 100644
index 0000000..679eb35
--- /dev/null
+++ b/gnss/2.1/default/Gnss.cpp
@@ -0,0 +1,432 @@
+/*
+ * 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 "Gnss"
+
+#include "Gnss.h"
+#include "GnssDebug.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_1::implementation::
+ GnssMeasurementCorrections;
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+sp<V2_1::IGnssCallback> Gnss::sGnssCallback_2_1 = nullptr;
+sp<V2_0::IGnssCallback> Gnss::sGnssCallback_2_0 = nullptr;
+sp<V1_1::IGnssCallback> Gnss::sGnssCallback_1_1 = nullptr;
+sp<V1_0::IGnssCallback> Gnss::sGnssCallback_1_0 = nullptr;
+
+Gnss::Gnss() : mMinIntervalMs(1000), mGnssConfiguration{new GnssConfiguration()} {}
+
+Gnss::~Gnss() {
+ stop();
+}
+
+Return<bool> Gnss::start() {
+ ALOGD("start");
+ if (mIsActive) {
+ ALOGW("Gnss has started. Restarting...");
+ stop();
+ }
+
+ mIsActive = true;
+ mThread = std::thread([this]() {
+ while (mIsActive == true) {
+ auto svStatus = filterBlacklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
+ this->reportSvStatus(svStatus);
+
+ if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) {
+ const auto location = Utils::getMockLocationV2_0();
+ this->reportLocation(location);
+ } else {
+ const auto location = Utils::getMockLocationV1_0();
+ this->reportLocation(location);
+ }
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
+ }
+ });
+ 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;
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+ return true;
+}
+
+// Methods from V1_0::IGnss follow.
+Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>& callback) {
+ if (callback == nullptr) {
+ ALOGE("%s: Null callback ignored", __func__);
+ return false;
+ }
+
+ sGnssCallback_1_0 = callback;
+
+ uint32_t capabilities = 0x0 | V1_0::IGnssCallback::Capabilities::MEASUREMENTS |
+ V1_0::IGnssCallback::Capabilities::SCHEDULING;
+ auto ret = sGnssCallback_1_0->gnssSetCapabilitesCb(capabilities);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018};
+
+ ret = sGnssCallback_1_0->gnssSetSystemInfoCb(gnssInfo);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ return true;
+}
+
+Return<void> Gnss::cleanup() {
+ sGnssCallback_2_1 = nullptr;
+ sGnssCallback_2_0 = nullptr;
+ return Void();
+}
+
+Return<bool> Gnss::injectTime(int64_t, int64_t, int32_t) {
+ return true;
+}
+
+Return<bool> Gnss::injectLocation(double, double, float) {
+ return true;
+}
+
+Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData) {
+ // TODO implement
+ return Void();
+}
+
+Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode,
+ V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs,
+ uint32_t, uint32_t) {
+ mMinIntervalMs = minIntervalMs;
+ return true;
+}
+
+Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() {
+ // TODO implement
+ return ::android::sp<V1_0::IAGnssRil>{};
+}
+
+Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing() {
+ // TODO implement
+ return ::android::sp<V1_0::IGnssGeofencing>{};
+}
+
+Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss() {
+ // TODO implement
+ return ::android::sp<V1_0::IAGnss>{};
+}
+
+Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi() {
+ // TODO implement
+ return ::android::sp<V1_0::IGnssNi>{};
+}
+
+Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
+ ALOGD("Gnss::getExtensionGnssMeasurement");
+ return new GnssMeasurement();
+}
+
+Return<sp<V1_0::IGnssNavigationMessage>> Gnss::getExtensionGnssNavigationMessage() {
+ // TODO implement
+ return ::android::sp<V1_0::IGnssNavigationMessage>{};
+}
+
+Return<sp<V1_0::IGnssXtra>> Gnss::getExtensionXtra() {
+ // TODO implement
+ return ::android::sp<V1_0::IGnssXtra>{};
+}
+
+Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration() {
+ // TODO implement
+ return ::android::sp<V1_0::IGnssConfiguration>{};
+}
+
+Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() {
+ return new V1_1::implementation::GnssDebug();
+}
+
+Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching() {
+ // TODO implement
+ return ::android::sp<V1_0::IGnssBatching>{};
+}
+
+// Methods from V1_1::IGnss follow.
+Return<bool> Gnss::setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) {
+ if (callback == nullptr) {
+ ALOGE("%s: Null callback ignored", __func__);
+ return false;
+ }
+
+ sGnssCallback_1_1 = callback;
+
+ uint32_t capabilities = 0x0;
+ auto ret = sGnssCallback_1_1->gnssSetCapabilitesCb(capabilities);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018};
+
+ ret = sGnssCallback_1_1->gnssSetSystemInfoCb(gnssInfo);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ auto gnssName = "Google Mock GNSS Implementation v2.1";
+ ret = sGnssCallback_1_1->gnssNameCb(gnssName);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ return true;
+}
+
+Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode,
+ V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs,
+ uint32_t, uint32_t, bool) {
+ mMinIntervalMs = minIntervalMs;
+ return true;
+}
+
+Return<sp<V1_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_1_1() {
+ // TODO implement
+ return ::android::sp<V1_1::IGnssConfiguration>{};
+}
+
+Return<sp<V1_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_1_1() {
+ // TODO implement
+ return ::android::sp<V1_1::IGnssMeasurement>{};
+}
+
+Return<bool> Gnss::injectBestLocation(const V1_0::GnssLocation&) {
+ return true;
+}
+
+// Methods from V2_0::IGnss follow.
+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() {
+ ALOGD("Gnss::getExtensionGnssConfiguration_2_0");
+ return mGnssConfiguration;
+}
+
+Return<sp<V2_0::IGnssDebug>> Gnss::getExtensionGnssDebug_2_0() {
+ // TODO implement
+ return ::android::sp<V2_0::IGnssDebug>{};
+}
+
+Return<sp<V2_0::IAGnss>> Gnss::getExtensionAGnss_2_0() {
+ // TODO implement
+ return ::android::sp<V2_0::IAGnss>{};
+}
+
+Return<sp<V2_0::IAGnssRil>> Gnss::getExtensionAGnssRil_2_0() {
+ // TODO implement
+ return ::android::sp<V2_0::IAGnssRil>{};
+}
+
+Return<sp<V2_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_0() {
+ ALOGD("Gnss::getExtensionGnssMeasurement_2_0");
+ return new GnssMeasurement();
+}
+
+Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
+Gnss::getExtensionMeasurementCorrections() {
+ ALOGD("Gnss::getExtensionMeasurementCorrections()");
+ return new GnssMeasurementCorrections();
+}
+
+Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> Gnss::getExtensionVisibilityControl() {
+ // TODO implement
+ return ::android::sp<visibility_control::V1_0::IGnssVisibilityControl>{};
+}
+
+Return<sp<V2_0::IGnssBatching>> Gnss::getExtensionGnssBatching_2_0() {
+ // TODO implement
+ return ::android::sp<V2_0::IGnssBatching>{};
+}
+
+Return<bool> Gnss::injectBestLocation_2_0(const V2_0::GnssLocation&) {
+ // TODO(b/124012850): Implement function.
+ return bool{};
+}
+
+// Methods from V2_1::IGnss follow.
+Return<bool> Gnss::setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) {
+ ALOGD("Gnss::setCallback_2_1");
+ if (callback == nullptr) {
+ ALOGE("%s: Null callback ignored", __func__);
+ return false;
+ }
+
+ sGnssCallback_2_1 = 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_1->gnssSetCapabilitiesCb_2_0(capabilities);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2020};
+
+ ret = sGnssCallback_2_1->gnssSetSystemInfoCb(gnssInfo);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ auto gnssName = "Android Mock GNSS Implementation v2.1";
+ ret = sGnssCallback_2_1->gnssNameCb(gnssName);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ return true;
+}
+
+Return<sp<V2_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_1() {
+ ALOGD("Gnss::getExtensionGnssMeasurement_2_1");
+ return new GnssMeasurement();
+}
+
+Return<sp<V2_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_1() {
+ ALOGD("Gnss::getExtensionGnssConfiguration_2_1");
+ return mGnssConfiguration;
+}
+
+Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
+Gnss::getExtensionMeasurementCorrections_1_1() {
+ ALOGD("Gnss::getExtensionMeasurementCorrections_1_1()");
+ return new GnssMeasurementCorrections();
+}
+
+void Gnss::reportSvStatus(const hidl_vec<GnssSvInfo>& svInfoList) const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ // TODO(skz): update this to call 2_0 callback if non-null
+ if (sGnssCallback_2_1 == nullptr) {
+ ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
+ return;
+ }
+ auto ret = sGnssCallback_2_1->gnssSvStatusCb_2_1(svInfoList);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+void Gnss::reportLocation(const V1_0::GnssLocation& location) const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (sGnssCallback_1_1 != nullptr) {
+ auto ret = sGnssCallback_1_1->gnssLocationCb(location);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback v1.1", __func__);
+ }
+ return;
+ }
+ if (sGnssCallback_1_0 == nullptr) {
+ ALOGE("%s: No non-null callback", __func__);
+ return;
+ }
+ auto ret = sGnssCallback_1_0->gnssLocationCb(location);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback v1.0", __func__);
+ }
+}
+
+void Gnss::reportLocation(const V2_0::GnssLocation& location) const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ 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;
+ }
+ 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 v2.0", __func__);
+ }
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h
new file mode 100644
index 0000000..c47206a
--- /dev/null
+++ b/gnss/2.1/default/Gnss.h
@@ -0,0 +1,116 @@
+/*
+ * 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/2.1/IGnss.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <atomic>
+#include <mutex>
+#include <thread>
+#include "GnssConfiguration.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+
+using GnssSvInfo = IGnssCallback::GnssSvInfo;
+
+namespace implementation {
+
+struct Gnss : public IGnss {
+ Gnss();
+ ~Gnss();
+ // Methods from V1_0::IGnss follow.
+ Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback) override;
+ Return<bool> start() override;
+ Return<bool> stop() override;
+ Return<void> cleanup() override;
+ Return<bool> injectTime(int64_t timeMs, int64_t timeReferenceMs,
+ int32_t uncertaintyMs) override;
+ Return<bool> injectLocation(double latitudeDegrees, double longitudeDegrees,
+ float accuracyMeters) override;
+ Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override;
+ Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs) override;
+ Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
+ Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
+ Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
+ Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
+ Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
+ Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override;
+ Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override;
+ Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
+ Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
+ Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
+
+ // Methods from V1_1::IGnss follow.
+ Return<bool> setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) override;
+ Return<bool> setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs, bool lowPowerMode) override;
+ Return<sp<V1_1::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override;
+ Return<sp<V1_1::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override;
+ Return<bool> injectBestLocation(const V1_0::GnssLocation& location) override;
+
+ // Methods from V2_0::IGnss follow.
+ Return<bool> setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) override;
+ Return<sp<V2_0::IGnssConfiguration>> getExtensionGnssConfiguration_2_0() override;
+ Return<sp<V2_0::IGnssDebug>> getExtensionGnssDebug_2_0() override;
+ Return<sp<V2_0::IAGnss>> getExtensionAGnss_2_0() override;
+ Return<sp<V2_0::IAGnssRil>> getExtensionAGnssRil_2_0() override;
+ Return<sp<V2_0::IGnssMeasurement>> getExtensionGnssMeasurement_2_0() override;
+ Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
+ getExtensionMeasurementCorrections() override;
+ Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> getExtensionVisibilityControl()
+ override;
+ Return<sp<V2_0::IGnssBatching>> getExtensionGnssBatching_2_0() override;
+ Return<bool> injectBestLocation_2_0(const V2_0::GnssLocation& location) override;
+
+ // 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;
+ Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
+ getExtensionMeasurementCorrections_1_1() override;
+
+ private:
+ void reportLocation(const V2_0::GnssLocation&) const;
+ void reportLocation(const V1_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;
+ static sp<V1_1::IGnssCallback> sGnssCallback_1_1;
+ static sp<V1_0::IGnssCallback> sGnssCallback_1_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
+} // namespace V2_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
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/GnssDebug.cpp b/gnss/2.1/default/GnssDebug.cpp
new file mode 100644
index 0000000..a9f7ded
--- /dev/null
+++ b/gnss/2.1/default/GnssDebug.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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 "GnssDebug"
+
+#include <log/log.h>
+
+#include "Constants.h"
+#include "GnssDebug.h"
+
+using namespace ::android::hardware::gnss::common;
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
+Return<void> GnssDebug::getDebugData(V1_0::IGnssDebug::getDebugData_cb _hidl_cb) {
+ PositionDebug positionDebug = {
+ .valid = true,
+ .latitudeDegrees = kMockLatitudeDegrees,
+ .longitudeDegrees = kMockLongitudeDegrees,
+ .altitudeMeters = kMockAltitudeMeters,
+ .speedMetersPerSec = kMockSpeedMetersPerSec,
+ .bearingDegrees = kMockBearingDegrees,
+ .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
+ .verticalAccuracyMeters = kMockVerticalAccuracyMeters,
+ .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond,
+ .bearingAccuracyDegrees = kMockBearingAccuracyDegrees,
+ .ageSeconds = 0.99};
+
+ TimeDebug timeDebug = {.timeEstimate = kMockTimestamp,
+ .timeUncertaintyNs = 1000,
+ .frequencyUncertaintyNsPerSec = 5.0e4};
+
+ DebugData data = {.position = positionDebug, .time = timeDebug};
+
+ _hidl_cb(data);
+
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/2.1/default/GnssDebug.h b/gnss/2.1/default/GnssDebug.h
new file mode 100644
index 0000000..969d337
--- /dev/null
+++ b/gnss/2.1/default/GnssDebug.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_gnss_V1_1_GnssDebug_H_
+#define android_hardware_gnss_V1_1_GnssDebug_H_
+
+#include <android/hardware/gnss/1.0/IGnssDebug.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using V1_0::IGnssDebug;
+
+/* Interface for GNSS Debug support. */
+struct GnssDebug : public IGnssDebug {
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
+ * These declarations were generated from IGnssDebug.hal.
+ */
+ Return<void> getDebugData(V1_0::IGnssDebug::getDebugData_cb _hidl_cb) override;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_V1_1_GnssDebug_H_
diff --git a/gnss/2.1/default/GnssMeasurement.cpp b/gnss/2.1/default/GnssMeasurement.cpp
new file mode 100644
index 0000000..34e20e5
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurement.cpp
@@ -0,0 +1,152 @@
+/*
+ * 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 "GnssMeasurement"
+
+#include "GnssMeasurement.h"
+#include <log/log.h>
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+
+using common::Utils;
+
+namespace V2_1 {
+namespace implementation {
+
+sp<V2_1::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_1 = nullptr;
+sp<V2_0::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_0 = nullptr;
+
+GnssMeasurement::GnssMeasurement() : mMinIntervalMillis(1000) {}
+
+GnssMeasurement::~GnssMeasurement() {
+ stop();
+}
+
+// Methods from V1_0::IGnssMeasurement follow.
+Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback(
+ const sp<V1_0::IGnssMeasurementCallback>&) {
+ // TODO implement
+ return V1_0::IGnssMeasurement::GnssMeasurementStatus{};
+}
+
+Return<void> GnssMeasurement::close() {
+ ALOGD("close");
+ std::unique_lock<std::mutex> lock(mMutex);
+ stop();
+ sCallback_2_1 = nullptr;
+ sCallback_2_0 = nullptr;
+ return Void();
+}
+
+// Methods from V1_1::IGnssMeasurement follow.
+Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_1_1(
+ const sp<V1_1::IGnssMeasurementCallback>&, bool) {
+ // TODO implement
+ return V1_0::IGnssMeasurement::GnssMeasurementStatus{};
+}
+
+// Methods from V2_0::IGnssMeasurement follow.
+Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_0(
+ 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.
+Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_1(
+ const sp<V2_1::IGnssMeasurementCallback>& callback, bool) {
+ ALOGD("setCallback_2_1");
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback_2_1 = callback;
+
+ if (mIsActive) {
+ ALOGW("GnssMeasurement callback already set. Resetting the callback...");
+ stop();
+ }
+ start();
+
+ return V1_0::IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
+}
+
+void GnssMeasurement::start() {
+ ALOGD("start");
+ mIsActive = true;
+ mThread = std::thread([this]() {
+ while (mIsActive == true) {
+ 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));
+ }
+ });
+}
+
+void GnssMeasurement::stop() {
+ ALOGD("stop");
+ mIsActive = false;
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+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_2_1 == nullptr) {
+ ALOGE("%s: GnssMeasurement::sCallback_2_1 is null.", __func__);
+ return;
+ }
+ auto ret = sCallback_2_1->gnssMeasurementCb_2_1(data);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/2.1/default/GnssMeasurement.h b/gnss/2.1/default/GnssMeasurement.h
new file mode 100644
index 0000000..3ed7bc5
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurement.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/2.1/IGnssMeasurement.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <atomic>
+#include <mutex>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData;
+using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData;
+
+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 GnssMeasurement : public IGnssMeasurement {
+ GnssMeasurement();
+ ~GnssMeasurement();
+ // Methods from V1_0::IGnssMeasurement follow.
+ Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback(
+ const sp<V1_0::IGnssMeasurementCallback>& callback) override;
+ Return<void> close() override;
+
+ // Methods from V1_1::IGnssMeasurement follow.
+ Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_1_1(
+ const sp<V1_1::IGnssMeasurementCallback>& callback, bool enableFullTracking) override;
+
+ // Methods from V2_0::IGnssMeasurement follow.
+ Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_2_0(
+ const sp<V2_0::IGnssMeasurementCallback>& callback, bool enableFullTracking) override;
+
+ // Methods from V2_1::IGnssMeasurement follow.
+ Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_2_1(
+ const sp<V2_1::IGnssMeasurementCallback>& callback, bool enableFullTracking) override;
+
+ private:
+ void start();
+ void stop();
+ void reportMeasurement(const GnssDataV2_0&);
+ void reportMeasurement(const GnssDataV2_1&);
+
+ 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;
+ mutable std::mutex mMutex;
+};
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.cpp b/gnss/2.1/default/GnssMeasurementCorrections.cpp
new file mode 100644
index 0000000..9dedbf6
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurementCorrections.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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_1 {
+namespace implementation {
+
+// Methods from V1_0::IMeasurementCorrections follow.
+Return<bool> GnssMeasurementCorrections::setCorrections(
+ const V1_0::MeasurementCorrections& corrections) {
+ ALOGD("setCorrections");
+ ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu, "
+ "satCorrections.size: %d",
+ 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;
+}
+
+// Methods from V1_1::IMeasurementCorrections follow.
+Return<bool> GnssMeasurementCorrections::setCorrections_1_1(
+ const V1_1::MeasurementCorrections& corrections) {
+ ALOGD("setCorrections_1_1");
+ ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu,"
+ "satCorrections.size: %d, hasEnvironmentBearing: %d, environmentBearingDeg: %f,"
+ "environmentBearingUncDeg: %f",
+ corrections.v1_0.latitudeDegrees, corrections.v1_0.longitudeDegrees,
+ corrections.v1_0.altitudeMeters, corrections.v1_0.horizontalPositionUncertaintyMeters,
+ corrections.v1_0.verticalPositionUncertaintyMeters,
+ static_cast<unsigned long long>(corrections.v1_0.toaGpsNanosecondsOfWeek),
+ static_cast<int>(corrections.v1_0.satCorrections.size()),
+ corrections.hasEnvironmentBearing, corrections.environmentBearingDegrees,
+ corrections.environmentBearingUncertaintyDegrees);
+ for (auto singleSatCorrection : corrections.v1_0.satCorrections) {
+ ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d, cfHz: %f, probLos: %f,"
+ " epl: %f, eplUnc: %f",
+ static_cast<int>(singleSatCorrection.singleSatCorrectionFlags),
+ static_cast<int>(singleSatCorrection.constellation),
+ static_cast<int>(singleSatCorrection.svid), singleSatCorrection.carrierFrequencyHz,
+ singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters,
+ singleSatCorrection.excessPathLengthUncertaintyMeters);
+ ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
+ singleSatCorrection.reflectingPlane.latitudeDegrees,
+ singleSatCorrection.reflectingPlane.longitudeDegrees,
+ singleSatCorrection.reflectingPlane.altitudeMeters,
+ singleSatCorrection.reflectingPlane.azimuthDegrees);
+ }
+
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // 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..036e855
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurementCorrections.h
@@ -0,0 +1,52 @@
+/*
+ * 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.1/IMeasurementCorrections.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_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;
+
+struct GnssMeasurementCorrections : public IMeasurementCorrections {
+ // Methods from V1_0::IMeasurementCorrections follow.
+ Return<bool> setCorrections(const V1_0::MeasurementCorrections& corrections) override;
+ Return<bool> setCallback(const sp<V1_0::IMeasurementCorrectionsCallback>& callback) override;
+
+ // Methods from V1_1::IMeasurementCorrections follow.
+ Return<bool> setCorrections_1_1(const V1_1::MeasurementCorrections& corrections) override;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace measurement_corrections
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/2.1/default/OWNERS b/gnss/2.1/default/OWNERS
new file mode 100644
index 0000000..b7b4a2e
--- /dev/null
+++ b/gnss/2.1/default/OWNERS
@@ -0,0 +1,4 @@
+gomo@google.com
+smalkos@google.com
+wyattriley@google.com
+yuhany@google.com
diff --git a/gnss/2.1/default/android.hardware.gnss@2.1-service.rc b/gnss/2.1/default/android.hardware.gnss@2.1-service.rc
new file mode 100644
index 0000000..5926c77
--- /dev/null
+++ b/gnss/2.1/default/android.hardware.gnss@2.1-service.rc
@@ -0,0 +1,4 @@
+service vendor.gnss-2-1 /vendor/bin/hw/android.hardware.gnss@2.1-service
+ class hal
+ user system
+ group system
diff --git a/gnss/2.1/default/android.hardware.gnss@2.1-service.xml b/gnss/2.1/default/android.hardware.gnss@2.1-service.xml
new file mode 100644
index 0000000..12a1fdf
--- /dev/null
+++ b/gnss/2.1/default/android.hardware.gnss@2.1-service.xml
@@ -0,0 +1,12 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.gnss</name>
+ <transport>hwbinder</transport>
+ <version>2.1</version>
+ <version>1.1</version>
+ <interface>
+ <name>IGnss</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/gnss/2.1/default/service.cpp b/gnss/2.1/default/service.cpp
new file mode 100644
index 0000000..5e004d5
--- /dev/null
+++ b/gnss/2.1/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.gnss@2.1-service"
+
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include "Gnss.h"
+
+using ::android::OK;
+using ::android::sp;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::gnss::V2_1::IGnss;
+using ::android::hardware::gnss::V2_1::implementation::Gnss;
+
+int main(int /* argc */, char* /* argv */[]) {
+ sp<IGnss> gnss = new Gnss();
+ configureRpcThreadpool(1, true /* will join */);
+ if (gnss->registerAsService() != OK) {
+ ALOGE("Could not register gnss 2.1 service.");
+ return 1;
+ }
+ joinRpcThreadpool();
+
+ ALOGE("Service exited!");
+ return 1;
+}
\ No newline at end of file
diff --git a/gnss/2.1/types.hal b/gnss/2.1/types.hal
new file mode 100644
index 0000000..e4484c1
--- /dev/null
+++ b/gnss/2.1/types.hal
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@2.1;
+
+import @2.0::GnssConstellationType;
+
+/**
+ * Represents a GNSS signal type.
+ */
+struct GnssSignalType {
+ /**
+ * Constellation type of the SV that transmits the signal.
+ */
+ GnssConstellationType constellation;
+
+ /**
+ * Carrier frequency in Hz of the signal.
+ */
+ double carrierFrequencyHz;
+
+ /**
+ * The type of code of the GNSS signal.
+ *
+ * This is used to specify the observation descriptor defined in GNSS Observation Data File
+ * Header Section Description in the RINEX standard (Version 3.XX). In RINEX Version 3.03,
+ * in Appendix Table A2 Attributes are listed as uppercase letters (for instance, "A" for
+ * "A channel").
+ *
+ * See the comment of @2.0::IGnssMeasurementCallback.GnssMeasurement.codeType for more details.
+ */
+ string codeType;
+};
diff --git a/gnss/2.1/vts/OWNERS b/gnss/2.1/vts/OWNERS
new file mode 100644
index 0000000..b7b4a2e
--- /dev/null
+++ b/gnss/2.1/vts/OWNERS
@@ -0,0 +1,4 @@
+gomo@google.com
+smalkos@google.com
+wyattriley@google.com
+yuhany@google.com
diff --git a/gnss/2.1/vts/functional/Android.bp b/gnss/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..f008a26
--- /dev/null
+++ b/gnss/2.1/vts/functional/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalGnssV2_1TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "gnss_hal_test.cpp",
+ "gnss_hal_test_cases.cpp",
+ "VtsHalGnssV2_1TargetTest.cpp",
+ ],
+ static_libs: [
+ "android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss.measurement_corrections@1.1",
+ "android.hardware.gnss.visibility_control@1.0",
+ "android.hardware.gnss@1.0",
+ "android.hardware.gnss@1.1",
+ "android.hardware.gnss@2.0",
+ "android.hardware.gnss@2.1",
+ "android.hardware.gnss@common-vts-lib",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp b/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp
new file mode 100644
index 0000000..e61d885
--- /dev/null
+++ b/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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 "VtsHalGnssV2_1TargetTest"
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "gnss_hal_test.h"
+
+using android::hardware::gnss::V2_1::IGnss;
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GnssHalTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp
new file mode 100644
index 0000000..93f89f5
--- /dev/null
+++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp
@@ -0,0 +1,265 @@
+/*
+ * 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 "GnssHalTest"
+
+#include <gnss_hal_test.h>
+#include <chrono>
+#include "Utils.h"
+
+#include <gtest/gtest.h>
+
+using ::android::hardware::gnss::common::Utils;
+
+// Implementations for the main test class for GNSS HAL
+void GnssHalTest::SetUp() {
+ gnss_hal_ = IGnss::getService(GetParam());
+ ASSERT_NE(gnss_hal_, nullptr);
+
+ SetUpGnssCallback();
+}
+
+void GnssHalTest::TearDown() {
+ if (gnss_hal_ != nullptr) {
+ gnss_hal_->cleanup();
+ gnss_hal_ = nullptr;
+ }
+
+ // Set to nullptr to destruct the callback event queues and warn of any unprocessed events.
+ gnss_cb_ = nullptr;
+}
+
+void GnssHalTest::SetUpGnssCallback() {
+ gnss_cb_ = new GnssCallback();
+ ASSERT_NE(gnss_cb_, nullptr);
+
+ auto result = gnss_hal_->setCallback_2_1(gnss_cb_);
+ if (!result.isOk()) {
+ ALOGE("result of failed setCallback %s", result.description().c_str());
+ }
+
+ ASSERT_TRUE(result.isOk());
+ ASSERT_TRUE(result);
+
+ /*
+ * All capabilities, name and systemInfo callbacks should trigger
+ */
+ EXPECT_TRUE(gnss_cb_->capabilities_cbq_.retrieve(gnss_cb_->last_capabilities_, TIMEOUT_SEC));
+ EXPECT_TRUE(gnss_cb_->info_cbq_.retrieve(gnss_cb_->last_info_, TIMEOUT_SEC));
+ EXPECT_TRUE(gnss_cb_->name_cbq_.retrieve(gnss_cb_->last_name_, TIMEOUT_SEC));
+
+ EXPECT_EQ(gnss_cb_->capabilities_cbq_.calledCount(), 1);
+ EXPECT_EQ(gnss_cb_->info_cbq_.calledCount(), 1);
+ EXPECT_EQ(gnss_cb_->name_cbq_.calledCount(), 1);
+}
+
+void GnssHalTest::StopAndClearLocations() {
+ const auto result = gnss_hal_->stop();
+
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ /*
+ * Clear notify/waiting counter, allowing up till the timeout after
+ * the last reply for final startup messages to arrive (esp. system
+ * info.)
+ */
+ while (gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, TIMEOUT_SEC)) {
+ }
+ gnss_cb_->location_cbq_.reset();
+}
+
+void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) {
+ const int kPreferredAccuracy = 0; // Ideally perfect (matches GnssLocationProvider)
+ const int kPreferredTimeMsec = 0; // Ideally immediate
+
+ const auto result = gnss_hal_->setPositionMode_1_1(
+ IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC,
+ min_interval_msec, kPreferredAccuracy, kPreferredTimeMsec, low_power_mode);
+
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+}
+
+bool GnssHalTest::StartAndCheckFirstLocation() {
+ const auto result = gnss_hal_->start();
+
+ 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.
+ */
+ const int kFirstGnssLocationTimeoutSeconds = 75;
+
+ EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+ kFirstGnssLocationTimeoutSeconds));
+ int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+ EXPECT_EQ(locationCalledCount, 1);
+
+ if (locationCalledCount > 0) {
+ // don't require speed on first fix
+ CheckLocation(gnss_cb_->last_location_, false);
+ return true;
+ }
+ return false;
+}
+
+void GnssHalTest::CheckLocation(const GnssLocation_2_0& location, bool check_speed) {
+ const bool check_more_accuracies =
+ (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017);
+
+ Utils::checkLocation(location.v1_0, check_speed, check_more_accuracies);
+}
+
+void GnssHalTest::StartAndCheckLocations(int count) {
+ const int kMinIntervalMsec = 500;
+ const int kLocationTimeoutSubsequentSec = 2;
+ const bool kLowPowerMode = false;
+
+ SetPositionMode(kMinIntervalMsec, kLowPowerMode);
+
+ EXPECT_TRUE(StartAndCheckFirstLocation());
+
+ for (int i = 1; i < count; i++) {
+ EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+ kLocationTimeoutSubsequentSec));
+ int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+ EXPECT_EQ(locationCalledCount, i + 1);
+ // Don't cause confusion by checking details if no location yet
+ if (locationCalledCount > 0) {
+ // Should be more than 1 location by now, but if not, still don't check first fix speed
+ CheckLocation(gnss_cb_->last_location_, locationCalledCount > 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_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"),
+ capabilities_cbq_("capabilities"),
+ location_cbq_("location"),
+ sv_info_list_cbq_("sv_info") {}
+
+Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
+ const IGnssCallback_1_0::GnssSystemInfo& info) {
+ ALOGI("Info received, year %d", info.yearOfHw);
+ info_cbq_.store(info);
+ return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
+ ALOGI("Capabilities received %d", capabilities);
+ capabilities_cbq_.store(capabilities);
+ return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
+ ALOGI("Capabilities (v2.0) received %d", capabilities);
+ capabilities_cbq_.store(capabilities);
+ return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
+ ALOGI("Name received: %s", name.c_str());
+ name_cbq_.store(name);
+ return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation_1_0& location) {
+ ALOGI("Location received");
+ GnssLocation_2_0 location_v2_0;
+ location_v2_0.v1_0 = location;
+ return gnssLocationCbImpl(location_v2_0);
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssLocationCb_2_0(const GnssLocation_2_0& location) {
+ ALOGI("Location (v2.0) received");
+ return gnssLocationCbImpl(location);
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssLocationCbImpl(const GnssLocation_2_0& location) {
+ location_cbq_.store(location);
+ return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus&) {
+ ALOGI("gnssSvStatusCb");
+ return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb_2_1(
+ const hidl_vec<IGnssCallback_2_1::GnssSvInfo>& svInfoList) {
+ ALOGI("gnssSvStatusCb_2_1. Size = %d", (int)svInfoList.size());
+ sv_info_list_cbq_.store(svInfoList);
+ return Void();
+}
+
+Return<void> GnssHalTest::GnssMeasurementCallback::gnssMeasurementCb_2_1(
+ const IGnssMeasurementCallback_2_1::GnssData& data) {
+ ALOGD("GnssMeasurement v2.1 received. Size = %d", (int)data.measurements.size());
+ measurement_cbq_.store(data);
+ return Void();
+}
+
+Return<void> GnssHalTest::GnssMeasurementCorrectionsCallback::setCapabilitiesCb(
+ uint32_t capabilities) {
+ ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities);
+ capabilities_cbq_.store(capabilities);
+ return Void();
+}
\ No newline at end of file
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h
new file mode 100644
index 0000000..b99cf23
--- /dev/null
+++ b/gnss/2.1/vts/functional/gnss_hal_test.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GNSS_HAL_TEST_H_
+#define GNSS_HAL_TEST_H_
+
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include "GnssCallbackEventQueue.h"
+
+#include <gtest/gtest.h>
+
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+
+using android::hardware::gnss::common::GnssCallbackEventQueue;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
+using android::hardware::gnss::V1_0::GnssLocationFlags;
+using android::hardware::gnss::V2_0::GnssConstellationType;
+using android::hardware::gnss::V2_1::IGnss;
+
+using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation;
+using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation;
+
+using IGnssCallback_1_0 = android::hardware::gnss::V1_0::IGnssCallback;
+using IGnssCallback_2_0 = android::hardware::gnss::V2_0::IGnssCallback;
+using IGnssCallback_2_1 = android::hardware::gnss::V2_1::IGnssCallback;
+
+using IGnssMeasurementCallback_1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_2_1 = android::hardware::gnss::V2_1::IGnssMeasurementCallback;
+
+using android::sp;
+
+#define TIMEOUT_SEC 2 // for basic commands/responses
+
+// The main test class for GNSS HAL.
+class GnssHalTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override;
+
+ virtual void TearDown() override;
+
+ /* Callback class for data & Event. */
+ class GnssCallback : public IGnssCallback_2_1 {
+ public:
+ IGnssCallback_1_0::GnssSystemInfo last_info_;
+ android::hardware::hidl_string last_name_;
+ uint32_t last_capabilities_;
+ GnssLocation_2_0 last_location_;
+
+ GnssCallbackEventQueue<IGnssCallback_1_0::GnssSystemInfo> info_cbq_;
+ GnssCallbackEventQueue<android::hardware::hidl_string> name_cbq_;
+ GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+ GnssCallbackEventQueue<GnssLocation_2_0> location_cbq_;
+ GnssCallbackEventQueue<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list_cbq_;
+
+ GnssCallback();
+ virtual ~GnssCallback() = default;
+
+ // Dummy callback handlers
+ Return<void> gnssStatusCb(const IGnssCallback_1_0::GnssStatusValue /* status */) override {
+ return Void();
+ }
+ Return<void> gnssNmeaCb(int64_t /* timestamp */,
+ const android::hardware::hidl_string& /* nmea */) override {
+ return Void();
+ }
+ Return<void> gnssAcquireWakelockCb() override { return Void(); }
+ Return<void> gnssReleaseWakelockCb() override { return Void(); }
+ Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override {
+ return Void();
+ }
+ Return<void> gnssRequestTimeCb() override { return Void(); }
+ // Actual (test) callback handlers
+ Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
+ Return<void> gnssLocationCb(const GnssLocation_1_0& location) override;
+ Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
+ Return<void> gnssSetSystemInfoCb(const IGnssCallback_1_0::GnssSystemInfo& info) override;
+ Return<void> gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus& svStatus) override;
+
+ // New in v2.0
+ Return<void> gnssLocationCb_2_0(const GnssLocation_2_0& location) override;
+ Return<void> gnssRequestLocationCb_2_0(bool /* independentFromGnss */,
+ bool /* isUserEmergency */) override {
+ return Void();
+ }
+ Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
+ Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback_2_0::GnssSvInfo>&) override {
+ return Void();
+ }
+
+ // New in v2.1
+ Return<void> gnssSvStatusCb_2_1(
+ const hidl_vec<IGnssCallback_2_1::GnssSvInfo>& svInfoList) override;
+
+ private:
+ Return<void> gnssLocationCbImpl(const GnssLocation_2_0& location);
+ };
+
+ /* Callback class for GnssMeasurement. */
+ class GnssMeasurementCallback : public IGnssMeasurementCallback_2_1 {
+ public:
+ GnssCallbackEventQueue<IGnssMeasurementCallback_2_1::GnssData> measurement_cbq_;
+
+ GnssMeasurementCallback() : measurement_cbq_("measurement"){};
+ virtual ~GnssMeasurementCallback() = default;
+
+ // Methods from V1_0::IGnssMeasurementCallback follow.
+ Return<void> GnssMeasurementCb(const IGnssMeasurementCallback_1_0::GnssData&) override {
+ return Void();
+ }
+
+ // Methods from V1_1::IGnssMeasurementCallback follow.
+ Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_1_1::GnssData&) override {
+ return Void();
+ }
+
+ // Methods from V2_0::IGnssMeasurementCallback follow.
+ Return<void> gnssMeasurementCb_2_0(const IGnssMeasurementCallback_2_0::GnssData&) override {
+ return Void();
+ }
+
+ // Methods from V2_1::IGnssMeasurementCallback follow.
+ Return<void> gnssMeasurementCb_2_1(const IGnssMeasurementCallback_2_1::GnssData&) override;
+ };
+
+ /* Callback class for GnssMeasurementCorrections. */
+ class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
+ public:
+ uint32_t last_capabilities_;
+ GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+
+ GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){};
+ virtual ~GnssMeasurementCorrectionsCallback() = default;
+
+ // Methods from V1_0::IMeasurementCorrectionsCallback follow.
+ Return<void> setCapabilitiesCb(uint32_t capabilities) override;
+ };
+
+ /*
+ * SetUpGnssCallback:
+ * Set GnssCallback and verify the result.
+ */
+ void SetUpGnssCallback();
+
+ /*
+ * StartAndCheckFirstLocation:
+ * Helper function to start location, and check the first one.
+ *
+ * <p> Note this leaves the Location request active, to enable Stop call vs. other call
+ * reordering tests.
+ *
+ * returns true if a location was successfully generated
+ */
+ bool StartAndCheckFirstLocation();
+
+ /*
+ * CheckLocation:
+ * Helper function to vet Location fields
+ *
+ * check_speed: true if speed related fields are also verified.
+ */
+ void CheckLocation(const GnssLocation_2_0& location, const bool check_speed);
+
+ /*
+ * StartAndCheckLocations:
+ * Helper function to collect, and check a number of
+ * normal ~1Hz locations.
+ *
+ * Note this leaves the Location request active, to enable Stop call vs. other call
+ * reordering tests.
+ */
+ void StartAndCheckLocations(int count);
+
+ /*
+ * StopAndClearLocations:
+ * Helper function to stop locations, and clear any remaining notifications
+ */
+ void StopAndClearLocations();
+
+ /*
+ * SetPositionMode:
+ * Helper function to set positioning mode and verify output
+ */
+ 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
+};
+
+#endif // GNSS_HAL_TEST_H_
diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
new file mode 100644
index 0000000..9ac9436
--- /dev/null
+++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
@@ -0,0 +1,598 @@
+/*
+ * 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 "GnssHalTestCases"
+
+#include <gnss_hal_test.h>
+#include <cmath>
+#include "Utils.h"
+
+#include <gtest/gtest.h>
+
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+
+using android::hardware::gnss::common::Utils;
+
+using IGnssMeasurement_2_1 = android::hardware::gnss::V2_1::IGnssMeasurement;
+using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
+using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
+using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
+
+using IGnssConfiguration_2_1 = android::hardware::gnss::V2_1::IGnssConfiguration;
+using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
+using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
+using IGnssConfiguration_1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
+
+using android::hardware::gnss::V2_0::GnssConstellationType;
+using android::hardware::gnss::V2_1::IGnssConfiguration;
+
+using GnssMeasurementFlags = IGnssMeasurementCallback_2_1::GnssMeasurementFlags;
+using IMeasurementCorrections_1_1 =
+ android::hardware::gnss::measurement_corrections::V1_1::IMeasurementCorrections;
+
+/*
+ * SetupTeardownCreateCleanup:
+ * Requests the gnss HAL then calls cleanup
+ *
+ * Empty test fixture to verify basic Setup & Teardown
+ */
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
+
+/*
+ * TestGnssMeasurementExtension:
+ * Gets the GnssMeasurementExtension and verifies that it returns an actual extension.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementExtension) {
+ auto gnssMeasurement_2_1 = gnss_hal_->getExtensionGnssMeasurement_2_1();
+ auto gnssMeasurement_2_0 = gnss_hal_->getExtensionGnssMeasurement_2_0();
+ auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
+ auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
+ ASSERT_TRUE(gnssMeasurement_2_1.isOk() && gnssMeasurement_2_0.isOk() &&
+ gnssMeasurement_1_1.isOk() && gnssMeasurement_1_0.isOk());
+ sp<IGnssMeasurement_2_1> iGnssMeas_2_1 = gnssMeasurement_2_1;
+ sp<IGnssMeasurement_2_0> iGnssMeas_2_0 = gnssMeasurement_2_0;
+ sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
+ sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
+ // At least one interface is non-null.
+ int numNonNull = (int)(iGnssMeas_2_1 != nullptr) + (int)(iGnssMeas_2_0 != nullptr) +
+ (int)(iGnssMeas_1_1 != nullptr) + (int)(iGnssMeas_1_0 != nullptr);
+ ASSERT_TRUE(numNonNull >= 1);
+}
+
+/*
+ * 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
+ * 2. ISB fields are valid if HAS_INTER_SIGNAL_BIAS is true.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementFields) {
+ const int kFirstGnssMeasurementTimeoutSeconds = 10;
+
+ auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_1();
+ ASSERT_TRUE(gnssMeasurement.isOk());
+
+ // Skip test if GnssMeasurement v2.1 is not supported
+ sp<IGnssMeasurement_2_1> iGnssMeasurement = gnssMeasurement;
+ if (iGnssMeasurement == nullptr) {
+ return;
+ }
+
+ sp<GnssMeasurementCallback> callback = new GnssMeasurementCallback();
+ auto result = iGnssMeasurement->setCallback_2_1(callback, /* enableFullTracking= */ true);
+ ASSERT_TRUE(result.isOk());
+ EXPECT_EQ(result, IGnssMeasurement_1_0::GnssMeasurementStatus::SUCCESS);
+
+ IGnssMeasurementCallback_2_1::GnssData lastMeasurement;
+ ASSERT_TRUE(callback->measurement_cbq_.retrieve(lastMeasurement,
+ kFirstGnssMeasurementTimeoutSeconds));
+ EXPECT_EQ(callback->measurement_cbq_.calledCount(), 1);
+ ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
+ for (auto measurement : lastMeasurement.measurements) {
+ // Verify basebandCn0DbHz is valid.
+ ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
+
+ if (((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_ISB) > 0) &&
+ ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_ISB_UNCERTAINTY) >
+ 0) &&
+ ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB) > 0) &&
+ ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB_UNCERTAINTY) >
+ 0)) {
+ GnssConstellationType referenceConstellation =
+ lastMeasurement.clock.referenceSignalTypeForIsb.constellation;
+ double carrierFrequencyHz =
+ lastMeasurement.clock.referenceSignalTypeForIsb.carrierFrequencyHz;
+ std::string codeType = lastMeasurement.clock.referenceSignalTypeForIsb.codeType;
+
+ ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN &&
+ referenceConstellation >= GnssConstellationType::IRNSS);
+ ASSERT_TRUE(carrierFrequencyHz > 0);
+ ASSERT_TRUE(codeType != "");
+
+ ASSERT_TRUE(std::abs(measurement.receiverInterSignalBiasNs) < 1.0e6);
+ ASSERT_TRUE(measurement.receiverInterSignalBiasUncertaintyNs >= 0);
+ ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
+ ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
+ }
+ }
+
+ iGnssMeasurement->close();
+}
+
+/*
+ * TestGnssSvInfoFields:
+ * Gets 1 location and a GnssSvInfo, and verifies
+ * 1. basebandCN0DbHz is valid.
+ */
+TEST_P(GnssHalTest, TestGnssSvInfoFields) {
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckFirstLocation();
+ 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, 0);
+ ALOGD("Observed %d GnssSvStatus, while awaiting one location (%d received)",
+ sv_info_list_cbq_size, location_called_count);
+
+ hidl_vec<IGnssCallback_2_1::GnssSvInfo> last_sv_info_list;
+ ASSERT_TRUE(gnss_cb_->sv_info_list_cbq_.retrieve(last_sv_info_list, 1));
+
+ bool nonZeroCn0Found = false;
+ for (auto sv_info : last_sv_info_list) {
+ ASSERT_TRUE(sv_info.basebandCN0DbHz >= 0.0 && sv_info.basebandCN0DbHz <= 65.0);
+ if (sv_info.basebandCN0DbHz > 0.0) {
+ nonZeroCn0Found = true;
+ }
+ }
+ // Assert at least one value is non-zero. Zero is ok in status as it's possibly
+ // reporting a searched but not found satellite.
+ 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);
+}
+
+/*
+ * TestGnssMeasurementCorrections:
+ * If measurement corrections capability is supported, verifies that it supports the
+ * gnss.measurement_corrections@1.1::IMeasurementCorrections interface by invoking a method.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementCorrections) {
+ if (!(gnss_cb_->last_capabilities_ &
+ IGnssCallback_2_1::Capabilities::MEASUREMENT_CORRECTIONS)) {
+ return;
+ }
+
+ // Verify IMeasurementCorrections is supported.
+ auto measurementCorrections = gnss_hal_->getExtensionMeasurementCorrections_1_1();
+ ASSERT_TRUE(measurementCorrections.isOk());
+ sp<IMeasurementCorrections_1_1> iMeasurementCorrections = measurementCorrections;
+ ASSERT_NE(iMeasurementCorrections, nullptr);
+
+ sp<GnssMeasurementCorrectionsCallback> callback = new GnssMeasurementCorrectionsCallback();
+ iMeasurementCorrections->setCallback(callback);
+
+ const int kMeasurementCorrectionsCapabilitiesTimeoutSeconds = 5;
+ callback->capabilities_cbq_.retrieve(callback->last_capabilities_,
+ kMeasurementCorrectionsCapabilitiesTimeoutSeconds);
+ ASSERT_TRUE(callback->capabilities_cbq_.calledCount() > 0);
+
+ // Set a mock MeasurementCorrections.
+ auto result =
+ iMeasurementCorrections->setCorrections_1_1(Utils::getMockMeasurementCorrections_1_1());
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+}
\ No newline at end of file
diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp
index 4ea97fa..577f6ae 100644
--- a/gnss/common/utils/default/Android.bp
+++ b/gnss/common/utils/default/Android.bp
@@ -28,6 +28,10 @@
],
export_include_dirs: ["include"],
shared_libs: [
+ "libhidlbase",
+ "libutils",
"android.hardware.gnss@1.0",
+ "android.hardware.gnss@2.0",
+ "android.hardware.gnss@2.1",
],
}
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index b9a06e8..0cdc865 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -16,6 +16,7 @@
#include <Constants.h>
#include <Utils.h>
+#include <utils/SystemClock.h>
namespace android {
namespace hardware {
@@ -23,31 +24,214 @@
namespace common {
using GnssSvFlags = V1_0::IGnssCallback::GnssSvFlags;
+using GnssMeasurementFlagsV1_0 = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags;
+using GnssMeasurementFlagsV2_1 = V2_1::IGnssMeasurementCallback::GnssMeasurementFlags;
+using GnssMeasurementStateV2_0 = V2_0::IGnssMeasurementCallback::GnssMeasurementState;
+using ElapsedRealtime = V2_0::ElapsedRealtime;
+using ElapsedRealtimeFlags = V2_0::ElapsedRealtimeFlags;
+using GnssConstellationTypeV2_0 = V2_0::GnssConstellationType;
+using IGnssMeasurementCallbackV2_0 = V2_0::IGnssMeasurementCallback;
+using GnssSignalType = V2_1::GnssSignalType;
-GnssLocation Utils::getMockLocation() {
- GnssLocation location = {.gnssLocationFlags = 0xFF,
- .latitudeDegrees = kMockLatitudeDegrees,
- .longitudeDegrees = kMockLongitudeDegrees,
- .altitudeMeters = kMockAltitudeMeters,
- .speedMetersPerSec = kMockSpeedMetersPerSec,
- .bearingDegrees = kMockBearingDegrees,
- .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
- .verticalAccuracyMeters = kMockVerticalAccuracyMeters,
- .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond,
- .bearingAccuracyDegrees = kMockBearingAccuracyDegrees,
- .timestamp = kMockTimestamp};
+GnssDataV2_1 Utils::getMockMeasurementV2_1() {
+ GnssDataV2_0 gnssDataV2_0 = Utils::getMockMeasurementV2_0();
+ V2_1::IGnssMeasurementCallback::GnssMeasurement gnssMeasurementV2_1 = {
+ .v2_0 = gnssDataV2_0.measurements[0],
+ .flags = (uint32_t)(GnssMeasurementFlagsV2_1::HAS_CARRIER_FREQUENCY |
+ GnssMeasurementFlagsV2_1::HAS_CARRIER_PHASE |
+ GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB |
+ GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB_UNCERTAINTY |
+ GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB |
+ GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB_UNCERTAINTY),
+ .receiverInterSignalBiasNs = 10.0,
+ .receiverInterSignalBiasUncertaintyNs = 100.0,
+ .satelliteInterSignalBiasNs = 20.0,
+ .satelliteInterSignalBiasUncertaintyNs = 150.0,
+ .basebandCN0DbHz = 25.0,
+ };
+ GnssSignalType referenceSignalTypeForIsb = {
+ .constellation = GnssConstellationTypeV2_0::GPS,
+ .carrierFrequencyHz = 1.59975e+09,
+ .codeType = "C",
+ };
+ V2_1::IGnssMeasurementCallback::GnssClock gnssClockV2_1 = {
+ .v1_0 = gnssDataV2_0.clock,
+ .referenceSignalTypeForIsb = referenceSignalTypeForIsb,
+ };
+ hidl_vec<V2_1::IGnssMeasurementCallback::GnssMeasurement> measurements(1);
+ measurements[0] = gnssMeasurementV2_1;
+ GnssDataV2_1 gnssDataV2_1 = {
+ .measurements = measurements,
+ .clock = gnssClockV2_1,
+ .elapsedRealtime = gnssDataV2_0.elapsedRealtime,
+ };
+ return gnssDataV2_1;
+}
+
+GnssDataV2_0 Utils::getMockMeasurementV2_0() {
+ V1_0::IGnssMeasurementCallback::GnssMeasurement measurement_1_0 = {
+ .flags = (uint32_t)GnssMeasurementFlagsV1_0::HAS_CARRIER_FREQUENCY,
+ .svid = (int16_t)6,
+ .constellation = V1_0::GnssConstellationType::UNKNOWN,
+ .timeOffsetNs = 0.0,
+ .receivedSvTimeInNs = 8195997131077,
+ .receivedSvTimeUncertaintyInNs = 15,
+ .cN0DbHz = 30.0,
+ .pseudorangeRateMps = -484.13739013671875,
+ .pseudorangeRateUncertaintyMps = 1.0379999876022339,
+ .accumulatedDeltaRangeState = (uint32_t)V1_0::IGnssMeasurementCallback::
+ GnssAccumulatedDeltaRangeState::ADR_STATE_UNKNOWN,
+ .accumulatedDeltaRangeM = 0.0,
+ .accumulatedDeltaRangeUncertaintyM = 0.0,
+ .carrierFrequencyHz = 1.59975e+09,
+ .multipathIndicator =
+ V1_0::IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN};
+ V1_1::IGnssMeasurementCallback::GnssMeasurement measurement_1_1 = {.v1_0 = measurement_1_0};
+ V2_0::IGnssMeasurementCallback::GnssMeasurement measurement_2_0 = {
+ .v1_1 = measurement_1_1,
+ .codeType = "C",
+ .state = GnssMeasurementStateV2_0::STATE_CODE_LOCK |
+ GnssMeasurementStateV2_0::STATE_BIT_SYNC |
+ GnssMeasurementStateV2_0::STATE_SUBFRAME_SYNC |
+ GnssMeasurementStateV2_0::STATE_TOW_DECODED |
+ GnssMeasurementStateV2_0::STATE_GLO_STRING_SYNC |
+ GnssMeasurementStateV2_0::STATE_GLO_TOD_DECODED,
+ .constellation = GnssConstellationTypeV2_0::GLONASS,
+ };
+
+ hidl_vec<IGnssMeasurementCallbackV2_0::GnssMeasurement> measurements(1);
+ measurements[0] = measurement_2_0;
+ V1_0::IGnssMeasurementCallback::GnssClock clock = {.timeNs = 2713545000000,
+ .fullBiasNs = -1226701900521857520,
+ .biasNs = 0.59689998626708984,
+ .biasUncertaintyNs = 47514.989972114563,
+ .driftNsps = -51.757811607455452,
+ .driftUncertaintyNsps = 310.64968328491528,
+ .hwClockDiscontinuityCount = 1};
+
+ ElapsedRealtime timestamp = {
+ .flags = ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
+ ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
+ .timestampNs = static_cast<uint64_t>(::android::elapsedRealtimeNano()),
+ // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
+ // In an actual implementation provide an estimate of the synchronization uncertainty
+ // or don't set the field.
+ .timeUncertaintyNs = 1000000};
+
+ GnssDataV2_0 gnssData = {
+ .measurements = measurements, .clock = clock, .elapsedRealtime = timestamp};
+ return gnssData;
+}
+
+V2_0::GnssLocation Utils::getMockLocationV2_0() {
+ const V2_0::ElapsedRealtime timestamp = {
+ .flags = V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
+ V2_0::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
+ .timestampNs = static_cast<uint64_t>(::android::elapsedRealtimeNano()),
+ // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
+ // In an actual implementation provide an estimate of the synchronization uncertainty
+ // or don't set the field.
+ .timeUncertaintyNs = 1000000};
+
+ V2_0::GnssLocation location = {.v1_0 = Utils::getMockLocationV1_0(),
+ .elapsedRealtime = timestamp};
return location;
}
-GnssSvInfo Utils::getSvInfo(int16_t svid, GnssConstellationType type, float cN0DbHz,
- float elevationDegrees, float azimuthDegrees) {
- GnssSvInfo svInfo = {.svid = svid,
- .constellation = type,
- .cN0Dbhz = cN0DbHz,
- .elevationDegrees = elevationDegrees,
- .azimuthDegrees = azimuthDegrees,
- .svFlag = GnssSvFlags::USED_IN_FIX | GnssSvFlags::HAS_EPHEMERIS_DATA |
- GnssSvFlags::HAS_ALMANAC_DATA};
+V1_0::GnssLocation Utils::getMockLocationV1_0() {
+ V1_0::GnssLocation location = {
+ .gnssLocationFlags = 0xFF,
+ .latitudeDegrees = kMockLatitudeDegrees,
+ .longitudeDegrees = kMockLongitudeDegrees,
+ .altitudeMeters = kMockAltitudeMeters,
+ .speedMetersPerSec = kMockSpeedMetersPerSec,
+ .bearingDegrees = kMockBearingDegrees,
+ .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
+ .verticalAccuracyMeters = kMockVerticalAccuracyMeters,
+ .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond,
+ .bearingAccuracyDegrees = kMockBearingAccuracyDegrees,
+ .timestamp = kMockTimestamp};
+ return location;
+}
+
+hidl_vec<GnssSvInfoV2_1> Utils::getMockSvInfoListV2_1() {
+ GnssSvInfoV1_0 gnssSvInfoV1_0 =
+ Utils::getMockSvInfoV1_0(3, V1_0::GnssConstellationType::GPS, 32.5, 59.1, 166.5);
+ GnssSvInfoV2_0 gnssSvInfoV2_0 =
+ Utils::getMockSvInfoV2_0(gnssSvInfoV1_0, V2_0::GnssConstellationType::GPS);
+ hidl_vec<GnssSvInfoV2_1> gnssSvInfoList = {
+ Utils::getMockSvInfoV2_1(gnssSvInfoV2_0, 27.5),
+ getMockSvInfoV2_1(
+ getMockSvInfoV2_0(getMockSvInfoV1_0(5, V1_0::GnssConstellationType::GPS, 27.0,
+ 29.0, 56.5),
+ V2_0::GnssConstellationType::GPS),
+ 22.0),
+ getMockSvInfoV2_1(
+ getMockSvInfoV2_0(getMockSvInfoV1_0(17, V1_0::GnssConstellationType::GPS, 30.5,
+ 71.0, 77.0),
+ V2_0::GnssConstellationType::GPS),
+ 25.5),
+ getMockSvInfoV2_1(
+ getMockSvInfoV2_0(getMockSvInfoV1_0(26, V1_0::GnssConstellationType::GPS, 24.1,
+ 28.0, 253.0),
+ V2_0::GnssConstellationType::GPS),
+ 19.1),
+ getMockSvInfoV2_1(
+ getMockSvInfoV2_0(getMockSvInfoV1_0(5, V1_0::GnssConstellationType::GLONASS,
+ 20.5, 11.5, 116.0),
+ V2_0::GnssConstellationType::GLONASS),
+ 15.5),
+ getMockSvInfoV2_1(
+ getMockSvInfoV2_0(getMockSvInfoV1_0(17, V1_0::GnssConstellationType::GLONASS,
+ 21.5, 28.5, 186.0),
+ V2_0::GnssConstellationType::GLONASS),
+ 16.5),
+ getMockSvInfoV2_1(
+ getMockSvInfoV2_0(getMockSvInfoV1_0(18, V1_0::GnssConstellationType::GLONASS,
+ 28.3, 38.8, 69.0),
+ V2_0::GnssConstellationType::GLONASS),
+ 25.3),
+ getMockSvInfoV2_1(
+ getMockSvInfoV2_0(getMockSvInfoV1_0(10, V1_0::GnssConstellationType::GLONASS,
+ 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;
+}
+
+GnssSvInfoV2_1 Utils::getMockSvInfoV2_1(GnssSvInfoV2_0 gnssSvInfoV2_0, float basebandCN0DbHz) {
+ GnssSvInfoV2_1 gnssSvInfoV2_1 = {
+ .v2_0 = gnssSvInfoV2_0,
+ .basebandCN0DbHz = basebandCN0DbHz,
+ };
+ return gnssSvInfoV2_1;
+}
+
+GnssSvInfoV2_0 Utils::getMockSvInfoV2_0(GnssSvInfoV1_0 gnssSvInfoV1_0,
+ V2_0::GnssConstellationType type) {
+ GnssSvInfoV2_0 gnssSvInfoV2_0 = {
+ .v1_0 = gnssSvInfoV1_0,
+ .constellation = type,
+ };
+ return gnssSvInfoV2_0;
+}
+
+GnssSvInfoV1_0 Utils::getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationType type,
+ float cN0DbHz, float elevationDegrees,
+ float azimuthDegrees) {
+ GnssSvInfoV1_0 svInfo = {.svid = svid,
+ .constellation = type,
+ .cN0Dbhz = cN0DbHz,
+ .elevationDegrees = elevationDegrees,
+ .azimuthDegrees = azimuthDegrees,
+ .svFlag = GnssSvFlags::USED_IN_FIX | GnssSvFlags::HAS_EPHEMERIS_DATA |
+ GnssSvFlags::HAS_ALMANAC_DATA};
return svInfo;
}
diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h
index 47c8812..e0c61a4 100644
--- a/gnss/common/utils/default/include/Utils.h
+++ b/gnss/common/utils/default/include/Utils.h
@@ -18,20 +18,34 @@
#define android_hardware_gnss_common_default_Utils_H_
#include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <android/hardware/gnss/2.1/IGnss.h>
-using GnssConstellationType = ::android::hardware::gnss::V1_0::GnssConstellationType;
-using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation;
-using GnssSvInfo = ::android::hardware::gnss::V1_0::IGnssCallback::GnssSvInfo;
+using ::android::hardware::hidl_vec;
namespace android {
namespace hardware {
namespace gnss {
namespace common {
+using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData;
+using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData;
+using GnssSvInfoV1_0 = V1_0::IGnssCallback::GnssSvInfo;
+using GnssSvInfoV2_0 = V2_0::IGnssCallback::GnssSvInfo;
+using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo;
+
struct Utils {
- static GnssLocation getMockLocation();
- static GnssSvInfo getSvInfo(int16_t svid, GnssConstellationType type, float cN0DbHz,
- float elevationDegrees, float azimuthDegrees);
+ static GnssDataV2_0 getMockMeasurementV2_0();
+ static GnssDataV2_1 getMockMeasurementV2_1();
+ static V2_0::GnssLocation getMockLocationV2_0();
+ static V1_0::GnssLocation getMockLocationV1_0();
+ static hidl_vec<GnssSvInfoV2_1> getMockSvInfoListV2_1();
+ static GnssSvInfoV2_1 getMockSvInfoV2_1(GnssSvInfoV2_0 gnssSvInfoV2_0, float basebandCN0DbHz);
+ static GnssSvInfoV2_0 getMockSvInfoV2_0(GnssSvInfoV1_0 gnssSvInfoV1_0,
+ V2_0::GnssConstellationType type);
+ static GnssSvInfoV1_0 getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationType type,
+ float cN0DbHz, float elevationDegrees,
+ float azimuthDegrees);
};
} // namespace common
diff --git a/gnss/common/utils/vts/Android.bp b/gnss/common/utils/vts/Android.bp
index 1988171..fd9613b 100644
--- a/gnss/common/utils/vts/Android.bp
+++ b/gnss/common/utils/vts/Android.bp
@@ -30,6 +30,7 @@
shared_libs: [
"android.hardware.gnss@1.0",
"android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss.measurement_corrections@1.1",
],
static_libs: [
"libgtest",
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index 51d3ea1..b6c3f5e 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -92,7 +92,7 @@
EXPECT_GT(location.timestamp, 1.48e12);
}
-const MeasurementCorrections Utils::getMockMeasurementCorrections() {
+const MeasurementCorrections_1_0 Utils::getMockMeasurementCorrections() {
ReflectingPlane reflectingPlane = {
.latitudeDegrees = 37.4220039,
.longitudeDegrees = -122.0840991,
@@ -127,7 +127,7 @@
hidl_vec<SingleSatCorrection> singleSatCorrections = {singleSatCorrection1,
singleSatCorrection2};
- MeasurementCorrections mockCorrections = {
+ MeasurementCorrections_1_0 mockCorrections = {
.latitudeDegrees = 37.4219999,
.longitudeDegrees = -122.0840575,
.altitudeMeters = 30.60062531,
@@ -139,6 +139,18 @@
return mockCorrections;
}
+const MeasurementCorrections_1_1 Utils::getMockMeasurementCorrections_1_1() {
+ MeasurementCorrections_1_0 mockCorrections_1_0 = getMockMeasurementCorrections();
+
+ MeasurementCorrections_1_1 mockCorrections_1_1 = {
+ .v1_0 = mockCorrections_1_0,
+ .hasEnvironmentBearing = true,
+ .environmentBearingDegrees = 45.0,
+ .environmentBearingUncertaintyDegrees = 4.0,
+ };
+ return mockCorrections_1_1;
+}
+
} // namespace common
} // namespace gnss
} // namespace hardware
diff --git a/gnss/common/utils/vts/include/GnssCallbackEventQueue.h b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h
new file mode 100644
index 0000000..3dc429b
--- /dev/null
+++ b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_gnss_common_vts_GnssCallbackEventQueue_H_
+#define android_hardware_gnss_common_vts_GnssCallbackEventQueue_H_
+
+#include <log/log.h>
+
+#include <condition_variable>
+#include <deque>
+#include <list>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+/*
+ * Producer/consumer queue for storing/retrieving callback events from GNSS HAL.
+ */
+template <class T>
+class GnssCallbackEventQueue {
+ public:
+ GnssCallbackEventQueue(const std::string& name) : name_(name), called_count_(0){};
+ ~GnssCallbackEventQueue() { reset(); }
+
+ /* Adds callback event to the end of the queue. */
+ void store(const T& event);
+
+ /*
+ * Removes the callack event at the front of the queue, stores it in event parameter
+ * and returns true. Returns false on timeout and event is not populated.
+ */
+ bool retrieve(T& event, int timeout_seconds);
+
+ /*
+ * Removes parameter count number of callack events at the front of the queue, stores
+ * them in event_list parameter and returns the number of events retrieved. Waits up to
+ * timeout_seconds to retrieve each event. If timeout occurs, it returns the number of
+ * items retrieved which will be less than count.
+ */
+ int retrieve(std::list<T>& event_list, int count, int timeout_seconds);
+
+ /* Returns the number of events pending to be retrieved from the callback event queue. */
+ int size() const;
+
+ /* Returns the number of callback events received since last reset(). */
+ int calledCount() const;
+
+ /* Clears the callback event queue and resets the calledCount() to 0. */
+ void reset();
+
+ private:
+ GnssCallbackEventQueue(const GnssCallbackEventQueue&) = delete;
+ GnssCallbackEventQueue& operator=(const GnssCallbackEventQueue&) = delete;
+
+ std::string name_;
+ int called_count_;
+ mutable std::recursive_mutex mtx_;
+ std::condition_variable_any cv_;
+ std::deque<T> events_;
+};
+
+template <class T>
+void GnssCallbackEventQueue<T>::store(const T& event) {
+ std::unique_lock<std::recursive_mutex> lock(mtx_);
+ events_.push_back(event);
+ ++called_count_;
+ lock.unlock();
+ cv_.notify_all();
+}
+
+template <class T>
+bool GnssCallbackEventQueue<T>::retrieve(T& event, int timeout_seconds) {
+ std::unique_lock<std::recursive_mutex> lock(mtx_);
+ cv_.wait_for(lock, std::chrono::seconds(timeout_seconds), [&] { return !events_.empty(); });
+ if (events_.empty()) {
+ return false;
+ }
+ event = events_.front();
+ events_.pop_front();
+ return true;
+}
+
+template <class T>
+int GnssCallbackEventQueue<T>::retrieve(std::list<T>& event_list, int count, int timeout_seconds) {
+ for (int i = 0; i < count; ++i) {
+ T event;
+ if (!retrieve(event, timeout_seconds)) {
+ return i;
+ }
+ event_list.push_back(event);
+ }
+
+ return count;
+}
+
+template <class T>
+int GnssCallbackEventQueue<T>::size() const {
+ std::unique_lock<std::recursive_mutex> lock(mtx_);
+ return events_.size();
+}
+
+template <class T>
+int GnssCallbackEventQueue<T>::calledCount() const {
+ std::unique_lock<std::recursive_mutex> lock(mtx_);
+ return called_count_;
+}
+
+template <class T>
+void GnssCallbackEventQueue<T>::reset() {
+ std::unique_lock<std::recursive_mutex> lock(mtx_);
+ if (!events_.empty()) {
+ ALOGW("%u unprocessed events discarded in callback queue %s", (unsigned int)events_.size(),
+ name_.c_str());
+ }
+ events_.clear();
+ called_count_ = 0;
+}
+
+} // namespace common
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_common_vts_GnssCallbackEventQueue_H_
diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h
index dce4c7b..781ad42 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -19,10 +19,16 @@
#include <android/hardware/gnss/1.0/IGnss.h>
#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation;
using namespace android::hardware::gnss::measurement_corrections::V1_0;
+using MeasurementCorrections_1_0 =
+ android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
+using MeasurementCorrections_1_1 =
+ android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections;
+
namespace android {
namespace hardware {
namespace gnss {
@@ -31,7 +37,8 @@
struct Utils {
static void checkLocation(const GnssLocation& location, bool check_speed,
bool check_more_accuracies);
- static const MeasurementCorrections getMockMeasurementCorrections();
+ static const MeasurementCorrections_1_0 getMockMeasurementCorrections();
+ static const MeasurementCorrections_1_1 getMockMeasurementCorrections_1_1();
};
} // namespace common
diff --git a/gnss/measurement_corrections/1.1/Android.bp b/gnss/measurement_corrections/1.1/Android.bp
new file mode 100644
index 0000000..1d69f20
--- /dev/null
+++ b/gnss/measurement_corrections/1.1/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.gnss.measurement_corrections@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IMeasurementCorrections.hal",
+ ],
+ interfaces: [
+ "android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/gnss/measurement_corrections/1.1/IMeasurementCorrections.hal b/gnss/measurement_corrections/1.1/IMeasurementCorrections.hal
new file mode 100644
index 0000000..9461a5e
--- /dev/null
+++ b/gnss/measurement_corrections/1.1/IMeasurementCorrections.hal
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss.measurement_corrections@1.1;
+
+import @1.0::IMeasurementCorrections;
+
+/**
+ * Interface for measurement corrections support.
+ */
+interface IMeasurementCorrections extends @1.0::IMeasurementCorrections {
+ /**
+ * Injects measurement corrections to be used by the HAL to improve the GNSS location output.
+ *
+ * These are NOT to be used to adjust the IGnssMeasurementCallback output values -
+ * those remain raw, uncorrected measurements.
+ *
+ * In general, these are injected when conditions defined by the platform are met, such as when
+ * GNSS Location is being requested at a sufficiently high accuracy, based on the capabilities
+ * of the GNSS chipset as reported in the IGnssCallback.
+ *
+ * @param corrections The computed corrections to be used by the HAL.
+ *
+ * @return success Whether the HAL can accept & use these corrections.
+ */
+ setCorrections_1_1(MeasurementCorrections corrections) generates (bool success);
+};
\ No newline at end of file
diff --git a/gnss/measurement_corrections/1.1/types.hal b/gnss/measurement_corrections/1.1/types.hal
new file mode 100644
index 0000000..40b6f52
--- /dev/null
+++ b/gnss/measurement_corrections/1.1/types.hal
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss.measurement_corrections@1.1;
+
+import @1.0::MeasurementCorrections;
+
+/**
+ * A struct containing a set of measurement corrections for all used GNSS satellites at the location
+ * specified by latitudeDegrees, longitudeDegrees, altitudeMeters and at the time of week specified
+ * toaGpsNanosecondsOfWeek
+ */
+struct MeasurementCorrections {
+ @1.0::MeasurementCorrections v1_0;
+
+ /**
+ * Boolean indicating if environment bearing is available.
+ */
+ bool hasEnvironmentBearing;
+
+ /**
+ * Environment bearing in degrees clockwise from true North (0.0 to 360.0], in direction of
+ * user motion. Environment bearing is provided when it is known with high probability that
+ * velocity is aligned with an environment feature, such as a building or road.
+ *
+ * If user speed is zero, environmentBearingDegrees represents bearing of most recent speed
+ * that was > 0.
+ *
+ * As position approaches another road, environmentBearingUncertaintyDegrees will grow, and at
+ * some stage hasEnvironmentBearing = false.
+ *
+ * As position moves towards an open area, environmentBearingUncertaintyDegrees will grow, and
+ * at some stage hasEnvironmentBearing = false.
+ *
+ * If the road is curved in the vicinity of the user location, then
+ * environmentBearingUncertaintyDegrees will include the amount by which the road direction
+ * changes in the area of position uncertainty.
+ */
+ float environmentBearingDegrees;
+
+ /**
+ * Bearing uncertainty [0 to 180].
+ */
+ float environmentBearingUncertaintyDegrees;
+};
\ No newline at end of file
diff --git a/graphics/allocator/4.0/Android.bp b/graphics/allocator/4.0/Android.bp
new file mode 100644
index 0000000..f5f9458
--- /dev/null
+++ b/graphics/allocator/4.0/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.graphics.allocator@4.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "IAllocator.hal",
+ ],
+ interfaces: [
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/graphics/allocator/4.0/IAllocator.hal b/graphics/allocator/4.0/IAllocator.hal
new file mode 100644
index 0000000..7934867
--- /dev/null
+++ b/graphics/allocator/4.0/IAllocator.hal
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.allocator@4.0;
+
+import android.hardware.graphics.mapper@4.0;
+
+interface IAllocator {
+ /**
+ * Allocates buffers with the properties specified by the descriptor.
+ *
+ * Allocations should be optimized for usage bits provided in the
+ * descriptor.
+ *
+ * @param descriptor Properties of the buffers to allocate. This must be
+ * obtained from IMapper::createDescriptor().
+ * @param count The number of buffers to allocate.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_DESCRIPTOR` if the descriptor is invalid.
+ * - `NO_RESOURCES` if the allocation cannot be fulfilled at this time.
+ * - `UNSUPPORTED` if any of the properties encoded in the descriptor
+ * are not supported.
+ * @return stride The number of pixels between two consecutive rows of
+ * an allocated buffer, when the concept of consecutive rows is defined.
+ * Otherwise, it has no meaning.
+ * @return buffers Array of raw handles to the allocated buffers.
+ */
+ allocate(BufferDescriptor descriptor, uint32_t count)
+ generates (Error error,
+ uint32_t stride,
+ vec<handle> buffers);
+};
+
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
new file mode 100644
index 0000000..601cabc
--- /dev/null
+++ b/graphics/common/aidl/Android.bp
@@ -0,0 +1,24 @@
+aidl_interface {
+ name: "android.hardware.graphics.common",
+ host_supported: true,
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ srcs: [
+ "android/hardware/graphics/common/*.aidl",
+ ],
+ stability: "vintf",
+ imports: [
+ "android.hardware.common",
+ ],
+ backend: {
+ java: {
+ enabled: false,
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl b/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl
new file mode 100644
index 0000000..2428135
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Blend modes, settable per layer.
+ */
+@VintfStability
+@Backing(type="int")
+enum BlendMode {
+ INVALID = 0,
+
+ /** colorOut = colorSrc */
+ NONE = 1,
+
+ /** colorOut = colorSrc + colorDst * (1 - alphaSrc) */
+ PREMULTIPLIED = 2,
+
+ /** colorOut = colorSrc * alphaSrc + colorDst * (1 - alphaSrc) */
+ COVERAGE = 3,
+}
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/ChromaSiting.aidl b/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl
new file mode 100644
index 0000000..562a664
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard chroma siting
+ */
+@VintfStability
+@Backing(type="long")
+enum ChromaSiting {
+ /* This format does not have chroma siting. */
+ NONE = 0,
+
+ /* This format has chroma siting but the type being used is unknown. */
+ UNKNOWN = 1,
+
+ /* Cb and Cr are sited interstitially, halfway between alternate luma samples.
+ * This is used by 4:2:0 for JPEG/JFIF, H.261, MPEG-1. */
+ SITED_INTERSTITIAL = 2,
+
+ /* Cb and Cr are horizontally sited coincident with a luma sample.
+ * Cb and Cr are vertically sited interstitially.
+ * This is used by 4:2:0 for MPEG-2 frame pictures. */
+ COSITED_HORIZONTAL = 3,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Compression.aidl b/graphics/common/aidl/android/hardware/graphics/common/Compression.aidl
new file mode 100644
index 0000000..4cca1ba
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Compression.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;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard compression strategies
+ */
+@VintfStability
+@Backing(type="long")
+enum Compression {
+ /* Represents all uncompressed buffers */
+ NONE = 0,
+
+ /* VESA Display Stream Compression (DSC) */
+ DISPLAY_STREAM_COMPRESSION = 1,
+}
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
new file mode 100644
index 0000000..42cdd81
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
@@ -0,0 +1,677 @@
+/**
+ * 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;
+
+@VintfStability
+@Backing(type="int")
+enum Dataspace {
+ /**
+ * Default-assumption data space, when not explicitly specified.
+ *
+ * It is safest to assume the buffer is an image with sRGB primaries and
+ * encoding ranges, but the consumer and/or the producer of the data may
+ * simply be using defaults. No automatic gamma transform should be
+ * expected, except for a possible display gamma transform when drawn to a
+ * screen.
+ */
+ UNKNOWN = 0x0,
+
+ /**
+ * Arbitrary dataspace with manually defined characteristics. Definition
+ * for colorspaces or other meaning must be communicated separately.
+ *
+ * This is used when specifying primaries, transfer characteristics,
+ * etc. separately.
+ *
+ * A typical use case is in video encoding parameters (e.g. for H.264),
+ * where a colorspace can have separately defined primaries, transfer
+ * characteristics, etc.
+ */
+ ARBITRARY = 0x1,
+
+ /**
+ * Color-description aspects
+ *
+ * The following aspects define various characteristics of the color
+ * specification. These represent bitfields, so that a data space value
+ * can specify each of them independently.
+ */
+
+ STANDARD_SHIFT = 16,
+
+ /**
+ * Standard aspect
+ *
+ * Defines the chromaticity coordinates of the source primaries in terms of
+ * the CIE 1931 definition of x and y specified in ISO 11664-1.
+ */
+ STANDARD_MASK = 63 << 16, // 63 << STANDARD_SHIFT = 0x3F
+
+ /**
+ * Chromacity coordinates are unknown or are determined by the application.
+ * Implementations shall use the following suggested standards:
+ *
+ * All YCbCr formats: BT709 if size is 720p or larger (since most video
+ * content is letterboxed this corresponds to width is
+ * 1280 or greater, or height is 720 or greater).
+ * BT601_625 if size is smaller than 720p or is JPEG.
+ * All RGB formats: BT709.
+ *
+ * For all other formats standard is undefined, and implementations should use
+ * an appropriate standard for the data represented.
+ */
+ STANDARD_UNSPECIFIED = 0 << 16, // STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.300 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_BT709 = 1 << 16, // 1 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+ * for RGB conversion from the one purely determined by the primaries
+ * to minimize the color shift into RGB space that uses BT.709
+ * primaries.
+ */
+ STANDARD_BT601_625 = 2 << 16, // 2 << STANDARD_SHIFT,
+
+ /**
+ * Primaries: x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_BT601_625_UNADJUSTED = 3 << 16, // 3 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ *
+ * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+ * for RGB conversion from the one purely determined by the primaries
+ * to minimize the color shift into RGB space that uses BT.709
+ * primaries.
+ */
+ STANDARD_BT601_525 = 4 << 16, // 4 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
+ * for RGB conversion (as in SMPTE 240M).
+ */
+ STANDARD_BT601_525_UNADJUSTED = 5 << 16, // 5 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.170 0.797
+ * blue 0.131 0.046
+ * red 0.708 0.292
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_BT2020 = 6 << 16, // 6 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.170 0.797
+ * blue 0.131 0.046
+ * red 0.708 0.292
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+ * for RGB conversion using the linear domain.
+ */
+ STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16, // 7 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.21 0.71
+ * blue 0.14 0.08
+ * red 0.67 0.33
+ * white (C) 0.310 0.316
+ *
+ * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_BT470M = 8 << 16, // 8 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.243 0.692
+ * blue 0.145 0.049
+ * red 0.681 0.319
+ * white (C) 0.310 0.316
+ *
+ * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_FILM = 9 << 16, // 9 << STANDARD_SHIFT
+
+ /**
+ * SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3)
+ * Primaries: x y
+ * green 0.265 0.690
+ * blue 0.150 0.060
+ * red 0.680 0.320
+ * white (D65) 0.3127 0.3290
+ */
+ STANDARD_DCI_P3 = 10 << 16, // 10 << STANDARD_SHIFT
+
+ /**
+ * Adobe RGB
+ * Primaries: x y
+ * green 0.210 0.710
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ */
+ STANDARD_ADOBE_RGB = 11 << 16, // 11 << STANDARD_SHIFT
+
+ TRANSFER_SHIFT = 22,
+
+ /**
+ * Transfer aspect
+ *
+ * Transfer characteristics are the opto-electronic transfer characteristic
+ * at the source as a function of linear optical intensity (luminance).
+ *
+ * For digital signals, E corresponds to the recorded value. Normally, the
+ * transfer function is applied in RGB space to each of the R, G and B
+ * components independently. This may result in color shift that can be
+ * minized by applying the transfer function in Lab space only for the L
+ * component. Implementation may apply the transfer function in RGB space
+ * for all pixel formats if desired.
+ */
+
+ TRANSFER_MASK = 31 << 22, // 31 << TRANSFER_SHIFT = 0x1F
+
+ /**
+ * Transfer characteristics are unknown or are determined by the
+ * application.
+ *
+ * Implementations should use the following transfer functions:
+ *
+ * For YCbCr formats: use TRANSFER_SMPTE_170M
+ * For RGB formats: use TRANSFER_SRGB
+ *
+ * For all other formats transfer function is undefined, and implementations
+ * should use an appropriate standard for the data represented.
+ */
+ TRANSFER_UNSPECIFIED = 0 << 22, // 0 << TRANSFER_SHIFT
+
+ /**
+ * Transfer characteristic curve:
+ * E = L
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_LINEAR = 1 << 22, // 1 << TRANSFER_SHIFT
+
+ /**
+ * Transfer characteristic curve:
+ *
+ * E = 1.055 * L^(1/2.4) - 0.055 for 0.0031308 <= L <= 1
+ * = 12.92 * L for 0 <= L < 0.0031308
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_SRGB = 2 << 22, // 2 << TRANSFER_SHIFT
+
+ /**
+ * BT.601 525, BT.601 625, BT.709, BT.2020
+ *
+ * Transfer characteristic curve:
+ * E = 1.099 * L ^ 0.45 - 0.099 for 0.018 <= L <= 1
+ * = 4.500 * L for 0 <= L < 0.018
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_SMPTE_170M = 3 << 22, // 3 << TRANSFER_SHIFT
+
+ /**
+ * Assumed display gamma 2.2.
+ *
+ * Transfer characteristic curve:
+ * E = L ^ (1/2.2)
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_GAMMA2_2 = 4 << 22, // 4 << TRANSFER_SHIFT
+
+ /**
+ * display gamma 2.6.
+ *
+ * Transfer characteristic curve:
+ * E = L ^ (1/2.6)
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_GAMMA2_6 = 5 << 22, // 5 << TRANSFER_SHIFT
+
+ /**
+ * display gamma 2.8.
+ *
+ * Transfer characteristic curve:
+ * E = L ^ (1/2.8)
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_GAMMA2_8 = 6 << 22, // 6 << TRANSFER_SHIFT
+
+ /**
+ * SMPTE ST 2084 (Dolby Perceptual Quantizer)
+ *
+ * Transfer characteristic curve:
+ * E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
+ * c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
+ * c2 = 32 * 2413 / 4096 = 18.8515625
+ * c3 = 32 * 2392 / 4096 = 18.6875
+ * m = 128 * 2523 / 4096 = 78.84375
+ * n = 0.25 * 2610 / 4096 = 0.1593017578125
+ * L - luminance of image 0 <= L <= 1 for HDR colorimetry.
+ * L = 1 corresponds to 10000 cd/m2
+ * E - corresponding electrical signal
+ */
+ TRANSFER_ST2084 = 7 << 22, // 7 << TRANSFER_SHIFT
+
+ /**
+ * ARIB STD-B67 Hybrid Log Gamma
+ *
+ * Transfer characteristic curve:
+ * E = r * L^0.5 for 0 <= L <= 1
+ * = a * ln(L - b) + c for 1 < L
+ * a = 0.17883277
+ * b = 0.28466892
+ * c = 0.55991073
+ * r = 0.5
+ * L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
+ * to reference white level of 100 cd/m2
+ * E - corresponding electrical signal
+ */
+ TRANSFER_HLG = 8 << 22, // 8 << TRANSFER_SHIFT
+
+ RANGE_SHIFT = 27,
+
+ /**
+ * Range aspect
+ *
+ * Defines the range of values corresponding to the unit range of 0-1.
+ * This is defined for YCbCr only, but can be expanded to RGB space.
+ */
+ RANGE_MASK = 7 << 27, // 7 << RANGE_SHIFT = 0x7
+
+ /**
+ * Range is unknown or are determined by the application. Implementations
+ * shall use the following suggested ranges:
+ *
+ * All YCbCr formats: limited range.
+ * All RGB or RGBA formats (including RAW and Bayer): full range.
+ * All Y formats: full range
+ *
+ * For all other formats range is undefined, and implementations should use
+ * an appropriate range for the data represented.
+ */
+ RANGE_UNSPECIFIED = 0 << 27, // 0 << RANGE_SHIFT = 0x0
+
+ /**
+ * Full range uses all values for Y, Cb and Cr from
+ * 0 to 2^b-1, where b is the bit depth of the color format.
+ */
+ RANGE_FULL = 1 << 27, // 1 << RANGE_SHIFT = 0x8000000
+
+ /**
+ * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
+ * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of
+ * the color format.
+ *
+ * E.g. For 8-bit-depth formats:
+ * Luma (Y) samples should range from 16 to 235, inclusive
+ * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+ *
+ * For 10-bit-depth formats:
+ * Luma (Y) samples should range from 64 to 940, inclusive
+ * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+ */
+ RANGE_LIMITED = 2 << 27, // 2 << RANGE_SHIFT = 0x10000000
+
+ /**
+ * Extended range is used for scRGB. Intended for use with
+ * floating point pixel formats. [0.0 - 1.0] is the standard
+ * sRGB space. Values outside the range 0.0 - 1.0 can encode
+ * color outside the sRGB gamut.
+ * Used to blend / merge multiple dataspaces on a single display.
+ */
+ RANGE_EXTENDED = 3 << 27, // 3 << RANGE_SHIFT = 0x18000000
+
+ /**
+ * sRGB linear encoding:
+ *
+ * The red, green, and blue components are stored in sRGB space, but
+ * are linear, not gamma-encoded.
+ * The RGB primaries and the white point are the same as BT.709.
+ *
+ * The values are encoded using the full range ([0,255] for 8-bit) for all
+ * components.
+ */
+ SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
+
+
+ /**
+ * scRGB linear encoding:
+ *
+ * The red, green, and blue components are stored in extended sRGB space,
+ * but are linear, not gamma-encoded.
+ * The RGB primaries and the white point are the same as BT.709.
+ *
+ * The values are floating point.
+ * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
+ * Values beyond the range [0.0 - 1.0] would correspond to other colors
+ * spaces and/or HDR content.
+ */
+ SCRGB_LINEAR = 1 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
+
+
+ /**
+ * sRGB gamma encoding:
+ *
+ * The red, green and blue components are stored in sRGB space, and
+ * converted to linear space when read, using the SRGB transfer function
+ * for each of the R, G and B components. When written, the inverse
+ * transformation is performed.
+ *
+ * The alpha component, if present, is always stored in linear space and
+ * is left unmodified when read or written.
+ *
+ * Use full range and BT.709 standard.
+ */
+ SRGB = 1 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
+
+
+ /**
+ * scRGB:
+ *
+ * The red, green, and blue components are stored in extended sRGB space,
+ * but are linear, not gamma-encoded.
+ * The RGB primaries and the white point are the same as BT.709.
+ *
+ * The values are floating point.
+ * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
+ * Values beyond the range [0.0 - 1.0] would correspond to other colors
+ * spaces and/or HDR content.
+ */
+ SCRGB = 1 << 16 | 2 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
+
+ /**
+ * YCbCr Colorspaces
+ * -----------------
+ *
+ * Primaries are given using (x,y) coordinates in the CIE 1931 definition
+ * of x and y specified by ISO 11664-1.
+ *
+ * Transfer characteristics are the opto-electronic transfer characteristic
+ * at the source as a function of linear optical intensity (luminance).
+ */
+
+ /**
+ * JPEG File Interchange Format (JFIF)
+ *
+ * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
+ *
+ * Use full range, SMPTE 170M transfer and BT.601_625 standard.
+ */
+ 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, SMPTE 170M transfer and BT.601_625 standard.
+ */
+ BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+
+ /**
+ * ITU-R Recommendation 601 (BT.601) - 525-line
+ *
+ * Standard-definition television, 525 Lines (NTSC)
+ *
+ * Use limited range, SMPTE 170M transfer and BT.601_525 standard.
+ */
+ 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, SMPTE 170M transfer and BT.709 standard.
+ */
+ BT709 = 1 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+
+ /**
+ * SMPTE EG 432-1 and SMPTE RP 431-2.
+ *
+ * Digital Cinema DCI-P3
+ *
+ * Use full range, linear transfer and D65 DCI-P3 standard
+ */
+ DCI_P3_LINEAR = 10 << 16 | 1 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_LINEAR | RANGE_FULL
+
+
+ /**
+ * SMPTE EG 432-1 and SMPTE RP 431-2.
+ *
+ * Digital Cinema DCI-P3
+ *
+ * Use full range, gamma 2.6 transfer and D65 DCI-P3 standard
+ * Note: Application is responsible for gamma encoding the data as
+ * a 2.6 gamma encoding is not supported in HW.
+ */
+ DCI_P3 = 10 << 16 | 5 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_GAMMA2_6 | RANGE_FULL
+
+
+ /**
+ * Display P3
+ *
+ * Display P3 uses same primaries and white-point as DCI-P3
+ * linear transfer function makes this the same as DCI_P3_LINEAR.
+ */
+ DISPLAY_P3_LINEAR = 10 << 16 | 1 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_LINEAR | RANGE_FULL
+
+
+ /**
+ * Display P3
+ *
+ * Use same primaries and white-point as DCI-P3
+ * but sRGB transfer function.
+ */
+ DISPLAY_P3 = 10 << 16 | 2 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL
+
+
+ /**
+ * Adobe RGB
+ *
+ * Use full range, gamma 2.2 transfer and Adobe RGB primaries
+ * Note: Application is responsible for gamma encoding the data as
+ * a 2.2 gamma encoding is not supported in HW.
+ */
+ ADOBE_RGB = 11 << 16 | 4 << 22 | 1 << 27, // STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2 | RANGE_FULL
+
+
+ /**
+ * ITU-R Recommendation 2020 (BT.2020)
+ *
+ * Ultra High-definition television
+ *
+ * Use full range, linear transfer and BT2020 standard
+ */
+ BT2020_LINEAR = 6 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_LINEAR | RANGE_FULL
+
+
+ /**
+ * ITU-R Recommendation 2020 (BT.2020)
+ *
+ * Ultra High-definition television
+ *
+ * Use full range, SMPTE 170M transfer and BT2020 standard
+ */
+ BT2020 = 6 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL
+
+ /**
+ * ITU-R Recommendation 2020 (BT.2020)
+ *
+ * Ultra High-definition television
+ *
+ * Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard
+ */
+ BT2020_PQ = 6 << 16 | 7 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL
+
+
+ /**
+ * Data spaces for non-color formats
+ */
+
+ /**
+ * The buffer contains depth ranging measurements from a depth camera.
+ * This value is valid with formats:
+ * HAL_PIXEL_FORMAT_Y16: 16-bit samples, consisting of a depth measurement
+ * and an associated confidence value. The 3 MSBs of the sample make
+ * up the confidence value, and the low 13 LSBs of the sample make up
+ * the depth measurement.
+ * For the confidence section, 0 means 100% confidence, 1 means 0%
+ * confidence. The mapping to a linear float confidence value between
+ * 0.f and 1.f can be obtained with
+ * float confidence = (((depthSample >> 13) - 1) & 0x7) / 7.0f;
+ * The depth measurement can be extracted simply with
+ * uint16_t range = (depthSample & 0x1FFF);
+ * HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as
+ * a variable-length float (x,y,z, confidence) coordinate point list.
+ * The point cloud will be represented with the android_depth_points
+ * structure.
+ */
+ DEPTH = 0x1000,
+
+ /**
+ * The buffer contains sensor events from sensor direct report.
+ * This value is valid with formats:
+ * HAL_PIXEL_FORMAT_BLOB: an array of sensor event structure that forms
+ * a lock free queue. Format of sensor event structure is specified
+ * in Sensors HAL.
+ */
+ SENSOR = 0x1001,
+
+ /**
+ * ITU-R Recommendation 2020 (BT.2020)
+ *
+ * Ultra High-definition television
+ *
+ * Use limited range, SMPTE 170M transfer and BT2020 standard
+ */
+ BT2020_ITU = 6 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+ /**
+ * ITU-R Recommendation 2100 (BT.2100)
+ *
+ * High dynamic range television
+ *
+ * Use limited/full range, PQ/HLG transfer, and BT2020 standard
+ * limited range is the preferred / normative definition for BT.2100
+ */
+ BT2020_ITU_PQ = 6 << 16 | 7 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED
+ BT2020_ITU_HLG = 6 << 16 | 8 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED
+ BT2020_HLG = 6 << 16 | 8 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_FULL
+
+ /**
+ * ITU-R Recommendation 2020 (BT.2020)
+ *
+ * Ultra High-definition television
+ *
+ * Use full range, sRGB transfer and BT2020 standard
+ */
+ DISPLAY_BT2020 = 6 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_SRGB | RANGE_FULL
+
+ /**
+ * ISO 16684-1:2011(E)
+ *
+ * Embedded depth metadata following the dynamic depth specification.
+ */
+ DYNAMIC_DEPTH = 0x1002,
+
+ /**
+ * JPEG APP segments format as specified by JEIDA spec
+ *
+ * The buffer must only contain APP1 (Application Marker) segment followed
+ * by zero or more APPn segments, as is specified by JEITA CP-3451C section 4.5.4.
+ * The APP1 segment optionally contains a thumbnail. The buffer will not
+ * contain main compressed image.
+ *
+ * This value is valid with formats:
+ * HAL_PIXEL_FORMAT_BLOB: JPEG APP segments optionally containing thumbnail image
+ * in APP1. BLOB buffer with this dataspace is output by HAL, and used by
+ * camera framework to encode into a HEIC image.
+ */
+ JPEG_APP_SEGMENTS = 0x1003,
+
+ /**
+ * ISO/IEC 23008-12
+ *
+ * High Efficiency Image File Format (HEIF)
+ *
+ * This value is valid with formats:
+ * HAL_PIXEL_FORMAT_BLOB: A HEIC image encoded by HEIC or HEVC encoder
+ * 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/ExtendableType.aidl b/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl
new file mode 100644
index 0000000..495693c
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl
@@ -0,0 +1,52 @@
+/**
+ * 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;
+
+/**
+ * This struct is used for types that are commonly extended by vendors. For example, buffer
+ * compression is typically SoC specific. It is not possible for Android to define every possible
+ * proprietary vendor compression strategy. Instead, compression is represented using this
+ * ExtendableType that can support standard compression strategies while still allowing
+ * every vendor to easily add their own non-standard definitions.
+ */
+@VintfStability
+parcelable ExtendableType {
+ /**
+ * Name of the stable aidl interface whose value is stored in this structure.
+ *
+ * For standard types, the "name" field will be set to the stable aidl name of the type such as
+ * "android.hardware.graphics.common.Compression".
+ *
+ * For custom vendor types, the "name" field will be set to the name of the custom
+ * @VendorStability vendor AIDL interface such as
+ * "vendor.mycompanyname.graphics.common.Compression". The name of the vendor extension should
+ * contain the name of the owner of the extension. Including the company
+ * name in the "name" field prevents type collisions between different vendors.
+ */
+ @utf8InCpp String name;
+
+ /**
+ * Enum value of the from the stable aidl interface
+ *
+ * For standard types, the "value" field will be set to an enum value from that stable aidl
+ * type such as "NONE".
+ *
+ * For vendor types, the "value" field should be set to the enum value from the custom
+ * @VendorStability vendor AIDL interface extended type such as "MY_COMPRESSION_TYPE1".
+ */
+ long value = 0;
+}
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/Interlaced.aidl b/graphics/common/aidl/android/hardware/graphics/common/Interlaced.aidl
new file mode 100644
index 0000000..a3f1baa
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Interlaced.aidl
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard interlaced strategies
+ */
+@VintfStability
+@Backing(type="long")
+enum Interlaced {
+ /* The buffer is not interlaced. */
+ NONE = 0,
+
+ /* The buffer's planes are interlaced horizontally. The height of each interlaced plane is
+ * 1/2 the height of the buffer's height. */
+ TOP_BOTTOM = 1,
+
+ /* The buffer's planes are interlaced vertically. The width of each interlaced plane is
+ * 1/2 the width of the buffer's width. */
+ RIGHT_LEFT = 2,
+}
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/PlaneLayout.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
new file mode 100644
index 0000000..168028d
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
@@ -0,0 +1,125 @@
+/**
+ * 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.PlaneLayoutComponent;
+import android.hardware.graphics.common.Rect;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe the plane layout of a buffer.
+ *
+ * PlaneLayout uses the following definitions:
+ *
+ * - Component - a component is one channel of a pixel. For example, an RGBA format has
+ * four components: R, G, B and A.
+ * - Sample - a sample is comprised of all the components in a given plane. For example,
+ * a buffer with one Y plane and one CbCr plane has one plane with a sample of Y
+ * and one plane with a sample of CbCr.
+ * - Pixel - a pixel is comprised of all the (non-metadata/raw) components in buffer across
+ * all planes. For example, a buffer with a plane of Y and a plane of CbCr has a pixel
+ * of YCbCr.
+ */
+
+@VintfStability
+parcelable PlaneLayout {
+ /**
+ * An list of plane layout components. This list of components should include
+ * every component in this plane. For example, a CbCr plane should return a
+ * vector of size two with one PlaneLayoutComponent for Cb and one for Cr.
+ */
+ PlaneLayoutComponent[] components;
+
+ /**
+ * Offset to the first byte of the plane (in bytes), from the start of the allocation.
+ */
+ long offsetInBytes;
+
+ /**
+ * Bits per sample increment (aka column increment): describes the distance
+ * in bits from one sample to the next sample (to the right) on the same row for the
+ * the component plane.
+ *
+ * The default value is 0. Return the default value if the increment is undefined, unknown,
+ * or variable.
+ *
+ * This can be negative. A negative increment indicates that the samples are read from
+ * right to left.
+ */
+ long sampleIncrementInBits;
+
+ /**
+ * Horizontal stride: number of bytes between two vertically adjacent
+ * samples in given plane. This can be mathematically described by:
+ *
+ * strideInBytes = ALIGN(widthInSamples * bps / 8, alignment)
+ *
+ * where,
+ *
+ * bps: average bits per sample
+ * alignment (in bytes): dependent upon pixel format and usage
+ *
+ * strideInBytes can contain additional padding beyond the widthInSamples.
+ *
+ * The default value is 0. Return the default value if the stride is undefined, unknown,
+ * or variable.
+ *
+ * This can be negative. A negative stride indicates that the rows are read from
+ * bottom to top.
+ */
+ long strideInBytes;
+
+ /**
+ * Dimensions of plane (in samples).
+ *
+ * This is the number of samples in the plane, even if subsampled.
+ *
+ * See 'strideInBytes' for relationship between strideInBytes and widthInSamples.
+ */
+ long widthInSamples;
+ long heightInSamples;
+
+ /**
+ * Can be used to get the total size in bytes of any memory used by the plane
+ * including extra padding. This should not include any extra metadata used to describe the
+ * plane.
+ */
+ long totalSizeInBytes;
+
+ /**
+ * Horizontal and vertical subsampling. Must be a positive power of 2.
+ *
+ * These fields indicate the number of horizontally or vertically adjacent pixels that use
+ * the same pixel data. A value of 1 indicates no subsampling.
+ */
+ long horizontalSubsampling;
+ long verticalSubsampling;
+
+ /**
+ * Some buffer producers require extra padding to their output buffer; therefore the
+ * physical size of the native buffer will be larger than its logical size.
+ * The crop rectangle determines the offset and logical size of the buffer that should be
+ * read by consumers.
+ *
+ * The crop rectangle is measured in samples and is relative to the offset of the
+ * plane. Valid crop rectangles are within the boundaries of the plane:
+ * [0, 0, widthInSamples, heightInSamples].
+ *
+ * The default crop rectangle is a rectangle the same size as the plane:
+ * [0, 0, widthInSamples, heightInSamples].
+ */
+ Rect crop;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl
new file mode 100644
index 0000000..3fca53b
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl
@@ -0,0 +1,67 @@
+/**
+ * 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.ExtendableType;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe the type and location of a component in a
+ * buffer's plane.
+ *
+ * PlaneLayoutComponent uses the following definitions:
+ *
+ * - Component - a component is one channel of a pixel. For example, an RGBA format has
+ * four components: R, G, B and A.
+ * - Sample - a sample is comprised of all the components in a given plane. For example,
+ * a buffer with one Y plane and one CbCr plane has one plane with a sample of Y
+ * and one plane with a sample of CbCr.
+ * - Pixel - a pixel is comprised of all the (non-metadata/raw) components in buffer across
+ * all planes. For example, a buffer with a plane of Y and a plane of CbCr has a pixel
+ * of YCbCr.
+ */
+
+@VintfStability
+parcelable PlaneLayoutComponent {
+ /**
+ * The type of this plane layout component.
+ *
+ * android.hardware.graphics.common.PlaneLayoutComponent defines the standard
+ * plane layout component types. Vendors may extend this type to include any
+ * non-standard plane layout component types. For instructions on how to
+ * create a vendor extension, refer to ExtendableType.aidl.
+ */
+ ExtendableType type;
+
+ /**
+ * Offset in bits to the first instance of this component in the plane.
+ * This is relative to the plane's offset (PlaneLayout::offset).
+ *
+ * If the offset cannot be described using a int64_t, this should be set to -1.
+ * For example, if the plane is compressed and the offset is not defined or
+ * relevant, return -1.
+ */
+ long offsetInBits;
+
+ /**
+ * The number of bits used per component in the plane.
+ *
+ * If the plane layout component cannot be described using componentSizeInBits, this
+ * should be set to -1. For example, if the component varies in size throughout
+ * the plane, return -1.
+ */
+ long sizeInBits;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
new file mode 100644
index 0000000..18c4a2e
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard plane layout component types
+ *
+ * The enum values have been taken directly from gralloc1's android_flex_component for compatiblity
+ * reasons. However, unlike gralloc1's android_flex_component, this field is NOT a bit field.
+ * A plane's components should NOT be expressed by bitwise OR-ing different
+ * PlaneLayoutComponentTypes together.
+ */
+@VintfStability
+@Backing(type="long")
+enum PlaneLayoutComponentType {
+ /* Luma */
+ Y = 1 << 0,
+ /* Chroma blue */
+ CB = 1 << 1,
+ /* Chroma red */
+ CR = 1 << 2,
+
+ /* Red */
+ R = 1 << 10,
+ /* Green */
+ G = 1 << 11,
+ /* Blue */
+ B = 1 << 12,
+
+ /* Alpha */
+ A = 1 << 30,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl b/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
new file mode 100644
index 0000000..1a3bc11
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
@@ -0,0 +1,29 @@
+/**
+ * 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;
+
+/**
+ * General purpose definition of a rectangle.
+ */
+
+@VintfStability
+parcelable Rect {
+ int left;
+ int top;
+ int right;
+ int bottom;
+}
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
new file mode 100644
index 0000000..7b46688
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -0,0 +1,330 @@
+/**
+ * Copyright (c) 2019,libgralloctypes_helper The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard metadata types.
+ *
+ * This is an enum that defines the common types of gralloc 4 buffer metadata. The comments for
+ * each enum include a description of the metadata that is associated with the type.
+ *
+ * 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")
+enum StandardMetadataType {
+ INVALID = 0,
+
+ /**
+ * Can be used to get the random ID of the buffer. This ID should be psuedorandom with
+ * sufficient entropy.
+ *
+ * This ID should only be used for debugging purposes. It cannot be used as a basis for any
+ * control flows.
+ *
+ * The buffer ID is determined at allocation time and should not change during the lifetime
+ * of the buffer.
+ *
+ * The buffer ID is a uint64_t.
+ *
+ * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+ */
+ BUFFER_ID = 1,
+
+ /**
+ * Can be used to get the name passed in by the client at allocation time in the
+ * BufferDescriptorInfo.
+ *
+ * The buffer name is determined at allocation time and should not change during the lifetime
+ * of the buffer.
+ *
+ * The buffer name is a string.
+ *
+ * When it is encoded into a byte stream, the length of the string is written using 8 bytes in
+ * little endian. It is followed by a char array of the string's
+ * characters. The array is not null-terminated.
+ */
+ NAME = 2,
+
+ /**
+ * Can be used to get the number of elements per buffer row requested at allocation time in
+ * the BufferDescriptorInfo.
+ *
+ * The width is determined at allocation time and should not change during the lifetime
+ * of the buffer.
+ *
+ * The width is a uint64_t.
+ *
+ * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+ */
+ WIDTH = 3,
+
+ /**
+ * Can be used to get the number of elements per buffer column requested at allocation time in
+ * the BufferDescriptorInfo.
+ *
+ * The height is determined at allocation time and should not change during the lifetime
+ * of the buffer.
+ *
+ * The height is a uint64_t.
+ *
+ * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+ */
+ HEIGHT = 4,
+
+ /**
+ * Can be used to get the number of layers requested at allocation time in the
+ * BufferDescriptorInfo.
+ *
+ * The layer count is determined at allocation time and should not change during the lifetime
+ * of the buffer.
+ *
+ * The layer count is a uint64_t.
+ *
+ * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+ */
+ LAYER_COUNT = 5,
+
+ /**
+ * Can be used to get the buffer format requested at allocation time in the
+ * BufferDescriptorInfo.
+ *
+ * The requested pixel format is determined at allocation time and should not change during
+ * the lifetime of the buffer.
+ *
+ * The requested pixel format is a android.hardware.graphics.common@1.2::PixelFormat.
+ *
+ * When it is encoded into a byte stream, it is first cast to a int32_t and then represented in
+ * the byte stream by 4 bytes written in little endian.
+ */
+ PIXEL_FORMAT_REQUESTED = 6,
+
+ /**
+ * Can be used to get the fourcc code for the format. Fourcc codes are standard across all
+ * devices of the same kernel version. Fourcc codes must follow the Linux definition of a
+ * fourcc format found in: include/uapi/drm/drm_fourcc.h.
+ *
+ * The pixel format fourcc code is represented by a uint32_t.
+ *
+ * When it is encoded into a byte stream, it is represented by 4 bytes written in little endian.
+ */
+ PIXEL_FORMAT_FOURCC = 7,
+
+ /**
+ * Can be used to get the modifier for the format. Together fourcc and modifier describe the
+ * real pixel format. Each fourcc and modifier pair is unique and must fully define the format
+ * and layout of the buffer. Modifiers can change any property of the buffer. Modifiers must
+ * follow the Linux definition of a modifier found in: include/uapi/drm/drm_fourcc.h.
+ *
+ * The pixel format modifier is represented by a uint64_t.
+ *
+ * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+ */
+ PIXEL_FORMAT_MODIFIER = 8,
+
+ /**
+ * Can be used to get the usage requested at allocation time in the BufferDescriptorInfo.
+ *
+ * The usage is determined at allocation time and should not change during the lifetime
+ * of the buffer.
+ *
+ * The usage is a uint64_t bit field of android.hardware.graphics.common@1.2::BufferUsage's.
+ *
+ * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+ */
+ USAGE = 9,
+
+ /**
+ * Can be used to get the total size in bytes of any memory used by the buffer including its
+ * metadata and extra padding. This is the total number of bytes used by the buffer allocation.
+ *
+ * The allocation size is a uint64_t.
+ *
+ * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+ */
+ ALLOCATION_SIZE = 10,
+
+ /**
+ * Can be used to get if a buffer has protected content. If the buffer does not have protected
+ * content, this should return 0. If a buffer has protected content, this should return 1.
+ *
+ * In future versions, this field will be extended to expose more information about the type
+ * of protected content in the buffer.
+ *
+ * The protected content is a uint64_t.
+ *
+ * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+ */
+ PROTECTED_CONTENT = 11,
+
+ /**
+ * Can be used to get the compression strategy of the buffer. If the device has more than one
+ * compression strategy, it should have different unique values for each compression
+ * strategy.
+ *
+ * Compression is a stable aidl android.hardware.graphics.common.ExtendableType.
+ *
+ * android.hardware.graphics.common.Compression defines the standard compression
+ * strategies. Vendors may extend this type to include any compression strategies.
+ *
+ * When it is encoded into a byte stream, the length of the name field string is written using
+ * 8 bytes in little endian. It is followed by a char array of the string's
+ * characters. The array is not null-terminated. Finally the value field is written as 8 bytes
+ * in little endian.
+ */
+ COMPRESSION = 12,
+
+ /**
+ * Can be used to get how the buffer's planes are interlaced.
+ *
+ * Interlaced is a stable aidl android.hardware.graphics.common.ExtendableType.
+ *
+ * android.hardware.graphics.common.Interlaced defines the standard interlaced
+ * strategies. Vendors may extend this type to include any non-standard interlaced
+ * strategies.
+ *
+ * When it is encoded into a byte stream, the length of the name field string is written using
+ * 8 bytes in little endian. It is followed by a char array of the string's
+ * characters. The array is not null-terminated. Finally the value field is written as 8 bytes
+ * in little endian.
+ */
+ INTERLACED = 13,
+
+ /**
+ * Can be used to get the chroma siting of a buffer.
+ *
+ * Chroma siting is a stable aidl android.hardware.graphics.common.ExtendableType.
+ *
+ * android.hardware.graphics.common.ChromaSiting defines the standard chroma
+ * sitings. Vendors may extend this type to include any non-standard chroma sitings.
+ *
+ * When it is encoded into a byte stream, the length of the name field string is written using
+ * 8 bytes in little endian. It is followed by a char array of the string's
+ * characters. The array is not null-terminated. Finally the value field is written as 8 bytes
+ * in little endian.
+ */
+ CHROMA_SITING = 14,
+
+ /**
+ * Can be used to get the PlaneLayout(s) of the buffer. There should be one PlaneLayout per
+ * plane in the buffer. For example if the buffer only has one plane, only one PlaneLayout
+ * should be returned.
+ *
+ * If the buffer has planes interlaced through time, the returned PlaneLayout structs should be
+ * ordered by time. The nth PlaneLayout should be from the same time or earlier than the
+ * n+1 PlaneLayout.
+ *
+ * The plane layout is a list of stable aidl android.hardware.graphics.common.PlaneLayout's.
+ *
+ * When it is encoded into a byte stream, the total number of PlaneLayouts is written using
+ * 8 bytes in little endian. It is followed by each PlaneLayout.
+ *
+ * To encode a PlaneLayout, write the length of its PlaneLayoutComponent[] components
+ * field as 8 bytes in little endian and then encode each of its components. Finally, write the
+ * following fields in this order each as 8 bytes in little endian: offsetInBytes,
+ * sampleIncrementInBits, strideInBytes, widthInSamples, totalSizeInBytes,
+ * horizontalSubsampling, verticalSubsampling.
+ *
+ * To encode a PlaneLayoutComponent, encode its PlaneLayoutComponentType type field. Next
+ * encode offsetInBits followed by sizeInBits each as 8 bytes in little endian.
+ *
+ * To encode a PlaneLayoutComponentType, write the length of the name field string as
+ * 8 bytes in little endian. It is followed by a char array of the string's
+ * characters. The array is not null-terminated. Finally the value field is written as 8 bytes
+ * in little endian.
+ */
+ PLANE_LAYOUTS = 15,
+
+ /**
+ * Can be used to get or set the dataspace of the buffer. The framework may attempt to set
+ * this value.
+ *
+ * The default dataspace is Dataspace::UNKNOWN. If this dataspace is set to any valid value
+ * other than Dataspace::UNKNOWN, this dataspace overrides all other dataspaces. For example,
+ * if the buffer has Dataspace::DISPLAY_P3 and it is being displayed on a composer Layer that
+ * is Dataspace::sRGB, the buffer should be treated as a DISPLAY_P3 buffer.
+ *
+ * The dataspace is a stable aidl android.hardware.graphics.common.Dataspace.
+ *
+ * When it is encoded into a byte stream, it is first cast to a int32_t and then represented in
+ * the byte stream by 4 bytes written in little endian.
+ */
+ DATASPACE = 16,
+
+ /**
+ * Can be used to get or set the BlendMode. The framework may attempt to set this value.
+ *
+ * The default blend mode is INVALID. If the BlendMode is set to any
+ * valid value other than INVALID, this BlendMode overrides all other
+ * blend modes. For a longer description of this behavior see MetadataType::DATASPACE.
+ *
+ * The blend mode is a stable aidl android.hardware.graphics.common.BlendMode.
+ *
+ * When it is encoded into a byte stream, it is first cast to a int32_t and then represented by
+ * 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/default/Android.bp b/graphics/composer/2.1/default/Android.bp
index 6157719..533687b 100644
--- a/graphics/composer/2.1/default/Android.bp
+++ b/graphics/composer/2.1/default/Android.bp
@@ -9,8 +9,7 @@
],
shared_libs: [
"android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.composer@2.1-resources",
"libbase",
"libcutils",
"libfmq",
diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
index ebac2e0..499d3b9 100644
--- a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
+++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
@@ -403,6 +403,11 @@
}
protected:
+ template <typename T>
+ void beginCommand(T command, uint16_t length) {
+ beginCommandBase(static_cast<IComposerClient::Command>(command), length);
+ }
+
void setClientTargetInternal(uint32_t slot, const native_handle_t* target, int acquireFence,
int32_t dataspace,
const std::vector<IComposerClient::Rect>& damage) {
@@ -429,7 +434,7 @@
endCommand();
}
- void beginCommand(IComposerClient::Command command, uint16_t length) {
+ void beginCommandBase(IComposerClient::Command command, uint16_t length) {
if (mCommandEnd) {
LOG_FATAL("endCommand was not called before command 0x%x", command);
}
@@ -621,9 +626,15 @@
}
protected:
+ template <typename T>
+ bool beginCommand(T* outCommand, uint16_t* outLength) {
+ return beginCommandBase(reinterpret_cast<IComposerClient::Command*>(outCommand),
+ outLength);
+ }
+
bool isEmpty() const { return (mDataRead >= mDataSize); }
- bool beginCommand(IComposerClient::Command* outCommand, uint16_t* outLength) {
+ bool beginCommandBase(IComposerClient::Command* outCommand, uint16_t* outLength) {
if (mCommandEnd) {
LOG_FATAL("endCommand was not called for last command");
}
diff --git a/graphics/composer/2.1/utils/hal/Android.bp b/graphics/composer/2.1/utils/hal/Android.bp
index 7a501fc..ea3666d 100644
--- a/graphics/composer/2.1/utils/hal/Android.bp
+++ b/graphics/composer/2.1/utils/hal/Android.bp
@@ -19,14 +19,12 @@
vendor_available: true,
shared_libs: [
"android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.composer@2.1-resources",
"libhardware", // TODO remove hwcomposer2.h dependency
],
export_shared_lib_headers: [
"android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.composer@2.1-resources",
"libhardware",
],
header_libs: [
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h
index 90d9b98..4b8c6bb 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h
@@ -67,6 +67,14 @@
}
}
+ // we do not have HWC2_CAPABILITY_SKIP_VALIDATE defined in
+ // IComposer::Capability. However, this is defined in hwcomposer2.h,
+ // so if the device returns it, add it manually to be returned to the
+ // client
+ if (mHal->hasCapability(HWC2_CAPABILITY_SKIP_VALIDATE)) {
+ caps.push_back(static_cast<IComposer::Capability>(HWC2_CAPABILITY_SKIP_VALIDATE));
+ }
+
hidl_vec<IComposer::Capability> caps_reply;
caps_reply.setToExternal(caps.data(), caps.size());
hidl_cb(caps_reply);
@@ -80,8 +88,7 @@
Return<void> createClient(IComposer::createClient_cb hidl_cb) override {
std::unique_lock<std::mutex> lock(mClientMutex);
- bool destroyed = waitForClientDestroyedLocked(lock);
- if (!destroyed) {
+ if (!waitForClientDestroyedLocked(lock)) {
hidl_cb(Error::NO_RESOURCES, nullptr);
return Void();
}
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
index 095189f..47ead41 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
@@ -27,7 +27,7 @@
#include <android/hardware/graphics/composer/2.1/IComposerClient.h>
#include <composer-hal/2.1/ComposerCommandEngine.h>
#include <composer-hal/2.1/ComposerHal.h>
-#include <composer-hal/2.1/ComposerResources.h>
+#include <composer-resources/2.1/ComposerResources.h>
#include <log/log.h>
namespace android {
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
index d87110a..ab67eb1 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
@@ -24,7 +24,7 @@
#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
#include <composer-hal/2.1/ComposerHal.h>
-#include <composer-hal/2.1/ComposerResources.h>
+#include <composer-resources/2.1/ComposerResources.h>
// TODO remove hwcomposer_defs.h dependency
#include <hardware/hwcomposer_defs.h>
#include <log/log.h>
@@ -39,8 +39,10 @@
// TODO own a CommandReaderBase rather than subclassing
class ComposerCommandEngine : protected CommandReaderBase {
public:
- ComposerCommandEngine(ComposerHal* hal, ComposerResources* resources)
- : mHal(hal), mResources(resources) {}
+ ComposerCommandEngine(ComposerHal* hal, ComposerResources* resources)
+ : mHal(hal), mResources(resources) {
+ mWriter = createCommandWriter(kWriterInitialSize);
+ }
virtual ~ComposerCommandEngine() = default;
@@ -74,16 +76,16 @@
return Error::BAD_PARAMETER;
}
- return mWriter.writeQueue(outQueueChanged, outCommandLength, outCommandHandles)
- ? Error::NONE
- : Error::NO_RESOURCES;
+ return mWriter->writeQueue(outQueueChanged, outCommandLength, outCommandHandles)
+ ? Error::NONE
+ : Error::NO_RESOURCES;
}
- const MQDescriptorSync<uint32_t>* getOutputMQDescriptor() { return mWriter.getMQDescriptor(); }
+ const MQDescriptorSync<uint32_t>* getOutputMQDescriptor() { return mWriter->getMQDescriptor(); }
void reset() {
CommandReaderBase::reset();
- mWriter.reset();
+ mWriter->reset();
}
protected:
@@ -140,13 +142,36 @@
}
}
+ virtual std::unique_ptr<CommandWriterBase> createCommandWriter(size_t writerInitialSize) {
+ return std::make_unique<CommandWriterBase>(writerInitialSize);
+ }
+
+ virtual Error executeValidateDisplayInternal() {
+ std::vector<Layer> changedLayers;
+ std::vector<IComposerClient::Composition> compositionTypes;
+ uint32_t displayRequestMask = 0x0;
+ std::vector<Layer> requestedLayers;
+ std::vector<uint32_t> requestMasks;
+
+ auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes,
+ &displayRequestMask, &requestedLayers, &requestMasks);
+ mResources->setDisplayMustValidateState(mCurrentDisplay, false);
+ if (err == Error::NONE) {
+ mWriter->setChangedCompositionTypes(changedLayers, compositionTypes);
+ mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
+ } else {
+ mWriter->setError(getCommandLoc(), err);
+ }
+ return err;
+ }
+
bool executeSelectDisplay(uint16_t length) {
if (length != CommandWriterBase::kSelectDisplayLength) {
return false;
}
mCurrentDisplay = read64();
- mWriter.selectDisplay(mCurrentDisplay);
+ mWriter->selectDisplay(mCurrentDisplay);
return true;
}
@@ -174,7 +199,7 @@
auto err = mHal->setColorTransform(mCurrentDisplay, matrix, transform);
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -195,7 +220,7 @@
bool closeFence = true;
const native_handle_t* clientTarget;
- ComposerResources::ReplacedBufferHandle replacedClientTarget;
+ ComposerResources::ReplacedHandle replacedClientTarget(true);
auto err = mResources->getDisplayClientTarget(mCurrentDisplay, slot, useCache, rawHandle,
&clientTarget, &replacedClientTarget);
if (err == Error::NONE) {
@@ -208,7 +233,7 @@
close(fence);
}
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -226,7 +251,7 @@
bool closeFence = true;
const native_handle_t* outputBuffer;
- ComposerResources::ReplacedBufferHandle replacedOutputBuffer;
+ ComposerResources::ReplacedHandle replacedOutputBuffer(true);
auto err = mResources->getDisplayOutputBuffer(mCurrentDisplay, slot, useCache, rawhandle,
&outputBuffer, &replacedOutputBuffer);
if (err == Error::NONE) {
@@ -239,7 +264,7 @@
close(fence);
}
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -249,23 +274,7 @@
if (length != CommandWriterBase::kValidateDisplayLength) {
return false;
}
-
- std::vector<Layer> changedLayers;
- std::vector<IComposerClient::Composition> compositionTypes;
- uint32_t displayRequestMask = 0x0;
- std::vector<Layer> requestedLayers;
- std::vector<uint32_t> requestMasks;
-
- auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes,
- &displayRequestMask, &requestedLayers, &requestMasks);
- mResources->setDisplayMustValidateState(mCurrentDisplay, false);
- if (err == Error::NONE) {
- mWriter.setChangedCompositionTypes(changedLayers, compositionTypes);
- mWriter.setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
- } else {
- mWriter.setError(getCommandLoc(), err);
- }
-
+ executeValidateDisplayInternal();
return true;
}
@@ -283,29 +292,17 @@
? Error::NOT_VALIDATED
: mHal->presentDisplay(mCurrentDisplay, &presentFence, &layers, &fences);
if (err == Error::NONE) {
- mWriter.setPresentOrValidateResult(1);
- mWriter.setPresentFence(presentFence);
- mWriter.setReleaseFences(layers, fences);
+ mWriter->setPresentOrValidateResult(1);
+ mWriter->setPresentFence(presentFence);
+ mWriter->setReleaseFences(layers, fences);
return true;
}
}
// Present has failed. We need to fallback to validate
- std::vector<Layer> changedLayers;
- std::vector<IComposerClient::Composition> compositionTypes;
- uint32_t displayRequestMask = 0x0;
- std::vector<Layer> requestedLayers;
- std::vector<uint32_t> requestMasks;
-
- auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes,
- &displayRequestMask, &requestedLayers, &requestMasks);
- mResources->setDisplayMustValidateState(mCurrentDisplay, false);
+ auto err = executeValidateDisplayInternal();
if (err == Error::NONE) {
- mWriter.setPresentOrValidateResult(0);
- mWriter.setChangedCompositionTypes(changedLayers, compositionTypes);
- mWriter.setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
- } else {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setPresentOrValidateResult(0);
}
return true;
@@ -318,7 +315,7 @@
auto err = mHal->acceptDisplayChanges(mCurrentDisplay);
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -334,10 +331,10 @@
std::vector<int> fences;
auto err = mHal->presentDisplay(mCurrentDisplay, &presentFence, &layers, &fences);
if (err == Error::NONE) {
- mWriter.setPresentFence(presentFence);
- mWriter.setReleaseFences(layers, fences);
+ mWriter->setPresentFence(presentFence);
+ mWriter->setReleaseFences(layers, fences);
} else {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -351,7 +348,7 @@
auto err = mHal->setLayerCursorPosition(mCurrentDisplay, mCurrentLayer, readSigned(),
readSigned());
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -369,7 +366,7 @@
bool closeFence = true;
const native_handle_t* buffer;
- ComposerResources::ReplacedBufferHandle replacedBuffer;
+ ComposerResources::ReplacedHandle replacedBuffer(true);
auto err = mResources->getLayerBuffer(mCurrentDisplay, mCurrentLayer, slot, useCache,
rawHandle, &buffer, &replacedBuffer);
if (err == Error::NONE) {
@@ -382,7 +379,7 @@
close(fence);
}
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -397,7 +394,7 @@
auto damage = readRegion(length / 4);
auto err = mHal->setLayerSurfaceDamage(mCurrentDisplay, mCurrentLayer, damage);
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -410,7 +407,7 @@
auto err = mHal->setLayerBlendMode(mCurrentDisplay, mCurrentLayer, readSigned());
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -423,7 +420,7 @@
auto err = mHal->setLayerColor(mCurrentDisplay, mCurrentLayer, readColor());
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -436,7 +433,7 @@
auto err = mHal->setLayerCompositionType(mCurrentDisplay, mCurrentLayer, readSigned());
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -449,7 +446,7 @@
auto err = mHal->setLayerDataspace(mCurrentDisplay, mCurrentLayer, readSigned());
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -462,7 +459,7 @@
auto err = mHal->setLayerDisplayFrame(mCurrentDisplay, mCurrentLayer, readRect());
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -475,7 +472,7 @@
auto err = mHal->setLayerPlaneAlpha(mCurrentDisplay, mCurrentLayer, readFloat());
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -489,14 +486,14 @@
auto rawHandle = readHandle();
const native_handle_t* stream;
- ComposerResources::ReplacedStreamHandle replacedStream;
+ ComposerResources::ReplacedHandle replacedStream(false);
auto err = mResources->getLayerSidebandStream(mCurrentDisplay, mCurrentLayer, rawHandle,
&stream, &replacedStream);
if (err == Error::NONE) {
err = mHal->setLayerSidebandStream(mCurrentDisplay, mCurrentLayer, stream);
}
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -509,7 +506,7 @@
auto err = mHal->setLayerSourceCrop(mCurrentDisplay, mCurrentLayer, readFRect());
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -522,7 +519,7 @@
auto err = mHal->setLayerTransform(mCurrentDisplay, mCurrentLayer, readSigned());
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -537,7 +534,7 @@
auto region = readRegion(length / 4);
auto err = mHal->setLayerVisibleRegion(mCurrentDisplay, mCurrentLayer, region);
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -550,7 +547,7 @@
auto err = mHal->setLayerZOrder(mCurrentDisplay, mCurrentLayer, read());
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -579,12 +576,12 @@
};
}
- ComposerHal* mHal;
- ComposerResources* mResources;
-
// 64KiB minus a small space for metadata such as read/write pointers
static constexpr size_t kWriterInitialSize = 64 * 1024 / sizeof(uint32_t) - 16;
- CommandWriterBase mWriter{kWriterInitialSize};
+
+ ComposerHal* mHal;
+ ComposerResources* mResources;
+ std::unique_ptr<CommandWriterBase> mWriter;
Display mCurrentDisplay = 0;
Layer mCurrentLayer = 0;
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
deleted file mode 100644
index 18d184e..0000000
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#ifndef LOG_TAG
-#warning "ComposerResources.h included without LOG_TAG"
-#endif
-
-#include <memory>
-#include <mutex>
-#include <unordered_map>
-#include <vector>
-
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace hal {
-
-// wrapper for IMapper to import buffers and sideband streams
-class ComposerHandleImporter {
- public:
- bool init() {
- mMapper3 = mapper::V3_0::IMapper::getService();
- if (mMapper3) {
- return true;
- }
- ALOGD_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0");
-
- mMapper2 = mapper::V2_0::IMapper::getService();
- ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service");
-
- return mMapper2 != nullptr;
- }
-
- Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle) {
- if (!rawHandle || (!rawHandle->numFds && !rawHandle->numInts)) {
- *outBufferHandle = nullptr;
- return Error::NONE;
- }
-
- const native_handle_t* bufferHandle;
- if (mMapper2) {
- mapper::V2_0::Error error;
- mMapper2->importBuffer(
- rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
- error = tmpError;
- bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
- });
- if (error != mapper::V2_0::Error::NONE) {
- return Error::NO_RESOURCES;
- }
- }
- if (mMapper3) {
- mapper::V3_0::Error error;
- mMapper3->importBuffer(
- rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
- error = tmpError;
- bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
- });
- if (error != mapper::V3_0::Error::NONE) {
- return Error::NO_RESOURCES;
- }
- }
-
- *outBufferHandle = bufferHandle;
- return Error::NONE;
- }
-
- void freeBuffer(const native_handle_t* bufferHandle) {
- if (bufferHandle) {
- if (mMapper2) {
- mMapper2->freeBuffer(
- static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
- } else if (mMapper3) {
- mMapper3->freeBuffer(
- static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
- }
- }
- }
-
- Error importStream(const native_handle_t* rawHandle, const native_handle_t** outStreamHandle) {
- const native_handle_t* streamHandle = nullptr;
- if (rawHandle) {
- streamHandle = native_handle_clone(rawHandle);
- if (!streamHandle) {
- return Error::NO_RESOURCES;
- }
- }
-
- *outStreamHandle = streamHandle;
- return Error::NONE;
- }
-
- void freeStream(const native_handle_t* streamHandle) {
- if (streamHandle) {
- native_handle_close(streamHandle);
- native_handle_delete(const_cast<native_handle_t*>(streamHandle));
- }
- }
-
- private:
- sp<mapper::V2_0::IMapper> mMapper2;
- sp<mapper::V3_0::IMapper> mMapper3;
-};
-
-class ComposerHandleCache {
- public:
- enum class HandleType {
- INVALID,
- BUFFER,
- STREAM,
- };
-
- ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, uint32_t cacheSize)
- : mImporter(importer), mHandleType(type), mHandles(cacheSize, nullptr) {}
-
- // must be initialized later with initCache
- ComposerHandleCache(ComposerHandleImporter& importer) : mImporter(importer) {}
-
- ~ComposerHandleCache() {
- switch (mHandleType) {
- case HandleType::BUFFER:
- for (auto handle : mHandles) {
- mImporter.freeBuffer(handle);
- }
- break;
- case HandleType::STREAM:
- for (auto handle : mHandles) {
- mImporter.freeStream(handle);
- }
- break;
- default:
- break;
- }
- }
-
- ComposerHandleCache(const ComposerHandleCache&) = delete;
- ComposerHandleCache& operator=(const ComposerHandleCache&) = delete;
-
- bool initCache(HandleType type, uint32_t cacheSize) {
- // already initialized
- if (mHandleType != HandleType::INVALID) {
- return false;
- }
-
- mHandleType = type;
- mHandles.resize(cacheSize, nullptr);
-
- return true;
- }
-
- Error lookupCache(uint32_t slot, const native_handle_t** outHandle) {
- if (slot >= 0 && slot < mHandles.size()) {
- *outHandle = mHandles[slot];
- return Error::NONE;
- } else {
- return Error::BAD_PARAMETER;
- }
- }
-
- Error updateCache(uint32_t slot, const native_handle_t* handle,
- const native_handle** outReplacedHandle) {
- if (slot >= 0 && slot < mHandles.size()) {
- auto& cachedHandle = mHandles[slot];
- *outReplacedHandle = cachedHandle;
- cachedHandle = handle;
- return Error::NONE;
- } else {
- return Error::BAD_PARAMETER;
- }
- }
-
- // when fromCache is true, look up in the cache; otherwise, update the cache
- Error getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
- const native_handle_t** outHandle, const native_handle** outReplacedHandle) {
- if (fromCache) {
- *outReplacedHandle = nullptr;
- return lookupCache(slot, outHandle);
- } else {
- *outHandle = inHandle;
- return updateCache(slot, inHandle, outReplacedHandle);
- }
- }
-
- private:
- ComposerHandleImporter& mImporter;
- HandleType mHandleType = HandleType::INVALID;
- std::vector<const native_handle_t*> mHandles;
-};
-
-// layer resource
-class ComposerLayerResource {
- public:
- ComposerLayerResource(ComposerHandleImporter& importer, uint32_t bufferCacheSize)
- : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize),
- mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {}
-
- virtual ~ComposerLayerResource() = default;
-
- Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
- const native_handle_t** outHandle, const native_handle** outReplacedHandle) {
- return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
- }
-
- Error getSidebandStream(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
- const native_handle_t** outHandle,
- const native_handle** outReplacedHandle) {
- return mSidebandStreamCache.getHandle(slot, fromCache, inHandle, outHandle,
- outReplacedHandle);
- }
-
- protected:
- ComposerHandleCache mBufferCache;
- ComposerHandleCache mSidebandStreamCache;
-};
-
-// display resource
-class ComposerDisplayResource {
- public:
- enum class DisplayType {
- PHYSICAL,
- VIRTUAL,
- };
-
- virtual ~ComposerDisplayResource() = default;
-
- ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
- uint32_t outputBufferCacheSize)
- : mType(type),
- mClientTargetCache(importer),
- mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER,
- outputBufferCacheSize),
- mMustValidate(true) {}
-
- bool initClientTargetCache(uint32_t cacheSize) {
- return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize);
- }
-
- bool isVirtual() const { return mType == DisplayType::VIRTUAL; }
-
- Error getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
- const native_handle_t** outHandle,
- const native_handle** outReplacedHandle) {
- return mClientTargetCache.getHandle(slot, fromCache, inHandle, outHandle,
- outReplacedHandle);
- }
-
- Error getOutputBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
- const native_handle_t** outHandle,
- const native_handle** outReplacedHandle) {
- return mOutputBufferCache.getHandle(slot, fromCache, inHandle, outHandle,
- outReplacedHandle);
- }
-
- bool addLayer(Layer layer, std::unique_ptr<ComposerLayerResource> layerResource) {
- auto result = mLayerResources.emplace(layer, std::move(layerResource));
- return result.second;
- }
-
- bool removeLayer(Layer layer) { return mLayerResources.erase(layer) > 0; }
-
- ComposerLayerResource* findLayerResource(Layer layer) {
- auto layerIter = mLayerResources.find(layer);
- if (layerIter == mLayerResources.end()) {
- return nullptr;
- }
-
- return layerIter->second.get();
- }
-
- std::vector<Layer> getLayers() const {
- std::vector<Layer> layers;
- layers.reserve(mLayerResources.size());
- for (const auto& layerKey : mLayerResources) {
- layers.push_back(layerKey.first);
- }
- return layers;
- }
-
- void setMustValidateState(bool mustValidate) { mMustValidate = mustValidate; }
-
- bool mustValidate() const { return mMustValidate; }
-
- protected:
- const DisplayType mType;
- ComposerHandleCache mClientTargetCache;
- ComposerHandleCache mOutputBufferCache;
- bool mMustValidate;
-
- std::unordered_map<Layer, std::unique_ptr<ComposerLayerResource>> mLayerResources;
-};
-
-class ComposerResources {
- private:
- template <bool isBuffer>
- class ReplacedHandle;
-
- public:
- static std::unique_ptr<ComposerResources> create() {
- auto resources = std::make_unique<ComposerResources>();
- return resources->init() ? std::move(resources) : nullptr;
- }
-
- ComposerResources() = default;
- virtual ~ComposerResources() = default;
-
- bool init() { return mImporter.init(); }
-
- using RemoveDisplay =
- std::function<void(Display display, bool isVirtual, const std::vector<Layer>& layers)>;
- void clear(RemoveDisplay removeDisplay) {
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- for (const auto& displayKey : mDisplayResources) {
- Display display = displayKey.first;
- const ComposerDisplayResource& displayResource = *displayKey.second;
- removeDisplay(display, displayResource.isVirtual(), displayResource.getLayers());
- }
- mDisplayResources.clear();
- }
-
- Error addPhysicalDisplay(Display display) {
- auto displayResource =
- createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0);
-
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- auto result = mDisplayResources.emplace(display, std::move(displayResource));
- return result.second ? Error::NONE : Error::BAD_DISPLAY;
- }
-
- Error addVirtualDisplay(Display display, uint32_t outputBufferCacheSize) {
- auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::VIRTUAL,
- outputBufferCacheSize);
-
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- auto result = mDisplayResources.emplace(display, std::move(displayResource));
- return result.second ? Error::NONE : Error::BAD_DISPLAY;
- }
-
- Error removeDisplay(Display display) {
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- return mDisplayResources.erase(display) > 0 ? Error::NONE : Error::BAD_DISPLAY;
- }
-
- Error setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize) {
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
- if (!displayResource) {
- return Error::BAD_DISPLAY;
- }
-
- return displayResource->initClientTargetCache(clientTargetCacheSize) ? Error::NONE
- : Error::BAD_PARAMETER;
- }
-
- Error addLayer(Display display, Layer layer, uint32_t bufferCacheSize) {
- auto layerResource = createLayerResource(bufferCacheSize);
-
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
- if (!displayResource) {
- return Error::BAD_DISPLAY;
- }
-
- return displayResource->addLayer(layer, std::move(layerResource)) ? Error::NONE
- : Error::BAD_LAYER;
- }
-
- Error removeLayer(Display display, Layer layer) {
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
- if (!displayResource) {
- return Error::BAD_DISPLAY;
- }
-
- return displayResource->removeLayer(layer) ? Error::NONE : Error::BAD_LAYER;
- }
-
- using ReplacedBufferHandle = ReplacedHandle<true>;
- using ReplacedStreamHandle = ReplacedHandle<false>;
-
- Error getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
- const native_handle_t* rawHandle,
- const native_handle_t** outBufferHandle,
- ReplacedBufferHandle* outReplacedBuffer) {
- return getHandle<Cache::CLIENT_TARGET>(display, 0, slot, fromCache, rawHandle,
- outBufferHandle, outReplacedBuffer);
- }
-
- Error getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
- const native_handle_t* rawHandle,
- const native_handle_t** outBufferHandle,
- ReplacedBufferHandle* outReplacedBuffer) {
- return getHandle<Cache::OUTPUT_BUFFER>(display, 0, slot, fromCache, rawHandle,
- outBufferHandle, outReplacedBuffer);
- }
-
- Error getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
- const native_handle_t* rawHandle, const native_handle_t** outBufferHandle,
- ReplacedBufferHandle* outReplacedBuffer) {
- return getHandle<Cache::LAYER_BUFFER>(display, layer, slot, fromCache, rawHandle,
- outBufferHandle, outReplacedBuffer);
- }
-
- Error getLayerSidebandStream(Display display, Layer layer, const native_handle_t* rawHandle,
- const native_handle_t** outStreamHandle,
- ReplacedStreamHandle* outReplacedStream) {
- return getHandle<Cache::LAYER_SIDEBAND_STREAM>(display, layer, 0, false, rawHandle,
- outStreamHandle, outReplacedStream);
- }
-
- void setDisplayMustValidateState(Display display, bool mustValidate) {
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- auto* displayResource = findDisplayResourceLocked(display);
- if (displayResource) {
- displayResource->setMustValidateState(mustValidate);
- }
- }
-
- bool mustValidateDisplay(Display display) {
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- auto* displayResource = findDisplayResourceLocked(display);
- if (displayResource) {
- return displayResource->mustValidate();
- }
- return false;
- }
-
- protected:
- virtual std::unique_ptr<ComposerDisplayResource> createDisplayResource(
- ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) {
- return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
- }
-
- virtual std::unique_ptr<ComposerLayerResource> createLayerResource(uint32_t bufferCacheSize) {
- return std::make_unique<ComposerLayerResource>(mImporter, bufferCacheSize);
- }
-
- ComposerDisplayResource* findDisplayResourceLocked(Display display) {
- auto iter = mDisplayResources.find(display);
- if (iter == mDisplayResources.end()) {
- return nullptr;
- }
- return iter->second.get();
- }
-
- ComposerHandleImporter mImporter;
-
- std::mutex mDisplayResourcesMutex;
- std::unordered_map<Display, std::unique_ptr<ComposerDisplayResource>> mDisplayResources;
-
- private:
- enum class Cache {
- CLIENT_TARGET,
- OUTPUT_BUFFER,
- LAYER_BUFFER,
- LAYER_SIDEBAND_STREAM,
- };
-
- // When a buffer in the cache is replaced by a new one, we must keep it
- // alive until it has been replaced in ComposerHal.
- template <bool isBuffer>
- class ReplacedHandle {
- public:
- ReplacedHandle() = default;
- ReplacedHandle(const ReplacedHandle&) = delete;
- ReplacedHandle& operator=(const ReplacedHandle&) = delete;
-
- ~ReplacedHandle() { reset(); }
-
- void reset(ComposerHandleImporter* importer = nullptr,
- const native_handle_t* handle = nullptr) {
- if (mHandle) {
- if (isBuffer) {
- mImporter->freeBuffer(mHandle);
- } else {
- mImporter->freeStream(mHandle);
- }
- }
-
- mImporter = importer;
- mHandle = handle;
- }
-
- private:
- ComposerHandleImporter* mImporter = nullptr;
- const native_handle_t* mHandle = nullptr;
- };
-
- template <Cache cache, bool isBuffer>
- Error getHandle(Display display, Layer layer, uint32_t slot, bool fromCache,
- const native_handle_t* rawHandle, const native_handle_t** outHandle,
- ReplacedHandle<isBuffer>* outReplacedHandle) {
- Error error;
-
- // import the raw handle (or ignore raw handle when fromCache is true)
- const native_handle_t* importedHandle = nullptr;
- if (!fromCache) {
- error = (isBuffer) ? mImporter.importBuffer(rawHandle, &importedHandle)
- : mImporter.importStream(rawHandle, &importedHandle);
- if (error != Error::NONE) {
- return error;
- }
- }
-
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-
- // find display/layer resource
- const bool needLayerResource =
- (cache == Cache::LAYER_BUFFER || cache == Cache::LAYER_SIDEBAND_STREAM);
- ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
- ComposerLayerResource* layerResource = (displayResource && needLayerResource)
- ? displayResource->findLayerResource(layer)
- : nullptr;
-
- // lookup or update cache
- const native_handle_t* replacedHandle = nullptr;
- if (displayResource && (!needLayerResource || layerResource)) {
- switch (cache) {
- case Cache::CLIENT_TARGET:
- error = displayResource->getClientTarget(slot, fromCache, importedHandle,
- outHandle, &replacedHandle);
- break;
- case Cache::OUTPUT_BUFFER:
- error = displayResource->getOutputBuffer(slot, fromCache, importedHandle,
- outHandle, &replacedHandle);
- break;
- case Cache::LAYER_BUFFER:
- error = layerResource->getBuffer(slot, fromCache, importedHandle, outHandle,
- &replacedHandle);
- break;
- case Cache::LAYER_SIDEBAND_STREAM:
- error = layerResource->getSidebandStream(slot, fromCache, importedHandle,
- outHandle, &replacedHandle);
- break;
- default:
- error = Error::BAD_PARAMETER;
- break;
- }
-
- if (error != Error::NONE) {
- ALOGW("invalid cache %d slot %d", int(cache), int(slot));
- }
- } else if (!displayResource) {
- error = Error::BAD_DISPLAY;
- } else {
- error = Error::BAD_LAYER;
- }
-
- // clean up on errors
- if (error != Error::NONE) {
- if (!fromCache) {
- if (isBuffer) {
- mImporter.freeBuffer(importedHandle);
- } else {
- mImporter.freeStream(importedHandle);
- }
- }
- return error;
- }
-
- outReplacedHandle->reset(&mImporter, replacedHandle);
-
- return Error::NONE;
- }
-};
-
-} // namespace hal
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/composer/2.1/utils/resources/Android.bp b/graphics/composer/2.1/utils/resources/Android.bp
new file mode 100644
index 0000000..ed827fe
--- /dev/null
+++ b/graphics/composer/2.1/utils/resources/Android.bp
@@ -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.
+
+cc_library_shared {
+ name: "android.hardware.graphics.composer@2.1-resources",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
+ "libcutils",
+ "libhardware", // TODO remove hwcomposer2.h dependency
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
+ export_include_dirs: ["include"],
+ srcs: [
+ "ComposerResources.cpp",
+ ],
+}
diff --git a/graphics/composer/2.1/utils/resources/ComposerResources.cpp b/graphics/composer/2.1/utils/resources/ComposerResources.cpp
new file mode 100644
index 0000000..21f6035
--- /dev/null
+++ b/graphics/composer/2.1/utils/resources/ComposerResources.cpp
@@ -0,0 +1,503 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ComposerResources"
+
+#include "composer-resources/2.1/ComposerResources.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+bool ComposerHandleImporter::init() {
+ mMapper4 = mapper::V4_0::IMapper::getService();
+ if (mMapper4) {
+ return true;
+ }
+ ALOGI_IF(!mMapper4, "failed to get mapper 4.0 service, falling back to mapper 3.0");
+
+ mMapper3 = mapper::V3_0::IMapper::getService();
+ if (mMapper3) {
+ return true;
+ }
+ ALOGI_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0");
+
+ mMapper2 = mapper::V2_0::IMapper::getService();
+ ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service");
+
+ return mMapper2 != nullptr;
+}
+
+Error ComposerHandleImporter::importBuffer(const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle) {
+ if (!rawHandle || (!rawHandle->numFds && !rawHandle->numInts)) {
+ *outBufferHandle = nullptr;
+ return Error::NONE;
+ }
+
+ const native_handle_t* bufferHandle;
+ if (mMapper2) {
+ mapper::V2_0::Error error;
+ mMapper2->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+ error = tmpError;
+ bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+ });
+ if (error != mapper::V2_0::Error::NONE) {
+ return Error::NO_RESOURCES;
+ }
+ }
+ if (mMapper3) {
+ mapper::V3_0::Error error;
+ mMapper3->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+ error = tmpError;
+ bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+ });
+ if (error != mapper::V3_0::Error::NONE) {
+ return Error::NO_RESOURCES;
+ }
+ }
+ if (mMapper4) {
+ mapper::V4_0::Error error;
+ mMapper4->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+ error = tmpError;
+ bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+ });
+ if (error != mapper::V4_0::Error::NONE) {
+ return Error::NO_RESOURCES;
+ }
+ }
+
+ *outBufferHandle = bufferHandle;
+ return Error::NONE;
+}
+
+void ComposerHandleImporter::freeBuffer(const native_handle_t* bufferHandle) {
+ if (bufferHandle) {
+ if (mMapper2) {
+ mMapper2->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+ } else if (mMapper3) {
+ mMapper3->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+ } else if (mMapper4) {
+ mMapper4->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+ }
+ }
+}
+
+Error ComposerHandleImporter::importStream(const native_handle_t* rawHandle,
+ const native_handle_t** outStreamHandle) {
+ const native_handle_t* streamHandle = nullptr;
+ if (rawHandle) {
+ streamHandle = native_handle_clone(rawHandle);
+ if (!streamHandle) {
+ return Error::NO_RESOURCES;
+ }
+ }
+
+ *outStreamHandle = streamHandle;
+ return Error::NONE;
+}
+
+void ComposerHandleImporter::freeStream(const native_handle_t* streamHandle) {
+ if (streamHandle) {
+ native_handle_close(streamHandle);
+ native_handle_delete(const_cast<native_handle_t*>(streamHandle));
+ }
+}
+
+ComposerHandleCache::ComposerHandleCache(ComposerHandleImporter& importer, HandleType type,
+ uint32_t cacheSize)
+ : mImporter(importer), mHandleType(type), mHandles(cacheSize, nullptr) {}
+
+// must be initialized later with initCache
+ComposerHandleCache::ComposerHandleCache(ComposerHandleImporter& importer) : mImporter(importer) {}
+
+ComposerHandleCache::~ComposerHandleCache() {
+ switch (mHandleType) {
+ case HandleType::BUFFER:
+ for (auto handle : mHandles) {
+ mImporter.freeBuffer(handle);
+ }
+ break;
+ case HandleType::STREAM:
+ for (auto handle : mHandles) {
+ mImporter.freeStream(handle);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool ComposerHandleCache::initCache(HandleType type, uint32_t cacheSize) {
+ // already initialized
+ if (mHandleType != HandleType::INVALID) {
+ return false;
+ }
+
+ mHandleType = type;
+ mHandles.resize(cacheSize, nullptr);
+
+ return true;
+}
+
+Error ComposerHandleCache::lookupCache(uint32_t slot, const native_handle_t** outHandle) {
+ if (slot >= 0 && slot < mHandles.size()) {
+ *outHandle = mHandles[slot];
+ return Error::NONE;
+ } else {
+ return Error::BAD_PARAMETER;
+ }
+}
+
+Error ComposerHandleCache::updateCache(uint32_t slot, const native_handle_t* handle,
+ const native_handle** outReplacedHandle) {
+ if (slot >= 0 && slot < mHandles.size()) {
+ auto& cachedHandle = mHandles[slot];
+ *outReplacedHandle = cachedHandle;
+ cachedHandle = handle;
+ return Error::NONE;
+ } else {
+ return Error::BAD_PARAMETER;
+ }
+}
+
+// when fromCache is true, look up in the cache; otherwise, update the cache
+Error ComposerHandleCache::getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ if (fromCache) {
+ *outReplacedHandle = nullptr;
+ return lookupCache(slot, outHandle);
+ } else {
+ *outHandle = inHandle;
+ return updateCache(slot, inHandle, outReplacedHandle);
+ }
+}
+
+ComposerLayerResource::ComposerLayerResource(ComposerHandleImporter& importer,
+ uint32_t bufferCacheSize)
+ : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize),
+ mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {}
+
+Error ComposerLayerResource::getBuffer(uint32_t slot, bool fromCache,
+ const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+Error ComposerLayerResource::getSidebandStream(uint32_t slot, bool fromCache,
+ const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ return mSidebandStreamCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+ComposerDisplayResource::ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+ uint32_t outputBufferCacheSize)
+ : mType(type),
+ mClientTargetCache(importer),
+ mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, outputBufferCacheSize),
+ mMustValidate(true) {}
+
+bool ComposerDisplayResource::initClientTargetCache(uint32_t cacheSize) {
+ return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize);
+}
+
+bool ComposerDisplayResource::isVirtual() const {
+ return mType == DisplayType::VIRTUAL;
+}
+
+Error ComposerDisplayResource::getClientTarget(uint32_t slot, bool fromCache,
+ const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ return mClientTargetCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+Error ComposerDisplayResource::getOutputBuffer(uint32_t slot, bool fromCache,
+ const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ return mOutputBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+bool ComposerDisplayResource::addLayer(Layer layer,
+ std::unique_ptr<ComposerLayerResource> layerResource) {
+ auto result = mLayerResources.emplace(layer, std::move(layerResource));
+ return result.second;
+}
+
+bool ComposerDisplayResource::removeLayer(Layer layer) {
+ return mLayerResources.erase(layer) > 0;
+}
+
+ComposerLayerResource* ComposerDisplayResource::findLayerResource(Layer layer) {
+ auto layerIter = mLayerResources.find(layer);
+ if (layerIter == mLayerResources.end()) {
+ return nullptr;
+ }
+
+ return layerIter->second.get();
+}
+
+std::vector<Layer> ComposerDisplayResource::getLayers() const {
+ std::vector<Layer> layers;
+ layers.reserve(mLayerResources.size());
+ for (const auto& layerKey : mLayerResources) {
+ layers.push_back(layerKey.first);
+ }
+ return layers;
+}
+
+void ComposerDisplayResource::setMustValidateState(bool mustValidate) {
+ mMustValidate = mustValidate;
+}
+
+bool ComposerDisplayResource::mustValidate() const {
+ return mMustValidate;
+}
+
+std::unique_ptr<ComposerResources> ComposerResources::create() {
+ auto resources = std::make_unique<ComposerResources>();
+ return resources->init() ? std::move(resources) : nullptr;
+}
+
+bool ComposerResources::init() {
+ return mImporter.init();
+}
+
+void ComposerResources::clear(RemoveDisplay removeDisplay) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ for (const auto& displayKey : mDisplayResources) {
+ Display display = displayKey.first;
+ const ComposerDisplayResource& displayResource = *displayKey.second;
+ removeDisplay(display, displayResource.isVirtual(), displayResource.getLayers());
+ }
+ mDisplayResources.clear();
+}
+
+Error ComposerResources::addPhysicalDisplay(Display display) {
+ auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0);
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ auto result = mDisplayResources.emplace(display, std::move(displayResource));
+ return result.second ? Error::NONE : Error::BAD_DISPLAY;
+}
+
+Error ComposerResources::addVirtualDisplay(Display display, uint32_t outputBufferCacheSize) {
+ auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::VIRTUAL,
+ outputBufferCacheSize);
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ auto result = mDisplayResources.emplace(display, std::move(displayResource));
+ return result.second ? Error::NONE : Error::BAD_DISPLAY;
+}
+
+Error ComposerResources::removeDisplay(Display display) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ return mDisplayResources.erase(display) > 0 ? Error::NONE : Error::BAD_DISPLAY;
+}
+
+Error ComposerResources::setDisplayClientTargetCacheSize(Display display,
+ uint32_t clientTargetCacheSize) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ if (!displayResource) {
+ return Error::BAD_DISPLAY;
+ }
+
+ return displayResource->initClientTargetCache(clientTargetCacheSize) ? Error::NONE
+ : Error::BAD_PARAMETER;
+}
+
+Error ComposerResources::addLayer(Display display, Layer layer, uint32_t bufferCacheSize) {
+ auto layerResource = createLayerResource(bufferCacheSize);
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ if (!displayResource) {
+ return Error::BAD_DISPLAY;
+ }
+
+ return displayResource->addLayer(layer, std::move(layerResource)) ? Error::NONE
+ : Error::BAD_LAYER;
+}
+
+Error ComposerResources::removeLayer(Display display, Layer layer) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ if (!displayResource) {
+ return Error::BAD_DISPLAY;
+ }
+
+ return displayResource->removeLayer(layer) ? Error::NONE : Error::BAD_LAYER;
+}
+
+Error ComposerResources::getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle,
+ ReplacedHandle* outReplacedBuffer) {
+ return getHandle(display, 0, slot, Cache::CLIENT_TARGET, fromCache, rawHandle, outBufferHandle,
+ outReplacedBuffer);
+}
+
+Error ComposerResources::getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle,
+ ReplacedHandle* outReplacedBuffer) {
+ return getHandle(display, 0, slot, Cache::OUTPUT_BUFFER, fromCache, rawHandle, outBufferHandle,
+ outReplacedBuffer);
+}
+
+Error ComposerResources::getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle,
+ ReplacedHandle* outReplacedBuffer) {
+ return getHandle(display, layer, slot, Cache::LAYER_BUFFER, fromCache, rawHandle,
+ outBufferHandle, outReplacedBuffer);
+}
+
+Error ComposerResources::getLayerSidebandStream(Display display, Layer layer,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outStreamHandle,
+ ReplacedHandle* outReplacedStream) {
+ return getHandle(display, layer, 0, Cache::LAYER_SIDEBAND_STREAM, false, rawHandle,
+ outStreamHandle, outReplacedStream);
+}
+
+void ComposerResources::setDisplayMustValidateState(Display display, bool mustValidate) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ auto* displayResource = findDisplayResourceLocked(display);
+ if (displayResource) {
+ displayResource->setMustValidateState(mustValidate);
+ }
+}
+
+bool ComposerResources::mustValidateDisplay(Display display) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ auto* displayResource = findDisplayResourceLocked(display);
+ if (displayResource) {
+ return displayResource->mustValidate();
+ }
+ return false;
+}
+
+std::unique_ptr<ComposerDisplayResource> ComposerResources::createDisplayResource(
+ ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) {
+ return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
+}
+
+std::unique_ptr<ComposerLayerResource> ComposerResources::createLayerResource(
+ uint32_t bufferCacheSize) {
+ return std::make_unique<ComposerLayerResource>(mImporter, bufferCacheSize);
+}
+
+ComposerDisplayResource* ComposerResources::findDisplayResourceLocked(Display display) {
+ auto iter = mDisplayResources.find(display);
+ if (iter == mDisplayResources.end()) {
+ return nullptr;
+ }
+ return iter->second.get();
+}
+
+Error ComposerResources::getHandle(Display display, Layer layer, uint32_t slot, Cache cache,
+ bool fromCache, const native_handle_t* rawHandle,
+ const native_handle_t** outHandle,
+ ReplacedHandle* outReplacedHandle) {
+ Error error;
+
+ // import the raw handle (or ignore raw handle when fromCache is true)
+ const native_handle_t* importedHandle = nullptr;
+ if (!fromCache) {
+ error = (outReplacedHandle->isBuffer())
+ ? mImporter.importBuffer(rawHandle, &importedHandle)
+ : mImporter.importStream(rawHandle, &importedHandle);
+ if (error != Error::NONE) {
+ return error;
+ }
+ }
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+
+ // find display/layer resource
+ const bool needLayerResource = (cache == ComposerResources::Cache::LAYER_BUFFER ||
+ cache == ComposerResources::Cache::LAYER_SIDEBAND_STREAM);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ ComposerLayerResource* layerResource = (displayResource && needLayerResource)
+ ? displayResource->findLayerResource(layer)
+ : nullptr;
+
+ // lookup or update cache
+ const native_handle_t* replacedHandle = nullptr;
+ if (displayResource && (!needLayerResource || layerResource)) {
+ switch (cache) {
+ case ComposerResources::Cache::CLIENT_TARGET:
+ error = displayResource->getClientTarget(slot, fromCache, importedHandle, outHandle,
+ &replacedHandle);
+ break;
+ case ComposerResources::Cache::OUTPUT_BUFFER:
+ error = displayResource->getOutputBuffer(slot, fromCache, importedHandle, outHandle,
+ &replacedHandle);
+ break;
+ case ComposerResources::Cache::LAYER_BUFFER:
+ error = layerResource->getBuffer(slot, fromCache, importedHandle, outHandle,
+ &replacedHandle);
+ break;
+ case ComposerResources::Cache::LAYER_SIDEBAND_STREAM:
+ error = layerResource->getSidebandStream(slot, fromCache, importedHandle, outHandle,
+ &replacedHandle);
+ break;
+ default:
+ error = Error::BAD_PARAMETER;
+ break;
+ }
+
+ if (error != Error::NONE) {
+ ALOGW("invalid cache %d slot %d", int(cache), int(slot));
+ }
+ } else if (!displayResource) {
+ error = Error::BAD_DISPLAY;
+ } else {
+ error = Error::BAD_LAYER;
+ }
+
+ // clean up on errors
+ if (error != Error::NONE) {
+ if (!fromCache) {
+ if (outReplacedHandle->isBuffer()) {
+ mImporter.freeBuffer(importedHandle);
+ } else {
+ mImporter.freeStream(importedHandle);
+ }
+ }
+ return error;
+ }
+
+ outReplacedHandle->reset(&mImporter, replacedHandle);
+
+ return Error::NONE;
+}
+
+} // namespace hal
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
new file mode 100644
index 0000000..3738278
--- /dev/null
+++ b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerResources.h included without LOG_TAG"
+#endif
+
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/types.h>
+
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+// wrapper for IMapper to import buffers and sideband streams
+class ComposerHandleImporter {
+ public:
+ bool init();
+
+ Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle);
+ void freeBuffer(const native_handle_t* bufferHandle);
+ Error importStream(const native_handle_t* rawHandle, const native_handle_t** outStreamHandle);
+ void freeStream(const native_handle_t* streamHandle);
+
+ private:
+ sp<mapper::V2_0::IMapper> mMapper2;
+ sp<mapper::V3_0::IMapper> mMapper3;
+ sp<mapper::V4_0::IMapper> mMapper4;
+};
+
+class ComposerHandleCache {
+ public:
+ enum class HandleType {
+ INVALID,
+ BUFFER,
+ STREAM,
+ };
+
+ ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, uint32_t cacheSize);
+
+ // must be initialized later with initCache
+ ComposerHandleCache(ComposerHandleImporter& importer);
+
+ ~ComposerHandleCache();
+
+ ComposerHandleCache(const ComposerHandleCache&) = delete;
+ ComposerHandleCache& operator=(const ComposerHandleCache&) = delete;
+
+ bool initCache(HandleType type, uint32_t cacheSize);
+ Error lookupCache(uint32_t slot, const native_handle_t** outHandle);
+ Error updateCache(uint32_t slot, const native_handle_t* handle,
+ const native_handle** outReplacedHandle);
+
+ // when fromCache is true, look up in the cache; otherwise, update the cache
+ Error getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle, const native_handle** outReplacedHandle);
+
+ private:
+ ComposerHandleImporter& mImporter;
+ HandleType mHandleType = HandleType::INVALID;
+ std::vector<const native_handle_t*> mHandles;
+};
+
+// layer resource
+class ComposerLayerResource {
+ public:
+ ComposerLayerResource(ComposerHandleImporter& importer, uint32_t bufferCacheSize);
+
+ virtual ~ComposerLayerResource() = default;
+
+ Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle, const native_handle** outReplacedHandle);
+ Error getSidebandStream(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle);
+
+ protected:
+ ComposerHandleCache mBufferCache;
+ ComposerHandleCache mSidebandStreamCache;
+};
+
+// display resource
+class ComposerDisplayResource {
+ public:
+ enum class DisplayType {
+ PHYSICAL,
+ VIRTUAL,
+ };
+
+ virtual ~ComposerDisplayResource() = default;
+
+ ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+ uint32_t outputBufferCacheSize);
+
+ bool initClientTargetCache(uint32_t cacheSize);
+
+ bool isVirtual() const;
+
+ Error getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle);
+
+ Error getOutputBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle);
+
+ bool addLayer(Layer layer, std::unique_ptr<ComposerLayerResource> layerResource);
+ bool removeLayer(Layer layer);
+ ComposerLayerResource* findLayerResource(Layer layer);
+ std::vector<Layer> getLayers() const;
+
+ void setMustValidateState(bool mustValidate);
+
+ bool mustValidate() const;
+
+ protected:
+ const DisplayType mType;
+ ComposerHandleCache mClientTargetCache;
+ ComposerHandleCache mOutputBufferCache;
+ bool mMustValidate;
+
+ std::unordered_map<Layer, std::unique_ptr<ComposerLayerResource>> mLayerResources;
+};
+
+class ComposerResources {
+ public:
+ static std::unique_ptr<ComposerResources> create();
+
+ ComposerResources() = default;
+ virtual ~ComposerResources() = default;
+
+ bool init();
+
+ using RemoveDisplay =
+ std::function<void(Display display, bool isVirtual, const std::vector<Layer>& layers)>;
+ void clear(RemoveDisplay removeDisplay);
+
+ Error addPhysicalDisplay(Display display);
+ Error addVirtualDisplay(Display display, uint32_t outputBufferCacheSize);
+
+ Error removeDisplay(Display display);
+
+ Error setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize);
+
+ Error addLayer(Display display, Layer layer, uint32_t bufferCacheSize);
+ Error removeLayer(Display display, Layer layer);
+
+ void setDisplayMustValidateState(Display display, bool mustValidate);
+
+ bool mustValidateDisplay(Display display);
+
+ // When a buffer in the cache is replaced by a new one, we must keep it
+ // alive until it has been replaced in ComposerHal.
+ class ReplacedHandle {
+ public:
+ explicit ReplacedHandle(bool isBuffer) : mIsBuffer(isBuffer) {}
+ ReplacedHandle(const ReplacedHandle&) = delete;
+ ReplacedHandle& operator=(const ReplacedHandle&) = delete;
+
+ ~ReplacedHandle() { reset(); }
+
+ bool isBuffer() { return mIsBuffer; }
+
+ void reset(ComposerHandleImporter* importer = nullptr,
+ const native_handle_t* handle = nullptr) {
+ if (mHandle) {
+ if (mIsBuffer) {
+ mImporter->freeBuffer(mHandle);
+ } else {
+ mImporter->freeStream(mHandle);
+ }
+ }
+
+ mImporter = importer;
+ mHandle = handle;
+ }
+
+ private:
+ bool mIsBuffer;
+ ComposerHandleImporter* mImporter = nullptr;
+ const native_handle_t* mHandle = nullptr;
+ };
+
+ Error getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle,
+ ReplacedHandle* outReplacedBuffer);
+
+ Error getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle,
+ ReplacedHandle* outReplacedBuffer);
+
+ Error getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle, const native_handle_t** outBufferHandle,
+ ReplacedHandle* outReplacedBuffer);
+
+ Error getLayerSidebandStream(Display display, Layer layer, const native_handle_t* rawHandle,
+ const native_handle_t** outStreamHandle,
+ ReplacedHandle* outReplacedStream);
+
+ protected:
+ virtual std::unique_ptr<ComposerDisplayResource> createDisplayResource(
+ ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize);
+
+ virtual std::unique_ptr<ComposerLayerResource> createLayerResource(uint32_t bufferCacheSize);
+
+ ComposerDisplayResource* findDisplayResourceLocked(Display display);
+
+ ComposerHandleImporter mImporter;
+
+ std::mutex mDisplayResourcesMutex;
+ std::unordered_map<Display, std::unique_ptr<ComposerDisplayResource>> mDisplayResources;
+
+ private:
+ enum class Cache {
+ CLIENT_TARGET,
+ OUTPUT_BUFFER,
+ LAYER_BUFFER,
+ LAYER_SIDEBAND_STREAM,
+ };
+
+ Error getHandle(Display display, Layer layer, uint32_t slot, Cache cache, bool fromCache,
+ const native_handle_t* rawHandle, const native_handle_t** outHandle,
+ ReplacedHandle* outReplacedHandle);
+};
+
+} // namespace hal
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index fcb327f..cdc0f35 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -27,10 +27,21 @@
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0-vts",
+ ],
+ export_static_lib_headers: [
+ "VtsHalHidlTargetTestBase",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.mapper@2.0-vts",
+ "android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0-vts",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
cflags: [
"-O0",
"-g",
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index c5d5823..a8e1480 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -317,11 +317,16 @@
Gralloc::Gralloc() {
[this] {
- ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+ ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
/*errOnFailure=*/false));
- if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) {
- mGralloc3 = nullptr;
- ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+ if (mGralloc4->getAllocator() == nullptr || mGralloc4->getMapper() == nullptr) {
+ mGralloc4 = nullptr;
+ ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+ /*errOnFailure=*/false));
+ if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) {
+ mGralloc3 = nullptr;
+ ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+ }
}
}();
}
@@ -329,7 +334,15 @@
const native_handle_t* Gralloc::allocate(uint32_t width, uint32_t height, uint32_t layerCount,
PixelFormat format, uint64_t usage, bool import,
uint32_t* outStride) {
- if (mGralloc3) {
+ if (mGralloc4) {
+ IMapper4::BufferDescriptorInfo info{};
+ info.width = width;
+ info.height = height;
+ info.layerCount = layerCount;
+ info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
+ info.usage = usage;
+ return mGralloc4->allocate(info, import, outStride);
+ } else if (mGralloc3) {
IMapper3::BufferDescriptorInfo info{};
info.width = width;
info.height = height;
@@ -350,7 +363,14 @@
void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
const AccessRegion& accessRegionRect, int acquireFence) {
- if (mGralloc3) {
+ if (mGralloc4) {
+ IMapper4::Rect accessRegion;
+ accessRegion.left = accessRegionRect.left;
+ accessRegion.top = accessRegionRect.top;
+ accessRegion.width = accessRegionRect.width;
+ accessRegion.height = accessRegionRect.height;
+ return mGralloc4->lock(bufferHandle, cpuUsage, accessRegion, acquireFence);
+ } else if (mGralloc3) {
IMapper3::Rect accessRegion;
accessRegion.left = accessRegionRect.left;
accessRegion.top = accessRegionRect.top;
@@ -371,7 +391,9 @@
}
int Gralloc::unlock(const native_handle_t* bufferHandle) {
- if (mGralloc3) {
+ if (mGralloc4) {
+ return mGralloc4->unlock(bufferHandle);
+ } else if (mGralloc3) {
return mGralloc3->unlock(bufferHandle);
} else {
return mGralloc2->unlock(bufferHandle);
@@ -379,7 +401,9 @@
}
void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
- if (mGralloc3) {
+ if (mGralloc4) {
+ mGralloc4->freeBuffer(bufferHandle);
+ } else if (mGralloc3) {
mGralloc3->freeBuffer(bufferHandle);
} else {
mGralloc2->freeBuffer(bufferHandle);
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
index 7811048..63aa713 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
@@ -27,6 +27,7 @@
#include <composer-vts/2.1/TestCommandReader.h>
#include <mapper-vts/2.0/MapperVts.h>
#include <mapper-vts/3.0/MapperVts.h>
+#include <mapper-vts/4.0/MapperVts.h>
#include <utils/StrongPointer.h>
#include "gtest/gtest.h"
@@ -44,8 +45,10 @@
using android::hardware::graphics::common::V1_0::PixelFormat;
using IMapper2 = android::hardware::graphics::mapper::V2_0::IMapper;
using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
+using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc;
class ComposerClient;
@@ -54,6 +57,7 @@
public:
Composer();
explicit Composer(const std::string& name);
+ explicit Composer(const sp<IComposer>& composer);
sp<IComposer> getRaw() const;
@@ -64,9 +68,6 @@
std::string dumpDebugInfo();
std::unique_ptr<ComposerClient> createClient();
- protected:
- explicit Composer(const sp<IComposer>& composer);
-
private:
const sp<IComposer> mComposer;
@@ -153,6 +154,7 @@
protected:
std::shared_ptr<Gralloc2> mGralloc2 = nullptr;
std::shared_ptr<Gralloc3> mGralloc3 = nullptr;
+ std::shared_ptr<Gralloc4> mGralloc4 = nullptr;
};
} // namespace vts
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index d54da60..5f1ed63 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -27,15 +27,21 @@
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.0-vts",
+ "android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@2.1-vts",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hardware.graphics.mapper@4.0-vts",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
],
- test_suites: ["general-tests"],
+ disable_framework: true,
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index fa5ace6..b92279d 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -20,11 +20,14 @@
#include <composer-vts/2.1/ComposerVts.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
#include <composer-vts/2.1/TestCommandReader.h>
+#include <gtest/gtest.h>
+#include <hardware/hwcomposer2.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <mapper-vts/2.0/MapperVts.h>
#include <mapper-vts/3.0/MapperVts.h>
+#include <mapper-vts/4.0/MapperVts.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <unistd.h>
#include <algorithm>
@@ -50,30 +53,11 @@
using android::hardware::graphics::common::V1_0::Transform;
using GrallocError = android::hardware::graphics::mapper::V2_0::Error;
-// 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 {
- VtsHalHidlTargetTestBase::SetUp();
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 GraphicsComposerCallback;
@@ -100,7 +84,6 @@
EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
}
- VtsHalHidlTargetTestBase::TearDown();
}
// returns an invalid display id (one that has not been registered to a
@@ -149,7 +132,7 @@
*
* Test that IComposer::getCapabilities returns no invalid capabilities.
*/
-TEST_F(GraphicsComposerHidlTest, GetCapabilities) {
+TEST_P(GraphicsComposerHidlTest, GetCapabilities) {
auto capabilities = mComposer->getCapabilities();
ASSERT_EQ(capabilities.end(),
std::find(capabilities.begin(), capabilities.end(), IComposer::Capability::INVALID));
@@ -158,7 +141,7 @@
/**
* Test IComposer::dumpDebugInfo.
*/
-TEST_F(GraphicsComposerHidlTest, DumpDebugInfo) {
+TEST_P(GraphicsComposerHidlTest, DumpDebugInfo) {
mComposer->dumpDebugInfo();
}
@@ -167,7 +150,7 @@
*
* Test that IComposerClient is a singleton.
*/
-TEST_F(GraphicsComposerHidlTest, CreateClientSingleton) {
+TEST_P(GraphicsComposerHidlTest, CreateClientSingleton) {
mComposer->getRaw()->createClient(
[&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::NO_RESOURCES, tmpError); });
}
@@ -178,7 +161,7 @@
*
* Test that virtual displays can be created and has the correct display type.
*/
-TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay) {
+TEST_P(GraphicsComposerHidlTest, CreateVirtualDisplay) {
if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
GTEST_SUCCEED() << "no virtual display support";
return;
@@ -203,7 +186,7 @@
* Test that passing a bad display handle to destroyVirtualDisplay
* returns a BAD_DISPLAY error
*/
-TEST_F(GraphicsComposerHidlTest, DestroyVirtualDisplayBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, DestroyVirtualDisplayBadDisplay) {
if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
GTEST_SUCCEED() << "no virtual display support";
return;
@@ -218,7 +201,7 @@
*
* Test that layers can be created and destroyed.
*/
-TEST_F(GraphicsComposerHidlTest, CreateLayer) {
+TEST_P(GraphicsComposerHidlTest, CreateLayer) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -232,7 +215,7 @@
* Test that passing in an invalid display handle to createLayer returns
* BAD_DISPLAY.
*/
-TEST_F(GraphicsComposerHidlTest, CreateLayerBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, CreateLayerBadDisplay) {
Error error;
mComposerClient->getRaw()->createLayer(
mInvalidDisplayId, kBufferSlotCount,
@@ -246,7 +229,7 @@
* Test that passing in an invalid display handle to destroyLayer returns
* BAD_DISPLAY
*/
-TEST_F(GraphicsComposerHidlTest, DestroyLayerBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, DestroyLayerBadDisplay) {
Error error;
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
@@ -265,7 +248,7 @@
* Test that passing in an invalid layer handle to destroyLayer returns
* BAD_LAYER
*/
-TEST_F(GraphicsComposerHidlTest, DestroyLayerBadLayerError) {
+TEST_P(GraphicsComposerHidlTest, DestroyLayerBadLayerError) {
// We haven't created any layers yet, so any id should be invalid
Error error = mComposerClient->getRaw()->destroyLayer(mPrimaryDisplay, 1);
@@ -278,7 +261,7 @@
* Test that passing in a bad display handle to getActiveConfig generates a
* BAD_DISPLAY error
*/
-TEST_F(GraphicsComposerHidlTest, GetActiveConfigBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetActiveConfigBadDisplay) {
Error error;
mComposerClient->getRaw()->getActiveConfig(
mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; });
@@ -291,7 +274,7 @@
* Test IComposerClient::getDisplayConfigs returns no error
* when passed in a valid display
*/
-TEST_F(GraphicsComposerHidlTest, GetDisplayConfig) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayConfig) {
std::vector<Config> configs;
ASSERT_NO_FATAL_FAILURE(configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay));
}
@@ -302,7 +285,7 @@
* Test IComposerClient::getDisplayConfigs returns BAD_DISPLAY
* when passed in an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, GetDisplayConfigBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayConfigBadDisplay) {
Error error;
mComposerClient->getRaw()->getDisplayConfigs(
mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; });
@@ -312,7 +295,7 @@
/**
* Test IComposerClient::getDisplayName.
*/
-TEST_F(GraphicsComposerHidlTest, GetDisplayName) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayName) {
mComposerClient->getDisplayName(mPrimaryDisplay);
}
@@ -322,7 +305,7 @@
* Test that IComposerClient::getDisplayType returns the correct display type
* for the primary display.
*/
-TEST_F(GraphicsComposerHidlTest, GetDisplayType) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayType) {
ASSERT_EQ(IComposerClient::DisplayType::PHYSICAL,
mComposerClient->getDisplayType(mPrimaryDisplay));
}
@@ -333,7 +316,7 @@
* Test that IComposerClient::getClientTargetSupport returns true for the
* required client targets.
*/
-TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport) {
+TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport) {
std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
for (auto config : configs) {
int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -356,7 +339,7 @@
* Test that IComposerClient::getClientTargetSupport returns BAD_DISPLAY when
* passed an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, GetClientTargetSupportBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetClientTargetSupportBadDisplay) {
std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
for (auto config : configs) {
int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -380,7 +363,7 @@
* Test that IComposerClient::getDisplayAttribute succeeds for the required
* formats, and succeeds or fails correctly for optional attributes.
*/
-TEST_F(GraphicsComposerHidlTest, GetDisplayAttribute) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute) {
std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
for (auto config : configs) {
const std::array<IComposerClient::Attribute, 3> requiredAttributes = {{
@@ -406,7 +389,7 @@
/**
* Test IComposerClient::getHdrCapabilities.
*/
-TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities) {
+TEST_P(GraphicsComposerHidlTest, GetHdrCapabilities) {
float maxLuminance;
float maxAverageLuminance;
float minLuminance;
@@ -417,7 +400,7 @@
/**
* Test IComposerClient::setClientTargetSlotCount.
*/
-TEST_F(GraphicsComposerHidlTest, SetClientTargetSlotCount) {
+TEST_P(GraphicsComposerHidlTest, SetClientTargetSlotCount) {
mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount);
}
@@ -427,7 +410,7 @@
* Test that IComposerClient::setActiveConfig succeeds for all display
* configs.
*/
-TEST_F(GraphicsComposerHidlTest, SetActiveConfig) {
+TEST_P(GraphicsComposerHidlTest, SetActiveConfig) {
std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
for (auto config : configs) {
mComposerClient->setActiveConfig(mPrimaryDisplay, config);
@@ -441,7 +424,7 @@
* Test that config set during IComposerClient::setActiveConfig is maintained
* during a display on/off power cycle
*/
-TEST_F(GraphicsComposerHidlTest, SetActiveConfigPowerCycle) {
+TEST_P(GraphicsComposerHidlTest, SetActiveConfigPowerCycle) {
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::OFF));
ASSERT_NO_FATAL_FAILURE(
@@ -465,7 +448,7 @@
*
* Test that IComposerClient::getColorMode always returns ColorMode::NATIVE
*/
-TEST_F(GraphicsComposerHidlTest, GetColorModes) {
+TEST_P(GraphicsComposerHidlTest, GetColorModes) {
std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
auto nativeModeLocation = std::find(modes.begin(), modes.end(), ColorMode::NATIVE);
@@ -477,7 +460,7 @@
*
* Test that IComposerClient::setColorMode succeeds for all color modes.
*/
-TEST_F(GraphicsComposerHidlTest, SetColorMode) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode) {
std::unordered_set<ColorMode> validModes;
for (auto mode : hidl_enum_range<ColorMode>()) {
validModes.insert(mode);
@@ -497,7 +480,7 @@
* Test that IComposerClient::setColorMode returns BAD_DISPLAY for
* an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, SetColorModeBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, SetColorModeBadDisplay) {
std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
for (auto mode : modes) {
Error error = mComposerClient->getRaw()->setColorMode(mInvalidDisplayId, mode);
@@ -511,7 +494,7 @@
* Test that IComposerClient::setColorMode returns BAD_PARAMETER when passed in
* an invalid color mode
*/
-TEST_F(GraphicsComposerHidlTest, SetColorModeBadParameter) {
+TEST_P(GraphicsComposerHidlTest, SetColorModeBadParameter) {
Error error =
mComposerClient->getRaw()->setColorMode(mPrimaryDisplay, static_cast<ColorMode>(-1));
ASSERT_EQ(Error::BAD_PARAMETER, error);
@@ -523,7 +506,7 @@
* Test that IComposerClient::getDozeSupport returns
* BAD_DISPLAY when passed an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, GetDozeSupportBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetDozeSupportBadDisplay) {
Error error;
mComposerClient->getRaw()->getDozeSupport(
mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; });
@@ -535,7 +518,7 @@
*
* Test that IComposerClient::setPowerMode succeeds for all power modes.
*/
-TEST_F(GraphicsComposerHidlTest, SetPowerMode) {
+TEST_P(GraphicsComposerHidlTest, SetPowerMode) {
std::vector<IComposerClient::PowerMode> modes;
modes.push_back(IComposerClient::PowerMode::OFF);
@@ -558,7 +541,7 @@
* Test IComposerClient::setPowerMode succeeds with different
* orderings of power modes
*/
-TEST_F(GraphicsComposerHidlTest, SetPowerModeVariations) {
+TEST_P(GraphicsComposerHidlTest, SetPowerModeVariations) {
std::vector<IComposerClient::PowerMode> modes;
modes.push_back(IComposerClient::PowerMode::OFF);
modes.push_back(IComposerClient::PowerMode::ON);
@@ -609,7 +592,7 @@
* Test IComposerClient::setPowerMode returns BAD_DISPLAY when passed an invalid
* display handle
*/
-TEST_F(GraphicsComposerHidlTest, SetPowerModeBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, SetPowerModeBadDisplay) {
Error error =
mComposerClient->getRaw()->setPowerMode(mInvalidDisplayId, IComposerClient::PowerMode::ON);
ASSERT_EQ(Error::BAD_DISPLAY, error);
@@ -621,7 +604,7 @@
* Test that IComposerClient::setPowerMode returns UNSUPPORTED when passed DOZE
* or DOZE_SUSPEND on devices that do not support DOZE/DOZE_SUSPEND
*/
-TEST_F(GraphicsComposerHidlTest, SetPowerModeUnsupported) {
+TEST_P(GraphicsComposerHidlTest, SetPowerModeUnsupported) {
if (!mComposerClient->getDozeSupport(mPrimaryDisplay)) {
Error error = mComposerClient->getRaw()->setPowerMode(mPrimaryDisplay,
IComposerClient::PowerMode::DOZE);
@@ -639,7 +622,7 @@
* Tests that IComposerClient::setPowerMode returns BAD_PARAMETER when passed an invalid
* PowerMode
*/
-TEST_F(GraphicsComposerHidlTest, SetPowerModeBadParameter) {
+TEST_P(GraphicsComposerHidlTest, SetPowerModeBadParameter) {
Error error = mComposerClient->getRaw()->setPowerMode(
mPrimaryDisplay, static_cast<IComposerClient::PowerMode>(-1));
ASSERT_EQ(Error::BAD_PARAMETER, error);
@@ -651,7 +634,7 @@
* Test that IComposerClient::setVsyncEnabled succeeds and there is no
* spurious vsync events.
*/
-TEST_F(GraphicsComposerHidlTest, SetVsyncEnabled) {
+TEST_P(GraphicsComposerHidlTest, SetVsyncEnabled) {
mComposerCallback->setVsyncAllowed(true);
mComposerClient->setVsyncEnabled(mPrimaryDisplay, true);
@@ -703,7 +686,7 @@
/**
* Test IComposerClient::Command::SET_COLOR_TRANSFORM.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_COLOR_TRANSFORM) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_COLOR_TRANSFORM) {
const std::array<float, 16> identity = {{
1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1.0f,
@@ -718,7 +701,7 @@
/**
* Test IComposerClient::Command::SET_CLIENT_TARGET.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_CLIENT_TARGET) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_CLIENT_TARGET) {
mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount);
mWriter->selectDisplay(mPrimaryDisplay);
@@ -731,7 +714,7 @@
/**
* Test IComposerClient::Command::SET_OUTPUT_BUFFER.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_OUTPUT_BUFFER) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_OUTPUT_BUFFER) {
if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
GTEST_SUCCEED() << "no virtual display support";
return;
@@ -754,7 +737,7 @@
/**
* Test IComposerClient::Command::VALIDATE_DISPLAY.
*/
-TEST_F(GraphicsComposerHidlCommandTest, VALIDATE_DISPLAY) {
+TEST_P(GraphicsComposerHidlCommandTest, VALIDATE_DISPLAY) {
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->validateDisplay();
execute();
@@ -763,7 +746,7 @@
/**
* Test IComposerClient::Command::ACCEPT_DISPLAY_CHANGES.
*/
-TEST_F(GraphicsComposerHidlCommandTest, ACCEPT_DISPLAY_CHANGES) {
+TEST_P(GraphicsComposerHidlCommandTest, ACCEPT_DISPLAY_CHANGES) {
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->validateDisplay();
mWriter->acceptDisplayChanges();
@@ -773,7 +756,7 @@
/**
* Test IComposerClient::Command::PRESENT_DISPLAY.
*/
-TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) {
+TEST_P(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) {
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->validateDisplay();
mWriter->presentDisplay();
@@ -787,7 +770,13 @@
* additional call to validateDisplay when only the layer buffer handle and
* surface damage have been set
*/
-TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) {
+TEST_P(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) {
+ if (!mComposer->hasCapability(
+ static_cast<IComposer::Capability>(HWC2_CAPABILITY_SKIP_VALIDATE))) {
+ std::cout << "Device does not have skip validate capability, skipping" << std::endl;
+ GTEST_SUCCEED();
+ return;
+ }
mWriter->selectDisplay(mPrimaryDisplay);
mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON);
mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE);
@@ -837,7 +826,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_CURSOR_POSITION.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -879,7 +868,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_BUFFER.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER) {
auto handle = allocate();
ASSERT_NE(nullptr, handle);
@@ -896,7 +885,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -915,7 +904,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_BLEND_MODE.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BLEND_MODE) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_BLEND_MODE) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -931,7 +920,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_COLOR.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COLOR) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_COLOR) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -946,7 +935,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COMPOSITION_TYPE) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_COMPOSITION_TYPE) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -963,7 +952,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_DATASPACE.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DATASPACE) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_DATASPACE) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -977,7 +966,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_DISPLAY_FRAME.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DISPLAY_FRAME) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_DISPLAY_FRAME) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -991,7 +980,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_PLANE_ALPHA.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PLANE_ALPHA) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_PLANE_ALPHA) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -1006,7 +995,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SIDEBAND_STREAM) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_SIDEBAND_STREAM) {
if (!mComposer->hasCapability(IComposer::Capability::SIDEBAND_STREAM)) {
GTEST_SUCCEED() << "no sideband stream support";
return;
@@ -1028,7 +1017,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_SOURCE_CROP.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SOURCE_CROP) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_SOURCE_CROP) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -1042,7 +1031,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_TRANSFORM.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_TRANSFORM) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_TRANSFORM) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -1063,7 +1052,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_VISIBLE_REGION.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_VISIBLE_REGION) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_VISIBLE_REGION) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -1082,7 +1071,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_Z_ORDER.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -1094,6 +1083,16 @@
execute();
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GraphicsComposerHidlCommandTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GraphicsComposerHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
} // namespace
} // namespace vts
} // namespace V2_1
@@ -1101,13 +1100,3 @@
} // namespace graphics
} // namespace hardware
} // namespace android
-
-int main(int argc, char** argv) {
- using android::hardware::graphics::composer::V2_1::vts::GraphicsComposerHidlEnvironment;
- ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
diff --git a/graphics/composer/2.2/default/Android.mk b/graphics/composer/2.2/default/Android.mk
index 4916557..156ecb6 100644
--- a/graphics/composer/2.2/default/Android.mk
+++ b/graphics/composer/2.2/default/Android.mk
@@ -11,8 +11,8 @@
LOCAL_SHARED_LIBRARIES := \
android.hardware.graphics.composer@2.1 \
android.hardware.graphics.composer@2.2 \
- android.hardware.graphics.mapper@2.0 \
- android.hardware.graphics.mapper@3.0 \
+ android.hardware.graphics.composer@2.1-resources \
+ android.hardware.graphics.composer@2.2-resources \
libbase \
libbinder \
libcutils \
diff --git a/graphics/composer/2.2/utils/OWNERS b/graphics/composer/2.2/utils/OWNERS
index a17a50c..3f1e82c 100644
--- a/graphics/composer/2.2/utils/OWNERS
+++ b/graphics/composer/2.2/utils/OWNERS
@@ -3,7 +3,3 @@
lpy@google.com
stoza@google.com
vhau@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
diff --git a/graphics/composer/2.2/utils/command-buffer/Android.bp b/graphics/composer/2.2/utils/command-buffer/Android.bp
index efaabd4..c4ceaab 100644
--- a/graphics/composer/2.2/utils/command-buffer/Android.bp
+++ b/graphics/composer/2.2/utils/command-buffer/Android.bp
@@ -3,11 +3,16 @@
defaults: ["hidl_defaults"],
vendor_available: true,
shared_libs: [
- "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ ],
+ export_shared_lib_headers: [
"android.hardware.graphics.composer@2.2",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
export_include_dirs: ["include"],
}
diff --git a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
index 138d700..00f427a 100644
--- a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
+++ b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
@@ -76,15 +76,14 @@
static constexpr uint16_t kSetLayerFloatColorLength = 4;
void setLayerFloatColor(IComposerClient::FloatColor color) {
- beginCommand_2_2(IComposerClient::Command::SET_LAYER_FLOAT_COLOR,
- kSetLayerFloatColorLength);
+ beginCommand(IComposerClient::Command::SET_LAYER_FLOAT_COLOR, kSetLayerFloatColorLength);
writeFloatColor(color);
endCommand();
}
void setLayerPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) {
- beginCommand_2_2(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
- metadataVec.size() * 2);
+ beginCommand(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
+ metadataVec.size() * 2);
for (const auto& metadata : metadataVec) {
writeSigned(static_cast<int32_t>(metadata.key));
writeFloat(metadata.value);
@@ -93,11 +92,6 @@
}
protected:
- void beginCommand_2_2(IComposerClient::Command command, uint16_t length) {
- V2_1::CommandWriterBase::beginCommand(
- static_cast<V2_1::IComposerClient::Command>(static_cast<int32_t>(command)), length);
- }
-
void writeFloatColor(const IComposerClient::FloatColor& color) {
writeFloat(color.r);
writeFloat(color.g);
diff --git a/graphics/composer/2.2/utils/hal/Android.bp b/graphics/composer/2.2/utils/hal/Android.bp
index 10dcae4..f334a11 100644
--- a/graphics/composer/2.2/utils/hal/Android.bp
+++ b/graphics/composer/2.2/utils/hal/Android.bp
@@ -19,9 +19,11 @@
vendor_available: true,
shared_libs: [
"android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.2-resources",
],
export_shared_lib_headers: [
"android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.2-resources",
],
header_libs: [
"android.hardware.graphics.composer@2.2-command-buffer",
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
index c760d0a..512d39d 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
@@ -24,7 +24,7 @@
#include <composer-hal/2.1/ComposerClient.h>
#include <composer-hal/2.2/ComposerCommandEngine.h>
#include <composer-hal/2.2/ComposerHal.h>
-#include <composer-hal/2.2/ComposerResources.h>
+#include <composer-resources/2.2/ComposerResources.h>
namespace android {
namespace hardware {
@@ -89,7 +89,7 @@
auto resources = static_cast<ComposerResources*>(mResources.get());
const native_handle_t* readbackBuffer;
- ComposerResources::ReplacedBufferHandle replacedReadbackBuffer;
+ ComposerResources::ReplacedHandle replacedReadbackBuffer(true);
error = resources->getDisplayReadbackBuffer(display, buffer.getNativeHandle(),
&readbackBuffer, &replacedReadbackBuffer);
if (error != Error::NONE) {
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
index 97e3a9e..8d70ba2 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
@@ -23,7 +23,7 @@
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
#include <composer-hal/2.1/ComposerCommandEngine.h>
#include <composer-hal/2.2/ComposerHal.h>
-#include <composer-hal/2.2/ComposerResources.h>
+#include <composer-resources/2.2/ComposerResources.h>
namespace android {
namespace hardware {
@@ -49,6 +49,11 @@
}
}
+ std::unique_ptr<V2_1::CommandWriterBase> createCommandWriter(
+ size_t writerInitialSize) override {
+ return std::make_unique<CommandWriterBase>(writerInitialSize);
+ }
+
bool executeSetLayerPerFrameMetadata(uint16_t length) {
// (key, value) pairs
if (length % 2 != 0) {
@@ -65,7 +70,7 @@
auto err = mHal->setLayerPerFrameMetadata(mCurrentDisplay, mCurrentLayer, metadata);
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -78,7 +83,7 @@
auto err = mHal->setLayerFloatColor(mCurrentDisplay, mCurrentLayer, readFloatColor());
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
deleted file mode 100644
index 85b6651..0000000
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#ifndef LOG_TAG
-#warning "ComposerResources.h included without LOG_TAG"
-#endif
-
-#include <composer-hal/2.1/ComposerResources.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_2 {
-namespace hal {
-
-using V2_1::hal::ComposerHandleCache;
-using V2_1::hal::ComposerHandleImporter;
-
-class ComposerDisplayResource : public V2_1::hal::ComposerDisplayResource {
- public:
- ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
- uint32_t outputBufferCacheSize)
- : V2_1::hal::ComposerDisplayResource(type, importer, outputBufferCacheSize),
- mReadbackBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, 1) {}
-
- Error getReadbackBuffer(const native_handle_t* inHandle, const native_handle_t** outHandle,
- const native_handle** outReplacedHandle) {
- const uint32_t slot = 0;
- const bool fromCache = false;
- return mReadbackBufferCache.getHandle(slot, fromCache, inHandle, outHandle,
- outReplacedHandle);
- }
-
- protected:
- ComposerHandleCache mReadbackBufferCache;
-};
-
-class ComposerResources : public V2_1::hal::ComposerResources {
- public:
- static std::unique_ptr<ComposerResources> create() {
- auto resources = std::make_unique<ComposerResources>();
- return resources->init() ? std::move(resources) : nullptr;
- }
-
- Error getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
- const native_handle_t** outHandle,
- ReplacedBufferHandle* outReplacedHandle) {
- // import buffer
- const native_handle_t* importedHandle;
- Error error = mImporter.importBuffer(rawHandle, &importedHandle);
- if (error != Error::NONE) {
- return error;
- }
-
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-
- auto iter = mDisplayResources.find(display);
- if (iter == mDisplayResources.end()) {
- mImporter.freeBuffer(importedHandle);
- return Error::BAD_DISPLAY;
- }
- ComposerDisplayResource& displayResource =
- *static_cast<ComposerDisplayResource*>(iter->second.get());
-
- // update cache
- const native_handle_t* replacedHandle;
- error = displayResource.getReadbackBuffer(importedHandle, outHandle, &replacedHandle);
- if (error != Error::NONE) {
- mImporter.freeBuffer(importedHandle);
- return error;
- }
-
- outReplacedHandle->reset(&mImporter, replacedHandle);
- return Error::NONE;
- }
-
- protected:
- std::unique_ptr<V2_1::hal::ComposerDisplayResource> createDisplayResource(
- ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override {
- return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
- }
-};
-
-} // namespace hal
-} // namespace V2_2
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
index 93da0a5..9b3aa90 100644
--- a/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
+++ b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
@@ -173,6 +173,14 @@
Error getRenderIntents(Display display, ColorMode mode,
std::vector<RenderIntent>* outIntents) override {
if (!mDispatch.getRenderIntents) {
+ IComposerClient::DisplayType type;
+ if (getDisplayType(display, &type) == Error::BAD_DISPLAY) {
+ return Error::BAD_DISPLAY;
+ }
+ if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3) {
+ return Error::BAD_PARAMETER;
+ }
+
*outIntents = std::vector<RenderIntent>({RenderIntent::COLORIMETRIC});
return Error::NONE;
}
@@ -199,6 +207,9 @@
Error setColorMode_2_2(Display display, ColorMode mode, RenderIntent intent) override {
if (!mDispatch.setColorModeWithRenderIntent) {
+ if (intent < RenderIntent::COLORIMETRIC || intent > RenderIntent::TONE_MAP_ENHANCE) {
+ return Error::BAD_PARAMETER;
+ }
if (intent != RenderIntent::COLORIMETRIC) {
return Error::UNSUPPORTED;
}
@@ -282,6 +293,7 @@
private:
using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
using BaseType2_1::getColorModes;
+ using BaseType2_1::getDisplayType;
using BaseType2_1::mDevice;
using BaseType2_1::setColorMode;
using BaseType2_1::createVirtualDisplay;
diff --git a/graphics/composer/2.2/utils/resources/Android.bp b/graphics/composer/2.2/utils/resources/Android.bp
new file mode 100644
index 0000000..752eb81
--- /dev/null
+++ b/graphics/composer/2.2/utils/resources/Android.bp
@@ -0,0 +1,29 @@
+//
+// 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.graphics.composer@2.2-resources",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.1-resources",
+ "android.hardware.graphics.composer@2.2",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.1-resources",
+ "android.hardware.graphics.composer@2.2",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.2/utils/resources/ComposerResources.cpp b/graphics/composer/2.2/utils/resources/ComposerResources.cpp
new file mode 100644
index 0000000..a0610a3
--- /dev/null
+++ b/graphics/composer/2.2/utils/resources/ComposerResources.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ComposerResources 2.2"
+
+#include "composer-resources/2.2/ComposerResources.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+using V2_1::hal::ComposerHandleCache;
+using V2_1::hal::ComposerHandleImporter;
+
+Error ComposerDisplayResource::getReadbackBuffer(const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ const uint32_t slot = 0;
+ const bool fromCache = false;
+ return mReadbackBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+std::unique_ptr<ComposerResources> ComposerResources::create() {
+ auto resources = std::make_unique<ComposerResources>();
+ return resources->init() ? std::move(resources) : nullptr;
+}
+
+Error ComposerResources::getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
+ const native_handle_t** outHandle,
+ ReplacedHandle* outReplacedHandle) {
+ // import buffer
+ const native_handle_t* importedHandle;
+ Error error = mImporter.importBuffer(rawHandle, &importedHandle);
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+
+ auto iter = mDisplayResources.find(display);
+ if (iter == mDisplayResources.end()) {
+ mImporter.freeBuffer(importedHandle);
+ return Error::BAD_DISPLAY;
+ }
+ ComposerDisplayResource& displayResource =
+ *static_cast<ComposerDisplayResource*>(iter->second.get());
+
+ // update cache
+ const native_handle_t* replacedHandle;
+ error = displayResource.getReadbackBuffer(importedHandle, outHandle, &replacedHandle);
+ if (error != Error::NONE) {
+ mImporter.freeBuffer(importedHandle);
+ return error;
+ }
+
+ outReplacedHandle->reset(&mImporter, replacedHandle);
+ return Error::NONE;
+}
+
+} // namespace hal
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h b/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
new file mode 100644
index 0000000..33012e9
--- /dev/null
+++ b/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerResources.h included without LOG_TAG"
+#endif
+
+#include <composer-resources/2.1/ComposerResources.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+using V2_1::hal::ComposerHandleCache;
+using V2_1::hal::ComposerHandleImporter;
+
+class ComposerDisplayResource : public V2_1::hal::ComposerDisplayResource {
+ public:
+ ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+ uint32_t outputBufferCacheSize)
+ : V2_1::hal::ComposerDisplayResource(type, importer, outputBufferCacheSize),
+ mReadbackBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, 1) {}
+
+ Error getReadbackBuffer(const native_handle_t* inHandle, const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ const uint32_t slot = 0;
+ const bool fromCache = false;
+ return mReadbackBufferCache.getHandle(slot, fromCache, inHandle, outHandle,
+ outReplacedHandle);
+ }
+
+ protected:
+ ComposerHandleCache mReadbackBufferCache;
+};
+
+class ComposerResources : public V2_1::hal::ComposerResources {
+ public:
+ static std::unique_ptr<ComposerResources> create() {
+ auto resources = std::make_unique<ComposerResources>();
+ return resources->init() ? std::move(resources) : nullptr;
+ }
+
+ Error getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
+ const native_handle_t** outHandle,
+ ReplacedHandle* outReplacedHandle) {
+ // import buffer
+ const native_handle_t* importedHandle;
+ Error error = mImporter.importBuffer(rawHandle, &importedHandle);
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+
+ auto iter = mDisplayResources.find(display);
+ if (iter == mDisplayResources.end()) {
+ mImporter.freeBuffer(importedHandle);
+ return Error::BAD_DISPLAY;
+ }
+ ComposerDisplayResource& displayResource =
+ *static_cast<ComposerDisplayResource*>(iter->second.get());
+
+ // update cache
+ const native_handle_t* replacedHandle;
+ error = displayResource.getReadbackBuffer(importedHandle, outHandle, &replacedHandle);
+ if (error != Error::NONE) {
+ mImporter.freeBuffer(importedHandle);
+ return error;
+ }
+
+ outReplacedHandle->reset(&mImporter, replacedHandle);
+ return Error::NONE;
+ }
+
+ protected:
+ std::unique_ptr<V2_1::hal::ComposerDisplayResource> createDisplayResource(
+ ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override {
+ return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
+ }
+};
+
+} // namespace hal
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index dd979cb..5432882 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -19,26 +19,36 @@
defaults: ["hidl_defaults"],
srcs: [
"ComposerVts.cpp",
+ "ReadbackVts.cpp",
+ "RenderEngineVts.cpp",
+ ],
+ shared_libs: [
+ "libui",
],
static_libs: [
"VtsHalHidlTargetTestBase",
- "android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
- "android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@2.1-vts",
+ "libarect",
+ "libmath",
+ "libnativewindow",
+ "librenderengine",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hardware.graphics.mapper@4.0-vts",
],
export_static_lib_headers: [
+ "VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1-vts",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.mapper@2.1-vts",
],
header_libs: [
- "android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
],
export_header_lib_headers: [
- "android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
],
cflags: [
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index cd6772a..93b67f0 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -182,17 +182,23 @@
Gralloc::Gralloc() {
[this] {
- ALOGD("Attempting to initialize gralloc3");
- ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+ ALOGD("Attempting to initialize gralloc4");
+ ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
/*errOnFailure=*/false));
- if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) {
- mGralloc3 = nullptr;
- ALOGD("Failed to create gralloc3, initializing gralloc2_1");
- mGralloc2_1 = std::make_shared<Gralloc2_1>(/*errOnFailure*/ false);
- if (!mGralloc2_1->getMapper()) {
- mGralloc2_1 = nullptr;
- ALOGD("Failed to create gralloc2_1, initializing gralloc2");
- ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+ if (mGralloc4->getMapper() == nullptr || mGralloc4->getAllocator() == nullptr) {
+ mGralloc4 = nullptr;
+ ALOGD("Failed to initialize gralloc4, initializing gralloc3");
+ ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+ /*errOnFailure=*/false));
+ if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) {
+ mGralloc3 = nullptr;
+ ALOGD("Failed to initialize gralloc3, initializing gralloc2_1");
+ mGralloc2_1 = std::make_shared<Gralloc2_1>(/*errOnFailure*/ false);
+ if (!mGralloc2_1->getMapper()) {
+ mGralloc2_1 = nullptr;
+ ALOGD("Failed to initialize gralloc2_1, initializing gralloc2");
+ ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+ }
}
}
}();
@@ -201,7 +207,15 @@
bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle, uint32_t width,
uint32_t height, uint32_t layerCount, PixelFormat format,
uint64_t usage, uint32_t stride) {
- if (mGralloc3) {
+ if (mGralloc4) {
+ IMapper4::BufferDescriptorInfo info{};
+ info.width = width;
+ info.height = height;
+ info.layerCount = layerCount;
+ info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
+ info.usage = usage;
+ return mGralloc4->validateBufferSize(bufferHandle, info, stride);
+ } else if (mGralloc3) {
IMapper3::BufferDescriptorInfo info{};
info.width = width;
info.height = height;
diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
new file mode 100644
index 0000000..7bb9121
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <composer-vts/2.2/ReadbackVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+
+void TestLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
+ writer->selectLayer(mLayer);
+ writer->setLayerDisplayFrame(mDisplayFrame);
+ writer->setLayerSourceCrop(mSourceCrop);
+ writer->setLayerZOrder(mZOrder);
+ writer->setLayerSurfaceDamage(mSurfaceDamage);
+ writer->setLayerTransform(mTransform);
+ writer->setLayerPlaneAlpha(mAlpha);
+ writer->setLayerBlendMode(mBlendMode);
+}
+
+const std::vector<ColorMode> ReadbackHelper::colorModes = {ColorMode::SRGB, ColorMode::DISPLAY_P3};
+const std::vector<Dataspace> ReadbackHelper::dataspaces = {Dataspace::V0_SRGB,
+ Dataspace::DISPLAY_P3};
+
+std::string ReadbackHelper::getColorModeString(ColorMode mode) {
+ switch (mode) {
+ case ColorMode::SRGB:
+ return std::string("SRGB");
+ case ColorMode::DISPLAY_P3:
+ return std::string("DISPLAY_P3");
+ default:
+ return std::string("Unsupported color mode for readback");
+ }
+}
+
+std::string ReadbackHelper::getDataspaceString(Dataspace dataspace) {
+ switch (dataspace) {
+ case Dataspace::V0_SRGB:
+ return std::string("V0_SRGB");
+ case Dataspace::DISPLAY_P3:
+ return std::string("DISPLAY_P3");
+ case Dataspace::UNKNOWN:
+ return std::string("UNKNOWN");
+ default:
+ return std::string("Unsupported dataspace for readback");
+ }
+}
+
+Dataspace ReadbackHelper::getDataspaceForColorMode(ColorMode mode) {
+ switch (mode) {
+ case ColorMode::DISPLAY_P3:
+ return Dataspace::DISPLAY_P3;
+ case ColorMode::SRGB:
+ default:
+ return Dataspace::UNKNOWN;
+ }
+}
+
+LayerSettings TestLayer::toRenderEngineLayerSettings() {
+ LayerSettings layerSettings;
+
+ layerSettings.alpha = half(mAlpha);
+ layerSettings.disableBlending = mBlendMode == IComposerClient::BlendMode::NONE;
+ layerSettings.geometry.boundaries = FloatRect(
+ static_cast<float>(mDisplayFrame.left), static_cast<float>(mDisplayFrame.top),
+ static_cast<float>(mDisplayFrame.right), static_cast<float>(mDisplayFrame.bottom));
+
+ const mat4 translation = mat4::translate(
+ vec4((mTransform & Transform::FLIP_H ? -mDisplayFrame.right : 0.0f),
+ (mTransform & Transform::FLIP_V ? -mDisplayFrame.bottom : 0.0f), 0.0f, 1.0f));
+
+ const mat4 scale = mat4::scale(vec4(mTransform & Transform::FLIP_H ? -1.0f : 1.0f,
+ mTransform & Transform::FLIP_V ? -1.0f : 1.0f, 1.0f, 1.0f));
+
+ layerSettings.geometry.positionTransform = scale * translation;
+
+ return layerSettings;
+}
+
+int32_t ReadbackHelper::GetBytesPerPixel(PixelFormat pixelFormat) {
+ switch (pixelFormat) {
+ case PixelFormat::RGBA_8888:
+ return 4;
+ case PixelFormat::RGB_888:
+ return 3;
+ default:
+ return -1;
+ }
+}
+
+void ReadbackHelper::fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
+ PixelFormat pixelFormat,
+ std::vector<IComposerClient::Color> desiredPixelColors) {
+ ASSERT_TRUE(pixelFormat == PixelFormat::RGB_888 || pixelFormat == PixelFormat::RGBA_8888);
+ int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
+ ASSERT_NE(-1, bytesPerPixel);
+ for (int row = 0; row < height; row++) {
+ for (int col = 0; col < width; col++) {
+ int pixel = row * width + col;
+ IComposerClient::Color srcColor = desiredPixelColors[pixel];
+
+ int offset = (row * stride + col) * bytesPerPixel;
+ uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+ pixelColor[0] = srcColor.r;
+ pixelColor[1] = srcColor.g;
+ pixelColor[2] = srcColor.b;
+
+ if (bytesPerPixel == 4) {
+ pixelColor[3] = srcColor.a;
+ }
+ }
+ }
+}
+
+void ReadbackHelper::clearColors(std::vector<IComposerClient::Color>& expectedColors, int32_t width,
+ int32_t height, int32_t displayWidth) {
+ for (int row = 0; row < height; row++) {
+ for (int col = 0; col < width; col++) {
+ int pixel = row * displayWidth + col;
+ expectedColors[pixel] = BLACK;
+ }
+ }
+}
+
+void ReadbackHelper::fillColorsArea(std::vector<IComposerClient::Color>& expectedColors,
+ int32_t stride, IComposerClient::Rect area,
+ IComposerClient::Color color) {
+ for (int row = area.top; row < area.bottom; row++) {
+ for (int col = area.left; col < area.right; col++) {
+ int pixel = row * stride + col;
+ expectedColors[pixel] = color;
+ }
+ }
+}
+
+bool ReadbackHelper::readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
+ const Error error) {
+ if (error != Error::NONE) {
+ return false;
+ }
+ // TODO: add support for RGBA_1010102
+ if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
+ return false;
+ }
+ if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
+ return false;
+ }
+ return true;
+}
+
+void ReadbackHelper::compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
+ void* bufferData, const uint32_t stride,
+ const uint32_t width, const uint32_t height,
+ const PixelFormat pixelFormat) {
+ const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
+ ASSERT_NE(-1, bytesPerPixel);
+ for (int row = 0; row < height; row++) {
+ for (int col = 0; col < width; col++) {
+ int pixel = row * width + col;
+ int offset = (row * stride + col) * bytesPerPixel;
+ uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+
+ ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
+ ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
+ ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
+ }
+ }
+}
+
+ReadbackBuffer::ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
+ const std::shared_ptr<Gralloc>& gralloc, uint32_t width,
+ uint32_t height, PixelFormat pixelFormat, Dataspace dataspace) {
+ mDisplay = display;
+
+ mComposerClient = client;
+ mGralloc = gralloc;
+
+ mPixelFormat = pixelFormat;
+ mDataspace = dataspace;
+
+ mWidth = width;
+ mHeight = height;
+ mLayerCount = 1;
+ mFormat = mPixelFormat;
+ mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
+
+ mAccessRegion.top = 0;
+ mAccessRegion.left = 0;
+ mAccessRegion.width = width;
+ mAccessRegion.height = height;
+}
+
+ReadbackBuffer::~ReadbackBuffer() {
+ if (mBufferHandle != nullptr) {
+ mGralloc->freeBuffer(mBufferHandle);
+ }
+}
+
+void ReadbackBuffer::setReadbackBuffer() {
+ if (mBufferHandle != nullptr) {
+ mGralloc->freeBuffer(mBufferHandle);
+ mBufferHandle = nullptr;
+ }
+ mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
+ /*import*/ true, &mStride);
+ ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount,
+ mFormat, mUsage, mStride));
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1));
+}
+
+void ReadbackBuffer::checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors) {
+ // lock buffer for reading
+ int32_t fenceHandle;
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle));
+
+ void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, fenceHandle);
+ ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
+ ReadbackHelper::compareColorBuffers(expectedColors, bufData, mStride, mWidth, mHeight,
+ mPixelFormat);
+ int32_t unlockFence = mGralloc->unlock(mBufferHandle);
+ if (unlockFence != -1) {
+ sync_wait(unlockFence, -1);
+ close(unlockFence);
+ }
+}
+
+void TestColorLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
+ TestLayer::write(writer);
+ writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
+ writer->setLayerColor(mColor);
+}
+
+LayerSettings TestColorLayer::toRenderEngineLayerSettings() {
+ LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
+
+ layerSettings.source.solidColor =
+ half3(static_cast<half>(mColor.r) / 255.0, static_cast<half>(mColor.g) / 255.0,
+ static_cast<half>(mColor.b) / 255.0);
+ layerSettings.alpha = mAlpha * (static_cast<half>(mColor.a) / 255.0);
+ return layerSettings;
+}
+
+TestBufferLayer::TestBufferLayer(const std::shared_ptr<ComposerClient>& client,
+ const std::shared_ptr<Gralloc>& gralloc, Display display,
+ int32_t width, int32_t height, PixelFormat format,
+ IComposerClient::Composition composition)
+ : TestLayer{client, display} {
+ mGralloc = gralloc;
+ mComposition = composition;
+ mWidth = width;
+ mHeight = height;
+ mLayerCount = 1;
+ mFormat = format;
+ mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY);
+
+ mAccessRegion.top = 0;
+ mAccessRegion.left = 0;
+ mAccessRegion.width = width;
+ mAccessRegion.height = height;
+
+ setSourceCrop({0, 0, (float)width, (float)height});
+}
+
+TestBufferLayer::~TestBufferLayer() {
+ if (mBufferHandle != nullptr) {
+ mGralloc->freeBuffer(mBufferHandle);
+ }
+}
+
+void TestBufferLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
+ TestLayer::write(writer);
+ writer->setLayerCompositionType(mComposition);
+ writer->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, mDisplayFrame));
+ if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence);
+}
+
+LayerSettings TestBufferLayer::toRenderEngineLayerSettings() {
+ LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
+ layerSettings.source.buffer.buffer =
+ new GraphicBuffer(mBufferHandle, GraphicBuffer::CLONE_HANDLE, mWidth, mHeight,
+ static_cast<int32_t>(mFormat), 1, mUsage, mStride);
+
+ layerSettings.source.buffer.usePremultipliedAlpha =
+ mBlendMode == IComposerClient::BlendMode::PREMULTIPLIED;
+
+ const float scaleX = (mSourceCrop.right - mSourceCrop.left) / (mWidth);
+ const float scaleY = (mSourceCrop.bottom - mSourceCrop.top) / (mHeight);
+ const float translateX = mSourceCrop.left / (mWidth);
+ const float translateY = mSourceCrop.top / (mHeight);
+
+ layerSettings.source.buffer.textureTransform =
+ mat4::translate(vec4(translateX, translateY, 0, 1)) *
+ mat4::scale(vec4(scaleX, scaleY, 1.0, 1.0));
+
+ return layerSettings;
+}
+
+void TestBufferLayer::fillBuffer(std::vector<IComposerClient::Color> expectedColors) {
+ void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, -1);
+ ASSERT_NO_FATAL_FAILURE(
+ ReadbackHelper::fillBuffer(mWidth, mHeight, mStride, bufData, mFormat, expectedColors));
+ mFillFence = mGralloc->unlock(mBufferHandle);
+ if (mFillFence != -1) {
+ sync_wait(mFillFence, -1);
+ close(mFillFence);
+ }
+}
+
+void TestBufferLayer::setBuffer(std::vector<IComposerClient::Color> colors) {
+ if (mBufferHandle != nullptr) {
+ mGralloc->freeBuffer(mBufferHandle);
+ mBufferHandle = nullptr;
+ }
+ mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
+ /*import*/ true, &mStride);
+ ASSERT_NE(nullptr, mBufferHandle);
+ ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
+ ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount,
+ mFormat, mUsage, mStride));
+}
+
+void TestBufferLayer::setDataspace(Dataspace dataspace,
+ const std::shared_ptr<CommandWriterBase>& writer) {
+ writer->selectLayer(mLayer);
+ writer->setLayerDataspace(dataspace);
+}
+
+void TestBufferLayer::setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer) {
+ writer->selectLayer(mLayer);
+ writer->setLayerCompositionType(IComposerClient::Composition::CLIENT);
+}
+
+} // namespace vts
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
new file mode 100644
index 0000000..a23d72c
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <composer-vts/2.2/RenderEngineVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+
+using mapper::V2_1::IMapper;
+using renderengine::DisplaySettings;
+using renderengine::LayerSettings;
+using renderengine::RenderEngineCreationArgs;
+
+TestRenderEngine::TestRenderEngine(const RenderEngineCreationArgs& args) {
+ mFormat = static_cast<common::V1_1::PixelFormat>(args.pixelFormat);
+ mRenderEngine = renderengine::RenderEngine::create(args);
+}
+
+void TestRenderEngine::setRenderLayers(std::vector<std::shared_ptr<TestLayer>> layers) {
+ sort(layers.begin(), layers.end(),
+ [](const std::shared_ptr<TestLayer>& lhs, const std::shared_ptr<TestLayer>& rhs) -> bool {
+ return lhs->mZOrder < rhs->mZOrder;
+ });
+
+ if (!mCompositionLayers.empty()) {
+ mCompositionLayers.clear();
+ }
+ for (auto& layer : layers) {
+ LayerSettings settings = layer->toRenderEngineLayerSettings();
+ mCompositionLayers.push_back(settings);
+ }
+}
+
+void TestRenderEngine::initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
+ uint64_t usage) {
+ mGraphicBuffer =
+ new GraphicBuffer(width, height, static_cast<int32_t>(mFormat), layerCount, usage);
+}
+
+void TestRenderEngine::drawLayers() {
+ base::unique_fd bufferFence;
+ base::unique_fd readyFence;
+
+ std::vector<const renderengine::LayerSettings*> compositionLayerPointers;
+ compositionLayerPointers.reserve(mCompositionLayers.size());
+ std::transform(mCompositionLayers.begin(), mCompositionLayers.end(),
+ std::back_insert_iterator(compositionLayerPointers),
+ [](renderengine::LayerSettings& settings) -> renderengine::LayerSettings* {
+ return &settings;
+ });
+ mRenderEngine->drawLayers(mDisplaySettings, compositionLayerPointers,
+ mGraphicBuffer->getNativeBuffer(), true, std::move(bufferFence),
+ &readyFence);
+ int fd = readyFence.release();
+ if (fd != -1) {
+ ASSERT_EQ(0, sync_wait(fd, -1));
+ ASSERT_EQ(0, close(fd));
+ }
+}
+
+void TestRenderEngine::checkColorBuffer(std::vector<V2_2::IComposerClient::Color>& expectedColors) {
+ void* bufferData;
+ ASSERT_EQ(0, mGraphicBuffer->lock(mGraphicBuffer->getUsage(), &bufferData));
+ ReadbackHelper::compareColorBuffers(expectedColors, bufferData, mGraphicBuffer->getStride(),
+ mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
+ mFormat);
+ ASSERT_EQ(0, mGraphicBuffer->unlock());
+}
+
+} // namespace vts
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 8fa9b7b..5d22305 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -44,9 +44,11 @@
using common::V1_1::RenderIntent;
using IMapper2_1 = android::hardware::graphics::mapper::V2_1::IMapper;
using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
using Gralloc2_1 = android::hardware::graphics::mapper::V2_1::vts::Gralloc;
using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
+using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc;
class ComposerClient;
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
new file mode 100644
index 0000000..7519a64
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.2/ComposerVts.h>
+#include <mapper-vts/2.1/MapperVts.h>
+#include <renderengine/RenderEngine.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+
+using android::hardware::hidl_handle;
+using common::V1_1::BufferUsage;
+using common::V1_1::Dataspace;
+using common::V1_1::PixelFormat;
+using IMapper2_1 = mapper::V2_1::IMapper;
+using Gralloc2_1 = mapper::V2_1::vts::Gralloc;
+using renderengine::LayerSettings;
+using V2_1::Display;
+using V2_1::Layer;
+using V2_1::vts::AccessRegion;
+using V2_1::vts::TestCommandReader;
+
+static const IComposerClient::Color BLACK = {0, 0, 0, 0xff};
+static const IComposerClient::Color RED = {0xff, 0, 0, 0xff};
+static const IComposerClient::Color TRANSLUCENT_RED = {0xff, 0, 0, 0x33};
+static const IComposerClient::Color GREEN = {0, 0xff, 0, 0xff};
+static const IComposerClient::Color BLUE = {0, 0, 0xff, 0xff};
+
+class TestLayer {
+ public:
+ TestLayer(const std::shared_ptr<ComposerClient>& client, Display display)
+ : mLayer(client->createLayer(display, kBufferSlotCount)), mComposerClient(client) {}
+
+ // ComposerClient will take care of destroying layers, no need to explicitly
+ // call destroyLayers here
+ virtual ~TestLayer(){};
+
+ virtual void write(const std::shared_ptr<CommandWriterBase>& writer);
+ virtual LayerSettings toRenderEngineLayerSettings();
+
+ void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; }
+ void setSourceCrop(IComposerClient::FRect crop) { mSourceCrop = crop; }
+ void setZOrder(uint32_t z) { mZOrder = z; }
+
+ void setSurfaceDamage(std::vector<IComposerClient::Rect> surfaceDamage) {
+ mSurfaceDamage = surfaceDamage;
+ }
+
+ void setTransform(Transform transform) { mTransform = transform; }
+ void setAlpha(float alpha) { mAlpha = alpha; }
+ void setBlendMode(IComposerClient::BlendMode blendMode) { mBlendMode = blendMode; }
+
+ static constexpr uint32_t kBufferSlotCount = 64;
+
+ IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0};
+ uint32_t mZOrder = 0;
+ std::vector<IComposerClient::Rect> mSurfaceDamage;
+ Transform mTransform = static_cast<Transform>(0);
+ IComposerClient::FRect mSourceCrop = {0, 0, 0, 0};
+ float mAlpha = 1.0;
+ IComposerClient::BlendMode mBlendMode = IComposerClient::BlendMode::NONE;
+
+ protected:
+ Layer mLayer;
+
+ private:
+ std::shared_ptr<ComposerClient> const mComposerClient;
+};
+
+class TestColorLayer : public TestLayer {
+ public:
+ TestColorLayer(const std::shared_ptr<ComposerClient>& client, Display display)
+ : TestLayer{client, display} {}
+
+ void write(const std::shared_ptr<CommandWriterBase>& writer) override;
+
+ LayerSettings toRenderEngineLayerSettings() override;
+
+ void setColor(IComposerClient::Color color) { mColor = color; }
+
+ private:
+ IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff};
+};
+
+class TestBufferLayer : public TestLayer {
+ public:
+ TestBufferLayer(
+ const std::shared_ptr<ComposerClient>& client, const std::shared_ptr<Gralloc>& gralloc,
+ Display display, int32_t width, int32_t height, PixelFormat format,
+ IComposerClient::Composition composition = IComposerClient::Composition::DEVICE);
+
+ ~TestBufferLayer();
+
+ void write(const std::shared_ptr<CommandWriterBase>& writer) override;
+
+ LayerSettings toRenderEngineLayerSettings() override;
+
+ void fillBuffer(std::vector<IComposerClient::Color> expectedColors);
+
+ void setBuffer(std::vector<IComposerClient::Color> colors);
+
+ void setDataspace(Dataspace dataspace, const std::shared_ptr<CommandWriterBase>& writer);
+
+ void setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer);
+
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mLayerCount;
+ PixelFormat mFormat;
+ uint64_t mUsage;
+ AccessRegion mAccessRegion;
+ uint32_t mStride;
+
+ protected:
+ IComposerClient::Composition mComposition;
+ std::shared_ptr<Gralloc> mGralloc;
+ int32_t mFillFence;
+ const native_handle_t* mBufferHandle = nullptr;
+};
+
+class ReadbackHelper : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ static std::string getColorModeString(ColorMode mode);
+
+ static std::string getDataspaceString(Dataspace dataspace);
+
+ static Dataspace getDataspaceForColorMode(ColorMode mode);
+
+ static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
+
+ static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
+ PixelFormat pixelFormat,
+ std::vector<IComposerClient::Color> desiredPixelColors);
+
+ static void clearColors(std::vector<IComposerClient::Color>& expectedColors, int32_t width,
+ int32_t height, int32_t displayWidth);
+
+ static void fillColorsArea(std::vector<IComposerClient::Color>& expectedColors, int32_t stride,
+ IComposerClient::Rect area, IComposerClient::Color color);
+
+ static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
+ const Error error);
+
+ static const std::vector<ColorMode> colorModes;
+ static const std::vector<Dataspace> dataspaces;
+
+ static void compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
+ void* bufferData, const uint32_t stride, const uint32_t width,
+ const uint32_t height, const PixelFormat pixelFormat);
+};
+
+class ReadbackBuffer {
+ public:
+ ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
+ const std::shared_ptr<Gralloc>& gralloc, uint32_t width, uint32_t height,
+ PixelFormat pixelFormat, Dataspace dataspace);
+ ~ReadbackBuffer();
+
+ void setReadbackBuffer();
+
+ void checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors);
+
+ protected:
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mLayerCount;
+ PixelFormat mFormat;
+ uint64_t mUsage;
+ AccessRegion mAccessRegion;
+ uint32_t mStride;
+ const native_handle_t* mBufferHandle = nullptr;
+ PixelFormat mPixelFormat;
+ Dataspace mDataspace;
+ Display mDisplay;
+ std::shared_ptr<Gralloc> mGralloc;
+ std::shared_ptr<ComposerClient> mComposerClient;
+};
+
+} // namespace vts
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
new file mode 100644
index 0000000..b936cab
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <composer-vts/2.2/ReadbackVts.h>
+#include <math/half.h>
+#include <math/vec3.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+
+using mapper::V2_1::IMapper;
+using renderengine::DisplaySettings;
+using renderengine::RenderEngineCreationArgs;
+using vts::Gralloc;
+
+class TestRenderEngine {
+ public:
+ static constexpr uint32_t sMaxFrameBufferAcquireBuffers = 2;
+
+ TestRenderEngine(const RenderEngineCreationArgs& args);
+ ~TestRenderEngine() = default;
+
+ void setRenderLayers(std::vector<std::shared_ptr<TestLayer>> layers);
+ void initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint64_t usage);
+ void setDisplaySettings(DisplaySettings& displaySettings) {
+ mDisplaySettings = displaySettings;
+ };
+ void drawLayers();
+ void checkColorBuffer(std::vector<V2_2::IComposerClient::Color>& expectedColors);
+
+ private:
+ common::V1_1::PixelFormat mFormat;
+ std::vector<renderengine::LayerSettings> mCompositionLayers;
+ std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
+ std::vector<renderengine::LayerSettings> mRenderLayers;
+ sp<GraphicBuffer> mGraphicBuffer;
+ DisplaySettings mDisplaySettings;
+};
+
+} // namespace vts
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index a8e70ae..f987516 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -19,18 +19,25 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
- "VtsHalGraphicsComposerV2_2TargetTest.cpp",
+ "VtsHalGraphicsComposerV2_2TargetTest.cpp"
],
// TODO(b/64437680): Assume these libs are always available on the device.
shared_libs: [
+ "libEGL",
+ "libGLESv1_CM",
+ "libGLESv2",
"libfmq",
+ "libgui",
"libhidlbase",
+ "libprocessgroup",
"libsync",
+ "libui",
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
@@ -42,10 +49,14 @@
"android.hardware.graphics.mapper@2.1-vts",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hardware.graphics.mapper@4.0-vts",
+ "librenderengine"
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
],
- test_suites: ["general-tests"],
+ disable_framework: true,
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index 02c4c9c..044bd96 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,15 +16,20 @@
#define LOG_TAG "graphics_composer_hidl_hal_readback_tests@2.2"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-#include <android-base/unique_fd.h>
-#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
#include <composer-vts/2.1/TestCommandReader.h>
#include <composer-vts/2.2/ComposerVts.h>
-#include <mapper-vts/2.1/MapperVts.h>
+#include <composer-vts/2.2/ReadbackVts.h>
+#include <composer-vts/2.2/RenderEngineVts.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
namespace android {
namespace hardware {
@@ -34,130 +39,24 @@
namespace vts {
namespace {
+using android::GraphicBuffer;
+using android::Rect;
using android::hardware::hidl_handle;
using common::V1_1::BufferUsage;
using common::V1_1::Dataspace;
using common::V1_1::PixelFormat;
using mapper::V2_1::IMapper;
+using V2_1::Config;
using V2_1::Display;
-using V2_1::Layer;
-using V2_1::vts::AccessRegion;
using V2_1::vts::TestCommandReader;
+using vts::Gralloc;
-static const IComposerClient::Color BLACK = {0, 0, 0, 0xff};
-static const IComposerClient::Color RED = {0xff, 0, 0, 0xff};
-static const IComposerClient::Color TRANSLUCENT_RED = {0xff, 0, 0, 0x33};
-static const IComposerClient::Color GREEN = {0, 0xff, 0, 0xff};
-static const IComposerClient::Color BLUE = {0, 0, 0xff, 0xff};
-
-// 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 TestLayer {
- public:
- TestLayer(const std::shared_ptr<ComposerClient>& client, Display display)
- : mLayer(client->createLayer(display, kBufferSlotCount)), mComposerClient(client) {}
-
- // ComposerClient will take care of destroying layers, no need to explicitly
- // call destroyLayers here
- virtual ~TestLayer(){};
-
- virtual void write(const std::shared_ptr<CommandWriterBase>& writer) {
- writer->selectLayer(mLayer);
- writer->setLayerDisplayFrame(mDisplayFrame);
- writer->setLayerSourceCrop(mSourceCrop);
- writer->setLayerZOrder(mZOrder);
- writer->setLayerSurfaceDamage(mSurfaceDamage);
- writer->setLayerTransform(mTransform);
- writer->setLayerPlaneAlpha(mAlpha);
- writer->setLayerBlendMode(mBlendMode);
- }
-
- void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; }
- void setSourceCrop(IComposerClient::FRect crop) { mSourceCrop = crop; }
- void setZOrder(uint32_t z) { mZOrder = z; }
-
- void setSurfaceDamage(std::vector<IComposerClient::Rect> surfaceDamage) {
- mSurfaceDamage = surfaceDamage;
- }
-
- void setTransform(Transform transform) { mTransform = transform; }
- void setAlpha(float alpha) { mAlpha = alpha; }
- void setBlendMode(IComposerClient::BlendMode blendMode) { mBlendMode = blendMode; }
-
- static constexpr uint32_t kBufferSlotCount = 64;
-
- IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0};
- uint32_t mZOrder = 0;
- std::vector<IComposerClient::Rect> mSurfaceDamage;
- Transform mTransform = static_cast<Transform>(0);
- IComposerClient::FRect mSourceCrop = {0, 0, 0, 0};
- float mAlpha = 1.0;
- IComposerClient::BlendMode mBlendMode = IComposerClient::BlendMode::NONE;
-
- protected:
- Layer mLayer;
-
- private:
- std::shared_ptr<ComposerClient> const mComposerClient;
-};
-
-class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
- static int32_t GetBytesPerPixel(PixelFormat pixelFormat) {
- switch (pixelFormat) {
- case PixelFormat::RGBA_8888:
- return 4;
- case PixelFormat::RGB_888:
- return 3;
- default:
- return -1;
- }
- }
-
- static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
- PixelFormat pixelFormat,
- std::vector<IComposerClient::Color> desiredPixelColors) {
- ASSERT_TRUE(pixelFormat == PixelFormat::RGB_888 || pixelFormat == PixelFormat::RGBA_8888);
- int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
- ASSERT_NE(-1, bytesPerPixel);
- for (int row = 0; row < height; row++) {
- for (int col = 0; col < width; col++) {
- int pixel = row * width + col;
- IComposerClient::Color srcColor = desiredPixelColors[pixel];
-
- int offset = (row * stride + col) * bytesPerPixel;
- uint8_t* pixelColor = (uint8_t*)bufferData + offset;
- pixelColor[0] = srcColor.r;
- pixelColor[1] = srcColor.g;
- pixelColor[2] = srcColor.b;
-
- if (bytesPerPixel == 4) {
- pixelColor[3] = srcColor.a;
- }
- }
- }
- }
-
- protected:
+class GraphicsCompositionTestBase : public ::testing::Test {
+ protected:
using PowerMode = V2_1::IComposerClient::PowerMode;
- void SetUp() override {
- VtsHalHidlTargetTestBase::SetUp();
+ void SetUpBase(const std::string& service_name) {
ASSERT_NO_FATAL_FAILURE(
- mComposer = std::make_unique<Composer>(
- GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+ mComposer = std::make_unique<Composer>(IComposer::getService(service_name)));
ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
mComposerClient->registerCallback(mComposerCallback);
@@ -173,6 +72,8 @@
mDisplayHeight = mComposerClient->getDisplayAttribute(
mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT));
+ setTestColorModes();
+
// explicitly disable vsync
ASSERT_NO_FATAL_FAILURE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false));
mComposerCallback->setVsyncAllowed(false);
@@ -182,22 +83,28 @@
mReader = std::make_unique<TestCommandReader>();
mGralloc = std::make_shared<Gralloc>();
- std::vector<ColorMode> colorModes = mComposerClient->getColorModes(mPrimaryDisplay);
- if (std::find(colorModes.begin(), colorModes.end(), ColorMode::SRGB) == colorModes.end()) {
- mHasReadbackBuffer = false;
- return;
- }
- mWriter->selectDisplay(mPrimaryDisplay);
- ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB,
- RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = readbackSupported(tmpPixelFormat, tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON));
+
+ ASSERT_NO_FATAL_FAILURE(
+ mTestRenderEngine = std::unique_ptr<TestRenderEngine>(new TestRenderEngine(
+ renderengine::RenderEngineCreationArgs::Builder()
+ .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+ .setImageCacheSize(TestRenderEngine::sMaxFrameBufferAcquireBuffers)
+ .setUseColorManagerment(true)
+ .setEnableProtectedContext(false)
+ .setPrecacheToneMapperShaderOnly(false)
+ .setContextPriority(renderengine::RenderEngine::ContextPriority::HIGH)
+ .build())));
+
+ renderengine::DisplaySettings clientCompositionDisplay;
+ clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight);
+ clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay;
+ clientCompositionDisplay.clearRegion = Region(clientCompositionDisplay.physicalDisplay);
+
+ mTestRenderEngine->initGraphicBuffer(
+ static_cast<uint32_t>(mDisplayWidth), static_cast<uint32_t>(mDisplayHeight), 1,
+ static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN));
+ mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
}
void TearDown() override {
@@ -209,7 +116,6 @@
EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
}
- VtsHalHidlTargetTestBase::TearDown();
}
void clearCommandReaderState() {
@@ -217,10 +123,6 @@
mReader->mErrors.clear();
}
- void execute() {
- ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get()));
- }
-
void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) {
for (auto layer : layers) {
layer->write(mWriter);
@@ -228,42 +130,10 @@
execute();
}
- void clearColors(std::vector<IComposerClient::Color>& expectedColors, int32_t width,
- int32_t height) {
- for (int row = 0; row < height; row++) {
- for (int col = 0; col < width; col++) {
- int pixel = row * mDisplayWidth + col;
- expectedColors[pixel] = BLACK;
- }
- }
+ void execute() {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get()));
}
- void fillColorsArea(std::vector<IComposerClient::Color>& expectedColors, int32_t stride,
- IComposerClient::Rect area, IComposerClient::Color color) {
- for (int row = area.top; row < area.bottom; row++) {
- for (int col = area.left; col < area.right; col++) {
- int pixel = row * stride + col;
- expectedColors[pixel] = color;
- }
- }
- }
-
- bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
- const Error error) {
- if (error != Error::NONE) {
- return false;
- }
- // TODO: add support for RGBA_1010102
- if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
- return false;
- }
- if (dataspace != Dataspace::V0_SRGB) {
- return false;
- }
- return true;
- }
-
-
std::unique_ptr<Composer> mComposer;
std::shared_ptr<ComposerClient> mComposerClient;
@@ -272,9 +142,11 @@
Display mPrimaryDisplay;
int32_t mDisplayWidth;
int32_t mDisplayHeight;
+ std::vector<ColorMode> mTestColorModes;
std::shared_ptr<CommandWriterBase> mWriter;
std::unique_ptr<TestCommandReader> mReader;
std::shared_ptr<Gralloc> mGralloc;
+ std::unique_ptr<TestRenderEngine> mTestRenderEngine;
bool mHasReadbackBuffer;
PixelFormat mPixelFormat;
@@ -293,735 +165,782 @@
return displays[0];
}
}
-};
-class ReadbackBuffer {
- public:
- ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
- const std::shared_ptr<Gralloc>& gralloc, uint32_t width, uint32_t height,
- PixelFormat pixelFormat, Dataspace dataspace) {
- mDisplay = display;
- mComposerClient = client;
- mGralloc = gralloc;
-
- mFormat = pixelFormat;
- mDataspace = dataspace;
-
- mWidth = width;
- mHeight = height;
- mLayerCount = 1;
- mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
-
- mAccessRegion.top = 0;
- mAccessRegion.left = 0;
- mAccessRegion.width = width;
- mAccessRegion.height = height;
- };
-
- ~ReadbackBuffer() {
- if (mBufferHandle != nullptr) {
- mGralloc->freeBuffer(mBufferHandle);
- }
- }
-
- void setReadbackBuffer() {
- if (mBufferHandle != nullptr) {
- mGralloc->freeBuffer(mBufferHandle);
- mBufferHandle = nullptr;
- }
- mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
- /*import*/ true, &mStride);
- ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount,
- mFormat, mUsage, mStride));
- ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1));
- }
-
- void checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors) {
- // lock buffer for reading
- int32_t fenceHandle;
- ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle));
-
- void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, fenceHandle);
- ASSERT_TRUE(mFormat == PixelFormat::RGB_888 || mFormat == PixelFormat::RGBA_8888);
- int32_t bytesPerPixel = GraphicsComposerReadbackTest::GetBytesPerPixel(mFormat);
- ASSERT_NE(-1, bytesPerPixel);
- for (int row = 0; row < mHeight; row++) {
- for (int col = 0; col < mWidth; col++) {
- int pixel = row * mWidth + col;
- int offset = (row * mStride + col) * bytesPerPixel;
- uint8_t* pixelColor = (uint8_t*)bufData + offset;
-
- ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
- ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
- ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
+ void setTestColorModes() {
+ mTestColorModes.clear();
+ mComposerClient->getRaw()->getColorModes_2_2(mPrimaryDisplay, [&](const auto& tmpError,
+ const auto& tmpModes) {
+ ASSERT_EQ(Error::NONE, tmpError);
+ for (ColorMode mode : tmpModes) {
+ if (std::find(ReadbackHelper::colorModes.begin(), ReadbackHelper::colorModes.end(),
+ mode) != ReadbackHelper::colorModes.end()) {
+ mTestColorModes.push_back(mode);
+ }
}
- }
- int32_t unlockFence = mGralloc->unlock(mBufferHandle);
- if (unlockFence != -1) {
- sync_wait(unlockFence, -1);
- close(unlockFence);
- }
+ });
}
-
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mLayerCount;
- PixelFormat mFormat;
- uint64_t mUsage;
- AccessRegion mAccessRegion;
-
- protected:
- uint32_t mStride;
- const native_handle_t* mBufferHandle = nullptr;
- Dataspace mDataspace;
- Display mDisplay;
- std::shared_ptr<Gralloc> mGralloc;
- std::shared_ptr<ComposerClient> mComposerClient;
};
-class TestColorLayer : public TestLayer {
- public:
- TestColorLayer(const std::shared_ptr<ComposerClient>& client, Display display)
- : TestLayer{client, display} {}
-
- void write(const std::shared_ptr<CommandWriterBase>& writer) override {
- TestLayer::write(writer);
- writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
- writer->setLayerColor(mColor);
- }
-
- void setColor(IComposerClient::Color color) { mColor = color; }
-
- private:
- IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff};
+class GraphicsCompositionTest : public GraphicsCompositionTestBase,
+ public testing::WithParamInterface<std::string> {
+ public:
+ void SetUp() override { SetUpBase(GetParam()); }
};
-class TestBufferLayer : public TestLayer {
- public:
- TestBufferLayer(const std::shared_ptr<ComposerClient>& client,
- const std::shared_ptr<Gralloc>& gralloc, Display display, int32_t width,
- int32_t height, PixelFormat format,
- IComposerClient::Composition composition = IComposerClient::Composition::DEVICE)
- : TestLayer{client, display} {
- mGralloc = gralloc;
- mComposition = composition;
- mWidth = width;
- mHeight = height;
- mLayerCount = 1;
- mFormat = format;
- mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY);
-
- mAccessRegion.top = 0;
- mAccessRegion.left = 0;
- mAccessRegion.width = width;
- mAccessRegion.height = height;
-
- setSourceCrop({0, 0, (float)width, (float)height});
- }
-
- ~TestBufferLayer() {
- if (mBufferHandle != nullptr) {
- mGralloc->freeBuffer(mBufferHandle);
- }
- }
-
- void write(const std::shared_ptr<CommandWriterBase>& writer) override {
- TestLayer::write(writer);
- writer->setLayerCompositionType(mComposition);
- writer->setLayerDataspace(Dataspace::UNKNOWN);
- writer->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, mDisplayFrame));
- if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence);
- }
-
- void fillBuffer(std::vector<IComposerClient::Color> expectedColors) {
- void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, -1);
- ASSERT_NO_FATAL_FAILURE(GraphicsComposerReadbackTest::fillBuffer(
- mWidth, mHeight, mStride, bufData, mFormat, expectedColors));
- mFillFence = mGralloc->unlock(mBufferHandle);
- if (mFillFence != -1) {
- sync_wait(mFillFence, -1);
- close(mFillFence);
- }
- }
- void setBuffer(std::vector<IComposerClient::Color> colors) {
- if (mBufferHandle != nullptr) {
- mGralloc->freeBuffer(mBufferHandle);
- mBufferHandle = nullptr;
- }
- mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
- /*import*/ true, &mStride);
- ASSERT_NE(nullptr, mBufferHandle);
- ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
- ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount,
- mFormat, mUsage, mStride));
- }
-
- void setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer) {
- writer->selectLayer(mLayer);
- writer->setLayerCompositionType(IComposerClient::Composition::CLIENT);
- }
-
- AccessRegion mAccessRegion;
- uint32_t mStride;
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mLayerCount;
- PixelFormat mFormat;
-
- protected:
- uint64_t mUsage;
- IComposerClient::Composition mComposition;
- std::shared_ptr<Gralloc> mGralloc;
- int32_t mFillFence;
- const native_handle_t* mBufferHandle = nullptr;
-};
-
-TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
+TEST_P(GraphicsCompositionTest, SingleSolidColorLayer) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
<< std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
- }
-
- auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
- IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setColor(BLUE);
- layer->setDisplayFrame(coloredSquare);
- layer->setZOrder(10);
-
- std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
- // expected color for each pixel
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- // if hwc cannot handle and asks for composition change,
- // just succeed the test
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-}
-
-TEST_F(GraphicsComposerReadbackTest, SetLayerBuffer) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
- << std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
- }
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, GREEN);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
-
- auto layer =
- std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
- mDisplayHeight, PixelFormat::RGBA_8888);
- layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setZOrder(10);
- ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
-
- std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
-
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
-
- mWriter->presentDisplay();
- execute();
-
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-}
-
-TEST_F(GraphicsComposerReadbackTest, SetLayerBufferNoEffect) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
- << std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
- }
-
-
- auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
- IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setColor(BLUE);
- layer->setDisplayFrame(coloredSquare);
- layer->setZOrder(10);
- layer->write(mWriter);
-
- // This following buffer call should have no effect
- PixelFormat format = PixelFormat::RGBA_8888;
- uint64_t usage =
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
- const native_handle_t* bufferHandle =
- mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, format, usage);
- mWriter->setLayerBuffer(0, bufferHandle, -1);
-
- // expected color for each pixel
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- mWriter->validateDisplay();
- execute();
-
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-}
-
-TEST_F(GraphicsComposerReadbackTest, ClientComposition) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
- << std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
- }
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, GREEN);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
-
- auto layer =
- std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
- mDisplayHeight, PixelFormat::RGBA_FP16);
- layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setZOrder(10);
-
- std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
-
- if (mReader->mCompositionChanges.size() != 0) {
- ASSERT_EQ(1, mReader->mCompositionChanges.size());
- ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
-
+ mWriter->selectDisplay(mPrimaryDisplay);
ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setColor(BLUE);
+ layer->setDisplayFrame(coloredSquare);
+ layer->setZOrder(10);
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ // expected color for each pixel
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ // if hwc cannot handle and asks for composition change,
+ // just succeed the test
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ mTestRenderEngine->setRenderLayers(layers);
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+ }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerBuffer) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2},
+ GREEN);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
+ BLUE);
+
+ auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+ mDisplayWidth, mDisplayHeight,
+ PixelFormat::RGBA_8888);
+ layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setZOrder(10);
+ layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ mWriter->presentDisplay();
+ execute();
+
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ mTestRenderEngine->setRenderLayers(layers);
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+ }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setColor(BLUE);
+ layer->setDisplayFrame(coloredSquare);
+ layer->setZOrder(10);
+ layer->write(mWriter);
+
+ // This following buffer call should have no effect
+ uint64_t usage =
+ static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
+ const native_handle_t* bufferHandle =
+ mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage);
+ mWriter->setLayerBuffer(0, bufferHandle, -1);
+
+ // expected color for each pixel
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ mWriter->validateDisplay();
+ execute();
+
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ }
+}
+
+TEST_P(GraphicsCompositionTest, ClientComposition) {
+ ASSERT_NO_FATAL_FAILURE(
mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
- // create client target buffer
- uint32_t clientStride;
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2},
+ GREEN);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
+ BLUE);
+
+ auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+ mDisplayWidth, mDisplayHeight,
+ PixelFormat::RGBA_FP16);
+ layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setZOrder(10);
+ layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+
+ if (mReader->mCompositionChanges.size() != 0) {
+ ASSERT_EQ(1, mReader->mCompositionChanges.size());
+ ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
+
+ PixelFormat clientFormat = PixelFormat::RGBA_8888;
+ uint64_t clientUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN |
+ BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_CLIENT_TARGET);
+ Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
+ IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
+
+ bool clientTargetSupported = mComposerClient->getClientTargetSupport_2_2(
+ mPrimaryDisplay, layer->mWidth, layer->mHeight, clientFormat, clientDataspace);
+ // if the client target format is not supported, skip this
+ // configuration
+ if (!clientTargetSupported) {
+ std::cout << "Client target configuration width: " << layer->mWidth
+ << " height: " << layer->mHeight
+ << " pixel format: PixelFormat::RGBA_8888 dataspace: "
+ << ReadbackHelper::getDataspaceString(clientDataspace)
+ << " unsupported for display" << std::endl;
+ continue;
+ }
+
+ // create client target buffer
+ uint32_t clientStride;
+ const native_handle_t* clientBufferHandle =
+ mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount,
+ clientFormat, clientUsage, /*import*/ true, &clientStride);
+ ASSERT_NE(nullptr, clientBufferHandle);
+
+ void* clientBufData =
+ mGralloc->lock(clientBufferHandle, clientUsage, layer->mAccessRegion, -1);
+
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(layer->mWidth, layer->mHeight,
+ clientStride, clientBufData,
+ clientFormat, expectedColors));
+ int clientFence = mGralloc->unlock(clientBufferHandle);
+ if (clientFence != -1) {
+ sync_wait(clientFence, -1);
+ close(clientFence);
+ }
+
+ mWriter->setClientTarget(0, clientBufferHandle, clientFence, clientDataspace,
+ std::vector<IComposerClient::Rect>(1, damage));
+
+ layer->setToClientComposition(mWriter);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mCompositionChanges.size());
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ mWriter->presentDisplay();
+ execute();
+
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ }
+}
+
+TEST_P(GraphicsCompositionTest, DeviceAndClientComposition) {
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
+
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+ << std::endl;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ auto deviceLayer = std::make_shared<TestBufferLayer>(
+ mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2,
+ PixelFormat::RGBA_8888);
+ std::vector<IComposerClient::Color> deviceColors(deviceLayer->mWidth *
+ deviceLayer->mHeight);
+ ReadbackHelper::fillColorsArea(deviceColors, deviceLayer->mWidth,
+ {0, 0, static_cast<int32_t>(deviceLayer->mWidth),
+ static_cast<int32_t>(deviceLayer->mHeight)},
+ GREEN);
+ deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->mWidth),
+ static_cast<int32_t>(deviceLayer->mHeight)});
+ deviceLayer->setZOrder(10);
+ deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
+ deviceLayer->write(mWriter);
+
PixelFormat clientFormat = PixelFormat::RGBA_8888;
uint64_t clientUsage =
static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
BufferUsage::COMPOSER_CLIENT_TARGET);
+ Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
+ int32_t clientWidth = mDisplayWidth;
+ int32_t clientHeight = mDisplayHeight / 2;
+
+ bool clientTargetSupported = mComposerClient->getClientTargetSupport_2_2(
+ mPrimaryDisplay, clientWidth, clientHeight, clientFormat, clientDataspace);
+ // if the client target format is not supported, skip this
+ // configuration
+ if (!clientTargetSupported) {
+ std::cout << "Client target configuration width: " << clientWidth
+ << " height: " << clientHeight
+ << " pixel format: PixelFormat::RGBA_8888 dataspace: "
+ << ReadbackHelper::getDataspaceString(clientDataspace)
+ << " unsupported for display" << std::endl;
+ continue;
+ }
+
+ auto clientLayer = std::make_shared<TestBufferLayer>(
+ mComposerClient, mGralloc, mPrimaryDisplay, clientWidth, clientHeight,
+ PixelFormat::RGBA_FP16, IComposerClient::Composition::DEVICE);
+ IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
+ clientLayer->setDisplayFrame(clientFrame);
+ clientLayer->setZOrder(0);
+ clientLayer->write(mWriter);
+ mWriter->validateDisplay();
+ execute();
+
+ if (mReader->mCompositionChanges.size() != 1) {
+ std::cout << "HWC asked for none or more than 1 composition change, skipping"
+ << std::endl;
+ mReader->mCompositionChanges.clear();
+ continue;
+ }
+ // create client target buffer
+ ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
+ uint32_t clientStride;
const native_handle_t* clientBufferHandle =
- mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount, clientFormat,
- clientUsage, /*import*/ true, &clientStride);
+ mGralloc->allocate(mDisplayWidth, mDisplayHeight, clientLayer->mLayerCount,
+ clientFormat, clientUsage, /*import*/ true, &clientStride);
ASSERT_NE(nullptr, clientBufferHandle);
- void* clientBufData =
- mGralloc->lock(clientBufferHandle, clientUsage, layer->mAccessRegion, -1);
+ void* clientBufData = mGralloc->lock(clientBufferHandle, clientUsage,
+ {0, 0, mDisplayWidth, mDisplayHeight}, -1);
- ASSERT_NO_FATAL_FAILURE(fillBuffer(layer->mWidth, layer->mHeight, clientStride,
- clientBufData, clientFormat, expectedColors));
+ std::vector<IComposerClient::Color> clientColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED);
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mDisplayWidth, mDisplayHeight,
+ clientStride, clientBufData,
+ clientFormat, clientColors));
int clientFence = mGralloc->unlock(clientBufferHandle);
if (clientFence != -1) {
sync_wait(clientFence, -1);
close(clientFence);
}
- IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
- mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN,
- std::vector<IComposerClient::Rect>(1, damage));
-
- layer->setToClientComposition(mWriter);
+ mWriter->setClientTarget(0, clientBufferHandle, clientFence, clientDataspace,
+ std::vector<IComposerClient::Rect>(1, clientFrame));
+ clientLayer->setToClientComposition(mWriter);
mWriter->validateDisplay();
execute();
ASSERT_EQ(0, mReader->mCompositionChanges.size());
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
- ASSERT_EQ(0, mReader->mErrors.size());
-
- mWriter->presentDisplay();
- execute();
-
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
+TEST_P(GraphicsCompositionTest, SetLayerDamage) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
<< std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ IComposerClient::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4};
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+ auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+ mDisplayWidth, mDisplayHeight,
+ PixelFormat::RGBA_8888);
+ layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setZOrder(10);
+ layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+
+ // update surface damage and recheck
+ redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2};
+ ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+ ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors));
+ layer->setSurfaceDamage(std::vector<IComposerClient::Rect>(
+ 1, {0, 0, mDisplayWidth / 2, mDisplayWidth / 2}));
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_EQ(0, mReader->mCompositionChanges.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-
- ASSERT_NO_FATAL_FAILURE(
- mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- auto deviceLayer =
- std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
- mDisplayHeight / 2, PixelFormat::RGBA_8888);
- std::vector<IComposerClient::Color> deviceColors(deviceLayer->mWidth * deviceLayer->mHeight);
- fillColorsArea(deviceColors, deviceLayer->mWidth,
- {0, 0, static_cast<int32_t>(deviceLayer->mWidth),
- static_cast<int32_t>(deviceLayer->mHeight)},
- GREEN);
- deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->mWidth),
- static_cast<int32_t>(deviceLayer->mHeight)});
- deviceLayer->setZOrder(10);
- ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
- deviceLayer->write(mWriter);
-
- auto clientLayer = std::make_shared<TestBufferLayer>(
- mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2,
- PixelFormat::RGBA_8888, IComposerClient::Composition::CLIENT);
- IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
- clientLayer->setDisplayFrame(clientFrame);
- clientLayer->setZOrder(0);
- clientLayer->write(mWriter);
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- uint64_t clientUsage =
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_CLIENT_TARGET);
- uint32_t clientStride;
- const native_handle_t* clientBufferHandle =
- mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888,
- clientUsage, /*import*/ true, &clientStride);
- ASSERT_NE(nullptr, clientBufferHandle);
-
- AccessRegion clientAccessRegion;
- clientAccessRegion.left = 0;
- clientAccessRegion.top = 0;
- clientAccessRegion.width = mDisplayWidth;
- clientAccessRegion.height = mDisplayHeight;
- void* clientData = mGralloc->lock(clientBufferHandle, clientUsage, clientAccessRegion, -1);
- std::vector<IComposerClient::Color> clientColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED);
- ASSERT_NO_FATAL_FAILURE(fillBuffer(mDisplayWidth, mDisplayHeight, clientStride, clientData,
- PixelFormat::RGBA_8888, clientColors));
- int clientFence = mGralloc->unlock(clientBufferHandle);
- if (clientFence != -1) {
- sync_wait(clientFence, -1);
- close(clientFence);
- }
-
- mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN,
- std::vector<IComposerClient::Rect>(1, clientFrame));
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-TEST_F(GraphicsComposerReadbackTest, SetLayerDamage) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
+TEST_P(GraphicsCompositionTest, SetLayerPlaneAlpha) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
<< std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelformat/dataspace";
- return;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ layer->setColor(RED);
+ layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setZOrder(10);
+ layer->setAlpha(0);
+ layer->setBlendMode(IComposerClient::BlendMode::PREMULTIPLIED);
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ mTestRenderEngine->setRenderLayers(layers);
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
}
-
- IComposerClient::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4};
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
-
- auto layer =
- std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
- mDisplayHeight, PixelFormat::RGBA_8888);
- layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setZOrder(10);
- ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
-
- std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-
- // update surface damage and recheck
- redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2};
- clearColors(expectedColors, mDisplayWidth, mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
-
- ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors));
- layer->setSurfaceDamage(
- std::vector<IComposerClient::Rect>(1, {0, 0, mDisplayWidth / 2, mDisplayWidth / 2}));
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_EQ(0, mReader->mCompositionChanges.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-TEST_F(GraphicsComposerReadbackTest, SetLayerPlaneAlpha) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
+TEST_P(GraphicsCompositionTest, SetLayerSourceCrop) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
<< std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
+ BLUE);
+
+ auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+ mDisplayWidth, mDisplayHeight,
+ PixelFormat::RGBA_8888);
+ layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+ layer->setZOrder(10);
+ layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ layer->setSourceCrop({0, static_cast<float>(mDisplayHeight / 2),
+ static_cast<float>(mDisplayWidth),
+ static_cast<float>(mDisplayHeight)});
+ ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+ // update expected colors to match crop
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ mTestRenderEngine->setRenderLayers(layers);
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
}
-
- auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
- layer->setColor(RED);
- layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setZOrder(10);
- layer->setAlpha(0);
- layer->setBlendMode(IComposerClient::BlendMode::PREMULTIPLIED);
-
- std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
-
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-TEST_F(GraphicsComposerReadbackTest, SetLayerSourceCrop) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
+TEST_P(GraphicsCompositionTest, SetLayerZOrder) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
<< std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ IComposerClient::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2};
+ IComposerClient::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight};
+ auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ redLayer->setColor(RED);
+ redLayer->setDisplayFrame(redRect);
+
+ auto blueLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+ blueLayer->setColor(BLUE);
+ blueLayer->setDisplayFrame(blueRect);
+ blueLayer->setZOrder(5);
+
+ std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, blueLayer};
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+ // red in front of blue
+ redLayer->setZOrder(10);
+
+ // fill blue first so that red will overwrite on overlap
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+
+ redLayer->setZOrder(1);
+ ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ writeLayers(layers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mCompositionChanges.size());
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ mTestRenderEngine->setRenderLayers(layers);
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
}
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
-
- auto layer =
- std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
- mDisplayHeight, PixelFormat::RGBA_8888);
- layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
- layer->setZOrder(10);
- layer->setSourceCrop({0, static_cast<float>(mDisplayHeight / 2),
- static_cast<float>(mDisplayWidth), static_cast<float>(mDisplayHeight)});
- ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
-
- std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
- // update expected colors to match crop
- fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-TEST_F(GraphicsComposerReadbackTest, SetLayerZOrder) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
- << std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
- }
-
- IComposerClient::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2};
- IComposerClient::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight};
- auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
- redLayer->setColor(RED);
- redLayer->setDisplayFrame(redRect);
-
- auto blueLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
- blueLayer->setColor(BLUE);
- blueLayer->setDisplayFrame(blueRect);
- blueLayer->setZOrder(5);
-
- std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, blueLayer};
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
- // red in front of blue
- redLayer->setZOrder(10);
-
- // fill blue first so that red will overwrite on overlap
- fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
- fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-
- redLayer->setZOrder(1);
- clearColors(expectedColors, mDisplayWidth, mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
- fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- writeLayers(layers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- ASSERT_EQ(0, mReader->mCompositionChanges.size());
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-}
-
-class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTest,
- public ::testing::WithParamInterface<float> {
- public:
+class GraphicsBlendModeCompositionTest
+ : public GraphicsCompositionTestBase,
+ public testing::WithParamInterface<std::tuple<string, string>> {
+ public:
void SetUp() override {
- GraphicsComposerReadbackTest::SetUp();
+ SetUpBase(std::get<0>(GetParam()));
+ mTestColorModes = {ColorMode::SRGB}; // TODO: add more color mode support
mBackgroundColor = BLACK;
mTopLayerColor = RED;
}
- void TearDown() override { GraphicsComposerReadbackTest::TearDown(); }
-
void setBackgroundColor(IComposerClient::Color color) { mBackgroundColor = color; }
void setTopLayerColor(IComposerClient::Color color) { mTopLayerColor = color; }
@@ -1029,8 +948,8 @@
void setUpLayers(IComposerClient::BlendMode blendMode) {
mLayers.clear();
std::vector<IComposerClient::Color> topLayerPixelColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(topLayerPixelColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight},
- mTopLayerColor);
+ ReadbackHelper::fillColorsArea(topLayerPixelColors, mDisplayWidth,
+ {0, 0, mDisplayWidth, mDisplayHeight}, mTopLayerColor);
auto backgroundLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
@@ -1042,10 +961,11 @@
PixelFormat::RGBA_8888);
layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
layer->setZOrder(10);
+ layer->setDataspace(Dataspace::UNKNOWN, mWriter);
ASSERT_NO_FATAL_FAILURE(layer->setBuffer(topLayerPixelColors));
layer->setBlendMode(blendMode);
- layer->setAlpha(GetParam());
+ layer->setAlpha(std::stof(std::get<1>(GetParam())));
mLayers.push_back(backgroundLayer);
mLayers.push_back(layer);
@@ -1053,7 +973,7 @@
void setExpectedColors(std::vector<IComposerClient::Color>& expectedColors) {
ASSERT_EQ(2, mLayers.size());
- clearColors(expectedColors, mDisplayWidth, mDisplayHeight);
+ ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
auto layer = mLayers[1];
IComposerClient::BlendMode blendMode = layer->mBlendMode;
@@ -1091,122 +1011,178 @@
IComposerClient::Color mTopLayerColor;
};
-TEST_P(GraphicsComposerBlendModeReadbackTest, None) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
+// TODO(b/145557764): Re-enable after the bug is fixed.
+TEST_P(GraphicsBlendModeCompositionTest, DISABLED_None) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
<< std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+ setBackgroundColor(BLACK);
+ setTopLayerColor(TRANSLUCENT_RED);
+ setUpLayers(IComposerClient::BlendMode::NONE);
+ setExpectedColors(expectedColors);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ writeLayers(mLayers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ mTestRenderEngine->setRenderLayers(mLayers);
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
}
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
- setBackgroundColor(BLACK);
- setTopLayerColor(TRANSLUCENT_RED);
- setUpLayers(IComposerClient::BlendMode::NONE);
- setExpectedColors(expectedColors);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- writeLayers(mLayers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
// TODO: bug 116865056: Readback returns (245, 0, 0) for layer plane
// alpha of .2, expected 10.2
-TEST_P(GraphicsComposerBlendModeReadbackTest, DISABLED_Coverage) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
+TEST_P(GraphicsBlendModeCompositionTest, DISABLED_Coverage) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
<< std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+ setBackgroundColor(BLACK);
+ setTopLayerColor(TRANSLUCENT_RED);
+
+ setUpLayers(IComposerClient::BlendMode::COVERAGE);
+ setExpectedColors(expectedColors);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ writeLayers(mLayers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
- setBackgroundColor(BLACK);
- setTopLayerColor(TRANSLUCENT_RED);
-
- setUpLayers(IComposerClient::BlendMode::COVERAGE);
- setExpectedColors(expectedColors);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- writeLayers(mLayers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-TEST_P(GraphicsComposerBlendModeReadbackTest, Premultiplied) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
+TEST_P(GraphicsBlendModeCompositionTest, Premultiplied) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
<< std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+ mWriter->selectDisplay(mPrimaryDisplay);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+ setBackgroundColor(BLACK);
+ setTopLayerColor(TRANSLUCENT_RED);
+ setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED);
+ setExpectedColors(expectedColors);
+
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ writeLayers(mLayers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ mTestRenderEngine->setRenderLayers(mLayers);
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
}
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
- setBackgroundColor(BLACK);
- setTopLayerColor(TRANSLUCENT_RED);
- setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED);
- setExpectedColors(expectedColors);
-
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- writeLayers(mLayers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-INSTANTIATE_TEST_CASE_P(BlendModeTest, GraphicsComposerBlendModeReadbackTest,
- ::testing::Values(.2, 1.0));
-
-class GraphicsComposerTransformReadbackTest : public GraphicsComposerReadbackTest {
- protected:
+class GraphicsTransformCompositionTest : public GraphicsCompositionTest {
+ protected:
void SetUp() override {
- GraphicsComposerReadbackTest::SetUp();
+ GraphicsCompositionTest::SetUp();
+
+ mWriter->selectDisplay(mPrimaryDisplay);
auto backgroundLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
backgroundLayer->setColor({0, 0, 0, 0});
@@ -1225,8 +1201,8 @@
mLayer->setZOrder(10);
std::vector<IComposerClient::Color> baseColors(mSideLength * mSideLength);
- fillColorsArea(baseColors, mSideLength, redRect, RED);
- fillColorsArea(baseColors, mSideLength, blueRect, BLUE);
+ ReadbackHelper::fillColorsArea(baseColors, mSideLength, redRect, RED);
+ ReadbackHelper::fillColorsArea(baseColors, mSideLength, blueRect, BLUE);
ASSERT_NO_FATAL_FAILURE(mLayer->setBuffer(baseColors));
mLayers = {backgroundLayer, mLayer};
@@ -1239,112 +1215,189 @@
int mSideLength;
};
-TEST_F(GraphicsComposerTransformReadbackTest, FLIP_H) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
+TEST_P(GraphicsTransformCompositionTest, FLIP_H) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
<< std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
- }
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- mLayer->setTransform(Transform::FLIP_H);
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth,
- {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE);
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- writeLayers(mLayers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+ mLayer->setTransform(Transform::FLIP_H);
+ mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE);
+
+ writeLayers(mLayers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ mTestRenderEngine->setRenderLayers(mLayers);
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+ }
}
-TEST_F(GraphicsComposerTransformReadbackTest, FLIP_V) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
+TEST_P(GraphicsTransformCompositionTest, FLIP_V) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
<< std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ mLayer->setTransform(Transform::FLIP_V);
+ mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE);
+
+ writeLayers(mLayers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ mTestRenderEngine->setRenderLayers(mLayers);
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- mLayer->setTransform(Transform::FLIP_V);
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth,
- {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED);
- fillColorsArea(expectedColors, mDisplayWidth,
- {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE);
-
- writeLayers(mLayers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
-TEST_F(GraphicsComposerTransformReadbackTest, ROT_180) {
- if (!mHasReadbackBuffer) {
- std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
- "valid color mode"
+TEST_P(GraphicsTransformCompositionTest, ROT_180) {
+ for (ColorMode mode : mTestColorModes) {
+ std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
<< std::endl;
- GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
- return;
+ mWriter->selectDisplay(mPrimaryDisplay);
+ ASSERT_NO_FATAL_FAILURE(
+ mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+ mComposerClient->getRaw()->getReadbackBufferAttributes(
+ mPrimaryDisplay,
+ [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+ tmpDataspace, tmpError);
+ mPixelFormat = tmpPixelFormat;
+ mDataspace = tmpDataspace;
+ });
+
+ if (!mHasReadbackBuffer) {
+ std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+ GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+ return;
+ }
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+ mDisplayHeight, mPixelFormat, mDataspace);
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+ mLayer->setTransform(Transform::ROT_180);
+ mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+ std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength},
+ RED);
+ ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+ {0, 0, mSideLength / 2, mSideLength / 2}, BLUE);
+
+ writeLayers(mLayers);
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ clearCommandReaderState();
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+ mTestRenderEngine->setRenderLayers(mLayers);
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+ ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
- mLayer->setTransform(Transform::ROT_180);
-
- std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
- fillColorsArea(expectedColors, mDisplayWidth,
- {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}, RED);
- fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mSideLength / 2, mSideLength / 2}, BLUE);
-
- writeLayers(mLayers);
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->validateDisplay();
- execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- GTEST_SUCCEED();
- return;
- }
- ASSERT_EQ(0, mReader->mErrors.size());
- mWriter->presentDisplay();
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
- ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GraphicsCompositionTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_CASE_P(
+ BlendModeTest, GraphicsBlendModeCompositionTest,
+ testing::Combine(
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+ testing::Values("0.2", "1.0")),
+ android::hardware::PrintInstanceTupleNameToString<>);
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GraphicsTransformCompositionTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
} // anonymous namespace
} // namespace vts
} // namespace V2_2
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 51832f9..95a0f69 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -16,12 +16,14 @@
#define LOG_TAG "graphics_composer_hidl_hal_test@2.2"
-#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
#include <composer-vts/2.1/TestCommandReader.h>
#include <composer-vts/2.2/ComposerVts.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <mapper-vts/2.0/MapperVts.h>
namespace android {
@@ -41,29 +43,11 @@
using common::V1_1::RenderIntent;
using mapper::V2_0::IMapper;
-// 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;
@@ -188,7 +172,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));
@@ -239,7 +223,7 @@
/**
* Test IComposerClient::getPerFrameMetadataKeys.
*/
-TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys) {
+TEST_P(GraphicsComposerHidlTest, GetPerFrameMetadataKeys) {
std::vector<IComposerClient::PerFrameMetadataKey> keys;
Error error = Error::NONE;
mComposerClient->getRaw()->getPerFrameMetadataKeys(
@@ -261,7 +245,7 @@
*
* Test that virtual displays can be created and has the correct display type.
*/
-TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay_2_2) {
+TEST_P(GraphicsComposerHidlTest, CreateVirtualDisplay_2_2) {
if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
GTEST_SUCCEED() << "no virtual display support";
return;
@@ -286,7 +270,7 @@
* Test that IComposerClient::getClientTargetSupport returns true for the
* required client targets.
*/
-TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_2) {
+TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_2) {
std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
for (auto config : configs) {
int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -310,7 +294,7 @@
* Error::BAD_DISPLAY when passed in an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_2BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_2BadDisplay) {
std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
for (auto config : configs) {
int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -332,7 +316,7 @@
/**
* Test IComposerClient::setPowerMode_2_2.
*/
-TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2) {
+TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2) {
std::vector<IComposerClient::PowerMode> modes;
modes.push_back(IComposerClient::PowerMode::OFF);
modes.push_back(IComposerClient::PowerMode::ON_SUSPEND);
@@ -349,7 +333,7 @@
* Test that IComposerClient::setPowerMode_2_2 succeeds for different varations
* of PowerMode
*/
-TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2Variations) {
+TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2Variations) {
std::vector<IComposerClient::PowerMode> modes;
modes.push_back(IComposerClient::PowerMode::OFF);
@@ -404,7 +388,7 @@
* Tests that IComposerClient::setPowerMode_2_2 returns BAD_DISPLAY when passed an
* invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2BadDisplay) {
Error error = mComposerClient->getRaw()->setPowerMode_2_2(mInvalidDisplayId,
IComposerClient::PowerMode::ON);
ASSERT_EQ(Error::BAD_DISPLAY, error);
@@ -416,7 +400,7 @@
* Test that IComposerClient::setPowerMode_2_2 returns BAD_PARAMETER when passed
* an invalid PowerMode
*/
-TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2BadParameter) {
+TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2BadParameter) {
Error error = mComposerClient->getRaw()->setPowerMode_2_2(
mPrimaryDisplay, static_cast<IComposerClient::PowerMode>(-1));
ASSERT_EQ(Error::BAD_PARAMETER, error);
@@ -428,7 +412,7 @@
* Test that IComposerClient::setPowerMode_2_2 returns UNSUPPORTED when passed
* DOZE or DOZE_SUPPORT on a device that does not support these modes
*/
-TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2Unsupported) {
+TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2Unsupported) {
if (!mComposerClient->getDozeSupport(mPrimaryDisplay)) {
Error error = mComposerClient->getRaw()->setPowerMode_2_2(mPrimaryDisplay,
IComposerClient::PowerMode::DOZE);
@@ -445,7 +429,7 @@
*
* Test IComposerClient::setReadbackBuffer
*/
-TEST_F(GraphicsComposerHidlTest, SetReadbackBuffer) {
+TEST_P(GraphicsComposerHidlTest, SetReadbackBuffer) {
if (!mHasReadbackBuffer) {
return;
}
@@ -469,7 +453,7 @@
* Test that IComposerClient::setReadbackBuffer returns an Error::BAD_DISPLAY
* when passed an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, SetReadbackBufferBadDisplay) {
if (!mHasReadbackBuffer) {
return;
}
@@ -493,7 +477,7 @@
* Test that IComposerClient::setReadbackBuffer returns Error::BAD_PARAMETER
* when passed an invalid buffer handle
*/
-TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadParameter) {
+TEST_P(GraphicsComposerHidlTest, SetReadbackBufferBadParameter) {
if (!mHasReadbackBuffer) {
return;
}
@@ -502,7 +486,7 @@
ASSERT_EQ(Error::BAD_PARAMETER, error);
}
-TEST_F(GraphicsComposerHidlTest, GetReadbackBufferFenceInactive) {
+TEST_P(GraphicsComposerHidlTest, GetReadbackBufferFenceInactive) {
if (!mHasReadbackBuffer) {
return;
}
@@ -516,7 +500,7 @@
/**
* Test IComposerClient::Command::SET_LAYER_FLOAT_COLOR.
*/
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_FLOAT_COLOR) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_FLOAT_COLOR) {
V2_1::Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -554,7 +538,7 @@
/**
* Test IComposerClient::getDataspaceSaturationMatrix.
*/
-TEST_F(GraphicsComposerHidlTest, GetDataspaceSaturationMatrix) {
+TEST_P(GraphicsComposerHidlTest, GetDataspaceSaturationMatrix) {
auto matrix = mComposerClient->getDataspaceSaturationMatrix(Dataspace::SRGB_LINEAR);
// the last row is known
ASSERT_EQ(0.0f, matrix[12]);
@@ -570,7 +554,7 @@
* Error::BAD_PARAMETER when passed a dataspace other than
* Dataspace::SRGB_LINEAR
*/
-TEST_F(GraphicsComposerHidlTest, GetDataspaceSaturationMatrixBadParameter) {
+TEST_P(GraphicsComposerHidlTest, GetDataspaceSaturationMatrixBadParameter) {
mComposerClient->getRaw()->getDataspaceSaturationMatrix(
Dataspace::UNKNOWN,
[&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_PARAMETER, tmpError); });
@@ -579,7 +563,7 @@
/**
* Test IComposerClient::getColorMode_2_2.
*/
-TEST_F(GraphicsComposerHidlTest, GetColorMode_2_2) {
+TEST_P(GraphicsComposerHidlTest, GetColorMode_2_2) {
std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
auto nativeMode = std::find(modes.cbegin(), modes.cend(), ColorMode::NATIVE);
@@ -592,7 +576,7 @@
* Test that IComposerClient::getColorMode returns Error::BAD_DISPLAY when
* passed an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, GetColorMode_2_2BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetColorMode_2_2BadDisplay) {
mComposerClient->getRaw()->getColorModes_2_2(
mInvalidDisplayId,
[&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_DISPLAY, tmpError); });
@@ -601,7 +585,7 @@
/**
* Test IComposerClient::getRenderIntents.
*/
-TEST_F(GraphicsComposerHidlTest, GetRenderIntents) {
+TEST_P(GraphicsComposerHidlTest, GetRenderIntents) {
std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
for (auto mode : modes) {
std::vector<RenderIntent> intents =
@@ -631,7 +615,7 @@
* Test that IComposerClient::getRenderIntent returns Error::BAD_DISPLAY when
* passed an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, GetRenderIntentsBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetRenderIntentsBadDisplay) {
std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
for (auto mode : modes) {
mComposerClient->getRaw()->getRenderIntents(
@@ -646,7 +630,7 @@
* Test that IComposerClient::getRenderIntents returns Error::BAD_PARAMETER when
* pased either an invalid Color mode or an invalid Render Intent
*/
-TEST_F(GraphicsComposerHidlTest, GetRenderIntentsBadParameter) {
+TEST_P(GraphicsComposerHidlTest, GetRenderIntentsBadParameter) {
mComposerClient->getRaw()->getRenderIntents(
mPrimaryDisplay, static_cast<ColorMode>(-1),
[&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_PARAMETER, tmpError); });
@@ -655,7 +639,7 @@
/**
* Test IComposerClient::setColorMode_2_2.
*/
-TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode_2_2) {
std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
for (auto mode : modes) {
std::vector<RenderIntent> intents =
@@ -674,7 +658,7 @@
* Test that IComposerClient::setColorMode_2_2 returns an Error::BAD_DISPLAY
* when passed an invalid display handle
*/
-TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode_2_2BadDisplay) {
Error error = mComposerClient->getRaw()->setColorMode_2_2(mInvalidDisplayId, ColorMode::NATIVE,
RenderIntent::COLORIMETRIC);
@@ -687,7 +671,7 @@
* Test that IComposerClient::setColorMode_2_2 returns Error::BAD_PARAMETER when
* passed an invalid Color mode or an invalid render intent
*/
-TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadParameter) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode_2_2BadParameter) {
Error colorModeError = mComposerClient->getRaw()->setColorMode_2_2(
mPrimaryDisplay, static_cast<ColorMode>(-1), RenderIntent::COLORIMETRIC);
EXPECT_EQ(Error::BAD_PARAMETER, colorModeError);
@@ -697,6 +681,16 @@
EXPECT_EQ(Error::BAD_PARAMETER, renderIntentError);
}
+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_2
@@ -704,12 +698,3 @@
} // namespace graphics
} // namespace hardware
} // namespace android
-
-int main(int argc, char** argv) {
- using android::hardware::graphics::composer::V2_2::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.3/default/Android.bp b/graphics/composer/2.3/default/Android.bp
index 59b9436..a5696dd 100644
--- a/graphics/composer/2.3/default/Android.bp
+++ b/graphics/composer/2.3/default/Android.bp
@@ -28,8 +28,8 @@
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.composer@2.1-resources",
+ "android.hardware.graphics.composer@2.2-resources",
"libbase",
"libbinder",
"libcutils",
diff --git a/graphics/composer/2.3/utils/OWNERS b/graphics/composer/2.3/utils/OWNERS
index b3ea6be..cc6d937 100644
--- a/graphics/composer/2.3/utils/OWNERS
+++ b/graphics/composer/2.3/utils/OWNERS
@@ -2,7 +2,3 @@
lpy@google.com
stoza@google.com
vhau@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
diff --git a/graphics/composer/2.3/utils/command-buffer/Android.bp b/graphics/composer/2.3/utils/command-buffer/Android.bp
index c48fe7a..36ac297 100644
--- a/graphics/composer/2.3/utils/command-buffer/Android.bp
+++ b/graphics/composer/2.3/utils/command-buffer/Android.bp
@@ -3,12 +3,15 @@
defaults: ["hidl_defaults"],
vendor_available: true,
shared_libs: [
- "android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
+ ],
+ export_shared_lib_headers: [
"android.hardware.graphics.composer@2.3",
],
header_libs: [
- "android.hardware.graphics.composer@2.1-command-buffer",
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ ],
+ export_header_lib_headers: [
"android.hardware.graphics.composer@2.2-command-buffer",
],
export_include_dirs: ["include"],
diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
index e1a870e..afc22d8 100644
--- a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
+++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
@@ -46,8 +46,8 @@
class CommandWriterBase : public V2_2::CommandWriterBase {
public:
void setLayerPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) {
- beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
- metadataVec.size() * 2);
+ beginCommand(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
+ metadataVec.size() * 2);
for (const auto& metadata : metadataVec) {
writeSigned(static_cast<int32_t>(metadata.key));
writeFloat(metadata.value);
@@ -69,8 +69,8 @@
static constexpr uint16_t kSetLayerColorTransformLength = 16;
void setLayerColorTransform(const float* matrix) {
- beginCommand_2_3(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM,
- kSetLayerColorTransformLength);
+ beginCommand(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM,
+ kSetLayerColorTransformLength);
for (int i = 0; i < 16; i++) {
writeFloat(matrix[i]);
}
@@ -109,7 +109,7 @@
// Blobs are written as:
// {numElements, key1, size1, blob1, key2, size2, blob2, key3, size3...}
uint16_t length = static_cast<uint16_t>(commandLength);
- beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length);
+ beginCommand(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length);
write(static_cast<uint32_t>(metadata.size()));
for (auto metadataBlob : metadata) {
writeSigned(static_cast<int32_t>(metadataBlob.key));
@@ -120,11 +120,6 @@
}
protected:
- void beginCommand_2_3(IComposerClient::Command command, uint16_t length) {
- V2_2::CommandWriterBase::beginCommand_2_2(
- static_cast<V2_2::IComposerClient::Command>(static_cast<int32_t>(command)), length);
- }
-
void writeBlob(uint32_t length, const unsigned char* blob) {
memcpy(&mData[mDataWritten], blob, length);
uint32_t numElements = length / 4;
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
index b289b6a..041fbc8 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
@@ -21,9 +21,9 @@
#endif
#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
-#include <composer-hal/2.2/ComposerResources.h>
#include <composer-hal/2.3/ComposerCommandEngine.h>
#include <composer-hal/2.3/ComposerHal.h>
+#include <composer-resources/2.2/ComposerResources.h>
namespace android {
namespace hardware {
@@ -184,18 +184,18 @@
}
protected:
+ using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
+ using BaseType2_1::mHal;
+ using BaseType2_1::mResources;
std::unique_ptr<V2_1::hal::ComposerCommandEngine> createCommandEngine() override {
return std::make_unique<ComposerCommandEngine>(
mHal, static_cast<V2_2::hal::ComposerResources*>(mResources.get()));
}
- private:
+ private:
using BaseType2_2 = V2_2::hal::detail::ComposerClientImpl<Interface, Hal>;
- using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
using BaseType2_1::mCommandEngine;
using BaseType2_1::mCommandEngineMutex;
- using BaseType2_1::mHal;
- using BaseType2_1::mResources;
};
} // namespace detail
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
index 1a40d96..02f6212 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
@@ -23,8 +23,8 @@
#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
#include <composer-hal/2.1/ComposerCommandEngine.h>
#include <composer-hal/2.2/ComposerCommandEngine.h>
-#include <composer-hal/2.2/ComposerResources.h>
#include <composer-hal/2.3/ComposerHal.h>
+#include <composer-resources/2.2/ComposerResources.h>
namespace android {
namespace hardware {
@@ -50,6 +50,11 @@
}
}
+ std::unique_ptr<V2_1::CommandWriterBase> createCommandWriter(
+ size_t writerInitialSize) override {
+ return std::make_unique<CommandWriterBase>(writerInitialSize);
+ }
+
bool executeSetLayerColorTransform(uint16_t length) {
if (length != CommandWriterBase::kSetLayerColorTransformLength) {
return false;
@@ -61,7 +66,7 @@
}
auto err = mHal->setLayerColorTransform(mCurrentDisplay, mCurrentLayer, matrix);
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -97,7 +102,7 @@
}
auto err = mHal->setLayerPerFrameMetadataBlobs(mCurrentDisplay, mCurrentLayer, metadata);
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
}
@@ -111,8 +116,8 @@
private:
using BaseType2_1 = V2_1::hal::ComposerCommandEngine;
- using BaseType2_1::mWriter;
using BaseType2_2 = V2_2::hal::ComposerCommandEngine;
+ using BaseType2_1::mWriter;
ComposerHal* mHal;
};
diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
index d3b29bb..e0e1394 100644
--- a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
+++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
@@ -294,9 +294,6 @@
(brightness < 0.0f && brightness != -1.0f)) {
return Error::BAD_PARAMETER;
}
- if (!mDispatch.setDisplayBrightness) {
- return Error::UNSUPPORTED;
- }
int32_t error = mDispatch.setDisplayBrightness(mDevice, display, brightness);
return static_cast<Error>(error);
}
@@ -307,6 +304,13 @@
return false;
}
+ if (!BaseType2_1::initDispatch(HWC2_FUNCTION_GET_DISPLAY_CAPABILITIES,
+ &mDispatch.getDisplayCapabilities) ||
+ !BaseType2_1::initDispatch(HWC2_FUNCTION_SET_DISPLAY_BRIGHTNESS,
+ &mDispatch.setDisplayBrightness)) {
+ return false;
+ }
+
this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA,
&mDispatch.getDisplayIdentificationData);
this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
@@ -317,14 +321,10 @@
&mDispatch.setDisplayedContentSamplingEnabled);
this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLE,
&mDispatch.getDisplayedContentSample);
- this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CAPABILITIES,
- &mDispatch.getDisplayCapabilities);
this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_PER_FRAME_METADATA_BLOBS,
&mDispatch.setLayerPerFrameMetadataBlobs);
this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_BRIGHTNESS_SUPPORT,
&mDispatch.getDisplayBrightnessSupport);
- this->initOptionalDispatch(HWC2_FUNCTION_SET_DISPLAY_BRIGHTNESS,
- &mDispatch.setDisplayBrightness);
return true;
}
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
index 2fe6cd6..f65a9c4 100644
--- a/graphics/composer/2.3/utils/vts/Android.bp
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -21,22 +21,17 @@
"ComposerVts.cpp",
],
static_libs: [
- "VtsHalHidlTargetTestBase",
- "android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.composer@2.1-vts",
- "android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.2-vts",
"android.hardware.graphics.composer@2.3",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@2.0-vts",
- "android.hardware.graphics.mapper@2.1",
- "android.hardware.graphics.mapper@2.1-vts",
- "android.hardware.graphics.mapper@3.0",
- "android.hardware.graphics.mapper@3.0-vts",
+ ],
+ export_static_lib_headers: [
+ "android.hardware.graphics.composer@2.2-vts",
+ "android.hardware.graphics.composer@2.3",
],
header_libs: [
- "android.hardware.graphics.composer@2.1-command-buffer",
- "android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ export_header_lib_headers: [
"android.hardware.graphics.composer@2.3-command-buffer",
],
cflags: [
diff --git a/graphics/composer/2.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 e421889..fa4823e 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -28,6 +28,7 @@
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
@@ -40,10 +41,14 @@
"android.hardware.graphics.mapper@2.1-vts",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hardware.graphics.mapper@4.0-vts",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
"android.hardware.graphics.composer@2.3-command-buffer",
],
+ 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/Android.bp b/graphics/composer/2.4/Android.bp
new file mode 100644
index 0000000..5f700be
--- /dev/null
+++ b/graphics/composer/2.4/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.graphics.composer@2.4",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IComposer.hal",
+ "IComposerCallback.hal",
+ "IComposerClient.hal",
+ ],
+ interfaces: [
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/graphics/composer/2.4/IComposer.hal b/graphics/composer/2.4/IComposer.hal
new file mode 100644
index 0000000..d3b3cb6
--- /dev/null
+++ b/graphics/composer/2.4/IComposer.hal
@@ -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.composer@2.4;
+
+import IComposerClient;
+import @2.1::Error;
+import @2.3::IComposer;
+
+interface IComposer extends @2.3::IComposer {
+ /**
+ * Creates a v2.4 client of the composer. Supersedes @2.3::createClient.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * NO_RESOURCES when the client could not be created.
+ * @return client is the newly created client.
+ */
+ createClient_2_4() generates (Error error, IComposerClient client);
+};
diff --git a/graphics/composer/2.4/IComposerCallback.hal b/graphics/composer/2.4/IComposerCallback.hal
new file mode 100644
index 0000000..f343cee
--- /dev/null
+++ b/graphics/composer/2.4/IComposerCallback.hal
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer@2.4;
+
+import @2.1::Display;
+import @2.1::IComposerCallback;
+
+interface IComposerCallback extends @2.1::IComposerCallback {
+ /**
+ * Notifies the client that a vsync event has occurred. This callback must
+ * only be triggered when vsync is enabled for this display (through
+ * setVsyncEnabled).
+ *
+ * @param display is the display which has received a vsync event
+ * @param timestamp is the CLOCK_MONOTONIC time at which the vsync event
+ * occurred, in nanoseconds.
+ * @param vsyncPeriodNanos is the display vsync period in nanoseconds i.e. the next onVsync_2_4
+ * is expected to be called vsyncPeriodNanos nanoseconds after this call.
+ */
+ oneway onVsync_2_4(Display display, int64_t timestamp, VsyncPeriodNanos vsyncPeriodNanos);
+
+ /**
+ * Notifies the client that the previously reported timing for vsync period change has been
+ * updated. This may occur if the composer missed the deadline for changing the vsync period
+ * or the client submitted a refresh frame too late.
+ *
+ * @param display is the display which vsync period change is in progress
+ * @param updatedTimeline is the new timeline for the vsync period change.
+ */
+ oneway onVsyncPeriodTimingChanged(Display display, VsyncPeriodChangeTimeline updatedTimeline);
+
+ /**
+ * Notifies the client that the conditions which previously led to returning
+ * SEAMLESS_NOT_POSSIBLE from setActiveConfigWithConstraints have changed and now seamless may
+ * be possible. Client should retry calling setActiveConfigWithConstraints.
+ *
+ * @param display is a display setActiveConfigWithConstraints previously failed with
+ * SEAMLESS_NOT_POSSIBLE.
+ */
+ oneway onSeamlessPossible(Display display);
+};
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
new file mode 100644
index 0000000..9e3cf0e
--- /dev/null
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer@2.4;
+
+import android.hardware.graphics.common@1.2::PixelFormat;
+import android.hardware.graphics.common@1.2::Dataspace;
+import android.hardware.graphics.composer@2.1::IComposerClient.Command;
+import IComposerCallback;
+import @2.1::Config;
+import @2.1::Display;
+import @2.1::Error;
+import @2.1::IComposerClient;
+import @2.3::IComposerClient;
+
+interface IComposerClient extends @2.3::IComposerClient {
+ /**
+ * Display attributes queryable through getDisplayAttribute_2_4.
+ */
+ enum Attribute : @2.1::IComposerClient.Attribute {
+ /**
+ * The configuration group ID (as int32_t) this config is associated to.
+ * Switching between configurations within the same group may be done seamlessly
+ * in some conditions via setActiveConfigWithConstraints.
+ */
+ CONFIG_GROUP = 7,
+ };
+
+ /**
+ * Required capabilities which are supported by the display. The
+ * particular set of supported capabilities for a given display may be
+ * retrieved using getDisplayCapabilities.
+ */
+ enum DisplayCapability : @2.3::IComposerClient.DisplayCapability {
+ /**
+ * Indicates that the display supports protected contents.
+ * When returned, hardware composer must be able to accept client target
+ * 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,
+ };
+
+ enum Command : @2.3::IComposerClient.Command {
+ /**
+ * SET_CLIENT_TARGET_PROPERTY has this pseudo prototype
+ *
+ * This command has the following binary layout in bytes:
+ *
+ * 0 - 3: clientTargetProperty.pixelFormat
+ * 4 - 7: clientTargetProperty.dataspace
+ *
+ * setClientTargetProperty(ClientTargetProperty clientTargetProperty);
+ */
+ SET_CLIENT_TARGET_PROPERTY = 0x105 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+
+ /**
+ * SET_LAYER_GENERIC_METADATA has this pseudo prototype
+ *
+ * setLayerGenericMetadata(string key, bool mandatory, vec<uint8_t> value);
+ *
+ * Sets a piece of generic metadata for the given layer. If this
+ * function is called twice with the same key but different values, the
+ * newer value must override the older one. Calling this function with a
+ * 0-length value must reset that key's metadata as if it had not been
+ * set.
+ *
+ * A given piece of metadata may either be mandatory or a hint
+ * (non-mandatory) as indicated by the second parameter. Mandatory
+ * metadata may affect the composition result, which is to say that it
+ * may cause a visible change in the final image. By contrast, hints may
+ * only affect the composition strategy, such as which layers are
+ * composited by the client, but must not cause a visible change in the
+ * final image. The value of the mandatory flag shall match the value
+ * returned from getLayerGenericMetadataKeys for the given key.
+ *
+ * Only keys which have been returned from getLayerGenericMetadataKeys()
+ * shall be accepted. Any other keys must result in an UNSUPPORTED error.
+ *
+ * The value passed into this function shall be the binary
+ * representation of a HIDL type corresponding to the given key. For
+ * example, a key of 'com.example.V1_3.Foo' shall be paired with a
+ * value of type com.example@1.3::Foo, which would be defined in a
+ * vendor HAL extension.
+ *
+ * This function will be encoded in the command buffer in this order:
+ * 1) The key length, stored as a uint32_t
+ * 2) The key itself, padded to a uint32_t boundary if necessary
+ * 3) The mandatory flag, stored as a uint32_t
+ * 4) The value length in bytes, stored as a uint32_t
+ * 5) The value itself, padded to a uint32_t boundary if necessary
+ *
+ * @param key indicates which metadata value should be set on this layer
+ * @param mandatory indicates whether this particular key represents
+ * mandatory metadata or a hint (non-mandatory metadata), as
+ * described above
+ * @param value is a binary representation of a HIDL struct
+ * corresponding to the key as described above
+ */
+ SET_LAYER_GENERIC_METADATA = 0x40e << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+ };
+
+ /**
+ * Supersedes {@link @2.1::IComposerClient.DisplayType}.
+ */
+ enum DisplayConnectionType : uint32_t {
+ /**
+ * Display is connected through internal port, e.g. DSI, eDP.
+ */
+ INTERNAL = 0,
+ /**
+ * Display is connected through external port, e.g. HDMI, DisplayPort.
+ */
+ 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.
+ */
+ struct VsyncPeriodChangeConstraints {
+ /**
+ * Time in CLOCK_MONOTONIC after which the vsync period may change
+ * (i.e., the vsync period must not change before this time).
+ */
+ int64_t desiredTimeNanos;
+
+ /**
+ * If true, requires that the vsync period change must happen seamlessly without
+ * a noticeable visual artifact.
+ */
+ bool seamlessRequired;
+ };
+
+ struct ClientTargetProperty {
+ PixelFormat pixelFormat;
+ Dataspace dataspace;
+ };
+
+ /**
+ * Provides a IComposerCallback object for the device to call.
+ *
+ * This function must be called only once.
+ *
+ * @param callback is the IComposerCallback object.
+ */
+ registerCallback_2_4(IComposerCallback callback);
+
+ /**
+ * Provides a list of supported capabilities (as described in the
+ * definition of DisplayCapability above). This list must not change after
+ * initialization.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * @return capabilities is a list of supported capabilities.
+ */
+ getDisplayCapabilities_2_4(Display display)
+ generates (Error error, vec<DisplayCapability> capabilities);
+
+ /**
+ * Returns whether the given physical display is internal or external.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when the given display is invalid or virtual.
+ * @return type is the connection type of the display.
+ */
+ getDisplayConnectionType(Display display) generates (Error error, DisplayConnectionType type);
+
+ /**
+ * Returns a display attribute value for a particular display
+ * configuration.
+ *
+ * @param display is the display to query.
+ * @param config is the display configuration for which to return
+ * attribute values.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_CONFIG when config does not name a valid configuration for
+ * this display.
+ * BAD_PARAMETER when attribute is unrecognized.
+ * UNSUPPORTED when attribute cannot be queried for the config.
+ * @return value is the value of the attribute.
+ */
+ getDisplayAttribute_2_4(Display display, Config config, Attribute attribute)
+ generates (Error error, int32_t value);
+
+ /**
+ * Retrieves which vsync period the display is currently using.
+ *
+ * If no display configuration is currently active, this function must
+ * return BAD_CONFIG. If the vsync period is about to change due to a
+ * setActiveConfigWithConstraints call, this function must return the current vsync period
+ * until the change takes place.
+ *
+ * @param display is the display for which the vsync period is queried.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_CONFIG when no configuration is currently active.
+ * @return vsyncPeriodNanos is the current vsync period of the display.
+ */
+ getDisplayVsyncPeriod(Display display)
+ generates (Error error, VsyncPeriodNanos vsyncPeriodNanos);
+
+ /**
+ * Sets the active configuration and the refresh rate for this display.
+ * If the new config shares the same config group as the current config,
+ * only the vsync period shall change.
+ * Upon returning, the given display configuration, except vsync period, must be active and
+ * remain so until either this function is called again or the display is disconnected.
+ * When the display starts to refresh at the new vsync period, onVsync_2_4 callback must be
+ * called with the new vsync period.
+ *
+ * @param display is the display for which the active config is set.
+ * @param config is the new display configuration.
+ * @param vsyncPeriodChangeConstraints are the constraints required for changing vsync period.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_CONFIG when the configuration handle passed in is not valid
+ * for this display.
+ * SEAMLESS_NOT_ALLOWED when seamlessRequired was true but config provided doesn't
+ * share the same config group as the current config.
+ * SEAMLESS_NOT_POSSIBLE when seamlessRequired was true but the display cannot achieve
+ * the vsync period change without a noticeable visual artifact.
+ * When the conditions change and it may be possible to change
+ * the vsync period seamlessly, onSeamlessPossible callback
+ * must be called to indicate that caller should retry.
+ * @return timeline is the timeline for the vsync period change.
+ */
+ 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);
+
+ struct LayerGenericMetadataKey {
+ /**
+ * Key names must comply with the requirements specified for
+ * getLayerGenericMetadataKeys below
+ */
+ string name;
+
+ /**
+ * The mandatory flag is defined in the description of
+ * setLayerGenericMetadata above
+ */
+ bool mandatory;
+ };
+
+ /**
+ * Retrieves the set of keys that may be passed into setLayerGenericMetadata
+ *
+ * Key names must meet the following requirements:
+ * - Must be specified in reverse domain name notation
+ * - Must not start with 'com.android' or 'android'
+ * - Must be unique within the returned vector
+ * - Must correspond to a matching HIDL struct type, which defines the
+ * structure of its values. For example, the key 'com.example.V1-3.Foo'
+ * should correspond to a value of type com.example@1.3::Foo, which is
+ * defined in a vendor HAL extension
+ */
+ getLayerGenericMetadataKeys()
+ generates(Error error, vec<LayerGenericMetadataKey> keys);
+};
diff --git a/graphics/composer/2.4/default/Android.bp b/graphics/composer/2.4/default/Android.bp
new file mode 100644
index 0000000..a30609b
--- /dev/null
+++ b/graphics/composer/2.4/default/Android.bp
@@ -0,0 +1,46 @@
+//
+// Copyright 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+ name: "android.hardware.graphics.composer@2.4-service",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: ["service.cpp"],
+ init_rc: ["android.hardware.graphics.composer@2.4-service.rc"],
+ header_libs: [
+ "android.hardware.graphics.composer@2.4-passthrough",
+ ],
+ shared_libs: [
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
+ "android.hardware.graphics.composer@2.4",
+ "android.hardware.graphics.composer@2.1-resources",
+ "android.hardware.graphics.composer@2.2-resources",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "libhwc2on1adapter",
+ "libhwc2onfbadapter",
+ "liblog",
+ "libsync",
+ "libutils",
+ ],
+}
diff --git a/graphics/composer/2.4/default/OWNERS b/graphics/composer/2.4/default/OWNERS
new file mode 100644
index 0000000..cc6d937
--- /dev/null
+++ b/graphics/composer/2.4/default/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+lpy@google.com
+stoza@google.com
+vhau@google.com
diff --git a/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc b/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc
new file mode 100644
index 0000000..a296b0a
--- /dev/null
+++ b/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc
@@ -0,0 +1,7 @@
+service vendor.hwcomposer-2-4 /vendor/bin/hw/android.hardware.graphics.composer@2.4-service
+ class hal animation
+ user system
+ group graphics drmrpc
+ capabilities SYS_NICE
+ onrestart restart surfaceflinger
+ writepid /dev/cpuset/system-background/tasks
diff --git a/graphics/composer/2.4/default/service.cpp b/graphics/composer/2.4/default/service.cpp
new file mode 100644
index 0000000..98dac3e
--- /dev/null
+++ b/graphics/composer/2.4/default/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sched.h>
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <binder/ProcessState.h>
+#include <composer-passthrough/2.4/HwcLoader.h>
+#include <hidl/HidlTransportSupport.h>
+
+using android::hardware::graphics::composer::V2_4::IComposer;
+using android::hardware::graphics::composer::V2_4::passthrough::HwcLoader;
+
+int main() {
+ // the conventional HAL might start binder services
+ android::ProcessState::initWithDriver("/dev/vndbinder");
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
+ android::ProcessState::self()->startThreadPool();
+
+ // same as SF main thread
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO: %d", errno);
+ }
+
+ android::hardware::configureRpcThreadpool(4, true /* will join */);
+
+ android::sp<IComposer> composer = HwcLoader::load();
+ if (composer == nullptr) {
+ return 1;
+ }
+ if (composer->registerAsService() != android::NO_ERROR) {
+ ALOGE("failed to register service");
+ return 1;
+ }
+
+ android::hardware::joinRpcThreadpool();
+
+ ALOGE("service is terminating");
+ return 1;
+}
diff --git a/graphics/composer/2.4/types.hal b/graphics/composer/2.4/types.hal
new file mode 100644
index 0000000..065f024
--- /dev/null
+++ b/graphics/composer/2.4/types.hal
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer@2.4;
+
+import @2.1::Error;
+
+enum Error : @2.1::Error {
+ /**
+ * Seamless cannot be required for configurations that don't share a config group
+ */
+ SEAMLESS_NOT_ALLOWED = 9,
+ /**
+ * Seamless requirements cannot be met
+ */
+ SEAMLESS_NOT_POSSIBLE = 10,
+};
+
+/**
+ * Timing for a vsync period change.
+ */
+struct VsyncPeriodChangeTimeline {
+ /**
+ * The time in CLOCK_MONOTONIC when the new display will start to refresh at
+ * the new vsync period.
+ */
+ int64_t newVsyncAppliedTimeNanos;
+
+ /**
+ * Set to true if the client is required to send a frame to be displayed before
+ * the change can take place.
+ */
+ bool refreshRequired;
+
+ /**
+ * The time in CLOCK_MONOTONIC when the client is expected to send the new frame.
+ * Should be ignored if refreshRequired is false.
+ */
+ int64_t refreshTimeNanos;
+};
+
+typedef uint32_t VsyncPeriodNanos;
diff --git a/graphics/composer/2.4/utils/OWNERS b/graphics/composer/2.4/utils/OWNERS
new file mode 100644
index 0000000..cc6d937
--- /dev/null
+++ b/graphics/composer/2.4/utils/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+lpy@google.com
+stoza@google.com
+vhau@google.com
diff --git a/graphics/composer/2.4/utils/command-buffer/Android.bp b/graphics/composer/2.4/utils/command-buffer/Android.bp
new file mode 100644
index 0000000..8acf0e1
--- /dev/null
+++ b/graphics/composer/2.4/utils/command-buffer/Android.bp
@@ -0,0 +1,18 @@
+cc_library_headers {
+ name: "android.hardware.graphics.composer@2.4-command-buffer",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.4",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.4",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
new file mode 100644
index 0000000..eb35e5c
--- /dev/null
+++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warn "ComposerCommandBuffer.h included without LOG_TAG"
+#endif
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 0
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+
+using android::hardware::MessageQueue;
+using android::hardware::graphics::composer::V2_4::Error;
+using android::hardware::graphics::composer::V2_4::IComposerClient;
+
+// This class helps build a command queue. Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase : public V2_3::CommandWriterBase {
+ public:
+ static constexpr uint16_t kSetClientTargetPropertyLength = 2;
+
+ CommandWriterBase(uint32_t initialMaxSize) : V2_3::CommandWriterBase(initialMaxSize) {}
+
+ void setClientTargetProperty(
+ const IComposerClient::ClientTargetProperty& clientTargetProperty) {
+ beginCommand(IComposerClient::Command::SET_CLIENT_TARGET_PROPERTY,
+ kSetClientTargetPropertyLength);
+ writeSigned(static_cast<int32_t>(clientTargetProperty.pixelFormat));
+ writeSigned(static_cast<int32_t>(clientTargetProperty.dataspace));
+ endCommand();
+ }
+
+ void setLayerGenericMetadata(const hidl_string& key, const bool mandatory,
+ const hidl_vec<uint8_t>& value) {
+ const size_t commandSize = 3 + sizeToElements(key.size()) + sizeToElements(value.size());
+ if (commandSize > std::numeric_limits<uint16_t>::max()) {
+ LOG_FATAL("Too much generic metadata (%zu elements)", commandSize);
+ return;
+ }
+
+ beginCommand(IComposerClient::Command::SET_LAYER_GENERIC_METADATA,
+ static_cast<uint16_t>(commandSize));
+ write(key.size());
+ writeBlob(key.size(), reinterpret_cast<const unsigned char*>(key.c_str()));
+ write(mandatory);
+ write(value.size());
+ writeBlob(value.size(), value.data());
+ endCommand();
+ }
+
+ protected:
+ uint32_t sizeToElements(uint32_t size) { return (size + 3) / 4; }
+};
+
+// This class helps parse a command queue. Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase : public V2_3::CommandReaderBase {
+ public:
+ CommandReaderBase() : V2_3::CommandReaderBase() {}
+};
+
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/hal/Android.bp b/graphics/composer/2.4/utils/hal/Android.bp
new file mode 100644
index 0000000..f4cdea4
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_headers {
+ name: "android.hardware.graphics.composer@2.4-hal",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.4",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.4",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.3-hal",
+ "android.hardware.graphics.composer@2.4-command-buffer",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.3-hal",
+ "android.hardware.graphics.composer@2.4-command-buffer",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h
new file mode 100644
index 0000000..129bae6
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "Composer.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <composer-hal/2.3/Composer.h>
+#include <composer-hal/2.4/ComposerClient.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+namespace detail {
+
+// ComposerImpl implements V2_*::IComposer on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerImpl : public V2_3::hal::detail::ComposerImpl<Interface, Hal> {
+ public:
+ static std::unique_ptr<ComposerImpl> create(std::unique_ptr<Hal> hal) {
+ return std::make_unique<ComposerImpl>(std::move(hal));
+ }
+
+ explicit ComposerImpl(std::unique_ptr<Hal> hal) : BaseType2_3(std::move(hal)) {}
+
+ // IComposer 2.4 interface
+
+ Return<void> createClient_2_4(IComposer::createClient_2_4_cb hidl_cb) override {
+ std::unique_lock<std::mutex> lock(mClientMutex);
+ if (!waitForClientDestroyedLocked(lock)) {
+ hidl_cb(Error::NO_RESOURCES, nullptr);
+ return Void();
+ }
+
+ sp<ComposerClient> client = ComposerClient::create(mHal.get()).release();
+ if (!client) {
+ hidl_cb(Error::NO_RESOURCES, nullptr);
+ return Void();
+ }
+
+ auto clientDestroyed = [this]() { onClientDestroyed(); };
+ client->setOnClientDestroyed(clientDestroyed);
+
+ mClient = client;
+ hidl_cb(Error::NONE, client);
+ return Void();
+ }
+
+ private:
+ using BaseType2_3 = V2_3::hal::detail::ComposerImpl<Interface, Hal>;
+ using BaseType2_1 = V2_1::hal::detail::ComposerImpl<Interface, Hal>;
+
+ using BaseType2_1::mClient;
+ using BaseType2_1::mClientMutex;
+ using BaseType2_1::mHal;
+ using BaseType2_1::onClientDestroyed;
+ using BaseType2_1::waitForClientDestroyedLocked;
+};
+
+} // namespace detail
+
+using Composer = detail::ComposerImpl<IComposer, ComposerHal>;
+
+} // namespace hal
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
new file mode 100644
index 0000000..c889069
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerClient.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.4/IComposerCallback.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-hal/2.4/ComposerCommandEngine.h>
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-resources/2.1/ComposerResources.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+namespace detail {
+
+// ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl<Interface, Hal> {
+ public:
+ ComposerClientImpl(Hal* hal) : BaseType2_3(hal) {}
+
+ ~ComposerClientImpl() override { mHal->unregisterEventCallback_2_4(); }
+
+ class HalEventCallback : public Hal::EventCallback_2_4 {
+ public:
+ HalEventCallback(const sp<IComposerCallback> callback,
+ V2_1::hal::ComposerResources* resources)
+ : mCallback(callback), mResources(resources) {}
+
+ void onHotplug(Display display, IComposerCallback::Connection connected) override {
+ if (connected == IComposerCallback::Connection::CONNECTED) {
+ mResources->addPhysicalDisplay(display);
+ } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
+ mResources->removeDisplay(display);
+ }
+
+ auto ret = mCallback->onHotplug(display, connected);
+ ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str());
+ }
+
+ void onRefresh(Display display) override {
+ mResources->setDisplayMustValidateState(display, true);
+ auto ret = mCallback->onRefresh(display);
+ ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s", ret.description().c_str());
+ }
+
+ void onVsync(Display display, int64_t timestamp) override {
+ auto ret = mCallback->onVsync(display, timestamp);
+ ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s", ret.description().c_str());
+ }
+
+ void onVsync_2_4(Display display, int64_t timestamp,
+ VsyncPeriodNanos vsyncPeriodNanos) override {
+ auto ret = mCallback->onVsync_2_4(display, timestamp, vsyncPeriodNanos);
+ ALOGE_IF(!ret.isOk(), "failed to send onVsync_2_4: %s", ret.description().c_str());
+ }
+
+ void onVsyncPeriodTimingChanged(Display display,
+ const VsyncPeriodChangeTimeline& updatedTimeline) override {
+ auto ret = mCallback->onVsyncPeriodTimingChanged(display, updatedTimeline);
+ ALOGE_IF(!ret.isOk(), "failed to send onVsyncPeriodTimingChanged: %s",
+ ret.description().c_str());
+ }
+
+ void onSeamlessPossible(Display display) override {
+ auto ret = mCallback->onSeamlessPossible(display);
+ ALOGE_IF(!ret.isOk(), "failed to send onSealmessPossible: %s",
+ ret.description().c_str());
+ }
+
+ protected:
+ const sp<IComposerCallback> mCallback;
+ V2_1::hal::ComposerResources* const mResources;
+ };
+
+ Return<void> registerCallback_2_4(const sp<IComposerCallback>& callback) override {
+ // no locking as we require this function to be called only once
+ mHalEventCallback_2_4 = std::make_unique<HalEventCallback>(callback, mResources.get());
+ mHal->registerEventCallback_2_4(mHalEventCallback_2_4.get());
+ return Void();
+ }
+
+ Return<void> getDisplayCapabilities_2_4(
+ Display display, IComposerClient::getDisplayCapabilities_2_4_cb hidl_cb) override {
+ std::vector<IComposerClient::DisplayCapability> capabilities;
+ Error error = mHal->getDisplayCapabilities_2_4(display, &capabilities);
+ hidl_cb(error, capabilities);
+ return Void();
+ }
+
+ Return<void> getDisplayConnectionType(
+ Display display, IComposerClient::getDisplayConnectionType_cb hidl_cb) override {
+ IComposerClient::DisplayConnectionType type;
+ Error error = mHal->getDisplayConnectionType(display, &type);
+ hidl_cb(error, type);
+ return Void();
+ }
+
+ Return<void> getDisplayAttribute_2_4(
+ Display display, Config config, IComposerClient::Attribute attribute,
+ IComposerClient::getDisplayAttribute_2_4_cb hidl_cb) override {
+ int32_t value = 0;
+ Error error = mHal->getDisplayAttribute_2_4(display, config, attribute, &value);
+ hidl_cb(error, value);
+ return Void();
+ }
+
+ Return<void> getDisplayVsyncPeriod(Display display,
+ IComposerClient::getDisplayVsyncPeriod_cb hidl_cb) override {
+ VsyncPeriodNanos vsyncPeriods;
+ Error error = mHal->getDisplayVsyncPeriod(display, &vsyncPeriods);
+ hidl_cb(error, vsyncPeriods);
+ return Void();
+ }
+
+ Return<void> setActiveConfigWithConstraints(
+ Display display, Config config,
+ const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ IComposerClient::setActiveConfigWithConstraints_cb hidl_cb) override {
+ VsyncPeriodChangeTimeline timeline = {};
+ Error error = mHal->setActiveConfigWithConstraints(display, config,
+ vsyncPeriodChangeConstraints, &timeline);
+ hidl_cb(error, timeline);
+ 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);
+ }
+
+ Return<void> getLayerGenericMetadataKeys(
+ IComposerClient::getLayerGenericMetadataKeys_cb hidl_cb) override {
+ std::vector<IComposerClient::LayerGenericMetadataKey> keys;
+ Error error = mHal->getLayerGenericMetadataKeys(&keys);
+ hidl_cb(error, keys);
+ return Void();
+ }
+
+ static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
+ auto client = std::make_unique<ComposerClientImpl>(hal);
+ return client->init() ? std::move(client) : nullptr;
+ }
+
+ protected:
+ std::unique_ptr<V2_1::hal::ComposerCommandEngine> createCommandEngine() override {
+ return std::make_unique<ComposerCommandEngine>(
+ mHal, static_cast<V2_2::hal::ComposerResources*>(mResources.get()));
+ }
+
+ private:
+ using BaseType2_3 = V2_3::hal::detail::ComposerClientImpl<Interface, Hal>;
+ using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
+ using BaseType2_1::mHal;
+ using BaseType2_1::mResources;
+ std::unique_ptr<HalEventCallback> mHalEventCallback_2_4;
+};
+
+} // namespace detail
+
+using ComposerClient = detail::ComposerClientImpl<IComposerClient, ComposerHal>;
+
+} // namespace hal
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
new file mode 100644
index 0000000..697d6b8
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerCommandEngine.h included without LOG_TAG"
+#endif
+
+#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
+#include <composer-hal/2.1/ComposerCommandEngine.h>
+#include <composer-hal/2.3/ComposerCommandEngine.h>
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-resources/2.2/ComposerResources.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+class ComposerCommandEngine : public V2_3::hal::ComposerCommandEngine {
+ public:
+ ComposerCommandEngine(ComposerHal* hal, V2_2::hal::ComposerResources* resources)
+ : BaseType2_3(hal, resources), mHal(hal) {}
+
+ protected:
+ std::unique_ptr<V2_1::CommandWriterBase> createCommandWriter(
+ size_t writerInitialSize) override {
+ return std::make_unique<CommandWriterBase>(writerInitialSize);
+ }
+
+ private:
+ using BaseType2_1 = V2_1::hal::ComposerCommandEngine;
+ using BaseType2_3 = V2_3::hal::ComposerCommandEngine;
+ using BaseType2_1::mWriter;
+
+ V2_1::Error executeValidateDisplayInternal() override {
+ std::vector<Layer> changedLayers;
+ std::vector<IComposerClient::Composition> compositionTypes;
+ uint32_t displayRequestMask = 0x0;
+ std::vector<Layer> requestedLayers;
+ std::vector<uint32_t> requestMasks;
+ IComposerClient::ClientTargetProperty clientTargetProperty{PixelFormat::RGBA_8888,
+ Dataspace::UNKNOWN};
+
+ auto err = mHal->validateDisplay_2_4(mCurrentDisplay, &changedLayers, &compositionTypes,
+ &displayRequestMask, &requestedLayers, &requestMasks,
+ &clientTargetProperty);
+ mResources->setDisplayMustValidateState(mCurrentDisplay, false);
+ if (err == Error::NONE) {
+ mWriter->setChangedCompositionTypes(changedLayers, compositionTypes);
+ mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
+ getWriter()->setClientTargetProperty(clientTargetProperty);
+ } else {
+ mWriter->setError(getCommandLoc(), static_cast<V2_1::Error>(err));
+ }
+ return static_cast<V2_1::Error>(err);
+ }
+
+ CommandWriterBase* getWriter() { return static_cast<CommandWriterBase*>(mWriter.get()); }
+
+ bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
+ switch (static_cast<IComposerClient::Command>(command)) {
+ case IComposerClient::Command::SET_LAYER_GENERIC_METADATA:
+ return executeSetLayerGenericMetadata(length);
+ default:
+ return BaseType2_3::executeCommand(command, length);
+ }
+ }
+
+ bool executeSetLayerGenericMetadata(uint16_t length) {
+ // We expect at least two buffer lengths and a mandatory flag
+ if (length < 3) {
+ return false;
+ }
+
+ const uint32_t keySize = read();
+ std::string key;
+ key.resize(keySize);
+ readBlob(keySize, key.data());
+
+ const bool mandatory = read();
+
+ const uint32_t valueSize = read();
+ std::vector<uint8_t> value(valueSize);
+ readBlob(valueSize, value.data());
+
+ auto error = mHal->setLayerGenericMetadata(mCurrentDisplay, mCurrentLayer, key, mandatory,
+ value);
+ if (error != Error::NONE) {
+ // The error cast is safe because setLayerGenericMetadata doesn't
+ // return any of the new values added in V2_4::Error
+ mWriter->setError(getCommandLoc(), static_cast<V2_1::Error>(error));
+ }
+
+ return true;
+ }
+
+ ComposerHal* mHal;
+};
+
+} // namespace hal
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
new file mode 100644
index 0000000..58991c1
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/graphics/composer/2.4/types.h>
+#include <composer-hal/2.3/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
+using common::V1_2::PixelFormat;
+using V2_1::Config;
+using V2_1::Display;
+using V2_1::Layer;
+using V2_4::Error;
+using V2_4::VsyncPeriodNanos;
+
+class ComposerHal : public V2_3::hal::ComposerHal {
+ public:
+ class EventCallback_2_4 {
+ public:
+ virtual ~EventCallback_2_4() = default;
+ virtual void onHotplug(Display display, IComposerCallback::Connection connected) = 0;
+ virtual void onRefresh(Display display) = 0;
+ virtual void onVsync(Display display, int64_t timestamp) = 0;
+ virtual void onVsync_2_4(Display display, int64_t timestamp,
+ VsyncPeriodNanos vsyncPeriodNanos) = 0;
+ virtual void onVsyncPeriodTimingChanged(Display display,
+ const VsyncPeriodChangeTimeline& timeline) = 0;
+ virtual void onSeamlessPossible(Display display) = 0;
+ };
+
+ virtual void registerEventCallback_2_4(EventCallback_2_4* callback) = 0;
+
+ virtual void unregisterEventCallback_2_4() = 0;
+
+ virtual Error getDisplayCapabilities_2_4(
+ Display display, std::vector<IComposerClient::DisplayCapability>* outCapabilities) = 0;
+ virtual Error getDisplayConnectionType(Display display,
+ IComposerClient::DisplayConnectionType* outType) = 0;
+ virtual Error getDisplayAttribute_2_4(Display display, Config config,
+ IComposerClient::Attribute attribute,
+ int32_t* outValue) = 0;
+ virtual Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) = 0;
+ virtual Error setActiveConfigWithConstraints(
+ 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;
+ virtual Error validateDisplay_2_4(
+ Display display, std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks,
+ IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0;
+ virtual Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+ bool mandatory, const std::vector<uint8_t>& value) = 0;
+ virtual Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
+};
+
+} // namespace hal
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/passthrough/Android.bp b/graphics/composer/2.4/utils/passthrough/Android.bp
new file mode 100644
index 0000000..43d9aaa
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_headers {
+ name: "android.hardware.graphics.composer@2.4-passthrough",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ header_libs: [
+ "android.hardware.graphics.composer@2.3-passthrough",
+ "android.hardware.graphics.composer@2.4-hal",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.3-passthrough",
+ "android.hardware.graphics.composer@2.4-hal",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
new file mode 100644
index 0000000..d28e006
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcHal.h included without LOG_TAG"
+#endif
+
+#include <type_traits>
+
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-passthrough/2.3/HwcHal.h>
+#include <hardware/hwcomposer_defs.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace passthrough {
+
+namespace detail {
+
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
+using common::V1_2::PixelFormat;
+using V2_1::Config;
+using V2_1::Display;
+using V2_1::Layer;
+using V2_4::Error;
+
+// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2
+template <typename Hal>
+class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
+ public:
+ void registerEventCallback_2_4(hal::ComposerHal::EventCallback_2_4* callback) override {
+ mEventCallback_2_4 = callback;
+
+ BaseType2_1::mDispatch.registerCallback(
+ mDevice, HWC2_CALLBACK_HOTPLUG, this,
+ reinterpret_cast<hwc2_function_pointer_t>(hotplugHook));
+ BaseType2_1::mDispatch.registerCallback(
+ mDevice, HWC2_CALLBACK_REFRESH, this,
+ reinterpret_cast<hwc2_function_pointer_t>(refreshHook));
+ BaseType2_1::mDispatch.registerCallback(
+ mDevice, HWC2_CALLBACK_VSYNC_2_4, this,
+ reinterpret_cast<hwc2_function_pointer_t>(vsync_2_4_Hook));
+ BaseType2_1::mDispatch.registerCallback(
+ mDevice, HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED, this,
+ reinterpret_cast<hwc2_function_pointer_t>(vsyncPeriodTimingChangedHook));
+ BaseType2_1::mDispatch.registerCallback(
+ mDevice, HWC2_CALLBACK_SEAMLESS_POSSIBLE, this,
+ reinterpret_cast<hwc2_function_pointer_t>(seamlessPossibleHook));
+ }
+
+ void unregisterEventCallback_2_4() override {
+ // we assume the callback functions
+ //
+ // - can be unregistered
+ // - can be in-flight
+ // - will never be called afterward
+ //
+ // 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_2_4, this, nullptr);
+ BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED,
+ this, nullptr);
+ BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_SEAMLESS_POSSIBLE, this,
+ nullptr);
+
+ mEventCallback_2_4 = nullptr;
+ }
+
+ Error getDisplayCapabilities_2_4(
+ Display display,
+ std::vector<IComposerClient::DisplayCapability>* outCapabilities) override {
+ std::vector<V2_3::IComposerClient::DisplayCapability> capabilities;
+ V2_3::Error error_2_3 = BaseType2_3::getDisplayCapabilities(display, &capabilities);
+ Error error = static_cast<Error>(error_2_3);
+ if (error != Error::NONE) {
+ return error;
+ }
+ outCapabilities->clear();
+ outCapabilities->reserve(capabilities.size());
+ for (auto capability : capabilities) {
+ outCapabilities->push_back(static_cast<IComposerClient::DisplayCapability>(capability));
+ }
+ return Error::NONE;
+ }
+
+ Error getDisplayConnectionType(Display display,
+ IComposerClient::DisplayConnectionType* outType) override {
+ if (!mDispatch.getDisplayConnectionType) {
+ return Error::UNSUPPORTED;
+ }
+
+ uint32_t type = HWC2_DISPLAY_CONNECTION_TYPE_INTERNAL;
+ int32_t error = mDispatch.getDisplayConnectionType(mDevice, display, &type);
+ *outType = static_cast<IComposerClient::DisplayConnectionType>(type);
+ return static_cast<Error>(error);
+ }
+
+ Error getDisplayAttribute_2_4(Display display, Config config,
+ IComposerClient::Attribute attribute,
+ int32_t* outValue) override {
+ int32_t err = BaseType2_1::mDispatch.getDisplayAttribute(
+ mDevice, display, config, static_cast<int32_t>(attribute), outValue);
+ if (err != HWC2_ERROR_NONE && *outValue == -1) {
+ // Convert the error from hwcomposer2 to IComposerClient definition
+ return Error::BAD_PARAMETER;
+ }
+ return static_cast<Error>(err);
+ }
+
+ Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) override {
+ if (!mDispatch.getDisplayVsyncPeriod) {
+ return Error::UNSUPPORTED;
+ }
+
+ int32_t error = mDispatch.getDisplayVsyncPeriod(mDevice, display, outVsyncPeriod);
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+ return Error::NONE;
+ }
+
+ Error setActiveConfigWithConstraints(
+ Display display, Config config,
+ const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ VsyncPeriodChangeTimeline* timeline) override {
+ if (!mDispatch.setActiveConfigWithConstraints) {
+ return Error::UNSUPPORTED;
+ }
+
+ hwc_vsync_period_change_constraints_t vsync_period_change_constraints;
+ vsync_period_change_constraints.desiredTimeNanos =
+ vsyncPeriodChangeConstraints.desiredTimeNanos;
+ vsync_period_change_constraints.seamlessRequired =
+ vsyncPeriodChangeConstraints.seamlessRequired;
+
+ hwc_vsync_period_change_timeline_t out_timeline;
+ int32_t error = mDispatch.setActiveConfigWithConstraints(
+ mDevice, display, config, &vsync_period_change_constraints, &out_timeline);
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+ timeline->newVsyncAppliedTimeNanos = out_timeline.newVsyncAppliedTimeNanos;
+ timeline->refreshRequired = out_timeline.refreshRequired;
+ timeline->refreshTimeNanos = out_timeline.refreshTimeNanos;
+ 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;
+ }
+
+ Error validateDisplay_2_4(
+ Display display, std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks,
+ IComposerClient::ClientTargetProperty* outClientTargetProperty) override {
+ auto err = static_cast<Error>(BaseType2_1::validateDisplay(
+ display, outChangedLayers, outCompositionTypes, outDisplayRequestMask,
+ outRequestedLayers, outRequestMasks));
+ if (err != Error::NONE) {
+ return err;
+ }
+
+ if (mDispatch.getClientTargetProperty) {
+ hwc_client_target_property_t clientTargetProperty;
+ err = static_cast<Error>(
+ mDispatch.getClientTargetProperty(mDevice, display, &clientTargetProperty));
+ outClientTargetProperty->pixelFormat =
+ static_cast<PixelFormat>(clientTargetProperty.pixelFormat);
+ outClientTargetProperty->dataspace =
+ static_cast<Dataspace>(clientTargetProperty.dataspace);
+ }
+
+ return err;
+ }
+
+ Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+ bool mandatory, const std::vector<uint8_t>& value) override {
+ if (!mDispatch.setLayerGenericMetadata) {
+ return Error::UNSUPPORTED;
+ }
+
+ if (key.size() > std::numeric_limits<uint32_t>::max()) {
+ return Error::BAD_PARAMETER;
+ }
+
+ if (value.size() > std::numeric_limits<uint32_t>::max()) {
+ return Error::BAD_PARAMETER;
+ }
+
+ int32_t error = mDispatch.setLayerGenericMetadata(
+ mDevice, display, layer, static_cast<uint32_t>(key.size()), key.c_str(), mandatory,
+ static_cast<uint32_t>(value.size()), value.data());
+ return static_cast<Error>(error);
+ }
+
+ Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override {
+ if (!mDispatch.getLayerGenericMetadataKey) {
+ return Error::UNSUPPORTED;
+ }
+
+ std::vector<IComposerClient::LayerGenericMetadataKey> keys;
+
+ uint32_t index = 0;
+ uint32_t keyLength = 0;
+ while (true) {
+ mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, nullptr, nullptr);
+ if (keyLength == 0) {
+ break;
+ }
+
+ IComposerClient::LayerGenericMetadataKey key;
+ std::string keyName;
+ keyName.resize(keyLength);
+ mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, keyName.data(),
+ &key.mandatory);
+ key.name = keyName;
+ keys.emplace_back(std::move(key));
+
+ // Only attempt to load the first 100 keys to avoid an infinite loop
+ // if something goes wrong
+ if (++index > 100) {
+ break;
+ }
+ }
+
+ *outKeys = std::move(keys);
+ return Error::NONE;
+ }
+
+ protected:
+ bool initDispatch() override {
+ if (!BaseType2_3::initDispatch()) {
+ return false;
+ }
+
+ if (!BaseType2_1::initDispatch(HWC2_FUNCTION_GET_DISPLAY_VSYNC_PERIOD,
+ &mDispatch.getDisplayVsyncPeriod) ||
+ !BaseType2_1::initDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS,
+ &mDispatch.setActiveConfigWithConstraints)) {
+ return false;
+ }
+
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CONNECTION_TYPE,
+ &mDispatch.getDisplayConnectionType);
+ 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);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_PROPERTY,
+ &mDispatch.getClientTargetProperty);
+ this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_GENERIC_METADATA,
+ &mDispatch.setLayerGenericMetadata);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_LAYER_GENERIC_METADATA_KEY,
+ &mDispatch.getLayerGenericMetadataKey);
+
+ return true;
+ }
+
+ static void hotplugHook(hwc2_callback_data_t callbackData, hwc2_display_t display,
+ int32_t connected) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ hal->mEventCallback_2_4->onHotplug(display,
+ static_cast<IComposerCallback::Connection>(connected));
+ }
+
+ static void refreshHook(hwc2_callback_data_t callbackData, hwc2_display_t display) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ hal->mEventCallback_2_4->onRefresh(display);
+ }
+
+ static void vsyncHook(hwc2_callback_data_t callbackData, hwc2_display_t display,
+ int64_t timestamp) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ hal->mEventCallback_2_4->onVsync(display, timestamp);
+ }
+
+ static void vsync_2_4_Hook(hwc2_callback_data_t callbackData, hwc2_display_t display,
+ int64_t timestamp, hwc2_vsync_period_t vsyncPeriodNanos) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ hal->mEventCallback_2_4->onVsync_2_4(display, timestamp, vsyncPeriodNanos);
+ }
+
+ static void vsyncPeriodTimingChangedHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display,
+ hwc_vsync_period_change_timeline_t* updated_timeline) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ VsyncPeriodChangeTimeline timeline;
+ timeline.newVsyncAppliedTimeNanos = updated_timeline->newVsyncAppliedTimeNanos;
+ timeline.refreshRequired = updated_timeline->refreshRequired;
+ timeline.refreshTimeNanos = updated_timeline->refreshTimeNanos;
+ hal->mEventCallback_2_4->onVsyncPeriodTimingChanged(display, timeline);
+ }
+
+ static void seamlessPossibleHook(hwc2_callback_data_t callbackData, hwc2_display_t display) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ hal->mEventCallback_2_4->onSeamlessPossible(display);
+ }
+
+ private:
+ struct {
+ 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;
+ HWC2_PFN_GET_CLIENT_TARGET_PROPERTY getClientTargetProperty;
+ HWC2_PFN_SET_LAYER_GENERIC_METADATA setLayerGenericMetadata;
+ HWC2_PFN_GET_LAYER_GENERIC_METADATA_KEY getLayerGenericMetadataKey;
+ } mDispatch = {};
+
+ hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr;
+
+ using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
+ using BaseType2_3 = V2_3::passthrough::detail::HwcHalImpl<Hal>;
+ using BaseType2_1::mDevice;
+};
+
+} // namespace detail
+
+using HwcHal = detail::HwcHalImpl<hal::ComposerHal>;
+
+} // namespace passthrough
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h
new file mode 100644
index 0000000..a7cc588
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcLoader.h included without LOG_TAG"
+#endif
+
+#include <composer-hal/2.4/Composer.h>
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-passthrough/2.3/HwcLoader.h>
+#include <composer-passthrough/2.4/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace passthrough {
+
+class HwcLoader : public V2_3::passthrough::HwcLoader {
+ public:
+ static IComposer* load() {
+ const hw_module_t* module = loadModule();
+ if (!module) {
+ return nullptr;
+ }
+
+ auto hal = createHalWithAdapter(module);
+ if (!hal) {
+ return nullptr;
+ }
+
+ return createComposer(std::move(hal)).release();
+ }
+
+ // create a ComposerHal instance
+ static std::unique_ptr<hal::ComposerHal> createHal(const hw_module_t* module) {
+ auto hal = std::make_unique<HwcHal>();
+ return hal->initWithModule(module) ? std::move(hal) : nullptr;
+ }
+
+ // create a ComposerHal instance, insert an adapter if necessary
+ static std::unique_ptr<hal::ComposerHal> createHalWithAdapter(const hw_module_t* module) {
+ bool adapted;
+ hwc2_device_t* device = openDeviceWithAdapter(module, &adapted);
+ if (!device) {
+ return nullptr;
+ }
+ auto hal = std::make_unique<HwcHal>();
+ return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr;
+ }
+
+ // create an IComposer instance
+ static std::unique_ptr<IComposer> createComposer(std::unique_ptr<hal::ComposerHal> hal) {
+ return hal::Composer::create(std::move(hal));
+ }
+};
+
+} // namespace passthrough
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp
new file mode 100644
index 0000000..673c15e
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+ name: "android.hardware.graphics.composer@2.4-vts",
+ defaults: ["hidl_defaults"],
+ srcs: [
+ "ComposerVts.cpp",
+ "GraphicsComposerCallback.cpp",
+ ],
+ static_libs: [
+ "VtsHalHidlTargetTestBase",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3-vts",
+ "android.hardware.graphics.composer@2.3",
+ "android.hardware.graphics.composer@2.4",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ cflags: [
+ "-O0",
+ "-g",
+ "-DLOG_TAG=\"ComposerVts\"",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
new file mode 100644
index 0000000..8cdc452
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <composer-vts/2.4/ComposerVts.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+
+using V2_4::Error;
+
+Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
+
+Composer::Composer(const std::string& name)
+ : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
+
+Composer::Composer(const sp<IComposer>& composer)
+ : V2_3::vts::Composer(composer), mComposer(composer) {}
+
+std::unique_ptr<ComposerClient> Composer::createClient() {
+ std::unique_ptr<ComposerClient> client;
+ mComposer->createClient_2_4([&client](const auto& tmpError, const auto& tmpClient) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+ client = std::make_unique<ComposerClient>(tmpClient);
+ });
+
+ return client;
+}
+
+sp<IComposerClient> ComposerClient::getRaw() const {
+ return mClient;
+}
+
+Error ComposerClient::getDisplayCapabilities(
+ Display display, std::vector<IComposerClient::DisplayCapability>* outCapabilities) {
+ Error error = Error::NONE;
+ mClient->getDisplayCapabilities_2_4(display,
+ [&](const auto& tmpError, const auto& tmpCapabilities) {
+ error = tmpError;
+ *outCapabilities = tmpCapabilities;
+ });
+ return error;
+}
+
+Error ComposerClient::getDisplayConnectionType(Display display,
+ IComposerClient::DisplayConnectionType* outType) {
+ Error error = Error::NONE;
+ mClient->getDisplayConnectionType(display, [&](const auto& tmpError, const auto& tmpType) {
+ error = tmpError;
+ *outType = tmpType;
+ });
+ return error;
+}
+
+int32_t ComposerClient::getDisplayAttribute_2_4(
+ android::hardware::graphics::composer::V2_1::Display display,
+ android::hardware::graphics::composer::V2_1::Config config,
+ IComposerClient::Attribute attribute) {
+ int32_t value = 0;
+ mClient->getDisplayAttribute_2_4(
+ display, config, attribute, [&](const auto& tmpError, const auto& tmpValue) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get display attribute";
+ value = tmpValue;
+ });
+
+ return value;
+}
+
+void ComposerClient::registerCallback_2_4(const sp<IComposerCallback>& callback) {
+ mClient->registerCallback_2_4(callback);
+}
+
+Error ComposerClient::getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) {
+ Error error = Error::NONE;
+ mClient->getDisplayVsyncPeriod(display, [&](const auto& tmpError, const auto& tmpVsyncPeriod) {
+ error = tmpError;
+ *outVsyncPeriod = tmpVsyncPeriod;
+ });
+ return error;
+}
+
+Error ComposerClient::setActiveConfigWithConstraints(
+ Display display, Config config,
+ const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ VsyncPeriodChangeTimeline* timeline) {
+ Error error = Error::NONE;
+ mClient->setActiveConfigWithConstraints(display, config, vsyncPeriodChangeConstraints,
+ [&](const auto& tmpError, const auto& tmpTimeline) {
+ error = tmpError;
+ *timeline = tmpTimeline;
+ });
+ 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);
+}
+
+Error ComposerClient::getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) {
+ Error error = Error::NONE;
+ mClient->getLayerGenericMetadataKeys([&](const auto tmpError, const auto& tmpKeys) {
+ error = tmpError;
+ *outKeys = tmpKeys;
+ });
+ return error;
+}
+
+} // namespace vts
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp b/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp
new file mode 100644
index 0000000..c9366a8
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <composer-vts/2.4/GraphicsComposerCallback.h>
+
+namespace android::hardware::graphics::composer::V2_4::vts {
+
+void GraphicsComposerCallback::setVsyncAllowed(bool allowed) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mVsyncAllowed = allowed;
+}
+
+std::vector<Display> GraphicsComposerCallback::getDisplays() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return std::vector<Display>(mDisplays.begin(), mDisplays.end());
+}
+
+int32_t GraphicsComposerCallback::getInvalidHotplugCount() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mInvalidHotplugCount;
+}
+
+int32_t GraphicsComposerCallback::getInvalidRefreshCount() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mInvalidRefreshCount;
+}
+
+int32_t GraphicsComposerCallback::getInvalidVsyncCount() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mInvalidVsyncCount;
+}
+
+int32_t GraphicsComposerCallback::getInvalidVsync_2_4Count() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mInvalidVsync_2_4Count;
+}
+
+int32_t GraphicsComposerCallback::getInvalidVsyncPeriodChangeCount() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mInvalidVsyncPeriodChangeCount;
+}
+
+int32_t GraphicsComposerCallback::getInvalidSeamlessPossibleCount() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mInvalidSeamlessPossibleCount;
+}
+
+std::optional<VsyncPeriodChangeTimeline>
+GraphicsComposerCallback::takeLastVsyncPeriodChangeTimeline() {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ std::optional<VsyncPeriodChangeTimeline> ret;
+ ret.swap(mTimeline);
+
+ return ret;
+}
+
+Return<void> GraphicsComposerCallback::onHotplug(Display display, Connection connection) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (connection == Connection::CONNECTED) {
+ if (!mDisplays.insert(display).second) {
+ mInvalidHotplugCount++;
+ }
+ } else if (connection == Connection::DISCONNECTED) {
+ if (!mDisplays.erase(display)) {
+ mInvalidHotplugCount++;
+ }
+ }
+
+ return Void();
+}
+
+Return<void> GraphicsComposerCallback::onRefresh(Display display) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (mDisplays.count(display) == 0) {
+ mInvalidRefreshCount++;
+ }
+
+ return Void();
+}
+
+Return<void> GraphicsComposerCallback::onVsync(Display, int64_t) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ // On composer 2.4, onVsync is not expected at all
+ mInvalidVsyncCount++;
+
+ return Void();
+}
+
+Return<void> GraphicsComposerCallback::onVsync_2_4(Display display, int64_t, VsyncPeriodNanos) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (!mVsyncAllowed || mDisplays.count(display) == 0) {
+ mInvalidVsync_2_4Count++;
+ }
+
+ return Void();
+}
+
+Return<void> GraphicsComposerCallback::onVsyncPeriodTimingChanged(
+ Display display, const VsyncPeriodChangeTimeline& updatedTimeline) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (mDisplays.count(display) == 0) {
+ mInvalidVsyncPeriodChangeCount++;
+ }
+
+ mTimeline = updatedTimeline;
+
+ return Void();
+}
+
+Return<void> GraphicsComposerCallback::onSeamlessPossible(Display) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ mInvalidSeamlessPossibleCount++;
+
+ return Void();
+}
+
+} // namespace android::hardware::graphics::composer::V2_4::vts
\ No newline at end of file
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
new file mode 100644
index 0000000..3dd8e50
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-vts/2.3/ComposerVts.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
+using common::V1_2::PixelFormat;
+using V2_1::Config;
+using V2_1::Display;
+using V2_4::Error;
+using V2_4::IComposer;
+using V2_4::IComposerClient;
+using V2_4::VsyncPeriodNanos;
+
+class ComposerClient;
+
+// A wrapper to IComposer.
+class Composer : public V2_3::vts::Composer {
+ public:
+ Composer();
+ explicit Composer(const std::string& name);
+ explicit Composer(const sp<IComposer>& composer);
+
+ std::unique_ptr<ComposerClient> createClient();
+
+ private:
+ const sp<IComposer> mComposer;
+};
+
+// A wrapper to IComposerClient.
+class ComposerClient : public V2_3::vts::ComposerClient {
+ public:
+ explicit ComposerClient(const sp<IComposerClient>& client)
+ : V2_3::vts::ComposerClient(client), mClient(client) {}
+
+ sp<IComposerClient> getRaw() const;
+
+ Error getDisplayCapabilities(
+ Display display,
+ std::vector<IComposerClient::DisplayCapability>* outDisplayCapabilities);
+
+ Error getDisplayConnectionType(Display display,
+ IComposerClient::DisplayConnectionType* outType);
+
+ int32_t getDisplayAttribute_2_4(Display display, Config config,
+ IComposerClient::Attribute attribute);
+
+ void registerCallback_2_4(const sp<IComposerCallback>& callback);
+
+ Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriods);
+
+ Error setActiveConfigWithConstraints(
+ Display display, Config config,
+ 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);
+
+ Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys);
+
+ private:
+ const sp<IComposerClient> mClient;
+};
+
+} // namespace vts
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h
new file mode 100644
index 0000000..f4e23ae
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android/hardware/graphics/composer/2.4/IComposerCallback.h>
+
+#include <mutex>
+#include <unordered_set>
+
+namespace android::hardware::graphics::composer::V2_4::vts {
+
+using Display = V2_1::Display;
+
+// IComposerCallback to be installed with IComposerClient::registerCallback.
+class GraphicsComposerCallback : public IComposerCallback {
+ public:
+ void setVsyncAllowed(bool allowed);
+
+ std::vector<Display> getDisplays() const;
+
+ int32_t getInvalidHotplugCount() const;
+
+ int32_t getInvalidRefreshCount() const;
+
+ int32_t getInvalidVsyncCount() const;
+
+ int32_t getInvalidVsync_2_4Count() const;
+
+ int32_t getInvalidVsyncPeriodChangeCount() const;
+
+ int32_t getInvalidSeamlessPossibleCount() const;
+
+ std::optional<VsyncPeriodChangeTimeline> takeLastVsyncPeriodChangeTimeline();
+
+ private:
+ Return<void> onHotplug(Display display, Connection connection) override;
+ Return<void> onRefresh(Display display) override;
+ Return<void> onVsync(Display display, int64_t) override;
+ Return<void> onVsync_2_4(Display display, int64_t, VsyncPeriodNanos vsyncPeriodNanos) override;
+ Return<void> onVsyncPeriodTimingChanged(
+ Display display, const VsyncPeriodChangeTimeline& updatedTimeline) override;
+ Return<void> onSeamlessPossible(Display display) override;
+
+ mutable std::mutex mMutex;
+ // the set of all currently connected displays
+ std::unordered_set<Display> mDisplays;
+ // true only when vsync is enabled
+ bool mVsyncAllowed = true;
+
+ std::optional<VsyncPeriodChangeTimeline> mTimeline;
+
+ // track invalid callbacks
+ int32_t mInvalidHotplugCount = 0;
+ int32_t mInvalidRefreshCount = 0;
+ int32_t mInvalidVsyncCount = 0;
+ int32_t mInvalidVsync_2_4Count = 0;
+ int32_t mInvalidVsyncPeriodChangeCount = 0;
+ int32_t mInvalidSeamlessPossibleCount = 0;
+};
+
+} // namespace android::hardware::graphics::composer::V2_4::vts
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
new file mode 100644
index 0000000..937af3d
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -0,0 +1,56 @@
+//
+// Copyright 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalGraphicsComposerV2_4TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalGraphicsComposerV2_4TargetTest.cpp"],
+
+ // TODO(b/64437680): Assume these libs are always available on the device.
+ shared_libs: [
+ "libfmq",
+ "libsync",
+ ],
+ static_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.allocator@4.0",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.1-vts",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.2-vts",
+ "android.hardware.graphics.composer@2.3",
+ "android.hardware.graphics.composer@2.3-vts",
+ "android.hardware.graphics.composer@2.4",
+ "android.hardware.graphics.composer@2.4-vts",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@2.0-vts",
+ "android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@2.1-vts",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hardware.graphics.mapper@4.0-vts",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ "android.hardware.graphics.composer@2.4-command-buffer",
+ ],
+ disable_framework: true,
+ test_suites: ["general-tests", "vts-core"],
+}
diff --git a/graphics/composer/2.4/vts/functional/OWNERS b/graphics/composer/2.4/vts/functional/OWNERS
new file mode 100644
index 0000000..b3ea6be
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/OWNERS
@@ -0,0 +1,8 @@
+# Graphics team
+lpy@google.com
+stoza@google.com
+vhau@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
new file mode 100644
index 0000000..f6b46ff
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -0,0 +1,657 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "graphics_composer_hidl_hal_test@2.4"
+
+#include <algorithm>
+#include <regex>
+#include <thread>
+
+#include <android-base/logging.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.4/ComposerVts.h>
+#include <composer-vts/2.4/GraphicsComposerCallback.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <mapper-vts/2.0/MapperVts.h>
+#include <mapper-vts/3.0/MapperVts.h>
+#include <mapper-vts/4.0/MapperVts.h>
+#include <utils/Timers.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+namespace {
+
+using common::V1_0::BufferUsage;
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::PixelFormat;
+using mapper::V2_0::IMapper;
+using V2_1::Layer;
+using V2_2::Transform;
+using V2_2::vts::Gralloc;
+
+using ContentType = IComposerClient::ContentType;
+using DisplayCapability = IComposerClient::DisplayCapability;
+
+class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(
+ mComposer = std::make_unique<Composer>(IComposer::getService(GetParam())));
+ ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
+
+ mComposerCallback = new GraphicsComposerCallback;
+ mComposerClient->registerCallback_2_4(mComposerCallback);
+
+ // assume the first display is primary and is never removed
+ mPrimaryDisplay = waitForFirstDisplay();
+
+ mInvalidDisplayId = GetInvalidDisplayId();
+
+ // explicitly disable vsync
+ mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+ mComposerCallback->setVsyncAllowed(false);
+
+ mWriter = std::make_unique<CommandWriterBase>(1024);
+ mReader = std::make_unique<V2_1::vts::TestCommandReader>();
+ }
+
+ void TearDown() override {
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_EQ(0, mReader->mCompositionChanges.size());
+ if (mComposerCallback != nullptr) {
+ EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidVsync_2_4Count());
+ EXPECT_EQ(0, mComposerCallback->getInvalidVsyncPeriodChangeCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidSeamlessPossibleCount());
+ }
+ }
+
+ // returns an invalid display id (one that has not been registered to a
+ // display. Currently assuming that a device will never have close to
+ // std::numeric_limit<uint64_t>::max() displays registered while running tests
+ Display GetInvalidDisplayId() {
+ std::vector<Display> validDisplays = mComposerCallback->getDisplays();
+ uint64_t id = std::numeric_limits<uint64_t>::max();
+ while (id > 0) {
+ if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) {
+ return id;
+ }
+ id--;
+ }
+
+ return 0;
+ }
+
+ // returns an invalid config id (one that has not been registered to a
+ // display). Currently assuming that a device will never have close to
+ // std::numeric_limit<uint64_t>::max() configs registered while running tests
+ Display GetInvalidConfigId(Display display) {
+ std::vector<Config> validConfigs = mComposerClient->getDisplayConfigs(display);
+ uint64_t id = std::numeric_limits<uint64_t>::max();
+ while (id > 0) {
+ if (std::find(validConfigs.begin(), validConfigs.end(), id) == validConfigs.end()) {
+ return id;
+ }
+ id--;
+ }
+
+ return 0;
+ }
+
+ void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+ void forEachTwoConfigs(Display display, std::function<void(Config, Config)> func) {
+ const auto displayConfigs = mComposerClient->getDisplayConfigs(display);
+ for (const Config config1 : displayConfigs) {
+ for (const Config config2 : displayConfigs) {
+ if (config1 != config2) {
+ func(config1, config2);
+ }
+ }
+ }
+ }
+
+ // use the slot count usually set by SF
+ static constexpr uint32_t kBufferSlotCount = 64;
+
+ 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<GraphicsComposerCallback> mComposerCallback;
+ // the first display and is assumed never to be removed
+ Display mPrimaryDisplay;
+ Display mInvalidDisplayId;
+ std::unique_ptr<CommandWriterBase> mWriter;
+ std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
+
+ private:
+ Display waitForFirstDisplay() {
+ while (true) {
+ std::vector<Display> displays = mComposerCallback->getDisplays();
+ if (displays.empty()) {
+ usleep(5 * 1000);
+ continue;
+ }
+
+ return displays[0];
+ }
+ }
+};
+
+// Tests for IComposerClient::Command.
+class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
+
+ ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
+
+ const Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay);
+ mDisplayWidth = mComposerClient->getDisplayAttribute_2_4(mPrimaryDisplay, activeConfig,
+ IComposerClient::Attribute::WIDTH);
+ mDisplayHeight = mComposerClient->getDisplayAttribute_2_4(
+ mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT);
+
+ mWriter = std::make_unique<CommandWriterBase>(1024);
+ mReader = std::make_unique<V2_1::vts::TestCommandReader>();
+ }
+
+ void TearDown() override {
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
+ }
+
+ const native_handle_t* allocate() {
+ return mGralloc->allocate(
+ /*width*/ 64, /*height*/ 64, /*layerCount*/ 1,
+ static_cast<common::V1_1::PixelFormat>(PixelFormat::RGBA_8888),
+ static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN));
+ }
+
+ void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+ void Test_setActiveConfigWithConstraints(
+ const IComposerClient::VsyncPeriodChangeConstraints& constraints, bool refreshMiss);
+
+ void sendRefreshFrame(const VsyncPeriodChangeTimeline&);
+
+ void waitForVsyncPeriodChange(Display display, const VsyncPeriodChangeTimeline& timeline,
+ int64_t desiredTimeNanos, int64_t oldPeriodNanos,
+ int64_t newPeriodNanos);
+
+ std::unique_ptr<CommandWriterBase> mWriter;
+ std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
+ int32_t mDisplayWidth;
+ int32_t mDisplayHeight;
+
+ private:
+ std::unique_ptr<Gralloc> mGralloc;
+};
+
+TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) {
+ std::vector<IComposerClient::DisplayCapability> capabilities;
+ const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities);
+ 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,
+ mComposerClient->getDisplayConnectionType(mInvalidDisplayId, &type));
+
+ for (Display display : mComposerCallback->getDisplays()) {
+ EXPECT_EQ(Error::NONE, mComposerClient->getDisplayConnectionType(display, &type));
+ }
+}
+
+TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute_2_4) {
+ std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+ for (auto config : configs) {
+ const std::array<IComposerClient::Attribute, 4> requiredAttributes = {{
+ IComposerClient::Attribute::WIDTH,
+ IComposerClient::Attribute::HEIGHT,
+ IComposerClient::Attribute::VSYNC_PERIOD,
+ IComposerClient::Attribute::CONFIG_GROUP,
+ }};
+ for (auto attribute : requiredAttributes) {
+ mComposerClient->getRaw()->getDisplayAttribute_2_4(
+ mPrimaryDisplay, config, attribute,
+ [&](const auto& tmpError, const auto& value) {
+ EXPECT_EQ(Error::NONE, tmpError);
+ EXPECT_NE(-1, value);
+ });
+ }
+
+ const std::array<IComposerClient::Attribute, 2> optionalAttributes = {{
+ IComposerClient::Attribute::DPI_X,
+ IComposerClient::Attribute::DPI_Y,
+ }};
+ for (auto attribute : optionalAttributes) {
+ mComposerClient->getRaw()->getDisplayAttribute_2_4(
+ mPrimaryDisplay, config, attribute, [&](const auto& tmpError, const auto&) {
+ EXPECT_TRUE(tmpError == Error::NONE || tmpError == Error::UNSUPPORTED);
+ });
+ }
+ }
+}
+
+TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) {
+ VsyncPeriodNanos vsyncPeriodNanos;
+ EXPECT_EQ(Error::BAD_DISPLAY,
+ mComposerClient->getDisplayVsyncPeriod(mInvalidDisplayId, &vsyncPeriodNanos));
+}
+
+TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod) {
+ for (Display display : mComposerCallback->getDisplays()) {
+ for (Config config : mComposerClient->getDisplayConfigs(display)) {
+ VsyncPeriodNanos expectedVsyncPeriodNanos = mComposerClient->getDisplayAttribute_2_4(
+ display, config, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
+
+ mComposerClient->setActiveConfig(display, config);
+ VsyncPeriodNanos vsyncPeriodNanos;
+ int retryCount = 100;
+ do {
+ std::this_thread::sleep_for(10ms);
+ EXPECT_EQ(Error::NONE,
+ mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+ --retryCount;
+ } while (vsyncPeriodNanos != expectedVsyncPeriodNanos && retryCount > 0);
+
+ EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos);
+ }
+ }
+}
+
+TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_BadDisplay) {
+ VsyncPeriodChangeTimeline timeline;
+ IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+ constraints.seamlessRequired = false;
+ constraints.desiredTimeNanos = systemTime();
+
+ EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setActiveConfigWithConstraints(
+ mInvalidDisplayId, Config(0), constraints, &timeline));
+}
+
+TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_BadConfig) {
+ VsyncPeriodChangeTimeline timeline;
+ IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+ constraints.seamlessRequired = false;
+ constraints.desiredTimeNanos = systemTime();
+
+ for (Display display : mComposerCallback->getDisplays()) {
+ Config invalidConfigId = GetInvalidConfigId(display);
+ EXPECT_EQ(Error::BAD_CONFIG, mComposerClient->setActiveConfigWithConstraints(
+ display, invalidConfigId, constraints, &timeline));
+ }
+}
+
+TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_SeamlessNotAllowed) {
+ VsyncPeriodChangeTimeline timeline;
+ IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+ constraints.seamlessRequired = true;
+ constraints.desiredTimeNanos = systemTime();
+
+ for (Display display : mComposerCallback->getDisplays()) {
+ forEachTwoConfigs(display, [&](Config config1, Config config2) {
+ const auto configGroup1 = mComposerClient->getDisplayAttribute_2_4(
+ display, config1, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP);
+ const auto configGroup2 = mComposerClient->getDisplayAttribute_2_4(
+ display, config2, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP);
+ if (configGroup1 != configGroup2) {
+ mComposerClient->setActiveConfig(display, config1);
+ EXPECT_EQ(Error::SEAMLESS_NOT_ALLOWED,
+ mComposerClient->setActiveConfigWithConstraints(display, config2,
+ constraints, &timeline));
+ }
+ });
+ }
+}
+
+static inline auto toTimePoint(nsecs_t time) {
+ return std::chrono::time_point<std::chrono::steady_clock>(std::chrono::nanoseconds(time));
+}
+
+void GraphicsComposerHidlCommandTest::sendRefreshFrame(const VsyncPeriodChangeTimeline& timeline) {
+ // Refresh time should be before newVsyncAppliedTimeNanos
+ EXPECT_LT(timeline.refreshTimeNanos, timeline.newVsyncAppliedTimeNanos);
+
+ std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mComposerClient->setPowerMode(mPrimaryDisplay, V2_1::IComposerClient::PowerMode::ON);
+ mComposerClient->setColorMode_2_3(mPrimaryDisplay, ColorMode::NATIVE,
+ RenderIntent::COLORIMETRIC);
+
+ auto handle = allocate();
+ ASSERT_NE(nullptr, handle);
+
+ IComposerClient::Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight};
+
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ mWriter->selectLayer(layer);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
+ mWriter->setLayerDisplayFrame(displayFrame);
+ mWriter->setLayerPlaneAlpha(1);
+ mWriter->setLayerSourceCrop({0, 0, (float)mDisplayWidth, (float)mDisplayHeight});
+ mWriter->setLayerTransform(static_cast<Transform>(0));
+ mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, displayFrame));
+ mWriter->setLayerZOrder(10);
+ mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE);
+ mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, displayFrame));
+ mWriter->setLayerBuffer(0, handle, -1);
+ mWriter->setLayerDataspace(Dataspace::UNKNOWN);
+
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ GTEST_SUCCEED() << "Composition change requested, skipping test";
+ return;
+ }
+
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ mWriter->selectLayer(layer);
+ auto handle2 = allocate();
+ ASSERT_NE(nullptr, handle2);
+ mWriter->setLayerBuffer(0, handle2, -1);
+ mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, {0, 0, 10, 10}));
+ mWriter->presentDisplay();
+ execute();
+}
+
+void GraphicsComposerHidlCommandTest::waitForVsyncPeriodChange(
+ Display display, const VsyncPeriodChangeTimeline& timeline, int64_t desiredTimeNanos,
+ int64_t oldPeriodNanos, int64_t newPeriodNanos) {
+ const auto CHANGE_DEADLINE = toTimePoint(timeline.newVsyncAppliedTimeNanos) + 100ms;
+ while (std::chrono::steady_clock::now() <= CHANGE_DEADLINE) {
+ VsyncPeriodNanos vsyncPeriodNanos;
+ EXPECT_EQ(Error::NONE, mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+ if (systemTime() <= desiredTimeNanos) {
+ EXPECT_EQ(vsyncPeriodNanos, oldPeriodNanos);
+ } else if (vsyncPeriodNanos == newPeriodNanos) {
+ break;
+ }
+ std::this_thread::sleep_for(std::chrono::nanoseconds(oldPeriodNanos));
+ }
+}
+
+void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints(
+ const IComposerClient::VsyncPeriodChangeConstraints& constraints, bool refreshMiss) {
+ VsyncPeriodChangeTimeline timeline = {};
+
+ for (Display display : mComposerCallback->getDisplays()) {
+ forEachTwoConfigs(display, [&](Config config1, Config config2) {
+ mComposerClient->setActiveConfig(display, config1);
+
+ int32_t vsyncPeriod1 = mComposerClient->getDisplayAttribute_2_4(
+ display, config1, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
+ int32_t vsyncPeriod2 = mComposerClient->getDisplayAttribute_2_4(
+ display, config2, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
+
+ if (vsyncPeriod1 == vsyncPeriod2) {
+ return; // continue
+ }
+
+ EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints(
+ display, config2, constraints, &timeline));
+
+ EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos);
+ // Refresh rate should change within a reasonable time
+ constexpr std::chrono::nanoseconds kReasonableTimeForChange = 1s; // 1 second
+ EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <=
+ kReasonableTimeForChange.count());
+
+ if (timeline.refreshRequired) {
+ if (refreshMiss) {
+ // Miss the refresh frame on purpose to make sure the implementation sends a
+ // callback
+ std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos) + 100ms);
+ }
+ sendRefreshFrame(timeline);
+ }
+ waitForVsyncPeriodChange(display, timeline, constraints.desiredTimeNanos, vsyncPeriod1,
+ vsyncPeriod2);
+
+ // At this point the refresh rate should have changed already, however in rare
+ // cases the implementation might have missed the deadline. In this case a new
+ // timeline should have been provided.
+ auto newTimelime = mComposerCallback->takeLastVsyncPeriodChangeTimeline();
+ if (timeline.refreshRequired && refreshMiss) {
+ EXPECT_TRUE(newTimelime.has_value());
+ }
+
+ if (newTimelime.has_value()) {
+ if (timeline.refreshRequired) {
+ sendRefreshFrame(newTimelime.value());
+ }
+ waitForVsyncPeriodChange(display, newTimelime.value(), constraints.desiredTimeNanos,
+ vsyncPeriod1, vsyncPeriod2);
+ }
+
+ VsyncPeriodNanos vsyncPeriodNanos;
+ EXPECT_EQ(Error::NONE,
+ mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+ EXPECT_EQ(vsyncPeriodNanos, vsyncPeriod2);
+ });
+ }
+}
+
+TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints) {
+ IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+ constraints.seamlessRequired = false;
+ constraints.desiredTimeNanos = systemTime();
+ Test_setActiveConfigWithConstraints(constraints, false);
+}
+
+TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_Delayed) {
+ IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+ constexpr nsecs_t kDelayForChange = 300'000'000; // 300ms
+ constraints.seamlessRequired = false;
+ constraints.desiredTimeNanos = systemTime() + kDelayForChange;
+ Test_setActiveConfigWithConstraints(constraints, false);
+}
+
+TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_MissRefresh) {
+ IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+ constraints.seamlessRequired = false;
+ constraints.desiredTimeNanos = systemTime();
+ Test_setActiveConfigWithConstraints(constraints, true);
+}
+
+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)),
+ android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GraphicsComposerHidlCommandTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
+TEST_F(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) {
+ std::vector<IComposerClient::LayerGenericMetadataKey> keys;
+ mComposerClient->getLayerGenericMetadataKeys(&keys);
+
+ std::regex reverseDomainName("^[a-zA-Z-]{2,}(\\.[a-zA-Z0-9-]+)+$");
+ std::unordered_set<std::string> uniqueNames;
+ for (const auto& key : keys) {
+ std::string name(key.name.c_str());
+
+ // Keys must not start with 'android' or 'com.android'
+ ASSERT_FALSE(name.find("android") == 0);
+ ASSERT_FALSE(name.find("com.android") == 0);
+
+ // Keys must be in reverse domain name format
+ ASSERT_TRUE(std::regex_match(name, reverseDomainName));
+
+ // Keys must be unique within this list
+ const auto& [iter, inserted] = uniqueNames.insert(name);
+ ASSERT_TRUE(inserted);
+ }
+}
+
+} // namespace
+} // namespace vts
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/mapper/4.0/Android.bp b/graphics/mapper/4.0/Android.bp
new file mode 100644
index 0000000..42c4942
--- /dev/null
+++ b/graphics/mapper/4.0/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.graphics.mapper@4.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ srcs: [
+ "types.hal",
+ "IMapper.hal",
+ ],
+ interfaces: [
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal
new file mode 100644
index 0000000..93c85bd
--- /dev/null
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -0,0 +1,648 @@
+/*
+ * 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.mapper@4.0;
+
+import android.hardware.graphics.common@1.2::BufferUsage;
+import android.hardware.graphics.common@1.2::PixelFormat;
+import android.hardware.graphics.common@1.2::Rect;
+
+interface IMapper {
+ struct BufferDescriptorInfo {
+ /**
+ * The name of the buffer. Useful for debugging/tracing.
+ */
+ string name;
+
+ /**
+ * The width specifies how many columns of pixels must be in the
+ * allocated buffer, but does not necessarily represent the offset in
+ * columns between the same column in adjacent rows. The rows may be
+ * padded.
+ */
+ uint32_t width;
+
+ /**
+ * The height specifies how many rows of pixels must be in the
+ * allocated buffer.
+ */
+ uint32_t height;
+
+ /**
+ * The number of image layers that must be in the allocated buffer.
+ */
+ uint32_t layerCount;
+
+ /**
+ * Buffer pixel format.
+ */
+ PixelFormat format;
+
+ /**
+ * Buffer usage mask; valid flags can be found in the definition of
+ * 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 {
+ int32_t left;
+ int32_t top;
+ int32_t width;
+ int32_t height;
+ };
+
+ /**
+ * Creates a buffer descriptor. The descriptor can be used with IAllocator
+ * to allocate buffers.
+ *
+ * Since the buffer descriptor fully describes a buffer, any device
+ * dependent or device independent checks must be performed here whenever
+ * 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
+ * - `NONE` upon success.
+ * - `BAD_VALUE` if any of the specified attributes are invalid or
+ * inconsistent.
+ * - `NO_RESOURCES` if the creation cannot be fullfilled due to
+ * unavailability of resources.
+ * - `UNSUPPORTED` when any of the specified attributes are not
+ * supported.
+ * @return descriptor Newly created buffer descriptor.
+ */
+ createDescriptor(BufferDescriptorInfo description)
+ generates (Error error,
+ BufferDescriptor descriptor);
+
+ /**
+ * Imports a raw buffer handle to create an imported buffer handle for use
+ * with the rest of the mapper or with other in-process libraries.
+ *
+ * A buffer handle is considered raw when it is cloned (e.g., with
+ * `native_handle_clone()`) from another buffer handle locally, or when it
+ * is received from another HAL server/client or another process. A raw
+ * buffer handle must not be used to access the underlying graphic
+ * buffer. It must be imported to create an imported handle first.
+ *
+ * This function must at least validate the raw handle before creating the
+ * imported handle. It must also support importing the same raw handle
+ * multiple times to create multiple imported handles. The imported handle
+ * must be considered valid everywhere in the process, including in
+ * another instance of the mapper.
+ *
+ * Because of passthrough HALs, a raw buffer handle received from a HAL
+ * may actually have been imported in the process. importBuffer() must treat
+ * such a handle as if it is raw and must not return `BAD_BUFFER`. The
+ * returned handle is independent from the input handle as usual, and
+ * freeBuffer() must be called on it when it is no longer needed.
+ *
+ * @param rawHandle Raw buffer handle to import.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `NO_RESOURCES` if the raw handle cannot be imported due to
+ * unavailability of resources.
+ * @return buffer Imported buffer handle that has the type
+ * `buffer_handle_t` which is a handle type.
+ */
+ importBuffer(handle rawHandle) generates (Error error, pointer buffer);
+
+ /**
+ * Frees a buffer handle. Buffer handles returned by importBuffer() must be
+ * freed with this function when no longer needed.
+ *
+ * This function must free up all resources allocated by importBuffer() for
+ * the imported handle. For example, if the imported handle was created
+ * with `native_handle_create()`, this function must call
+ * `native_handle_close()` and `native_handle_delete()`.
+ *
+ * @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.
+ */
+ freeBuffer(pointer buffer) generates (Error error);
+
+ /**
+ * Validates that the buffer can be safely accessed by a caller who assumes
+ * the specified @p description and @p stride. This must at least validate
+ * that the buffer size is large enough. Validating the buffer against
+ * individual buffer attributes is optional.
+ *
+ * @param buffer Buffer to validate against.
+ * @param description Attributes of the buffer.
+ * @param stride Stride returned by IAllocator::allocate().
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid.
+ * - `BAD_VALUE` if the buffer cannot be safely accessed.
+ */
+ validateBufferSize(pointer buffer,
+ BufferDescriptorInfo description,
+ uint32_t stride)
+ generates (Error error);
+
+ /**
+ * Calculates the transport size of a buffer. An imported buffer handle is a
+ * raw buffer handle with the process-local runtime data appended. This
+ * function, for example, allows a caller to omit the process-local runtime
+ * data at the tail when serializing the imported buffer handle.
+ *
+ * Note that a client might or might not omit the process-local runtime data
+ * when sending an imported buffer handle. The mapper must support both
+ * cases on the receiving end.
+ *
+ * @param buffer Buffer to get the transport size from.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid.
+ * @return numFds The number of file descriptors needed for transport.
+ * @return numInts The number of integers needed for transport.
+ */
+ getTransportSize(pointer buffer)
+ generates (Error error,
+ uint32_t numFds,
+ uint32_t numInts);
+
+ /**
+ * Locks the given buffer for the specified CPU usage.
+ *
+ * Locking the same buffer simultaneously from multiple threads is
+ * permitted, but if any of the threads attempt to lock the buffer for
+ * writing, the behavior is undefined, except that it must not cause
+ * process termination or block the client indefinitely. Leaving the
+ * buffer content in an indeterminate state or returning an error are both
+ * acceptable.
+ *
+ * 1D buffers (width = size in bytes, height = 1, pixel_format = BLOB) must
+ * "lock in place". The buffers must be directly accessible via mapping.
+ *
+ * The client must not modify the content of the buffer outside of
+ * @p accessRegion, and the device need not guarantee that content outside
+ * of @p accessRegion is valid for reading. The result of reading or writing
+ * 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,
+ * etc.
+ *
+ * This function must also work on buffers with
+ * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well
+ * as with any other formats requested by multimedia codecs when they are
+ * configured with a flexible-YUV-compatible color format.
+ *
+ * On success, @p data must be filled with a pointer to the locked buffer
+ * memory. This address will represent the top-left corner of the entire
+ * buffer, even if @p accessRegion does not begin at the top-left corner.
+ *
+ * The locked buffer must adhere to the format requested at allocation time
+ * in the BufferDescriptorInfo.
+ *
+ * @param buffer Buffer to lock.
+ * @param cpuUsage CPU usage flags to request. See +ndk
+ * libnativewindow#AHardwareBuffer_UsageFlags for possible values.
+ * @param accessRegion Portion of the buffer that the client intends to
+ * access.
+ * @param acquireFence Handle containing a file descriptor referring to a
+ * sync fence object, which will be signaled when it is safe for the
+ * mapper to lock the buffer. @p acquireFence may be an empty fence if
+ * it is already safe to lock.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or is incompatible with this
+ * function.
+ * - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or
+ * is incompatible with the buffer. Also if the @p accessRegion is
+ * outside the bounds of the buffer or the accessRegion is invalid.
+ * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note
+ * that locking may succeed at a later time.
+ * @return data CPU-accessible pointer to the buffer data.
+ */
+ lock(pointer buffer,
+ uint64_t cpuUsage,
+ Rect accessRegion,
+ handle acquireFence)
+ generates (Error error,
+ pointer data);
+
+ /**
+ * Unlocks a buffer to indicate all CPU accesses to the buffer have
+ * completed.
+ *
+ * @param buffer Buffer to unlock.
+ * @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.
+ */
+ 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
+ * description can be allocated on this implementation, unless resource
+ * exhaustion occurs. If this function returns false, it means that the
+ * allocation of the given description will never succeed.
+ *
+ * @param description the description of the buffer
+ * @return supported whether the description is supported
+ */
+ isSupported(BufferDescriptorInfo description)
+ generates (Error error,
+ bool supported);
+
+
+ /**
+ * Description for get(...), set(...) and getFromBufferDescriptorInfo(...)
+ *
+ * ------------ Overview -----------------------------------
+ * Gralloc 4 adds support for getting and setting buffer metadata on a buffer.
+ *
+ * To get buffer metadata, the client passes in a buffer handle and a token that
+ * represents the type of buffer metadata they would like to get. IMapper returns
+ * a byte stream that contains the buffer metadata. To set the buffer metadata, the
+ * client passes in a buffer handle and a token that represents the type of buffer
+ * metadata they would like to set and a byte stream that contains the buffer metadata
+ * they are setting.
+ *
+ * Buffer metadata is global for a buffer. When the metadata is set on the buffer
+ * in a process, the updated metadata should be available to all other processes.
+ * Please see "Storing and Propagating Metadata" below for more details.
+ *
+ * The getter and setter functions have been optimized for easy vendor extension.
+ * They do not require a formal HIDL extension to add support for getting and setting
+ * vendor defined buffer metadata. In order to allow easy extension, the types used
+ * here are not typical HIDL types. See "Buffer Metadata Token" and
+ * "Buffer Metadata Stream" below for more details.
+ *
+ * ------------ Storing and Propagating Metadata -----------
+ * Buffer metadata must be global. Any changes to the metadata must be propagated
+ * to all other processes immediately. Vendors may chose how they would like support
+ * this functionality.
+ *
+ * We recommend supporting this functionality by allocating an extra page of shared
+ * memory and storing it in the buffer's native_handle_t. The buffer metadata can
+ * be stored in the extra page of shared memory. Set operations are automatically
+ * propagated to all other processes.
+ *
+ * ------------ Buffer Metadata Synchronization ------------
+ * There are no explicit buffer metadata synchronization primitives. Many devices
+ * before gralloc 4 already support getting and setting of global buffer metadata
+ * with no explicit synchronization primitives. Adding synchronization primitives
+ * would just add unnecessary complexity.
+ *
+ * The general rule is if a process has permission to write to a buffer, they
+ * have permission to write to the buffer's metadata. If a process has permission
+ * to read from a buffer, they have permission to read the buffer's metadata.
+ *
+ * There is one exception to this rule. Fences CANNOT be used to protect a buffer's
+ * metadata. A process should finish writing to a buffer's metadata before
+ * sending the buffer to another process that will read or write to the buffer.
+ * This exception is needed because sometimes userspace needs to read the
+ * buffer's metadata before the buffer's contents are ready.
+ *
+ * As a simple example: an app renders to a buffer and then displays the buffer.
+ * In this example when the app renders to the buffer, both the buffer and its
+ * metadata need to be updated. The app's process queues up its work on the GPU
+ * and gets back an acquire fence. The app's process must update the buffer's
+ * metadata before enqueuing the buffer to SurfaceFlinger. The app process CANNOT
+ * update the buffer's metadata after enqueuing the buffer. When HardwareComposer
+ * receives the buffer, it is immediately safe to read the buffer's metadata
+ * and use it to program the display driver. To read the buffer's contents,
+ * display driver must still wait on the acquire fence.
+ *
+ * ------------ Buffer Metadata Token ----------------------
+ * In order to allow arbitrary vendor defined metadata, we could not use a
+ * HIDL enum as the buffer metadata token. Extending a HIDL enum requires a full
+ * HIDL extension. We also could not use a simple non-HIDL enum because vendor
+ * defined enums from different vendors could collide. Instead we have defined
+ * a struct that has a string representing the enum type and an int that
+ * represents the enum value. The string protects different enum values from
+ * colliding.
+ *
+ * The token struct (MetadataType) is defined as a HIDL struct since it
+ * is passed into a HIDL function. The standard buffer metadata types are NOT
+ * defined as a HIDL enum because it would have required a new IMapper version
+ * just to add future standard buffer metadata types. By putting the enum in the
+ * stable AIDL (hardware/interfaces/graphics/common/aidl/android/hardware/
+ * graphics/common/StandardMetadataType.aidl), vendors will be able to optionally
+ * choose to support future standard buffer metadata types without upgrading
+ * HIDL versions. For more information see the description of "struct MetadataType".
+ *
+ * ------------ Buffer Metadata Stream ---------------------
+ * The buffer metadata is get and set as a byte stream (vec<uint8_t>). By getting
+ * and setting buffer metadata as a byte stream, vendors can use the standard
+ * getters and setter functions defined here. Vendors do NOT need to add their own
+ * getters and setter functions for each new type of buffer metadata.
+ *
+ * Converting buffer metadata into a byte stream can be non-trivial. For the standard
+ * buffer metadata types defined in StandardMetadataType.aidl, there are also
+ * support functions that will encode the buffer metadata into a byte stream
+ * and decode the buffer metadata from a byte stream. We STRONGLY recommend using
+ * these support functions. The framework will use them when getting and setting
+ * metadata. The support functions are defined in
+ * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h.
+ */
+
+ /**
+ * MetadataType represents the different types of buffer metadata that could be
+ * associated with a buffer. It is used by IMapper to help get and set buffer metadata
+ * on the buffer's native handle.
+ *
+ * Standard buffer metadata will have the name field set to
+ * "android.hardware.graphics.common.StandardMetadataType" and will contain values
+ * from StandardMetadataType.aidl.
+ *
+ * This struct should be "extended" by devices that use a proprietary or non-standard
+ * buffer metadata. To extend the struct, first create a custom @VendorStability vendor
+ * AIDL interface that defines the new type(s) you would like to support. Set the
+ * struct's name field to the custom aidl interface's name
+ * (eg. "vendor.mycompanyname.graphics.common.MetadataType"). Set the struct's value
+ * field to the custom @VendorStabilty vendor AIDL interface.
+ *
+ * Each company should create their own StandardMetadataType.aidl extension. The name
+ * field prevents values from different companies from colliding.
+ */
+ struct MetadataType {
+ string name;
+ int64_t value;
+ };
+
+ /**
+ * Gets the buffer metadata for a given MetadataType.
+ *
+ * Buffer metadata can be changed after allocation so clients should avoid "caching"
+ * the buffer metadata. For example, if the video resolution changes and the buffers
+ * are not reallocated, several buffer metadata values may change without warning.
+ * Clients should not expect the values to be constant. They should requery them every
+ * frame. The only exception is buffer metadata that is determined at allocation
+ * time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH,
+ * HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because
+ * they are determined at allocation time.
+ *
+ * @param buffer Buffer containing desired metadata
+ * @param metadataType MetadataType for the metadata value being queried
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+ * resources.
+ * - `UNSUPPORTED` when metadataType is unknown/unsupported.
+ * IMapper must support getting all StandardMetadataType.aidl values defined
+ * at the time the device first launches.
+ * @return metadata Vector of bytes representing the buffer metadata associated with
+ * the MetadataType.
+ */
+ get(pointer buffer, MetadataType metadataType)
+ generates (Error error,
+ vec<uint8_t> metadata);
+
+ /**
+ * Sets the global value for a given MetadataType.
+ *
+ * Metadata fields are not required to be settable. This function can
+ * return Error::UNSUPPORTED whenever it doesn't support setting a
+ * particular Metadata field.
+ *
+ * The framework may attempt to set the following StandardMetadataType
+ * 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
+ * Composer/BufferQueue/etc. and into the buffer's Metadata fields.
+ * If a device's IMapper doesn't support setting those Metadata fields,
+ * eventually the device may not longer be able to support these fields.
+ *
+ * @param buffer Buffer receiving desired metadata
+ * @param metadataType MetadataType for the metadata value being set
+ * @param metadata Vector of bytes representing the value associated with
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `BAD_VALUE` when the field is constant and can never be set (such as
+ * BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and
+ * USAGE)
+ * - `NO_RESOURCES` if the set cannot be fullfilled due to unavailability of
+ * resources.
+ * - `UNSUPPORTED` when metadataType is unknown/unsupported or setting
+ * it is unsupported. Unsupported should also be returned if the metadata
+ * is malformed.
+ */
+ set(pointer buffer, MetadataType metadataType, vec<uint8_t> metadata)
+ generates (Error error);
+
+ /**
+ * Given a BufferDescriptorInfo, gets the starting value of a given
+ * MetadataType. This can be used to query basic information about a buffer
+ * before the buffer is allocated.
+ *
+ * @param description Attributes of the descriptor.
+ * @param metadataType MetadataType for the metadata value being queried
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_VALUE` if any of the specified BufferDescriptorInfo attributes
+ * are invalid.
+ * - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+ * resources.
+ * - `UNSUPPORTED` when any of the description attributes are unsupported or
+ * if the metadataType is unknown/unsupported. This should also be
+ * returned if the requested metadata is not defined until a buffer has been
+ * allocated.
+ * @return metadata Vector of bytes representing the value associated with
+ * the MetadataType value.
+ */
+ getFromBufferDescriptorInfo(BufferDescriptorInfo description,
+ MetadataType metadataType)
+ generates (Error error,
+ vec<uint8_t> metadata);
+
+ struct MetadataTypeDescription {
+ MetadataType metadataType;
+ /**
+ * description should contain a string representation of the MetadataType.
+ *
+ * For example: "MyExampleMetadataType is a 64-bit timestamp in nanoseconds
+ * that indicates when a buffer is decoded. It is set by the media HAL after
+ * a buffer is decoded. It is used by the display HAL for hardware
+ * synchronization".
+ *
+ * This field is required for any non-StandardMetadataTypes.
+ */
+ string description;
+ /**
+ * isGettable represents if the MetadataType can be get.
+ */
+ bool isGettable;
+ /**
+ * isSettable represents if the MetadataType can be set.
+ */
+ bool isSettable;
+ };
+
+ /**
+ * Lists all the MetadataTypes supported by IMapper as well as a description
+ * of each supported MetadataType. For StandardMetadataTypes, the description
+ * string can be left empty.
+ *
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+ * resources.
+ * @return descriptions Vector of MetadataTypeDescriptions that represent the
+ * MetadataTypes supported by the device.
+ */
+ listSupportedMetadataTypes()
+ generates (Error error, vec<MetadataTypeDescription> descriptions);
+
+ struct MetadataDump {
+ /**
+ * The type of metadata being dumped.
+ */
+ MetadataType metadataType;
+ /**
+ * The byte stream representation of the metadata. If the metadata is not
+ * gettable, the vector must be empty.
+ */
+ vec<uint8_t> metadata;
+ };
+
+ struct BufferDump {
+ /**
+ * A vector of all the metadata that is being dumped for a particular buffer.
+ */
+ vec<MetadataDump> metadataDump;
+ };
+
+ /**
+ * Dumps a buffer's metadata.
+ *
+ * @param buffer Buffer that is being dumped
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+ * resources.
+ * @return bufferDump Struct representing the metadata being dumped
+ */
+ dumpBuffer(pointer buffer)
+ generates (Error error, BufferDump bufferDump);
+
+ /**
+ * Dumps the metadata for all the buffers in the current process.
+ *
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+ * resources.
+ * @return bufferDumps Vector of structs representing the buffers being dumped
+ */
+ 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/types.hal b/graphics/mapper/4.0/types.hal
new file mode 100644
index 0000000..00b6607
--- /dev/null
+++ b/graphics/mapper/4.0/types.hal
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.mapper@4.0;
+
+/**
+ * Error values that may be returned by a method of IAllocator or IMapper.
+ */
+enum Error : int32_t {
+ /**
+ * No error.
+ */
+ NONE = 0,
+ /**
+ * Invalid BufferDescriptor.
+ */
+ BAD_DESCRIPTOR = 1,
+ /**
+ * Invalid buffer handle.
+ */
+ BAD_BUFFER = 2,
+ /**
+ * Invalid HardwareBufferDescription.
+ */
+ BAD_VALUE = 3,
+ /**
+ * Resource unavailable.
+ */
+ NO_RESOURCES = 5,
+ /**
+ * Permanent failure.
+ */
+ UNSUPPORTED = 7,
+};
+
+/**
+ * A buffer descriptor is an implementation-defined opaque data returned by
+ * createDescriptor(). It describes the properties of a buffer and is consumed
+ * by the allocator.
+ */
+typedef vec<uint8_t> BufferDescriptor;
+
diff --git a/graphics/mapper/4.0/utils/OWNERS b/graphics/mapper/4.0/utils/OWNERS
new file mode 100644
index 0000000..96f6d51
--- /dev/null
+++ b/graphics/mapper/4.0/utils/OWNERS
@@ -0,0 +1,3 @@
+# Graphics team
+marissaw@google.com
+stoza@google.com
diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp
new file mode 100644
index 0000000..56ff116
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/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_static {
+ name: "android.hardware.graphics.mapper@4.0-vts",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["MapperVts.cpp"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+ static_libs: [
+ "android.hardware.graphics.allocator@4.0",
+ "android.hardware.graphics.mapper@4.0",
+ ],
+ shared_libs: [
+ "libgralloctypes",
+ ],
+ export_static_lib_headers: [
+ "android.hardware.graphics.allocator@4.0",
+ "android.hardware.graphics.mapper@4.0",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
new file mode 100644
index 0000000..cb90fa0
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gralloctypes/Gralloc4.h>
+#include <mapper-vts/4.0/MapperVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V4_0 {
+namespace vts {
+
+Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName,
+ bool errOnFailure) {
+ if (errOnFailure) {
+ init(allocatorServiceName, mapperServiceName);
+ } else {
+ initNoErr(allocatorServiceName, mapperServiceName);
+ }
+}
+
+void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
+ mAllocator = IAllocator::getService(allocatorServiceName);
+ ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+
+ 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 = IAllocator::getService(allocatorServiceName);
+
+ mMapper = IMapper::getService(mapperServiceName);
+ if (mMapper.get()) {
+ ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
+ }
+}
+
+Gralloc::~Gralloc() {
+ for (auto bufferHandle : mClonedBuffers) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ native_handle_close(buffer);
+ native_handle_delete(buffer);
+ }
+ mClonedBuffers.clear();
+
+ for (auto bufferHandle : mImportedBuffers) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer)) << "failed to free buffer " << buffer;
+ }
+ mImportedBuffers.clear();
+}
+
+sp<IAllocator> Gralloc::getAllocator() const {
+ return mAllocator;
+}
+
+const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) {
+ const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
+ EXPECT_NE(nullptr, bufferHandle);
+
+ if (bufferHandle) {
+ mClonedBuffers.insert(bufferHandle);
+ }
+
+ return bufferHandle;
+}
+
+std::vector<const native_handle_t*> Gralloc::allocate(const BufferDescriptor& descriptor,
+ uint32_t count, bool import,
+ bool allowFailure, uint32_t* outStride) {
+ std::vector<const native_handle_t*> bufferHandles;
+ bufferHandles.reserve(count);
+ mAllocator->allocate(
+ descriptor, count,
+ [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
+ ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
+
+ for (uint32_t i = 0; i < count; i++) {
+ const native_handle_t* bufferHandle = nullptr;
+ if (import) {
+ if (allowFailure) {
+ bufferHandle = importBuffer(tmpBuffers[i]);
+ } else {
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = importBuffer(tmpBuffers[i]));
+ }
+ } else {
+ if (allowFailure) {
+ bufferHandle = cloneBuffer(tmpBuffers[i]);
+ } else {
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = cloneBuffer(tmpBuffers[i]));
+ }
+ }
+ if (bufferHandle) {
+ bufferHandles.push_back(bufferHandle);
+ }
+ }
+
+ if (outStride) {
+ *outStride = tmpStride;
+ }
+ });
+
+ if (::testing::Test::HasFatalFailure()) {
+ bufferHandles.clear();
+ }
+
+ return bufferHandles;
+}
+
+const native_handle_t* Gralloc::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+ bool import, bool allowFailure, uint32_t* outStride) {
+ BufferDescriptor descriptor = createDescriptor(descriptorInfo);
+ if (::testing::Test::HasFatalFailure()) {
+ return nullptr;
+ }
+
+ auto buffers = allocate(descriptor, 1, import, allowFailure, outStride);
+ if (::testing::Test::HasFatalFailure()) {
+ return nullptr;
+ }
+
+ if (buffers.size() != 1) {
+ return nullptr;
+ }
+ return buffers[0];
+}
+
+sp<IMapper> Gralloc::getMapper() const {
+ return mMapper;
+}
+
+BufferDescriptor Gralloc::createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+ BufferDescriptor descriptor;
+ mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
+ descriptor = tmpDescriptor;
+ });
+
+ return descriptor;
+}
+
+const native_handle_t* Gralloc::importBuffer(const hidl_handle& rawHandle) {
+ const native_handle_t* bufferHandle = nullptr;
+ mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to import buffer %p" << rawHandle.getNativeHandle();
+ bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
+ });
+
+ if (bufferHandle) {
+ mImportedBuffers.insert(bufferHandle);
+ }
+
+ return bufferHandle;
+}
+
+void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
+ if (bufferHandle == nullptr) {
+ return;
+ }
+
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ if (mImportedBuffers.erase(bufferHandle)) {
+ Error error = mMapper->freeBuffer(buffer);
+ ASSERT_EQ(Error::NONE, error) << "failed to free buffer " << buffer;
+ } else {
+ mClonedBuffers.erase(bufferHandle);
+ native_handle_close(buffer);
+ native_handle_delete(buffer);
+ }
+}
+
+void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int acquireFence) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ hidl_handle acquireFenceHandle;
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ void* data = nullptr;
+ mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpData) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to lock buffer " << buffer;
+ data = tmpData;
+ });
+
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ return data;
+}
+
+int Gralloc::unlock(const native_handle_t* bufferHandle) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ int releaseFence = -1;
+ mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock 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;
+}
+
+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) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ Error error = mMapper->validateBufferSize(buffer, descriptorInfo, stride);
+ return error == Error::NONE;
+}
+
+void Gralloc::getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ *outNumFds = 0;
+ *outNumInts = 0;
+ mMapper->getTransportSize(buffer, [&](const auto& tmpError, const auto& tmpNumFds,
+ const auto& tmpNumInts) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get transport size";
+ ASSERT_GE(bufferHandle->numFds, int(tmpNumFds)) << "invalid numFds " << tmpNumFds;
+ ASSERT_GE(bufferHandle->numInts, int(tmpNumInts)) << "invalid numInts " << tmpNumInts;
+
+ *outNumFds = tmpNumFds;
+ *outNumInts = tmpNumInts;
+ });
+}
+
+bool Gralloc::isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+ bool supported = false;
+ mMapper->isSupported(descriptorInfo, [&](const auto& tmpError, const auto& tmpSupported) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to check is supported";
+ supported = tmpSupported;
+ });
+ return supported;
+}
+
+Error Gralloc::get(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
+ hidl_vec<uint8_t>* outVec) {
+ Error err;
+ mMapper->get(const_cast<native_handle_t*>(bufferHandle), metadataType,
+ [&](const auto& tmpError, const hidl_vec<uint8_t>& tmpVec) {
+ err = tmpError;
+ *outVec = tmpVec;
+ });
+ return err;
+}
+
+Error Gralloc::set(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
+ const hidl_vec<uint8_t>& vec) {
+ return mMapper->set(const_cast<native_handle_t*>(bufferHandle), metadataType, vec);
+}
+
+Error Gralloc::getFromBufferDescriptorInfo(const IMapper::BufferDescriptorInfo& descriptorInfo,
+ const IMapper::MetadataType& metadataType,
+ hidl_vec<uint8_t>* outVec) {
+ Error err;
+ mMapper->getFromBufferDescriptorInfo(
+ descriptorInfo, metadataType,
+ [&](const auto& tmpError, const hidl_vec<uint8_t>& tmpVec) {
+ err = tmpError;
+ *outVec = tmpVec;
+ });
+ 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
+} // namespace graphics
+} // namespace hardware
+} // namespace android
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
new file mode 100644
index 0000000..cd40aa4
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#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 {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V4_0 {
+namespace vts {
+
+using android::hardware::graphics::allocator::V4_0::IAllocator;
+
+// A wrapper to IAllocator and IMapper.
+class Gralloc {
+ public:
+ Gralloc(const std::string& allocatorServiceName = "default",
+ const std::string& mapperServiceName = "default", bool errOnFailure = true);
+ ~Gralloc();
+
+ // IAllocator methods
+
+ sp<IAllocator> getAllocator() const;
+
+ // When import is false, this simply calls IAllocator::allocate. When import
+ // is true, the returned buffers are also imported into the mapper.
+ //
+ // Either case, the returned buffers must be freed with freeBuffer.
+ std::vector<const native_handle_t*> allocate(const BufferDescriptor& descriptor, uint32_t count,
+ bool import = true, bool allowFailure = false,
+ uint32_t* outStride = nullptr);
+ const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+ bool import = true, bool allowFailure = false,
+ uint32_t* outStride = nullptr);
+
+ // IMapper methods
+
+ sp<IMapper> getMapper() const;
+
+ BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
+
+ const native_handle_t* importBuffer(const hidl_handle& rawHandle);
+ void freeBuffer(const native_handle_t* bufferHandle);
+
+ // We use fd instead of hidl_handle in these functions to pass fences
+ // in and out of the mapper. The ownership of the fd is always transferred
+ // with each of these functions.
+ void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+ 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,
+ uint32_t* outNumInts);
+
+ bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo);
+
+ Error get(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
+ hidl_vec<uint8_t>* outVec);
+
+ Error set(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
+ const hidl_vec<uint8_t>& vec);
+
+ Error getFromBufferDescriptorInfo(const IMapper::BufferDescriptorInfo& descriptorInfo,
+ 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);
+
+ // initialize without checking for failure to get service
+ void initNoErr(const std::string& allocatorServiceName, const std::string& mapperServiceName);
+ const native_handle_t* cloneBuffer(const hidl_handle& rawHandle);
+
+ sp<IAllocator> mAllocator;
+ sp<IMapper> mMapper;
+
+ // Keep track of all cloned and imported handles. When a test fails with
+ // ASSERT_*, the destructor will free the handles for the test.
+ std::unordered_set<const native_handle_t*> mClonedBuffers;
+ std::unordered_set<const native_handle_t*> mImportedBuffers;
+};
+
+} // namespace vts
+} // namespace V4_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/mapper/4.0/vts/OWNERS b/graphics/mapper/4.0/vts/OWNERS
new file mode 100644
index 0000000..96f6d51
--- /dev/null
+++ b/graphics/mapper/4.0/vts/OWNERS
@@ -0,0 +1,3 @@
+# Graphics team
+marissaw@google.com
+stoza@google.com
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
new file mode 100644
index 0000000..3542a6e
--- /dev/null
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -0,0 +1,41 @@
+//
+// Copyright 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalGraphicsMapperV4_0TargetTest",
+ 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",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.mapper@4.0",
+ ],
+ header_libs: [
+ "libsystem_headers",
+ ],
+ 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
new file mode 100644
index 0000000..2aad242
--- /dev/null
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -0,0 +1,2189 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalGraphicsMapperV4_0TargetTest"
+
+#include <unistd.h>
+#include <chrono>
+#include <thread>
+#include <vector>
+
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.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>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V4_0 {
+namespace vts {
+namespace {
+
+using android::hardware::graphics::common::V1_2::BufferUsage;
+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)>;
+
+class GraphicsMapperHidlTest
+ : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+ protected:
+ void SetUp() override {
+ 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());
+
+ mDummyDescriptorInfo.name = "dummy";
+ mDummyDescriptorInfo.width = 64;
+ mDummyDescriptorInfo.height = 64;
+ mDummyDescriptorInfo.layerCount = 1;
+ 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 {}
+
+ void testGet(const IMapper::BufferDescriptorInfo& descriptorInfo,
+ const MetadataType& metadataType, DecodeFunction decode) {
+ const native_handle_t* bufferHandle = nullptr;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(descriptorInfo, true));
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &vec));
+
+ ASSERT_NO_FATAL_FAILURE(decode(descriptorInfo, vec));
+ }
+
+ void testSet(const IMapper::BufferDescriptorInfo& descriptorInfo,
+ const MetadataType& metadataType, const hidl_vec<uint8_t>& metadata,
+ DecodeFunction decode) {
+ const native_handle_t* bufferHandle = nullptr;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(descriptorInfo, true));
+
+ Error err = mGralloc->set(bufferHandle, metadataType, metadata);
+ if (err == Error::UNSUPPORTED) {
+ GTEST_SUCCEED() << "setting this metadata is unsupported";
+ }
+ ASSERT_EQ(err, Error::NONE);
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &vec));
+
+ ASSERT_NO_FATAL_FAILURE(decode(descriptorInfo, vec));
+ }
+
+ void verifyDummyDescriptorInfoPlaneLayouts(const std::vector<PlaneLayout>& planeLayouts) {
+ ASSERT_EQ(1, planeLayouts.size());
+
+ const auto& planeLayout = planeLayouts.front();
+
+ ASSERT_EQ(4, planeLayout.components.size());
+
+ int64_t offsetInBitsR = -1;
+ int64_t offsetInBitsG = -1;
+ int64_t offsetInBitsB = -1;
+ int64_t offsetInBitsA = -1;
+
+ for (const auto& component : planeLayout.components) {
+ if (!gralloc4::isStandardPlaneLayoutComponentType(component.type)) {
+ continue;
+ }
+ EXPECT_EQ(8, component.sizeInBits);
+ if (component.type.value == gralloc4::PlaneLayoutComponentType_R.value) {
+ offsetInBitsR = component.offsetInBits;
+ }
+ if (component.type.value == gralloc4::PlaneLayoutComponentType_G.value) {
+ offsetInBitsG = component.offsetInBits;
+ }
+ if (component.type.value == gralloc4::PlaneLayoutComponentType_B.value) {
+ offsetInBitsB = component.offsetInBits;
+ }
+ if (component.type.value == gralloc4::PlaneLayoutComponentType_A.value) {
+ offsetInBitsA = component.offsetInBits;
+ }
+ }
+
+ EXPECT_EQ(0, offsetInBitsR);
+ EXPECT_EQ(8, offsetInBitsG);
+ EXPECT_EQ(16, offsetInBitsB);
+ EXPECT_EQ(24, offsetInBitsA);
+
+ EXPECT_EQ(0, planeLayout.offsetInBytes);
+ EXPECT_EQ(8, planeLayout.sampleIncrementInBits);
+ // Skip testing stride because any stride is valid
+ EXPECT_EQ(mDummyDescriptorInfo.width, planeLayout.widthInSamples);
+ EXPECT_EQ(mDummyDescriptorInfo.height, planeLayout.heightInSamples);
+ EXPECT_LE(planeLayout.widthInSamples * planeLayout.heightInSamples * 4,
+ planeLayout.totalSizeInBytes);
+ EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+ EXPECT_EQ(1, planeLayout.verticalSubsampling);
+
+ EXPECT_EQ(0, planeLayout.crop.left);
+ EXPECT_EQ(0, planeLayout.crop.top);
+ EXPECT_EQ(planeLayout.widthInSamples, planeLayout.crop.right);
+ EXPECT_EQ(planeLayout.heightInSamples, planeLayout.crop.bottom);
+ }
+
+ void verifyBufferDump(const IMapper::BufferDump& bufferDump,
+ const native_handle_t* bufferHandle = nullptr) {
+ std::set<StandardMetadataType> foundMetadataTypes;
+
+ const std::vector<IMapper::MetadataDump> metadataDump = bufferDump.metadataDump;
+
+ for (const auto& dump : metadataDump) {
+ const auto& metadataType = dump.metadataType;
+ const auto& metadata = dump.metadata;
+
+ if (!gralloc4::isStandardMetadataType(metadataType)) {
+ continue;
+ }
+
+ StandardMetadataType type = gralloc4::getStandardMetadataTypeValue(metadataType);
+
+ if (sRequiredMetadataTypes.find(type) == sRequiredMetadataTypes.end()) {
+ continue;
+ }
+
+ ASSERT_EQ(foundMetadataTypes.find(type), foundMetadataTypes.end());
+ foundMetadataTypes.insert(type);
+
+ if (!bufferHandle) {
+ continue;
+ }
+
+ hidl_vec<uint8_t> metadataFromGet;
+ ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &metadataFromGet));
+
+ ASSERT_EQ(metadataFromGet, metadata);
+ }
+
+ EXPECT_EQ(sRequiredMetadataTypes, foundMetadataTypes);
+ }
+
+ void getAndroidYCbCr(const native_handle_t* bufferHandle, uint8_t* data,
+ android_ycbcr* outYCbCr) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+ std::vector<PlaneLayout> planeLayouts;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+
+ outYCbCr->y = nullptr;
+ outYCbCr->cb = nullptr;
+ outYCbCr->cr = nullptr;
+ outYCbCr->ystride = 0;
+ outYCbCr->cstride = 0;
+ outYCbCr->chroma_step = 0;
+
+ for (const auto& planeLayout : planeLayouts) {
+ for (const auto& planeLayoutComponent : planeLayout.components) {
+ if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
+ continue;
+ }
+ ASSERT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+
+ uint8_t* tmpData =
+ data + planeLayout.offsetInBytes + (planeLayoutComponent.offsetInBits / 8);
+ uint64_t sampleIncrementInBytes;
+
+ auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
+ switch (type) {
+ case PlaneLayoutComponentType::Y:
+ ASSERT_EQ(nullptr, outYCbCr->y);
+ ASSERT_EQ(8, planeLayoutComponent.sizeInBits);
+ ASSERT_EQ(8, planeLayout.sampleIncrementInBits);
+ outYCbCr->y = tmpData;
+ outYCbCr->ystride = planeLayout.strideInBytes;
+ break;
+
+ case PlaneLayoutComponentType::CB:
+ case PlaneLayoutComponentType::CR:
+ ASSERT_EQ(0, planeLayout.sampleIncrementInBits % 8);
+
+ sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
+ ASSERT_TRUE(sampleIncrementInBytes == 1 || sampleIncrementInBytes == 2);
+
+ if (outYCbCr->cstride == 0 && outYCbCr->chroma_step == 0) {
+ outYCbCr->cstride = planeLayout.strideInBytes;
+ outYCbCr->chroma_step = sampleIncrementInBytes;
+ } else {
+ ASSERT_EQ(outYCbCr->cstride, planeLayout.strideInBytes);
+ ASSERT_EQ(outYCbCr->chroma_step, sampleIncrementInBytes);
+ }
+
+ if (type == PlaneLayoutComponentType::CB) {
+ ASSERT_EQ(nullptr, outYCbCr->cb);
+ outYCbCr->cb = tmpData;
+ } else {
+ ASSERT_EQ(nullptr, outYCbCr->cr);
+ outYCbCr->cr = tmpData;
+ }
+ break;
+ default:
+ break;
+ };
+ }
+ }
+
+ ASSERT_NE(nullptr, outYCbCr->y);
+ ASSERT_NE(nullptr, outYCbCr->cb);
+ 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;
+};
+
+const std::set<StandardMetadataType> GraphicsMapperHidlTest::sRequiredMetadataTypes{
+ StandardMetadataType::BUFFER_ID,
+ StandardMetadataType::NAME,
+ StandardMetadataType::WIDTH,
+ StandardMetadataType::HEIGHT,
+ StandardMetadataType::LAYER_COUNT,
+ StandardMetadataType::PIXEL_FORMAT_REQUESTED,
+ StandardMetadataType::PIXEL_FORMAT_FOURCC,
+ StandardMetadataType::PIXEL_FORMAT_MODIFIER,
+ StandardMetadataType::USAGE,
+ StandardMetadataType::ALLOCATION_SIZE,
+ StandardMetadataType::PROTECTED_CONTENT,
+ StandardMetadataType::COMPRESSION,
+ StandardMetadataType::INTERLACED,
+ StandardMetadataType::CHROMA_SITING,
+ StandardMetadataType::PLANE_LAYOUTS,
+ StandardMetadataType::DATASPACE,
+ StandardMetadataType::BLEND_MODE,
+};
+
+/**
+ * Test IAllocator::allocate with valid buffer descriptors.
+ */
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocate) {
+ BufferDescriptor descriptor;
+ ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
+
+ for (uint32_t count = 0; count < 5; count++) {
+ std::vector<const native_handle_t*> bufferHandles;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(
+ bufferHandles = mGralloc->allocate(descriptor, count, false, false, &stride));
+
+ if (count >= 1) {
+ EXPECT_LE(mDummyDescriptorInfo.width, stride) << "invalid buffer stride";
+ }
+
+ for (auto bufferHandle : bufferHandles) {
+ mGralloc->freeBuffer(bufferHandle);
+ }
+ }
+}
+
+/**
+ * Test IAllocator::allocate with invalid buffer descriptors.
+ */
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
+ // this assumes any valid descriptor is non-empty
+ BufferDescriptor descriptor;
+ mGralloc->getAllocator()->allocate(descriptor, 1,
+ [&](const auto& tmpError, const auto&, const auto&) {
+ EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
+ });
+}
+
+/**
+ * Test IAllocator::allocate does not leak.
+ */
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
+ auto info = mDummyDescriptorInfo;
+ info.width = 1024;
+ info.height = 1024;
+
+ for (int i = 0; i < 2048; i++) {
+ auto bufferHandle = mGralloc->allocate(info, false);
+ mGralloc->freeBuffer(bufferHandle);
+ }
+}
+
+/**
+ * Test that IAllocator::allocate is thread-safe.
+ */
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
+ BufferDescriptor descriptor;
+ ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
+
+ std::atomic<bool> timeUp(false);
+ std::atomic<uint64_t> allocationCount(0);
+ auto threadLoop = [&]() {
+ while (!timeUp) {
+ mGralloc->getAllocator()->allocate(
+ descriptor, 1,
+ [&](const auto&, const auto&, const auto&) { allocationCount++; });
+ }
+ };
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 8; i++) {
+ threads.push_back(std::thread(threadLoop));
+ }
+
+ std::this_thread::sleep_for(std::chrono::seconds(3));
+ timeUp = true;
+ LOG(VERBOSE) << "Made " << allocationCount << " threaded allocations";
+
+ for (auto& thread : threads) {
+ thread.join();
+ }
+}
+
+/**
+ * Test IMapper::createDescriptor with valid descriptor info.
+ */
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorBasic) {
+ ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
+}
+
+/**
+ * Test IMapper::createDescriptor with invalid descriptor info.
+ */
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorNegative) {
+ auto info = mDummyDescriptorInfo;
+ info.width = 0;
+ mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_VALUE, tmpError) << "createDescriptor did not fail with BAD_VALUE";
+ });
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
+ */
+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));
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
+ */
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferClone) {
+ const native_handle_t* clonedBufferHandle;
+ ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+
+ // A cloned handle is a raw handle. Check that we can import it multiple
+ // times.
+ const native_handle_t* importedBufferHandles[2];
+ ASSERT_NO_FATAL_FAILURE(importedBufferHandles[0] = mGralloc->importBuffer(clonedBufferHandle));
+ ASSERT_NO_FATAL_FAILURE(importedBufferHandles[1] = mGralloc->importBuffer(clonedBufferHandle));
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[0]));
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[1]));
+
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(clonedBufferHandle));
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
+ */
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
+ const native_handle_t* rawHandle;
+ ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+
+ native_handle_t* importedHandle = nullptr;
+ mGralloc->getMapper()->importBuffer(rawHandle, [&](const auto& tmpError, const auto& buffer) {
+ ASSERT_EQ(Error::NONE, tmpError);
+ importedHandle = static_cast<native_handle_t*>(buffer);
+ });
+
+ // free the imported handle with another mapper
+ std::unique_ptr<Gralloc> anotherGralloc;
+ 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);
+
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawHandle));
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
+ */
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
+ auto info = mDummyDescriptorInfo;
+ info.width = 1024;
+ info.height = 1024;
+
+ for (int i = 0; i < 2048; i++) {
+ auto bufferHandle = mGralloc->allocate(info, true);
+ mGralloc->freeBuffer(bufferHandle);
+ }
+}
+
+/**
+ * Test IMapper::importBuffer with invalid buffers.
+ */
+TEST_P(GraphicsMapperHidlTest, ImportBufferNegative) {
+ native_handle_t* invalidHandle = nullptr;
+ mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "importBuffer with nullptr did not fail with BAD_BUFFER";
+ });
+
+ invalidHandle = native_handle_create(0, 0);
+ mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "importBuffer with invalid handle did not fail with BAD_BUFFER";
+ });
+ native_handle_delete(invalidHandle);
+}
+
+/**
+ * Test IMapper::freeBuffer with invalid buffers.
+ */
+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";
+
+ invalidHandle = native_handle_create(0, 0);
+ error = mGralloc->getMapper()->freeBuffer(invalidHandle);
+ EXPECT_EQ(Error::BAD_BUFFER, error)
+ << "freeBuffer with invalid handle did not fail with BAD_BUFFER";
+ native_handle_delete(invalidHandle);
+
+ const native_handle_t* clonedBufferHandle;
+ ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+ error = mGralloc->getMapper()->freeBuffer(invalidHandle);
+ EXPECT_EQ(Error::BAD_BUFFER, error)
+ << "freeBuffer with un-imported handle did not fail with BAD_BUFFER";
+
+ mGralloc->freeBuffer(clonedBufferHandle);
+}
+
+/**
+ * Test IMapper::lock and IMapper::unlock.
+ */
+TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) {
+ const auto& info = mDummyDescriptorInfo;
+
+ const native_handle_t* bufferHandle;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, false, &stride));
+
+ // lock buffer for writing
+ const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+ static_cast<int32_t>(info.height)};
+ int fence = -1;
+ uint8_t* data;
+ ASSERT_NO_FATAL_FAILURE(
+ data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
+
+ // RGBA_8888
+ 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)));
+ ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(data, info.height, stride * 4, info.width * 4));
+
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+ if (fence >= 0) {
+ close(fence);
+ }
+}
+
+TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) {
+ auto info = mDummyDescriptorInfo;
+ info.format = PixelFormat::YCBCR_420_888;
+
+ const native_handle_t* bufferHandle;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, false, &stride));
+
+ // lock buffer for writing
+ const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+ static_cast<int32_t>(info.height)};
+ int fence = -1;
+ uint8_t* data;
+
+ ASSERT_NO_FATAL_FAILURE(
+ data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
+
+ android_ycbcr yCbCr;
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(bufferHandle, data, &yCbCr));
+
+ auto yData = static_cast<uint8_t*>(yCbCr.y);
+ auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+ auto crData = static_cast<uint8_t*>(yCbCr.cr);
+ auto yStride = yCbCr.ystride;
+ auto cStride = yCbCr.cstride;
+ auto chromaStep = yCbCr.chroma_step;
+
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (uint32_t x = 0; x < info.width; x++) {
+ auto val = static_cast<uint8_t>(info.height * y + x);
+
+ yData[yStride * y + x] = val;
+
+ if (y % chromaStep && x % chromaStep == 0) {
+ cbData[cStride * y / chromaStep + x / chromaStep] = val;
+ crData[cStride * y / chromaStep + x / chromaStep] = val;
+ }
+ }
+ }
+
+ 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)));
+
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(bufferHandle, data, &yCbCr));
+
+ yData = static_cast<uint8_t*>(yCbCr.y);
+ cbData = static_cast<uint8_t*>(yCbCr.cb);
+ crData = static_cast<uint8_t*>(yCbCr.cr);
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (uint32_t x = 0; x < info.width; x++) {
+ auto val = static_cast<uint8_t>(info.height * y + x);
+
+ EXPECT_EQ(val, yData[yStride * y + x]);
+
+ if (y % chromaStep == 0 && x % chromaStep == 0) {
+ EXPECT_EQ(val, cbData[cStride * y / chromaStep + x / chromaStep]);
+ EXPECT_EQ(val, crData[cStride * y / chromaStep + x / chromaStep]);
+ }
+ }
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+ if (fence >= 0) {
+ close(fence);
+ }
+}
+
+/**
+ * Test IMapper::unlock with bad access region
+ */
+TEST_P(GraphicsMapperHidlTest, LockBadAccessRegion) {
+ const auto& info = mDummyDescriptorInfo;
+
+ const native_handle_t* bufferHandle;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));
+
+ const IMapper::Rect accessRegion{0, 0, static_cast<int32_t>(info.width * 2),
+ static_cast<int32_t>(info.height * 2)};
+ int acquireFence = -1;
+
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ hidl_handle acquireFenceHandle;
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ mGralloc->getMapper()->lock(buffer, info.usage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& /*tmpData*/) {
+ EXPECT_EQ(Error::BAD_VALUE, tmpError)
+ << "locking with a bad access region should fail";
+ });
+
+ if (::testing::Test::HasFailure()) {
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ int releaseFence = -1;
+ ASSERT_NO_FATAL_FAILURE(releaseFence = mGralloc->unlock(bufferHandle));
+
+ if (releaseFence >= 0) {
+ close(releaseFence);
+ }
+ }
+}
+
+/**
+ * Test IMapper::unlock with invalid buffers.
+ */
+TEST_P(GraphicsMapperHidlTest, UnlockNegative) {
+ native_handle_t* invalidHandle = nullptr;
+ mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "unlock with nullptr did not fail with BAD_BUFFER";
+ });
+
+ invalidHandle = native_handle_create(0, 0);
+ mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "unlock with invalid handle did not fail with BAD_BUFFER";
+ });
+ native_handle_delete(invalidHandle);
+
+ ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
+ mGralloc->allocate(mDummyDescriptorInfo, false)));
+ mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "unlock with un-imported handle did not fail with BAD_BUFFER";
+ });
+ mGralloc->freeBuffer(invalidHandle);
+
+// disabled as it fails on many existing drivers
+#if 0
+ ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
+ mGralloc->allocate(mDummyDescriptorInfo, true)));
+ mGralloc->getMapper()->unlock(
+ invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "unlock with unlocked handle did not fail with BAD_BUFFER";
+ });
+ mGralloc->freeBuffer(invalidHandle);
+#endif
+}
+
+/**
+ * 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_P(GraphicsMapperHidlTest, IsSupportedRGBA8888) {
+ const auto& info = mDummyDescriptorInfo;
+ bool supported = false;
+
+ ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+ ASSERT_TRUE(supported);
+}
+
+/**
+ * Test IMapper::isSupported with required format YV12
+ */
+TEST_P(GraphicsMapperHidlTest, IsSupportedYV12) {
+ auto info = mDummyDescriptorInfo;
+ info.format = PixelFormat::YV12;
+ bool supported = false;
+
+ ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+ ASSERT_TRUE(supported);
+}
+
+/**
+ * Test IMapper::isSupported with optional format Y16
+ */
+TEST_P(GraphicsMapperHidlTest, IsSupportedY16) {
+ auto info = mDummyDescriptorInfo;
+ info.format = PixelFormat::Y16;
+ bool supported = false;
+
+ ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+}
+
+/**
+ * Test IMapper::get(BufferId)
+ */
+TEST_P(GraphicsMapperHidlTest, GetBufferId) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_BufferId,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ uint64_t bufferId = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeBufferId(vec, &bufferId));
+ });
+}
+
+/**
+ * Test IMapper::get(Name)
+ */
+TEST_P(GraphicsMapperHidlTest, GetName) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Name,
+ [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
+ std::string name;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeName(vec, &name));
+ EXPECT_EQ(info.name, name);
+ });
+}
+
+/**
+ * Test IMapper::get(Width)
+ */
+TEST_P(GraphicsMapperHidlTest, GetWidth) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Width,
+ [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
+ uint64_t width = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeWidth(vec, &width));
+ EXPECT_EQ(info.width, width);
+ });
+}
+
+/**
+ * Test IMapper::get(Height)
+ */
+TEST_P(GraphicsMapperHidlTest, GetHeight) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Height,
+ [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
+ uint64_t height = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeHeight(vec, &height));
+ EXPECT_EQ(info.height, height);
+ });
+}
+
+/**
+ * Test IMapper::get(LayerCount)
+ */
+TEST_P(GraphicsMapperHidlTest, GetLayerCount) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_LayerCount,
+ [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
+ uint64_t layerCount = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeLayerCount(vec, &layerCount));
+ EXPECT_EQ(info.layerCount, layerCount);
+ });
+}
+
+/**
+ * Test IMapper::get(PixelFormatRequested)
+ */
+TEST_P(GraphicsMapperHidlTest, GetPixelFormatRequested) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatRequested,
+ [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
+ PixelFormat pixelFormatRequested = PixelFormat::BLOB;
+ ASSERT_EQ(NO_ERROR,
+ gralloc4::decodePixelFormatRequested(vec, &pixelFormatRequested));
+ EXPECT_EQ(info.format, pixelFormatRequested);
+ });
+}
+
+/**
+ * Test IMapper::get(PixelFormatFourCC)
+ */
+TEST_P(GraphicsMapperHidlTest, GetPixelFormatFourCC) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ uint32_t pixelFormatFourCC = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &pixelFormatFourCC));
+ });
+}
+
+/**
+ * Test IMapper::get(PixelFormatModifier)
+ */
+TEST_P(GraphicsMapperHidlTest, GetPixelFormatModifier) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ uint64_t pixelFormatModifier = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatModifier(vec, &pixelFormatModifier));
+ });
+}
+
+/**
+ * Test IMapper::get(Usage)
+ */
+TEST_P(GraphicsMapperHidlTest, GetUsage) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage,
+ [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
+ uint64_t usage = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &usage));
+ EXPECT_EQ(info.usage, usage);
+ });
+}
+
+/**
+ * Test IMapper::get(AllocationSize)
+ */
+TEST_P(GraphicsMapperHidlTest, GetAllocationSize) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_AllocationSize,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ uint64_t allocationSize = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &allocationSize));
+ });
+}
+
+/**
+ * Test IMapper::get(ProtectedContent)
+ */
+TEST_P(GraphicsMapperHidlTest, GetProtectedContent) {
+ auto info = mDummyDescriptorInfo;
+ info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
+
+ const native_handle_t* bufferHandle = nullptr;
+ bufferHandle = mGralloc->allocate(info, true, true);
+ if (bufferHandle) {
+ GTEST_SUCCEED() << "unable to allocate protected content";
+ }
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_ProtectedContent, &vec));
+
+ uint64_t protectedContent = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &protectedContent));
+ EXPECT_EQ(1, protectedContent);
+}
+
+/**
+ * Test IMapper::get(Compression)
+ */
+TEST_P(GraphicsMapperHidlTest, GetCompression) {
+ auto info = mDummyDescriptorInfo;
+ info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+ testGet(info, gralloc4::MetadataType_Compression,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ ExtendableType compression = gralloc4::Compression_DisplayStreamCompression;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeCompression(vec, &compression));
+
+ EXPECT_EQ(gralloc4::Compression_None.name, compression.name);
+ EXPECT_EQ(gralloc4::Compression_None.value, compression.value);
+ });
+}
+
+/**
+ * Test IMapper::get(Interlaced)
+ */
+TEST_P(GraphicsMapperHidlTest, GetInterlaced) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ ExtendableType interlaced = gralloc4::Interlaced_TopBottom;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeInterlaced(vec, &interlaced));
+
+ EXPECT_EQ(gralloc4::Interlaced_None.name, interlaced.name);
+ EXPECT_EQ(gralloc4::Interlaced_None.value, interlaced.value);
+ });
+}
+
+/**
+ * Test IMapper::get(ChromaSiting)
+ */
+TEST_P(GraphicsMapperHidlTest, GetChromaSiting) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_ChromaSiting,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ ExtendableType chromaSiting = gralloc4::ChromaSiting_Unknown;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeChromaSiting(vec, &chromaSiting));
+
+ EXPECT_EQ(gralloc4::ChromaSiting_None.name, chromaSiting.name);
+ EXPECT_EQ(gralloc4::ChromaSiting_None.value, chromaSiting.value);
+ });
+}
+
+/**
+ * Test IMapper::get(PlaneLayouts)
+ */
+TEST_P(GraphicsMapperHidlTest, GetPlaneLayouts) {
+ const native_handle_t* bufferHandle = nullptr;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+
+ std::vector<PlaneLayout> planeLayouts;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+
+ ASSERT_NO_FATAL_FAILURE(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts));
+}
+
+/**
+ * Test IMapper::get(Dataspace)
+ */
+TEST_P(GraphicsMapperHidlTest, GetDataspace) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ Dataspace dataspace = Dataspace::DISPLAY_P3;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &dataspace));
+ EXPECT_EQ(Dataspace::UNKNOWN, dataspace);
+ });
+}
+
+/**
+ * Test IMapper::get(BlendMode)
+ */
+TEST_P(GraphicsMapperHidlTest, GetBlendMode) {
+ testGet(mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode,
+ [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ BlendMode blendMode = BlendMode::NONE;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &blendMode));
+ EXPECT_EQ(BlendMode::INVALID, blendMode);
+ });
+}
+
+/**
+ * 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_P(GraphicsMapperHidlTest, GetMetadataBadValue) {
+ const native_handle_t* bufferHandle = nullptr;
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_BufferId, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Name, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Width, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Height, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_LayerCount, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Usage, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_AllocationSize, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_ProtectedContent, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_Compression, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_Interlaced, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_ChromaSiting, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+ ASSERT_EQ(0, vec.size());
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_Dataspace, &vec));
+ ASSERT_EQ(0, vec.size());
+ 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_P(GraphicsMapperHidlTest, GetUnsupportedMetadata) {
+ const native_handle_t* bufferHandle = nullptr;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+ MetadataType metadataTypeFake = {"FAKE", 1};
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::UNSUPPORTED, mGralloc->get(bufferHandle, metadataTypeFake, &vec));
+ ASSERT_EQ(0, vec.size());
+}
+
+/**
+ * Test IMapper::get(metadata) for unsupported standard metadata
+ */
+TEST_P(GraphicsMapperHidlTest, GetUnsupportedStandardMetadata) {
+ const native_handle_t* bufferHandle = nullptr;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+ MetadataType metadataTypeFake = {GRALLOC4_STANDARD_METADATA_TYPE, 9999};
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::UNSUPPORTED, mGralloc->get(bufferHandle, metadataTypeFake, &vec));
+ ASSERT_EQ(0, vec.size());
+}
+
+/**
+ * Test IMapper::set(PixelFormatFourCC)
+ */
+TEST_P(GraphicsMapperHidlTest, SetPixelFormatFourCC) {
+ uint32_t pixelFormatFourCC = 0x34324142; // DRM_FORMAT_BGRA8888
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatFourCC(pixelFormatFourCC, &vec));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ uint32_t realPixelFormatFourCC = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &realPixelFormatFourCC));
+ EXPECT_EQ(pixelFormatFourCC, realPixelFormatFourCC);
+ });
+}
+
+/**
+ * Test IMapper::set(PixelFormatModifier)
+ */
+TEST_P(GraphicsMapperHidlTest, SetPixelFormatModifier) {
+ uint64_t pixelFormatModifier = 10;
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatModifier(pixelFormatModifier, &vec));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ uint64_t realPixelFormatModifier = 0;
+ ASSERT_EQ(NO_ERROR,
+ gralloc4::decodePixelFormatModifier(vec, &realPixelFormatModifier));
+ EXPECT_EQ(pixelFormatModifier, realPixelFormatModifier);
+ });
+}
+
+/**
+ * Test IMapper::set(Usage) remove flag
+ */
+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));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ uint64_t realUsage = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage));
+ EXPECT_EQ(usage, realUsage);
+ });
+}
+/**
+ * Test IMapper::set(Usage) add flag
+ */
+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));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ uint64_t realUsage = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage));
+ EXPECT_EQ(usage, realUsage);
+ });
+}
+
+/**
+ * Test IMapper::set(Usage) to test protected content
+ */
+TEST_P(GraphicsMapperHidlTest, SetUsageProtected) {
+ const native_handle_t* bufferHandle = nullptr;
+ auto info = mDummyDescriptorInfo;
+ info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
+
+ bufferHandle = mGralloc->allocate(info, true, true);
+ if (bufferHandle) {
+ GTEST_SUCCEED() << "unable to allocate protected content";
+ }
+
+ uint64_t usage = static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY);
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec));
+
+ Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec);
+ ASSERT_EQ(err, Error::UNSUPPORTED);
+ vec.resize(0);
+
+ uint64_t realUsage = 0;
+ ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_Usage, &vec));
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage));
+ EXPECT_EQ(info.usage, realUsage);
+}
+
+/**
+ * Test IMapper::set(AllocationSize)
+ */
+TEST_P(GraphicsMapperHidlTest, SetAllocationSize) {
+ uint64_t allocationSize = 1000000;
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeAllocationSize(allocationSize, &vec));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_AllocationSize, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ uint64_t realAllocationSize = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &realAllocationSize));
+ EXPECT_EQ(allocationSize, realAllocationSize);
+ });
+}
+
+/**
+ * Test IMapper::set(ProtectedContent)
+ */
+TEST_P(GraphicsMapperHidlTest, SetProtectedContent) {
+ const native_handle_t* bufferHandle = nullptr;
+ auto info = mDummyDescriptorInfo;
+ info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
+
+ bufferHandle = mGralloc->allocate(info, true, true);
+ if (bufferHandle) {
+ GTEST_SUCCEED() << "unable to allocate protected content";
+ }
+
+ uint64_t protectedContent = 0;
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeProtectedContent(protectedContent, &vec));
+
+ Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_ProtectedContent, vec);
+ ASSERT_EQ(err, Error::UNSUPPORTED);
+ vec.resize(0);
+
+ uint64_t realProtectedContent = 0;
+ ASSERT_EQ(Error::NONE,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_ProtectedContent, &vec));
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &realProtectedContent));
+ EXPECT_EQ(1, realProtectedContent);
+}
+
+/**
+ * Test IMapper::set(Compression)
+ */
+TEST_P(GraphicsMapperHidlTest, SetCompression) {
+ auto info = mDummyDescriptorInfo;
+ info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+ ExtendableType compression = gralloc4::Compression_DisplayStreamCompression;
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeCompression(compression, &vec));
+
+ testSet(info, gralloc4::MetadataType_Compression, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ ExtendableType realCompression = gralloc4::Compression_None;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeCompression(vec, &realCompression));
+
+ EXPECT_EQ(compression.name, realCompression.name);
+ EXPECT_EQ(compression.value, realCompression.value);
+ });
+}
+
+/**
+ * Test IMapper::set(Interlaced)
+ */
+TEST_P(GraphicsMapperHidlTest, SetInterlaced) {
+ ExtendableType interlaced = gralloc4::Interlaced_RightLeft;
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeInterlaced(interlaced, &vec));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ ExtendableType realInterlaced = gralloc4::Interlaced_None;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeInterlaced(vec, &realInterlaced));
+
+ EXPECT_EQ(interlaced.name, realInterlaced.name);
+ EXPECT_EQ(interlaced.value, realInterlaced.value);
+ });
+}
+
+/**
+ * Test IMapper::set(ChromaSiting)
+ */
+TEST_P(GraphicsMapperHidlTest, SetChromaSiting) {
+ ExtendableType chromaSiting = gralloc4::ChromaSiting_SitedInterstitial;
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeChromaSiting(chromaSiting, &vec));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_ChromaSiting, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ ExtendableType realChromaSiting = gralloc4::ChromaSiting_None;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeChromaSiting(vec, &realChromaSiting));
+
+ EXPECT_EQ(chromaSiting.name, realChromaSiting.name);
+ EXPECT_EQ(chromaSiting.value, realChromaSiting.value);
+ });
+}
+
+/**
+ * Test IMapper::set(PlaneLayouts)
+ */
+TEST_P(GraphicsMapperHidlTest, SetPlaneLayouts) {
+ const native_handle_t* bufferHandle = nullptr;
+ auto info = mDummyDescriptorInfo;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));
+
+ std::vector<PlaneLayout> planeLayouts;
+ PlaneLayout planeLayoutA;
+ PlaneLayout planeLayoutRGB;
+ PlaneLayoutComponent component;
+
+ planeLayoutA.offsetInBytes = 0;
+ planeLayoutA.sampleIncrementInBits = 8;
+ planeLayoutA.strideInBytes = info.width + 20;
+ planeLayoutA.widthInSamples = info.width;
+ planeLayoutA.heightInSamples = info.height;
+ planeLayoutA.totalSizeInBytes = planeLayoutA.strideInBytes * info.height;
+ planeLayoutA.horizontalSubsampling = 1;
+ planeLayoutA.verticalSubsampling = 1;
+ planeLayoutA.crop.left = 0;
+ planeLayoutA.crop.top = 0;
+ planeLayoutA.crop.right = info.width;
+ planeLayoutA.crop.bottom = info.height;
+
+ component.type = gralloc4::PlaneLayoutComponentType_A;
+ component.offsetInBits = 0;
+ component.sizeInBits = 8;
+ planeLayoutA.components.push_back(component);
+
+ planeLayouts.push_back(planeLayoutA);
+
+ planeLayoutRGB.offsetInBytes = 0;
+ planeLayoutRGB.sampleIncrementInBits = 32;
+ planeLayoutRGB.strideInBytes = info.width + 20;
+ planeLayoutRGB.widthInSamples = info.width;
+ planeLayoutRGB.heightInSamples = info.height;
+ planeLayoutRGB.totalSizeInBytes = planeLayoutRGB.strideInBytes * info.height;
+ planeLayoutRGB.horizontalSubsampling = 1;
+ planeLayoutRGB.verticalSubsampling = 1;
+ planeLayoutRGB.crop.left = 0;
+ planeLayoutRGB.crop.top = 0;
+ planeLayoutRGB.crop.right = info.width;
+ planeLayoutRGB.crop.bottom = info.height;
+
+ component.type = gralloc4::PlaneLayoutComponentType_R;
+ planeLayoutRGB.components.push_back(component);
+ component.type = gralloc4::PlaneLayoutComponentType_G;
+ planeLayoutRGB.components.push_back(component);
+ component.type = gralloc4::PlaneLayoutComponentType_B;
+ planeLayoutRGB.components.push_back(component);
+
+ planeLayouts.push_back(planeLayoutRGB);
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodePlaneLayouts(planeLayouts, &vec));
+
+ Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec);
+ if (err == Error::UNSUPPORTED) {
+ GTEST_SUCCEED() << "setting this metadata is unsupported";
+ }
+ ASSERT_EQ(err, Error::NONE);
+
+ std::vector<PlaneLayout> realPlaneLayouts;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &realPlaneLayouts));
+
+ ASSERT_EQ(planeLayouts.size(), realPlaneLayouts.size());
+
+ for (int i = 0; i < realPlaneLayouts.size(); i++) {
+ const auto& planeLayout = planeLayouts[i];
+ const auto& realPlaneLayout = realPlaneLayouts[i];
+
+ EXPECT_EQ(planeLayout.offsetInBytes, realPlaneLayout.offsetInBytes);
+ EXPECT_EQ(planeLayout.sampleIncrementInBits, realPlaneLayout.sampleIncrementInBits);
+ EXPECT_EQ(planeLayout.strideInBytes, realPlaneLayout.strideInBytes);
+ EXPECT_EQ(planeLayout.widthInSamples, realPlaneLayout.widthInSamples);
+ EXPECT_EQ(planeLayout.heightInSamples, realPlaneLayout.heightInSamples);
+ EXPECT_LE(planeLayout.totalSizeInBytes, realPlaneLayout.totalSizeInBytes);
+ EXPECT_EQ(planeLayout.horizontalSubsampling, realPlaneLayout.horizontalSubsampling);
+ EXPECT_EQ(planeLayout.verticalSubsampling, realPlaneLayout.verticalSubsampling);
+
+ EXPECT_EQ(planeLayout.crop.left, realPlaneLayout.crop.left);
+ EXPECT_EQ(planeLayout.crop.top, realPlaneLayout.crop.top);
+ EXPECT_EQ(planeLayout.crop.right, realPlaneLayout.crop.right);
+ EXPECT_EQ(planeLayout.crop.bottom, realPlaneLayout.crop.bottom);
+
+ ASSERT_EQ(planeLayout.components.size(), realPlaneLayout.components.size());
+
+ for (int j = 0; j < realPlaneLayout.components.size(); j++) {
+ const auto& component = planeLayout.components[j];
+ const auto& realComponent = realPlaneLayout.components[j];
+
+ EXPECT_EQ(component.type.name, realComponent.type.name);
+ EXPECT_EQ(component.type.value, realComponent.type.value);
+ EXPECT_EQ(component.sizeInBits, realComponent.sizeInBits);
+ EXPECT_EQ(component.offsetInBits, realComponent.offsetInBits);
+ }
+ }
+}
+
+/**
+ * Test IMapper::set(Dataspace)
+ */
+TEST_P(GraphicsMapperHidlTest, SetDataspace) {
+ Dataspace dataspace = Dataspace::SRGB_LINEAR;
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &vec));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ Dataspace realDataspace = Dataspace::UNKNOWN;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &realDataspace));
+ EXPECT_EQ(dataspace, realDataspace);
+ });
+}
+
+/**
+ * Test IMapper::set(BlendMode)
+ */
+TEST_P(GraphicsMapperHidlTest, SetBlendMode) {
+ BlendMode blendMode = BlendMode::PREMULTIPLIED;
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeBlendMode(blendMode, &vec));
+
+ testSet(mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode, vec,
+ [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+ BlendMode realBlendMode = BlendMode::INVALID;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &realBlendMode));
+ EXPECT_EQ(blendMode, realBlendMode);
+ });
+}
+
+/**
+ * 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_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));
+ ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec));
+ ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec));
+ ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, vec));
+ ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_AllocationSize, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_ProtectedContent, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_Compression, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_Interlaced, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_ChromaSiting, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec));
+ ASSERT_EQ(Error::BAD_BUFFER,
+ 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_P(GraphicsMapperHidlTest, SetConstantMetadata) {
+ const native_handle_t* bufferHandle = nullptr;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec));
+ ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec));
+ ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec));
+ ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec));
+ ASSERT_EQ(Error::BAD_VALUE,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec));
+ ASSERT_EQ(Error::BAD_VALUE,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec));
+ ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec));
+}
+
+/**
+ * Test IMapper::set(metadata) for bad metadata
+ */
+TEST_P(GraphicsMapperHidlTest, SetBadMetadata) {
+ const native_handle_t* bufferHandle = nullptr;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec));
+ ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec));
+ ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec));
+ ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, vec));
+ ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_AllocationSize, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_ProtectedContent, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_Compression, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_Interlaced, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_ChromaSiting, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec));
+ ASSERT_EQ(Error::UNSUPPORTED,
+ 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_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBufferId) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+ gralloc4::MetadataType_BufferId, &vec));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Name)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoName) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_Name, &vec));
+
+ std::string name;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeName(vec, &name));
+ EXPECT_EQ(mDummyDescriptorInfo.name, name);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Width)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoWidth) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_Width, &vec));
+
+ uint64_t width = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeWidth(vec, &width));
+ EXPECT_EQ(mDummyDescriptorInfo.width, width);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Height)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoHeight) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_Height, &vec));
+
+ uint64_t height = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeHeight(vec, &height));
+ EXPECT_EQ(mDummyDescriptorInfo.height, height);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(PixelFormatRequested)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatRequested) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE,
+ mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatRequested, &vec));
+
+ PixelFormat pixelFormatRequested = PixelFormat::BLOB;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatRequested(vec, &pixelFormatRequested));
+ EXPECT_EQ(mDummyDescriptorInfo.format, pixelFormatRequested);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(PixelFormatFourCC)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatFourCC) {
+ hidl_vec<uint8_t> vec;
+ Error err = mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, &vec);
+ if (err == Error::UNSUPPORTED) {
+ GTEST_SUCCEED() << "setting this metadata is unsupported";
+ }
+ ASSERT_EQ(err, Error::NONE);
+
+ uint32_t pixelFormatFourCC = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &pixelFormatFourCC));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(PixelFormatModifier)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatModifier) {
+ hidl_vec<uint8_t> vec;
+ Error err = mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, &vec);
+ if (err == Error::UNSUPPORTED) {
+ GTEST_SUCCEED() << "setting this metadata is unsupported";
+ }
+ ASSERT_EQ(err, Error::NONE);
+
+ uint64_t pixelFormatModifier = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatModifier(vec, &pixelFormatModifier));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Usage)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUsage) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_Usage, &vec));
+
+ uint64_t usage = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &usage));
+ EXPECT_EQ(mDummyDescriptorInfo.usage, usage);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(AllocationSize)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoAllocationSize) {
+ hidl_vec<uint8_t> vec;
+ Error err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+ gralloc4::MetadataType_AllocationSize, &vec);
+ if (err == Error::UNSUPPORTED) {
+ GTEST_SUCCEED() << "setting this metadata is unsupported";
+ }
+ ASSERT_EQ(err, Error::NONE);
+
+ uint64_t allocationSize = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &allocationSize));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(ProtectedContent)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoProtectedContent) {
+ auto info = mDummyDescriptorInfo;
+ info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ info, gralloc4::MetadataType_ProtectedContent, &vec));
+
+ uint64_t protectedContent = 0;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &protectedContent));
+ EXPECT_EQ(1, protectedContent);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Compression)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCompression) {
+ auto info = mDummyDescriptorInfo;
+ info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ info, gralloc4::MetadataType_Compression, &vec));
+
+ ExtendableType compression = gralloc4::Compression_DisplayStreamCompression;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeCompression(vec, &compression));
+
+ EXPECT_EQ(gralloc4::Compression_None.name, compression.name);
+ EXPECT_EQ(gralloc4::Compression_None.value, compression.value);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Interlaced)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoInterlaced) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced, &vec));
+
+ ExtendableType interlaced = gralloc4::Interlaced_TopBottom;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeInterlaced(vec, &interlaced));
+
+ EXPECT_EQ(gralloc4::Interlaced_None.name, interlaced.name);
+ EXPECT_EQ(gralloc4::Interlaced_None.value, interlaced.value);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(ChromaSiting)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoChromaSiting) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE,
+ mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+ gralloc4::MetadataType_ChromaSiting, &vec));
+
+ ExtendableType chromaSiting = gralloc4::ChromaSiting_CositedHorizontal;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeChromaSiting(vec, &chromaSiting));
+
+ EXPECT_EQ(gralloc4::ChromaSiting_None.name, chromaSiting.name);
+ EXPECT_EQ(gralloc4::ChromaSiting_None.value, chromaSiting.value);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(PlaneLayouts)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE,
+ mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+ gralloc4::MetadataType_PlaneLayouts, &vec));
+
+ std::vector<PlaneLayout> planeLayouts;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+ ASSERT_NO_FATAL_FAILURE(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Dataspace)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoDataspace) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace, &vec));
+
+ Dataspace dataspace = Dataspace::DISPLAY_P3;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &dataspace));
+ EXPECT_EQ(Dataspace::UNKNOWN, dataspace);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(BlendMode)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) {
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+ mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode, &vec));
+
+ BlendMode blendMode = BlendMode::COVERAGE;
+ ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &blendMode));
+ EXPECT_EQ(BlendMode::INVALID, blendMode);
+}
+
+/**
+ * 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_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedMetadata) {
+ MetadataType metadataTypeFake = {"FAKE", 1};
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, metadataTypeFake, &vec));
+ ASSERT_EQ(0, vec.size());
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported standard metadata
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedStandardMetadata) {
+ MetadataType metadataTypeFake = {GRALLOC4_STANDARD_METADATA_TYPE, 9999};
+
+ hidl_vec<uint8_t> vec;
+ ASSERT_EQ(Error::UNSUPPORTED,
+ mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, metadataTypeFake, &vec));
+ ASSERT_EQ(0, vec.size());
+}
+
+/**
+ * Test IMapper::listSupportedMetadataTypes()
+ */
+TEST_P(GraphicsMapperHidlTest, ListSupportedMetadataTypes) {
+ hidl_vec<IMapper::MetadataTypeDescription> descriptions;
+ mGralloc->getMapper()->listSupportedMetadataTypes(
+ [&](const auto& tmpError, const auto& tmpDescriptions) {
+ ASSERT_EQ(Error::NONE, tmpError);
+ descriptions = tmpDescriptions;
+ });
+
+ std::set<StandardMetadataType> foundMetadataTypes;
+
+ std::set<StandardMetadataType> notSettableMetadataTypes{
+ StandardMetadataType::BUFFER_ID, StandardMetadataType::NAME,
+ StandardMetadataType::WIDTH, StandardMetadataType::HEIGHT,
+ StandardMetadataType::LAYER_COUNT, StandardMetadataType::PIXEL_FORMAT_REQUESTED,
+ StandardMetadataType::USAGE};
+
+ ASSERT_LE(sRequiredMetadataTypes.size(), descriptions.size());
+
+ for (const auto& description : descriptions) {
+ const auto& metadataType = description.metadataType;
+
+ if (!gralloc4::isStandardMetadataType(metadataType)) {
+ EXPECT_GT(0, description.description.size());
+ continue;
+ }
+
+ StandardMetadataType type = gralloc4::getStandardMetadataTypeValue(metadataType);
+
+ if (sRequiredMetadataTypes.find(type) == sRequiredMetadataTypes.end()) {
+ continue;
+ }
+
+ ASSERT_EQ(foundMetadataTypes.find(type), foundMetadataTypes.end());
+ foundMetadataTypes.insert(type);
+
+ ASSERT_TRUE(description.isGettable);
+
+ if (notSettableMetadataTypes.find(type) != notSettableMetadataTypes.end()) {
+ ASSERT_FALSE(description.isSettable);
+ }
+ }
+
+ ASSERT_EQ(sRequiredMetadataTypes, foundMetadataTypes);
+}
+
+/**
+ * Test IMapper::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);
+
+ IMapper::BufferDump bufferDump;
+ mGralloc->getMapper()->dumpBuffer(buffer, [&](const auto& tmpError, const auto& tmpBufferDump) {
+ ASSERT_EQ(Error::NONE, tmpError);
+ bufferDump = tmpBufferDump;
+ });
+
+ ASSERT_NO_FATAL_FAILURE(verifyBufferDump(bufferDump, buffer));
+}
+
+/**
+ * Test IMapper::dumpBuffer() with an invalid buffer
+ */
+TEST_P(GraphicsMapperHidlTest, DumpBufferNullBuffer) {
+ native_handle_t* bufferHandle = nullptr;
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ mGralloc->getMapper()->dumpBuffer(buffer,
+ [&](const auto& tmpError, const auto& /*tmpBufferDump*/) {
+ ASSERT_EQ(Error::BAD_BUFFER, tmpError);
+ });
+}
+
+/**
+ * Test IMapper::dumpBuffer() multiple
+ */
+TEST_P(GraphicsMapperHidlTest, DumpBuffers) {
+ size_t bufferCount = 10;
+
+ for (int i = 0; i < bufferCount; i++) {
+ ASSERT_NO_FATAL_FAILURE(mGralloc->allocate(mDummyDescriptorInfo, true));
+ }
+
+ hidl_vec<IMapper::BufferDump> bufferDump;
+ mGralloc->getMapper()->dumpBuffers([&](const auto& tmpError, const auto& tmpBufferDump) {
+ ASSERT_EQ(Error::NONE, tmpError);
+ bufferDump = tmpBufferDump;
+ });
+
+ ASSERT_EQ(bufferCount, bufferDump.size());
+
+ for (const auto& dump : bufferDump) {
+ ASSERT_NO_FATAL_FAILURE(verifyBufferDump(dump));
+ }
+}
+
+/**
+ * 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
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.0/support/Android.bp b/keymaster/4.0/support/Android.bp
index 2f40282..9c5fbab 100644
--- a/keymaster/4.0/support/Android.bp
+++ b/keymaster/4.0/support/Android.bp
@@ -27,11 +27,10 @@
"authorization_set.cpp",
"key_param_output.cpp",
"keymaster_utils.cpp",
- "Keymaster.cpp",
- "Keymaster3.cpp",
- "Keymaster4.cpp",
],
- export_include_dirs: ["include"],
+ export_include_dirs: [
+ "include",
+ ],
shared_libs: [
"android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
@@ -39,6 +38,5 @@
"libcrypto",
"libhardware",
"libhidlbase",
- "libutils",
- ]
+ ],
}
diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.0/support/Keymaster.cpp
deleted file mode 100644
index 1eb9a68..0000000
--- a/keymaster/4.0/support/Keymaster.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- ** Copyright 2018, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include <keymasterV4_0/Keymaster.h>
-
-#include <iomanip>
-
-#include <android-base/logging.h>
-#include <android/hidl/manager/1.2/IServiceManager.h>
-#include <keymasterV4_0/Keymaster3.h>
-#include <keymasterV4_0/Keymaster4.h>
-#include <keymasterV4_0/key_param_output.h>
-#include <keymasterV4_0/keymaster_utils.h>
-
-namespace android {
-namespace hardware {
-
-template <class T>
-std::ostream& operator<<(std::ostream& os, const hidl_vec<T>& vec) {
- os << "{ ";
- if (vec.size()) {
- for (size_t i = 0; i < vec.size() - 1; ++i) os << vec[i] << ", ";
- os << vec[vec.size() - 1];
- }
- os << " }";
- return os;
-}
-
-std::ostream& operator<<(std::ostream& os, const hidl_vec<uint8_t>& vec) {
- std::ios_base::fmtflags flags(os.flags());
- os << std::setw(2) << std::setfill('0') << std::hex;
- for (uint8_t c : vec) os << static_cast<int>(c);
- os.flags(flags);
- return os;
-}
-
-template <size_t N>
-std::ostream& operator<<(std::ostream& os, const hidl_array<uint8_t, N>& vec) {
- std::ios_base::fmtflags flags(os.flags());
- os << std::setw(2) << std::setfill('0') << std::hex;
- for (size_t i = 0; i < N; ++i) os << static_cast<int>(vec[i]);
- os.flags(flags);
- return os;
-}
-
-namespace keymaster {
-namespace V4_0 {
-
-std::ostream& operator<<(std::ostream& os, const HmacSharingParameters& params) {
- // Note that by design, although seed and nonce are used to compute a secret, they are
- // not secrets and it's just fine to log them.
- os << "(seed: " << params.seed << ", nonce: " << params.nonce << ')';
- return os;
-}
-
-namespace support {
-
-using ::android::sp;
-using ::android::hidl::manager::V1_2::IServiceManager;
-
-std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster) {
- auto& version = keymaster.halVersion();
- os << version.keymasterName << " from " << version.authorName
- << " SecurityLevel: " << toString(version.securityLevel)
- << " HAL: " << keymaster.descriptor() << "/" << keymaster.instanceName();
- return os;
-}
-
-template <typename Wrapper>
-std::vector<std::unique_ptr<Keymaster>> enumerateDevices(
- const sp<IServiceManager>& serviceManager) {
- Keymaster::KeymasterSet result;
-
- bool foundDefault = false;
- auto& descriptor = Wrapper::WrappedIKeymasterDevice::descriptor;
- serviceManager->listManifestByInterface(descriptor, [&](const hidl_vec<hidl_string>& names) {
- for (auto& name : names) {
- if (name == "default") foundDefault = true;
- auto device = Wrapper::WrappedIKeymasterDevice::getService(name);
- CHECK(device) << "Failed to get service for " << descriptor << " with interface name "
- << name;
- result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, name)));
- }
- });
-
- if (!foundDefault) {
- // "default" wasn't provided by listManifestByInterface. Maybe there's a passthrough
- // implementation.
- auto device = Wrapper::WrappedIKeymasterDevice::getService("default");
- if (device) result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, "default")));
- }
-
- return result;
-}
-
-void Keymaster::logIfKeymasterVendorError(ErrorCode ec) const {
- static constexpr int32_t k_keymaster_vendor_error_code_range_max = -10000;
- if (static_cast<int32_t>(ec) <= k_keymaster_vendor_error_code_range_max) {
- const auto& versionInfo = halVersion();
- LOG(ERROR) << "Keymaster reported error: " << static_cast<int32_t>(ec) << "\n"
- << "NOTE: This is an error in the vendor specific error range.\n"
- << " Refer to the vendor of the implementation for details.\n"
- << " Implementation name: " << versionInfo.keymasterName << "\n"
- << " Vendor name: " << versionInfo.authorName << "\n"
- << " MajorVersion: " << versionInfo.majorVersion;
- }
-}
-
-Keymaster::KeymasterSet Keymaster::enumerateAvailableDevices() {
- auto serviceManager = IServiceManager::getService();
- CHECK(serviceManager) << "Could not retrieve ServiceManager";
-
- auto km4s = enumerateDevices<Keymaster4>(serviceManager);
- auto km3s = enumerateDevices<Keymaster3>(serviceManager);
-
- auto result = std::move(km4s);
- result.insert(result.end(), std::make_move_iterator(km3s.begin()),
- std::make_move_iterator(km3s.end()));
-
- std::sort(result.begin(), result.end(),
- [](auto& a, auto& b) { return a->halVersion() > b->halVersion(); });
-
- size_t i = 1;
- LOG(INFO) << "List of Keymaster HALs found:";
- for (auto& hal : result) LOG(INFO) << "Keymaster HAL #" << i++ << ": " << *hal;
-
- return result;
-}
-
-static hidl_vec<HmacSharingParameters> getHmacParameters(
- const Keymaster::KeymasterSet& keymasters) {
- std::vector<HmacSharingParameters> params_vec;
- params_vec.reserve(keymasters.size());
- for (auto& keymaster : keymasters) {
- if (keymaster->halVersion().majorVersion < 4) continue;
- auto rc = keymaster->getHmacSharingParameters([&](auto error, auto& params) {
- CHECK(error == ErrorCode::OK)
- << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
- params_vec.push_back(params);
- });
- CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
- << " error: " << rc.description();
- }
- std::sort(params_vec.begin(), params_vec.end());
-
- return params_vec;
-}
-
-static void computeHmac(const Keymaster::KeymasterSet& keymasters,
- const hidl_vec<HmacSharingParameters>& params) {
- if (!params.size()) return;
-
- hidl_vec<uint8_t> sharingCheck;
- bool firstKeymaster = true;
- LOG(DEBUG) << "Computing HMAC with params " << params;
- for (auto& keymaster : keymasters) {
- if (keymaster->halVersion().majorVersion < 4) continue;
- LOG(DEBUG) << "Computing HMAC for " << *keymaster;
- auto rc = keymaster->computeSharedHmac(
- params, [&](ErrorCode error, const hidl_vec<uint8_t>& curSharingCheck) {
- CHECK(error == ErrorCode::OK)
- << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
- if (firstKeymaster) {
- sharingCheck = curSharingCheck;
- firstKeymaster = false;
- }
- if (curSharingCheck != sharingCheck)
- LOG(WARNING) << "HMAC computation failed for " << *keymaster //
- << " Expected: " << sharingCheck //
- << " got: " << curSharingCheck;
- });
- CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
- << " error: " << rc.description();
- }
-}
-
-void Keymaster::performHmacKeyAgreement(const KeymasterSet& keymasters) {
- computeHmac(keymasters, getHmacParameters(keymasters));
-}
-
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
diff --git a/keymaster/4.0/support/Keymaster3.cpp b/keymaster/4.0/support/Keymaster3.cpp
deleted file mode 100644
index b2cdbd9..0000000
--- a/keymaster/4.0/support/Keymaster3.cpp
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- **
- ** Copyright 2017, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include <keymasterV4_0/Keymaster3.h>
-
-#include <android-base/logging.h>
-#include <keymasterV4_0/keymaster_utils.h>
-
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
-
-using android::hardware::details::StatusOf;
-
-namespace {
-
-ErrorCode convert(V3_0::ErrorCode error) {
- return static_cast<ErrorCode>(error);
-}
-
-V3_0::KeyPurpose convert(KeyPurpose purpose) {
- return static_cast<V3_0::KeyPurpose>(purpose);
-}
-
-V3_0::KeyFormat convert(KeyFormat purpose) {
- return static_cast<V3_0::KeyFormat>(purpose);
-}
-
-V3_0::KeyParameter convert(const KeyParameter& param) {
- V3_0::KeyParameter converted;
- converted.tag = static_cast<V3_0::Tag>(param.tag);
- static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match");
- memcpy(&converted.f, ¶m.f, sizeof(param.f));
- converted.blob = param.blob;
- return converted;
-}
-
-KeyParameter convert(const V3_0::KeyParameter& param) {
- KeyParameter converted;
- converted.tag = static_cast<Tag>(param.tag);
- static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match");
- memcpy(&converted.f, ¶m.f, sizeof(param.f));
- converted.blob = param.blob;
- return converted;
-}
-
-hidl_vec<V3_0::KeyParameter> convert(const hidl_vec<KeyParameter>& params) {
- hidl_vec<V3_0::KeyParameter> converted(params.size());
- for (size_t i = 0; i < params.size(); ++i) {
- converted[i] = convert(params[i]);
- }
- return converted;
-}
-
-hidl_vec<KeyParameter> convert(const hidl_vec<V3_0::KeyParameter>& params) {
- hidl_vec<KeyParameter> converted(params.size());
- for (size_t i = 0; i < params.size(); ++i) {
- converted[i] = convert(params[i]);
- }
- return converted;
-}
-
-template <typename T, typename OutIter>
-inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
- const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value);
- return std::copy(value_ptr, value_ptr + sizeof(value), dest);
-}
-
-hidl_vec<V3_0::KeyParameter> convertAndAddAuthToken(const hidl_vec<KeyParameter>& params,
- const HardwareAuthToken& authToken) {
- hidl_vec<V3_0::KeyParameter> converted(params.size() + 1);
- for (size_t i = 0; i < params.size(); ++i) {
- converted[i] = convert(params[i]);
- }
- converted[params.size()].tag = V3_0::Tag::AUTH_TOKEN;
- converted[params.size()].blob = authToken2HidlVec(authToken);
-
- return converted;
-}
-
-KeyCharacteristics convert(const V3_0::KeyCharacteristics& chars) {
- KeyCharacteristics converted;
- converted.hardwareEnforced = convert(chars.teeEnforced);
- converted.softwareEnforced = convert(chars.softwareEnforced);
- return converted;
-}
-
-} // namespace
-
-void Keymaster3::getVersionIfNeeded() {
- if (haveVersion_) return;
-
- auto rc = km3_dev_->getHardwareFeatures(
- [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
- bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
- const hidl_string& keymasterAuthorName) {
- version_ = {keymasterName, keymasterAuthorName, 0 /* major version, filled below */,
- isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
- supportsEllipticCurve};
- supportsSymmetricCryptography_ = supportsSymmetricCryptography;
- supportsAttestation_ = supportsAttestation;
- supportsAllDigests_ = supportsAllDigests;
- });
-
- CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware features";
-
- if (version_.securityLevel == SecurityLevel::SOFTWARE) {
- version_.majorVersion = 3;
- } else if (supportsAttestation_) {
- version_.majorVersion = 3; // Could be 2, doesn't matter.
- } else if (supportsSymmetricCryptography_) {
- version_.majorVersion = 1;
- } else {
- version_.majorVersion = 0;
- }
-}
-
-Return<void> Keymaster3::getHardwareInfo(Keymaster3::getHardwareInfo_cb _hidl_cb) {
- getVersionIfNeeded();
- _hidl_cb(version_.securityLevel,
- std::string(version_.keymasterName) + " (wrapped by keystore::Keymaster3)",
- version_.authorName);
- return Void();
-}
-
-Return<ErrorCode> Keymaster3::addRngEntropy(const hidl_vec<uint8_t>& data) {
- auto rc = km3_dev_->addRngEntropy(data);
- if (!rc.isOk()) {
- return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
- }
- return convert(rc);
-}
-
-Return<void> Keymaster3::generateKey(const hidl_vec<KeyParameter>& keyParams,
- generateKey_cb _hidl_cb) {
- auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
- const V3_0::KeyCharacteristics& characteristics) {
- _hidl_cb(convert(error), keyBlob, convert(characteristics));
- };
- auto rc = km3_dev_->generateKey(convert(keyParams), cb);
- rc.isOk(); // move ctor prereq
- return rc;
-}
-
-Return<void> Keymaster3::getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
- const hidl_vec<uint8_t>& clientId,
- const hidl_vec<uint8_t>& appData,
- getKeyCharacteristics_cb _hidl_cb) {
- auto cb = [&](V3_0::ErrorCode error, const V3_0::KeyCharacteristics& chars) {
- _hidl_cb(convert(error), convert(chars));
- };
-
- auto rc = km3_dev_->getKeyCharacteristics(keyBlob, clientId, appData, cb);
- rc.isOk(); // move ctor prereq
- return rc;
-}
-
-Return<void> Keymaster3::importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
- const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) {
- auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
- const V3_0::KeyCharacteristics& chars) {
- _hidl_cb(convert(error), keyBlob, convert(chars));
- };
- auto rc = km3_dev_->importKey(convert(params), convert(keyFormat), keyData, cb);
- rc.isOk(); // move ctor prereq
- return rc;
-}
-
-Return<void> Keymaster3::exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
- const hidl_vec<uint8_t>& clientId,
- const hidl_vec<uint8_t>& appData, exportKey_cb _hidl_cb) {
- auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyMaterial) {
- _hidl_cb(convert(error), keyMaterial);
- };
- auto rc = km3_dev_->exportKey(convert(exportFormat), keyBlob, clientId, appData, cb);
- rc.isOk(); // move ctor prereq
- return rc;
-}
-
-Return<void> Keymaster3::attestKey(const hidl_vec<uint8_t>& keyToAttest,
- const hidl_vec<KeyParameter>& attestParams,
- attestKey_cb _hidl_cb) {
- auto cb = [&](V3_0::ErrorCode error, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
- _hidl_cb(convert(error), certChain);
- };
- auto rc = km3_dev_->attestKey(keyToAttest, convert(attestParams), cb);
- rc.isOk(); // move ctor prereq
- return rc;
-}
-
-Return<void> Keymaster3::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
- const hidl_vec<KeyParameter>& upgradeParams,
- upgradeKey_cb _hidl_cb) {
- auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& upgradedKeyBlob) {
- _hidl_cb(convert(error), upgradedKeyBlob);
- };
- auto rc = km3_dev_->upgradeKey(keyBlobToUpgrade, convert(upgradeParams), cb);
- rc.isOk(); // move ctor prereq
- return rc;
-}
-
-Return<ErrorCode> Keymaster3::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
- auto rc = km3_dev_->deleteKey(keyBlob);
- if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
- return convert(rc);
-}
-
-Return<ErrorCode> Keymaster3::deleteAllKeys() {
- auto rc = km3_dev_->deleteAllKeys();
- if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
- return convert(rc);
-}
-
-Return<ErrorCode> Keymaster3::destroyAttestationIds() {
- auto rc = km3_dev_->destroyAttestationIds();
- if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
- return convert(rc);
-}
-
-Return<void> Keymaster3::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
- const hidl_vec<KeyParameter>& inParams,
- const HardwareAuthToken& authToken, begin_cb _hidl_cb) {
- auto cb = [&](V3_0::ErrorCode error, const hidl_vec<V3_0::KeyParameter>& outParams,
- OperationHandle operationHandle) {
- _hidl_cb(convert(error), convert(outParams), operationHandle);
- };
-
- auto rc =
- km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb);
- rc.isOk(); // move ctor prereq
- return rc;
-}
-
-Return<void> Keymaster3::update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
- const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
- const VerificationToken& /* verificationToken */,
- update_cb _hidl_cb) {
- auto cb = [&](V3_0::ErrorCode error, uint32_t inputConsumed,
- const hidl_vec<V3_0::KeyParameter>& outParams, const hidl_vec<uint8_t>& output) {
- _hidl_cb(convert(error), inputConsumed, convert(outParams), output);
- };
-
- auto rc =
- km3_dev_->update(operationHandle, convertAndAddAuthToken(inParams, authToken), input, cb);
- rc.isOk(); // move ctor prereq
- return rc;
-}
-
-Return<void> Keymaster3::finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
- const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
- const HardwareAuthToken& authToken,
- const VerificationToken& /* verificationToken */,
- finish_cb _hidl_cb) {
- auto cb = [&](V3_0::ErrorCode error, const hidl_vec<V3_0::KeyParameter>& outParams,
- const hidl_vec<uint8_t>& output) {
- _hidl_cb(convert(error), convert(outParams), output);
- };
-
- auto rc = km3_dev_->finish(operationHandle, convertAndAddAuthToken(inParams, authToken), input,
- signature, cb);
- rc.isOk(); // move ctor prereq
- return rc;
-}
-
-Return<ErrorCode> Keymaster3::abort(uint64_t operationHandle) {
- auto rc = km3_dev_->abort(operationHandle);
- if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
- return convert(rc);
-}
-
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
diff --git a/keymaster/4.0/support/Keymaster4.cpp b/keymaster/4.0/support/Keymaster4.cpp
deleted file mode 100644
index cc3d656..0000000
--- a/keymaster/4.0/support/Keymaster4.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <keymasterV4_0/Keymaster4.h>
-
-#include <android-base/logging.h>
-
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
-
-void Keymaster4::getVersionIfNeeded() {
- if (haveVersion_) return;
-
- auto rc =
- dev_->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& keymasterName,
- const hidl_string& authorName) {
- version_ = {keymasterName, authorName, 4 /* major version */, securityLevel,
- true /* supportsEc */};
- haveVersion_ = true;
- });
-
- CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
-}
-
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
diff --git a/keymaster/4.0/support/attestation_record.cpp b/keymaster/4.0/support/attestation_record.cpp
index 000d46e..27e00c1 100644
--- a/keymaster/4.0/support/attestation_record.cpp
+++ b/keymaster/4.0/support/attestation_record.cpp
@@ -321,19 +321,20 @@
LOG(ERROR) << AT << "Failed record parsing";
return ErrorCode::UNKNOWN_ERROR;
}
- if (!record->tee_enforced) {
- LOG(ERROR) << AT << "Failed hardware characteristic parsing";
+
+ KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+ if (record->tee_enforced && record->tee_enforced->root_of_trust) {
+ root_of_trust = record->tee_enforced->root_of_trust;
+ } else if (record->software_enforced && record->software_enforced->root_of_trust) {
+ root_of_trust = record->software_enforced->root_of_trust;
+ } else {
+ LOG(ERROR) << AT << " Failed root of trust parsing";
return ErrorCode::INVALID_ARGUMENT;
}
- if (!record->tee_enforced->root_of_trust) {
- LOG(ERROR) << AT << "Failed root of trust parsing";
+ if (!root_of_trust->verified_boot_key) {
+ LOG(ERROR) << AT << " Failed verified boot key parsing";
return ErrorCode::INVALID_ARGUMENT;
}
- if (!record->tee_enforced->root_of_trust->verified_boot_key) {
- LOG(ERROR) << AT << "Failed verified boot key parsing";
- return ErrorCode::INVALID_ARGUMENT;
- }
- KM_ROOT_OF_TRUST* root_of_trust = record->tee_enforced->root_of_trust;
auto& vb_key = root_of_trust->verified_boot_key;
verified_boot_key->resize(vb_key->length);
@@ -342,19 +343,19 @@
*verified_boot_state = static_cast<keymaster_verified_boot_t>(
ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
if (!verified_boot_state) {
- LOG(ERROR) << AT << "Failed verified boot state parsing";
+ LOG(ERROR) << AT << " Failed verified boot state parsing";
return ErrorCode::INVALID_ARGUMENT;
}
*device_locked = root_of_trust->device_locked;
if (!device_locked) {
- LOG(ERROR) << AT << "Failed device locked parsing";
+ LOG(ERROR) << AT << " Failed device locked parsing";
return ErrorCode::INVALID_ARGUMENT;
}
auto& vb_hash = root_of_trust->verified_boot_hash;
if (!vb_hash) {
- LOG(ERROR) << AT << "Failed verified boot hash parsing";
+ LOG(ERROR) << AT << " Failed verified boot hash parsing";
return ErrorCode::INVALID_ARGUMENT;
}
verified_boot_hash->resize(vb_hash->length);
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
index d6b50f5..a024ff9 100644
--- a/keymaster/4.0/support/authorization_set.cpp
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -25,7 +25,7 @@
namespace keymaster {
namespace V4_0 {
-inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
+bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
if (a.tag != b.tag) return a.tag < b.tag;
int retval;
switch (typeFromTag(a.tag)) {
@@ -58,7 +58,7 @@
return false;
}
-inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
+bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
if (a.tag != b.tag) return false;
switch (typeFromTag(a.tag)) {
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
deleted file mode 100644
index 43a34b0..0000000
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- **
- ** Copyright 2017, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
-#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
-
-#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
-
-#include <memory>
-#include <vector>
-
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
-
-/**
- * Keymaster abstracts the underlying V4_0::IKeymasterDevice. There is one implementation
- * (Keymaster4) which is a trivial passthrough and one that wraps a V3_0::IKeymasterDevice.
- *
- * The reason for adding this additional layer, rather than simply using the latest HAL directly and
- * subclassing it to wrap any older HAL, is because this provides a place to put additional methods
- * which clients can use when they need to distinguish between different underlying HAL versions,
- * while still having to use only the latest interface.
- */
-class Keymaster : public IKeymasterDevice {
- public:
- using KeymasterSet = std::vector<std::unique_ptr<Keymaster>>;
-
- Keymaster(const hidl_string& descriptor, const hidl_string& instanceName)
- : descriptor_(descriptor), instanceName_(instanceName) {}
- virtual ~Keymaster() {}
-
- struct VersionResult {
- hidl_string keymasterName;
- hidl_string authorName;
- uint8_t majorVersion;
- SecurityLevel securityLevel;
- bool supportsEc;
-
- bool operator>(const VersionResult& other) const {
- auto lhs = std::tie(securityLevel, majorVersion, supportsEc);
- auto rhs = std::tie(other.securityLevel, other.majorVersion, other.supportsEc);
- return lhs > rhs;
- }
- };
-
- virtual const VersionResult& halVersion() const = 0;
- const hidl_string& descriptor() const { return descriptor_; }
- const hidl_string& instanceName() const { return instanceName_; }
-
- /**
- * If ec is in the vendor error code range (<-10000), logs the fact to logcat.
- * There are no side effects otherwise.
- */
- void logIfKeymasterVendorError(ErrorCode ec) const;
-
- /**
- * Returns all available Keymaster3 and Keymaster4 instances, in order of most secure to least
- * secure (as defined by VersionResult::operator<).
- */
- static KeymasterSet enumerateAvailableDevices();
-
- /**
- * Ask provided Keymaster instances to compute a shared HMAC key using
- * getHmacSharingParameters() and computeSharedHmac(). This computation is idempotent as long
- * as the same set of Keymaster instances is used each time (and if all of the instances work
- * correctly). It must be performed once per boot, but should do no harm to be repeated.
- *
- * If key agreement fails, this method will crash the process (with CHECK).
- */
- static void performHmacKeyAgreement(const KeymasterSet& keymasters);
-
- private:
- hidl_string descriptor_;
- hidl_string instanceName_;
-};
-
-std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster);
-
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
-
-#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
deleted file mode 100644
index c40be7c..0000000
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- **
- ** Copyright 2017, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
-#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
-
-#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
-
-#include "Keymaster.h"
-
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
-
-using IKeymaster3Device = ::android::hardware::keymaster::V3_0::IKeymasterDevice;
-
-using ::android::sp;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::details::return_status;
-
-class Keymaster3 : public Keymaster {
- public:
- using WrappedIKeymasterDevice = IKeymaster3Device;
- Keymaster3(sp<IKeymaster3Device> km3_dev, const hidl_string& instanceName)
- : Keymaster(IKeymaster3Device::descriptor, instanceName),
- km3_dev_(km3_dev),
- haveVersion_(false) {}
-
- const VersionResult& halVersion() const override {
- const_cast<Keymaster3*>(this)->getVersionIfNeeded();
- return version_;
- }
-
- Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb);
-
- Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
- _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
- return Void();
- }
-
- Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>&,
- computeSharedHmac_cb _hidl_cb) override {
- _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
- return Void();
- }
-
- Return<void> verifyAuthorization(uint64_t, const hidl_vec<KeyParameter>&,
- const HardwareAuthToken&,
- verifyAuthorization_cb _hidl_cb) override {
- _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
- return Void();
- }
-
- Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
- Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
- generateKey_cb _hidl_cb) override;
- Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
- const hidl_vec<uint8_t>& clientId,
- const hidl_vec<uint8_t>& appData,
- getKeyCharacteristics_cb _hidl_cb) override;
- Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
- const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override;
-
- Return<void> importWrappedKey(const hidl_vec<uint8_t>& /* wrappedKeyData */,
- const hidl_vec<uint8_t>& /* wrappingKeyBlob */,
- const hidl_vec<uint8_t>& /* maskingKey */,
- const hidl_vec<KeyParameter>& /* unwrappingParams */,
- uint64_t /* passwordSid */, uint64_t /* biometricSid */,
- importWrappedKey_cb _hidl_cb) {
- _hidl_cb(ErrorCode::UNIMPLEMENTED, {}, {});
- return Void();
- }
-
- Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
- const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
- exportKey_cb _hidl_cb) override;
- Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
- const hidl_vec<KeyParameter>& attestParams,
- attestKey_cb _hidl_cb) override;
- Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
- const hidl_vec<KeyParameter>& upgradeParams,
- upgradeKey_cb _hidl_cb) override;
- Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
- Return<ErrorCode> deleteAllKeys() override;
- Return<ErrorCode> destroyAttestationIds() override;
- Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
- const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
- begin_cb _hidl_cb) override;
- Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
- const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
- const VerificationToken& verificationToken, update_cb _hidl_cb) override;
- Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
- const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
- const HardwareAuthToken& authToken,
- const VerificationToken& verificationToken, finish_cb _hidl_cb) override;
- Return<ErrorCode> abort(uint64_t operationHandle) override;
-
- private:
- void getVersionIfNeeded();
-
- sp<IKeymaster3Device> km3_dev_;
-
- bool haveVersion_;
- VersionResult version_;
- bool supportsSymmetricCryptography_;
- bool supportsAttestation_;
- bool supportsAllDigests_;
-};
-
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
-
-#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
deleted file mode 100644
index dfd03ef..0000000
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- **
- ** Copyright 2017, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
-#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
-
-#include "Keymaster.h"
-
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
-
-using android::sp;
-using IKeymaster4Device = ::android::hardware::keymaster::V4_0::IKeymasterDevice;
-
-class Keymaster4 : public Keymaster {
- public:
- using WrappedIKeymasterDevice = IKeymaster4Device;
- Keymaster4(sp<IKeymasterDevice> km4_dev, const hidl_string& instanceName)
- : Keymaster(IKeymaster4Device::descriptor, instanceName),
- haveVersion_(false),
- dev_(km4_dev) {}
-
- const VersionResult& halVersion() const override {
- const_cast<Keymaster4*>(this)->getVersionIfNeeded();
- return version_;
- }
-
- Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
- return dev_->getHardwareInfo(_hidl_cb);
- }
-
- Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
- return dev_->getHmacSharingParameters(_hidl_cb);
- }
-
- Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>& params,
- computeSharedHmac_cb _hidl_cb) override {
- return dev_->computeSharedHmac(params, _hidl_cb);
- }
-
- Return<void> verifyAuthorization(uint64_t operationHandle, const hidl_vec<KeyParameter>& params,
- const HardwareAuthToken& authToken,
- verifyAuthorization_cb _hidl_cb) override {
- return dev_->verifyAuthorization(operationHandle, params, authToken, _hidl_cb);
- }
-
- Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override {
- return dev_->addRngEntropy(data);
- }
-
- Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
- generateKey_cb _hidl_cb) override {
- return dev_->generateKey(keyParams, _hidl_cb);
- }
-
- Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
- const hidl_vec<uint8_t>& clientId,
- const hidl_vec<uint8_t>& appData,
- getKeyCharacteristics_cb _hidl_cb) override {
- return dev_->getKeyCharacteristics(keyBlob, clientId, appData, _hidl_cb);
- }
-
- Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
- const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override {
- return dev_->importKey(params, keyFormat, keyData, _hidl_cb);
- }
-
- Return<void> importWrappedKey(const hidl_vec<uint8_t>& wrappedKeyData,
- const hidl_vec<uint8_t>& wrappingKeyBlob,
- const hidl_vec<uint8_t>& maskingKey,
- const hidl_vec<KeyParameter>& unwrappingParams,
- uint64_t passwordSid, uint64_t biometricSid,
- importWrappedKey_cb _hidl_cb) {
- return dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey, unwrappingParams,
- passwordSid, biometricSid, _hidl_cb);
- }
-
- Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
- const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
- exportKey_cb _hidl_cb) override {
- return dev_->exportKey(exportFormat, keyBlob, clientId, appData, _hidl_cb);
- }
-
- Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
- const hidl_vec<KeyParameter>& attestParams,
- attestKey_cb _hidl_cb) override {
- return dev_->attestKey(keyToAttest, attestParams, _hidl_cb);
- }
-
- Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
- const hidl_vec<KeyParameter>& upgradeParams,
- upgradeKey_cb _hidl_cb) override {
- return dev_->upgradeKey(keyBlobToUpgrade, upgradeParams, _hidl_cb);
- }
-
- Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override {
- return dev_->deleteKey(keyBlob);
- }
-
- Return<ErrorCode> deleteAllKeys() override { return dev_->deleteAllKeys(); }
-
- Return<ErrorCode> destroyAttestationIds() override { return dev_->destroyAttestationIds(); }
-
- Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
- const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
- begin_cb _hidl_cb) override {
- return dev_->begin(purpose, key, inParams, authToken, _hidl_cb);
- }
-
- Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
- const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
- const VerificationToken& verificationToken, update_cb _hidl_cb) override {
- return dev_->update(operationHandle, inParams, input, authToken, verificationToken,
- _hidl_cb);
- }
-
- Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
- const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
- const HardwareAuthToken& authToken,
- const VerificationToken& verificationToken, finish_cb _hidl_cb) override {
- return dev_->finish(operationHandle, inParams, input, signature, authToken,
- verificationToken, _hidl_cb);
- }
-
- Return<ErrorCode> abort(uint64_t operationHandle) override {
- return dev_->abort(operationHandle);
- }
-
- private:
- void getVersionIfNeeded();
-
- bool haveVersion_;
- VersionResult version_;
- sp<IKeymaster4Device> dev_;
-};
-
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
-
-#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index cb29c64..bc7f311 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -355,95 +355,61 @@
return accessTagValue(ttag, param);
}
+inline bool operator<(const KeyParameter& a, const KeyParameter& b) {
+ if (a.tag != b.tag) return a.tag < b.tag;
+ int retval;
+ switch (typeFromTag(a.tag)) {
+ case TagType::INVALID:
+ case TagType::BOOL:
+ return false;
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
+ return a.f.integer < b.f.integer;
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
+ return a.f.longInteger < b.f.longInteger;
+ case TagType::DATE:
+ return a.f.dateTime < b.f.dateTime;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ // Handle the empty cases.
+ if (a.blob.size() == 0) return b.blob.size() != 0;
+ if (b.blob.size() == 0) return false;
+
+ retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
+ // if one is the prefix of the other the longer wins
+ if (retval == 0) return a.blob.size() < b.blob.size();
+ // Otherwise a is less if a is less.
+ else
+ return retval < 0;
+ }
+ return false;
+}
+
inline bool operator==(const KeyParameter& a, const KeyParameter& b) {
- if (a.tag != b.tag) {
- return false;
- }
+ if (a.tag != b.tag) return false;
- switch (a.tag) {
- /* Boolean tags */
- case Tag::INVALID:
- case Tag::CALLER_NONCE:
- case Tag::INCLUDE_UNIQUE_ID:
- case Tag::BOOTLOADER_ONLY:
- case Tag::NO_AUTH_REQUIRED:
- case Tag::ALLOW_WHILE_ON_BODY:
- case Tag::UNLOCKED_DEVICE_REQUIRED:
- case Tag::ROLLBACK_RESISTANCE:
- case Tag::RESET_SINCE_ID_ROTATION:
- case Tag::TRUSTED_CONFIRMATION_REQUIRED:
- case Tag::TRUSTED_USER_PRESENCE_REQUIRED:
+ switch (typeFromTag(a.tag)) {
+ case TagType::INVALID:
+ case TagType::BOOL:
return true;
-
- /* Integer tags */
- case Tag::KEY_SIZE:
- case Tag::MIN_MAC_LENGTH:
- case Tag::MIN_SECONDS_BETWEEN_OPS:
- case Tag::MAX_USES_PER_BOOT:
- case Tag::OS_VERSION:
- case Tag::OS_PATCHLEVEL:
- case Tag::MAC_LENGTH:
- case Tag::USER_ID:
- case Tag::AUTH_TIMEOUT:
- case Tag::VENDOR_PATCHLEVEL:
- case Tag::BOOT_PATCHLEVEL:
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
return a.f.integer == b.f.integer;
-
- /* Long integer tags */
- case Tag::RSA_PUBLIC_EXPONENT:
- case Tag::USER_SECURE_ID:
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
return a.f.longInteger == b.f.longInteger;
-
- /* Date-time tags */
- case Tag::ACTIVE_DATETIME:
- case Tag::ORIGINATION_EXPIRE_DATETIME:
- case Tag::USAGE_EXPIRE_DATETIME:
- case Tag::CREATION_DATETIME:
+ case TagType::DATE:
return a.f.dateTime == b.f.dateTime;
-
- /* Bytes tags */
- case Tag::APPLICATION_ID:
- case Tag::APPLICATION_DATA:
- case Tag::ROOT_OF_TRUST:
- case Tag::UNIQUE_ID:
- case Tag::ATTESTATION_CHALLENGE:
- case Tag::ATTESTATION_APPLICATION_ID:
- case Tag::ATTESTATION_ID_BRAND:
- case Tag::ATTESTATION_ID_DEVICE:
- case Tag::ATTESTATION_ID_PRODUCT:
- case Tag::ATTESTATION_ID_SERIAL:
- case Tag::ATTESTATION_ID_IMEI:
- case Tag::ATTESTATION_ID_MEID:
- case Tag::ATTESTATION_ID_MANUFACTURER:
- case Tag::ATTESTATION_ID_MODEL:
- case Tag::ASSOCIATED_DATA:
- case Tag::CONFIRMATION_TOKEN:
- case Tag::NONCE:
- return a.blob == b.blob;
-
- /* Enum tags */
- case Tag::PURPOSE:
- return a.f.purpose == b.f.purpose;
- case Tag::ALGORITHM:
- return a.f.algorithm == b.f.algorithm;
- case Tag::BLOCK_MODE:
- return a.f.blockMode == b.f.blockMode;
- case Tag::DIGEST:
- return a.f.digest == b.f.digest;
- case Tag::PADDING:
- return a.f.paddingMode == b.f.paddingMode;
- case Tag::EC_CURVE:
- return a.f.ecCurve == b.f.ecCurve;
- case Tag::BLOB_USAGE_REQUIREMENTS:
- return a.f.keyBlobUsageRequirements == b.f.keyBlobUsageRequirements;
- case Tag::USER_AUTH_TYPE:
- return a.f.integer == b.f.integer;
- case Tag::ORIGIN:
- return a.f.origin == b.f.origin;
- case Tag::HARDWARE_TYPE:
- return a.f.hardwareType == b.f.hardwareType;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ if (a.blob.size() != b.blob.size()) return false;
+ return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
}
-
return false;
}
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
index 5e5ae8d..61645f8 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
@@ -52,6 +52,9 @@
HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer);
hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token);
+uint32_t getOsVersion();
+uint32_t getOsPatchlevel();
+
} // namespace support
} // namespace V4_0
} // namespace keymaster
diff --git a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
index cc71dd1..b3869f4 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
@@ -18,6 +18,8 @@
#define HARDWARE_INTERFACES_KEYMASTER_4_0_SUPPORT_OPENSSL_UTILS_H_
#include <android/hardware/keymaster/4.0/types.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
template <typename T, void (*F)(T*)>
struct UniquePtrDeleter {
diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp
index e35fdd3..850a776 100644
--- a/keymaster/4.0/support/keymaster_utils.cpp
+++ b/keymaster/4.0/support/keymaster_utils.cpp
@@ -14,11 +14,13 @@
* limitations under the License.
*/
+#include <regex.h>
+
+#include <android-base/properties.h>
#include <hardware/hw_auth_token.h>
#include <keymasterV4_0/keymaster_utils.h>
-namespace android {
-namespace hardware {
+namespace android::hardware {
inline static bool operator<(const hidl_vec<uint8_t>& a, const hidl_vec<uint8_t>& b) {
auto result = memcmp(a.data(), b.data(), std::min(a.size(), b.size()));
@@ -32,8 +34,7 @@
return memcmp(a.data(), b.data(), SIZE) == -1;
}
-namespace keymaster {
-namespace V4_0 {
+namespace keymaster::V4_0 {
bool operator<(const HmacSharingParameters& a, const HmacSharingParameters& b) {
return std::tie(a.seed, a.nonce) < std::tie(b.seed, b.nonce);
@@ -58,9 +59,9 @@
hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token) {
static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
- sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
- sizeof(token.timestamp) + kHmacSize ==
- sizeof(hw_auth_token_t),
+ sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+ sizeof(token.timestamp) + kHmacSize ==
+ sizeof(hw_auth_token_t),
"HardwareAuthToken content size does not match hw_auth_token_t size");
hidl_vec<uint8_t> result;
@@ -86,9 +87,9 @@
HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer) {
HardwareAuthToken token;
static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
- sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
- sizeof(token.timestamp) + kHmacSize ==
- sizeof(hw_auth_token_t),
+ sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+ sizeof(token.timestamp) + kHmacSize ==
+ sizeof(hw_auth_token_t),
"HardwareAuthToken content size does not match hw_auth_token_t size");
if (buffer.size() != sizeof(hw_auth_token_t)) return {};
@@ -100,7 +101,7 @@
pos = copy_bytes_from_iterator(&token.authenticatorId, pos);
pos = copy_bytes_from_iterator(&token.authenticatorType, pos);
token.authenticatorType = static_cast<HardwareAuthenticatorType>(
- ntohl(static_cast<uint32_t>(token.authenticatorType)));
+ ntohl(static_cast<uint32_t>(token.authenticatorType)));
pos = copy_bytes_from_iterator(&token.timestamp, pos);
token.timestamp = ntohq(token.timestamp);
token.mac.resize(kHmacSize);
@@ -109,8 +110,93 @@
return token;
}
+namespace {
+
+constexpr char kPlatformVersionProp[] = "ro.build.version.release";
+constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?";
+constexpr size_t kMajorVersionMatch = 1;
+constexpr size_t kMinorVersionMatch = 3;
+constexpr size_t kSubminorVersionMatch = 5;
+constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1;
+
+constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch";
+constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$";
+constexpr size_t kYearMatch = 1;
+constexpr size_t kMonthMatch = 2;
+constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1;
+
+uint32_t match_to_uint32(const char* expression, const regmatch_t& match) {
+ if (match.rm_so == -1) return 0;
+
+ size_t len = match.rm_eo - match.rm_so;
+ std::string s(expression + match.rm_so, len);
+ return std::stoul(s);
+}
+
+std::string wait_and_get_property(const char* prop) {
+ std::string prop_value;
+ while (!android::base::WaitForPropertyCreation(prop))
+ ;
+ prop_value = android::base::GetProperty(prop, "" /* default */);
+ return prop_value;
+}
+
+} // anonymous namespace
+
+uint32_t getOsVersion(const char* version_str) {
+ regex_t regex;
+ if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) {
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformVersionMatchCount];
+ int not_match =
+ regexec(®ex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */);
+ regfree(®ex);
+ if (not_match) {
+ return 0;
+ }
+
+ uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]);
+ uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]);
+ uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]);
+
+ return (major * 100 + minor) * 100 + subminor;
+}
+
+uint32_t getOsVersion() {
+ std::string version = wait_and_get_property(kPlatformVersionProp);
+ return getOsVersion(version.c_str());
+}
+
+uint32_t getOsPatchlevel(const char* patchlevel_str) {
+ regex_t regex;
+ if (regcomp(®ex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) {
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformPatchlevelMatchCount];
+ int not_match =
+ regexec(®ex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */);
+ regfree(®ex);
+ if (not_match) {
+ return 0;
+ }
+
+ uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]);
+ uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]);
+
+ if (month < 1 || month > 12) {
+ return 0;
+ }
+ return year * 100 + month;
+}
+
+uint32_t getOsPatchlevel() {
+ std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp);
+ return getOsPatchlevel(patchlevel.c_str());
+}
+
} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
+} // namespace keymaster::V4_0
+} // namespace android::hardware
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index 5649f20..db50080 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -19,7 +19,6 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"HmacKeySharingTest.cpp",
- "KeymasterHidlTest.cpp",
"VerificationTokenTest.cpp",
"keymaster_hidl_hal_test.cpp",
],
@@ -27,7 +26,25 @@
"android.hardware.keymaster@4.0",
"libcrypto_static",
"libkeymaster4support",
- "libsoftkeymasterdevice",
+ "libkeymaster4vtstest",
],
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
+
+cc_test_library {
+ name: "libkeymaster4vtstest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "KeymasterHidlTest.cpp",
+ ],
+ export_include_dirs: [
+ ".",
+ ],
+ static_libs: [
+ "android.hardware.keymaster@4.0",
+ "libkeymaster4support",
+ ],
}
diff --git a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
index c228ef7..f57a668 100644
--- a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
+++ b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
@@ -28,6 +28,16 @@
*/
class HmacKeySharingTest : public KeymasterHidlTest {
protected:
+ const std::vector<sp<IKeymasterDevice>>& allKeymasters() {
+ if (all_keymasters_.empty()) {
+ auto names = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
+ for (const auto& name : names) {
+ all_keymasters_.push_back(IKeymasterDevice::getService(name));
+ }
+ }
+ return all_keymasters_;
+ }
+
struct GetParamsResult {
ErrorCode error;
HmacSharingParameters params;
@@ -99,8 +109,13 @@
EXPECT_EQ(expected, response.sharing_check) << "Sharing check values should match.";
}
}
+
+ private:
+ static std::vector<sp<IKeymasterDevice>> all_keymasters_;
};
+std::vector<sp<IKeymasterDevice>> HmacKeySharingTest::all_keymasters_;
+
TEST_P(HmacKeySharingTest, GetParameters) {
auto result1 = getHmacSharingParameters(keymaster());
EXPECT_EQ(ErrorCode::OK, result1.error);
@@ -115,26 +130,26 @@
}
TEST_P(HmacKeySharingTest, ComputeSharedHmac) {
- auto params = getHmacSharingParameters(all_keymasters());
- ASSERT_EQ(all_keymasters().size(), params.size())
- << "One or more keymasters failed to provide parameters.";
+ auto params = getHmacSharingParameters(allKeymasters());
+ ASSERT_EQ(allKeymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
auto nonces = copyNonces(params);
- EXPECT_EQ(all_keymasters().size(), nonces.size());
+ EXPECT_EQ(allKeymasters().size(), nonces.size());
std::sort(nonces.begin(), nonces.end());
std::unique(nonces.begin(), nonces.end());
- EXPECT_EQ(all_keymasters().size(), nonces.size());
+ EXPECT_EQ(allKeymasters().size(), nonces.size());
- auto responses = computeSharedHmac(all_keymasters(), params);
+ auto responses = computeSharedHmac(allKeymasters(), params);
ASSERT_GT(responses.size(), 0U);
verifyResponses(responses[0].sharing_check, responses);
// Do it a second time. Should get the same answers.
- params = getHmacSharingParameters(all_keymasters());
- ASSERT_EQ(all_keymasters().size(), params.size())
- << "One or more keymasters failed to provide parameters.";
+ params = getHmacSharingParameters(allKeymasters());
+ ASSERT_EQ(allKeymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
- responses = computeSharedHmac(all_keymasters(), params);
+ responses = computeSharedHmac(allKeymasters(), params);
ASSERT_GT(responses.size(), 0U);
ASSERT_EQ(32U, responses[0].sharing_check.size());
verifyResponses(responses[0].sharing_check, responses);
@@ -160,15 +175,16 @@
// 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
// (barring crashes :-/) re-run the unmodified agreement process on our way out.
- auto fixup_hmac = finally(
- [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
+ auto fixup_hmac = finally([&]() {
+ computeSharedHmac(allKeymasters(), getHmacSharingParameters(allKeymasters()));
+ });
- auto params = getHmacSharingParameters(all_keymasters());
- ASSERT_EQ(all_keymasters().size(), params.size())
- << "One or more keymasters failed to provide parameters.";
+ auto params = getHmacSharingParameters(allKeymasters());
+ ASSERT_EQ(allKeymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
// All should be well in the normal case
- auto responses = computeSharedHmac(all_keymasters(), params);
+ auto responses = computeSharedHmac(allKeymasters(), params);
ASSERT_GT(responses.size(), 0U);
HidlBuf correct_response = responses[0].sharing_check;
@@ -181,7 +197,7 @@
uint8_t bit_to_tweak = rand() % 8;
params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak);
- responses = computeSharedHmac(all_keymasters(), params);
+ responses = computeSharedHmac(allKeymasters(), params);
for (size_t i = 0; i < responses.size(); ++i) {
if (i == param_to_tweak) {
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
@@ -199,15 +215,16 @@
// 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
// (barring crashes :-/) re-run the unmodified agreement process on our way out.
- auto fixup_hmac = finally(
- [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
+ auto fixup_hmac = finally([&]() {
+ computeSharedHmac(allKeymasters(), getHmacSharingParameters(allKeymasters()));
+ });
- auto params = getHmacSharingParameters(all_keymasters());
- ASSERT_EQ(all_keymasters().size(), params.size())
- << "One or more keymasters failed to provide parameters.";
+ auto params = getHmacSharingParameters(allKeymasters());
+ ASSERT_EQ(allKeymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
// All should be well in the normal case
- auto responses = computeSharedHmac(all_keymasters(), params);
+ auto responses = computeSharedHmac(allKeymasters(), params);
ASSERT_GT(responses.size(), 0U);
HidlBuf correct_response = responses[0].sharing_check;
@@ -223,7 +240,7 @@
}
to_tweak[0]++;
- responses = computeSharedHmac(all_keymasters(), params);
+ responses = computeSharedHmac(allKeymasters(), params);
for (size_t i = 0; i < responses.size(); ++i) {
if (i == param_to_tweak) {
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
@@ -236,10 +253,7 @@
}
}
-INSTANTIATE_TEST_SUITE_P(
- PerInstance, HmacKeySharingTest,
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)),
- android::hardware::PrintInstanceNameToString);
+INSTANTIATE_KEYMASTER_HIDL_TEST(HmacKeySharingTest);
} // namespace test
} // namespace V4_0
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index 7241984..d0ad433 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -23,6 +23,7 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <keymasterV4_0/key_param_output.h>
+#include <keymasterV4_0/keymaster_utils.h>
namespace android {
namespace hardware {
@@ -41,39 +42,26 @@
namespace test {
-void KeymasterHidlTest::InitializeKeymaster() {
- service_name_ = GetParam();
- keymaster_ = IKeymasterDevice::getService(service_name_);
- ASSERT_NE(keymaster_, nullptr);
+using namespace std::literals::chrono_literals;
+void KeymasterHidlTest::InitializeKeymaster(sp<IKeymasterDevice> keymaster) {
+ ASSERT_NE(keymaster, nullptr);
+ keymaster_ = keymaster;
ASSERT_TRUE(keymaster_
- ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
- const hidl_string& author) {
- securityLevel_ = securityLevel;
- name_ = name;
- author_ = author;
- })
- .isOk());
+ ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
+ const hidl_string& author) {
+ securityLevel_ = securityLevel;
+ name_ = name;
+ author_ = author;
+ })
+ .isOk());
+
+ os_version_ = support::getOsVersion();
+ os_patch_level_ = support::getOsPatchlevel();
}
void KeymasterHidlTest::SetUp() {
- InitializeKeymaster();
-
- os_version_ = ::keymaster::GetOsVersion();
- os_patch_level_ = ::keymaster::GetOsPatchlevel();
-
- auto service_manager = android::hidl::manager::V1_0::IServiceManager::getService();
- ASSERT_NE(nullptr, service_manager.get());
- all_keymasters_.push_back(keymaster_);
- service_manager->listByInterface(
- IKeymasterDevice::descriptor, [&](const hidl_vec<hidl_string>& names) {
- for (auto& name : names) {
- if (name == service_name_) continue;
- auto keymaster = IKeymasterDevice::getService(name);
- ASSERT_NE(keymaster, nullptr);
- all_keymasters_.push_back(keymaster);
- }
- });
+ InitializeKeymaster(IKeymasterDevice::getService(GetParam()));
}
ErrorCode KeymasterHidlTest::GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
@@ -138,7 +126,7 @@
string masking_key,
const AuthorizationSet& unwrapping_params) {
ErrorCode error;
- ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key);
+ EXPECT_EQ(ErrorCode::OK, ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key));
EXPECT_TRUE(keymaster_
->importWrappedKey(HidlBuf(wrapped_key), key_blob_, HidlBuf(masking_key),
unwrapping_params.hidl_data(), 0 /* passwordSid */,
@@ -207,7 +195,9 @@
HidlBuf empty_buf = {};
EXPECT_EQ(ErrorCode::OK,
GetCharacteristics(key_blob, client_id, app_data, key_characteristics));
- EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0);
+ if (SecLevel() != SecurityLevel::SOFTWARE) {
+ EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0);
+ }
EXPECT_GT(key_characteristics->softwareEnforced.size(), 0);
EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
@@ -647,23 +637,25 @@
switch (algorithm) {
case Algorithm::RSA:
switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
case SecurityLevel::TRUSTED_ENVIRONMENT:
return {2048, 3072, 4096};
case SecurityLevel::STRONGBOX:
return {2048};
default:
- CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
+ ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
break;
}
break;
case Algorithm::EC:
switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
case SecurityLevel::TRUSTED_ENVIRONMENT:
return {224, 256, 384, 521};
case SecurityLevel::STRONGBOX:
return {256};
default:
- CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
+ ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
break;
}
break;
@@ -678,25 +670,27 @@
return retval;
}
default:
- CHECK(false) << "Invalid Algorithm: " << algorithm;
+ ADD_FAILURE() << "Invalid Algorithm: " << algorithm;
return {};
}
- CHECK(false) << "Should be impossible to get here";
+ ADD_FAILURE() << "Should be impossible to get here";
return {};
}
+
std::vector<uint32_t> KeymasterHidlTest::InvalidKeySizes(Algorithm algorithm) {
- if (SecLevel() == SecurityLevel::TRUSTED_ENVIRONMENT) return {};
- CHECK(SecLevel() == SecurityLevel::STRONGBOX);
- switch (algorithm) {
- case Algorithm::RSA:
- return {3072, 4096};
- case Algorithm::EC:
- return {224, 384, 521};
- case Algorithm::AES:
- return {192};
- default:
- return {};
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ switch (algorithm) {
+ case Algorithm::RSA:
+ return {3072, 4096};
+ case Algorithm::EC:
+ return {224, 384, 521};
+ case Algorithm::AES:
+ return {192};
+ default:
+ return {};
+ }
}
+ return {};
}
std::vector<EcCurve> KeymasterHidlTest::ValidCurves() {
@@ -715,6 +709,7 @@
std::vector<Digest> KeymasterHidlTest::ValidDigests(bool withNone, bool withMD5) {
switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
case SecurityLevel::TRUSTED_ENVIRONMENT:
if (withNone) {
if (withMD5)
@@ -740,10 +735,10 @@
return {Digest::SHA_2_256};
break;
default:
- CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
+ ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
break;
}
- CHECK(false) << "Should be impossible to get here";
+ ADD_FAILURE() << "Should be impossible to get here";
return {};
}
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index 4bd8b26..f495516 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -21,7 +21,6 @@
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
-#include <keymaster/keymaster_configuration.h>
#include <keymasterV4_0/authorization_set.h>
@@ -35,16 +34,18 @@
namespace test {
using ::android::sp;
-using ::std::string;
using hidl::base::V1_0::DebugInfo;
+using ::std::string;
class HidlBuf : public hidl_vec<uint8_t> {
- typedef hidl_vec<uint8_t> super;
+ using super = hidl_vec<uint8_t>;
- public:
+ public:
HidlBuf() {}
HidlBuf(const super& other) : super(other) {}
- HidlBuf(super&& other) : super(std::move(other)) {}
+ HidlBuf(super&& other) : super(std::move(other)) { other = {}; }
+ HidlBuf(const HidlBuf& other) : super(other) {}
+ HidlBuf(HidlBuf&& other) : super(std::move(other)) { other = HidlBuf(); }
explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }
HidlBuf& operator=(const super& other) {
@@ -54,6 +55,18 @@
HidlBuf& operator=(super&& other) {
super::operator=(std::move(other));
+ other = {};
+ return *this;
+ }
+
+ HidlBuf& operator=(const HidlBuf& other) {
+ super::operator=(other);
+ return *this;
+ }
+
+ HidlBuf& operator=(HidlBuf&& other) {
+ super::operator=(std::move(other));
+ other.super::operator=({});
return *this;
}
@@ -70,20 +83,16 @@
class KeymasterHidlTest : public ::testing::TestWithParam<std::string> {
public:
- void SetUp();
+ void SetUp() override;
void TearDown() override {
if (key_blob_.size()) {
CheckedDeleteKey();
}
AbortIfNeeded();
- keymaster_.clear();
- all_keymasters_.clear();
}
- void InitializeKeymaster();
-
+ void InitializeKeymaster(sp<IKeymasterDevice> keymaster);
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_; }
@@ -209,18 +218,26 @@
KeyCharacteristics key_characteristics_;
OperationHandle op_handle_ = kOpHandleSentinel;
- private:
- sp<IKeymasterDevice> keymaster_;
- std::vector<sp<IKeymasterDevice>> all_keymasters_;
- uint32_t os_version_;
- uint32_t os_patch_level_;
+ static std::vector<std::string> build_params() {
+ auto params = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
+ return params;
+ }
- SecurityLevel securityLevel_;
- hidl_string name_;
- hidl_string author_;
- string service_name_;
+ private:
+ sp<IKeymasterDevice> keymaster_;
+ uint32_t os_version_;
+ uint32_t os_patch_level_;
+
+ SecurityLevel securityLevel_;
+ hidl_string name_;
+ hidl_string author_;
};
+#define INSTANTIATE_KEYMASTER_HIDL_TEST(name) \
+ INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
+ testing::ValuesIn(KeymasterHidlTest::build_params()), \
+ android::hardware::PrintInstanceNameToString)
+
} // namespace test
} // namespace V4_0
} // namespace keymaster
diff --git a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
index 693f4ae..bab1439 100644
--- a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
+++ b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
@@ -185,10 +185,7 @@
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);
+INSTANTIATE_KEYMASTER_HIDL_TEST(VerificationTokenTest);
} // namespace test
} // namespace V4_0
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 66132ad..6cbe4da 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -352,11 +352,11 @@
EXPECT_EQ(ErrorCode::OK, error);
if (error != ErrorCode::OK) return false;
- EXPECT_TRUE(att_attestation_version == 3);
+ EXPECT_GE(att_attestation_version, 3U);
expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id));
- EXPECT_EQ(att_keymaster_version, 4U);
+ EXPECT_GE(att_keymaster_version, 4U);
EXPECT_EQ(security_level, att_keymaster_security_level);
EXPECT_EQ(security_level, att_attestation_security_level);
@@ -397,10 +397,16 @@
// true. A provided boolean tag that can be pulled back out of the certificate indicates correct
// encoding. No need to check if it's in both lists, since the AuthorizationSet compare below
// will handle mismatches of tags.
- EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ if (security_level == SecurityLevel::SOFTWARE) {
+ EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ } else {
+ EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ }
// Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
// the authorization list during key generation) isn't being attested to in the certificate.
+ EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+ EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
@@ -461,10 +467,10 @@
verified_boot_key.size()));
} else if (!strcmp(property_value, "red")) {
EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_FAILED);
- EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
} else {
- EXPECT_TRUE(false);
+ EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_UNVERIFIED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
}
att_sw_enforced.Sort();
@@ -840,6 +846,8 @@
.Authorization(TAG_MIN_MAC_LENGTH, 128)));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(NewKeyGenerationTest);
+
typedef KeymasterHidlTest SigningOperationsTest;
/*
@@ -1509,6 +1517,8 @@
}
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(SigningOperationsTest);
+
typedef KeymasterHidlTest VerificationOperationsTest;
/*
@@ -1749,6 +1759,8 @@
CheckedDeleteKey(&verification_key);
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(VerificationOperationsTest);
+
typedef KeymasterHidlTest ExportKeyTest;
/*
@@ -1828,6 +1840,8 @@
EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::RAW, &export_data));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ExportKeyTest);
+
class ImportKeyTest : public KeymasterHidlTest {
public:
template <TagType tag_type, Tag tag, typename ValueT>
@@ -2093,6 +2107,8 @@
VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ImportKeyTest);
+
auto wrapped_key = hex2str(
"3082017902010004820100934bf94e2aa28a3f83c9f79297250262fbe3276b5a1c91159bbfa3ef8957aac84b59b30b"
"455a79c2973480823d8b3863c3deef4a8e243590268d80e18751a0e130f67ce6a1ace9f79b95e097474febc981195b"
@@ -2214,6 +2230,8 @@
.Padding(PaddingMode::RSA_OAEP)));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ImportWrappedKeyTest);
+
typedef KeymasterHidlTest EncryptionOperationsTest;
/*
@@ -4111,6 +4129,8 @@
EXPECT_EQ(message, plaintext);
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(EncryptionOperationsTest);
+
typedef KeymasterHidlTest MaxOperationsTest;
/*
@@ -4166,6 +4186,8 @@
EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::SIGN, params));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(MaxOperationsTest);
+
typedef KeymasterHidlTest AddEntropyTest;
/*
@@ -4196,6 +4218,8 @@
EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(2 * 1024, 'a'))));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(AddEntropyTest);
+
typedef KeymasterHidlTest AttestationTest;
/*
@@ -4373,6 +4397,8 @@
&cert_chain));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(AttestationTest);
+
typedef KeymasterHidlTest KeyDeletionTest;
/**
@@ -4478,6 +4504,8 @@
}
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(KeyDeletionTest);
+
using UpgradeKeyTest = KeymasterHidlTest;
/*
@@ -4497,6 +4525,8 @@
EXPECT_EQ(result, std::make_pair(ErrorCode::OK, HidlBuf()));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(UpgradeKeyTest);
+
using ClearOperationsTest = KeymasterHidlTest;
/*
@@ -4533,51 +4563,14 @@
AbortIfNeeded();
}
-/*
- * ClearSlotsTest.ServiceDeath
- *
- * Verifies that the service is restarted after death and the ongoing
- * operations are cleared.
- */
-TEST_P(ClearOperationsTest, ServiceDeath) {
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .RsaEncryptionKey(2048, 65537)
- .Padding(PaddingMode::NONE)));
-
- auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
- int max_operations = SecLevel() == SecurityLevel::STRONGBOX ? 4 : 16;
- OperationHandle op_handles[max_operations];
- AuthorizationSet out_params;
- for(int i=0; i<max_operations; i++) {
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
- }
- EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
- Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
-
- DebugInfo debug_info;
- GetDebugInfo(&debug_info);
- kill(debug_info.pid, SIGKILL);
- // wait 1 second for keymaster to restart
- sleep(1);
- InitializeKeymaster();
-
- for(int i=0; i<max_operations; i++) {
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
- }
- EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
- Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
- for(int i=0; i<max_operations; i++) {
- EXPECT_EQ(ErrorCode::OK, Abort(op_handles[i]));
- }
-}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ClearOperationsTest);
typedef KeymasterHidlTest TransportLimitTest;
/*
- * TransportLimitTest.LargeFinishInput
+ * TransportLimitTest.FinishInput
*
- * Verifies that passing large input data to finish either succeeds or fails as expected.
+ * Verifies that passing input data to finish succeeds as expected.
*/
TEST_P(TransportLimitTest, LargeFinishInput) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -4586,7 +4579,7 @@
.BlockMode(BlockMode::ECB)
.Padding(PaddingMode::NONE)));
- for (int msg_size = 10 /*1KB*/; msg_size <= 17 /*128KB*/; msg_size++) {
+ for (int msg_size = 8 /* 256 bytes */; msg_size <= 11 /* 2 KiB */; msg_size++) {
auto cipher_params =
AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
@@ -4597,71 +4590,22 @@
string encrypted_message;
auto rc = Finish(plain_message, &encrypted_message);
- if (rc == ErrorCode::OK) {
- EXPECT_EQ(plain_message.size(), encrypted_message.size())
- << "Encrypt finish returned OK, but did not consume all of the given input";
- } else {
- EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
- << "Encrypt finish failed in an unexpected way when given a large input";
- continue;
- }
+ EXPECT_EQ(ErrorCode::OK, rc);
+ EXPECT_EQ(plain_message.size(), encrypted_message.size())
+ << "Encrypt finish returned OK, but did not consume all of the given input";
cipher_params.push_back(out_params);
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
string decrypted_message;
rc = Finish(encrypted_message, &decrypted_message);
-
- if (rc == ErrorCode::OK) {
- EXPECT_EQ(plain_message.size(), decrypted_message.size())
- << "Decrypt finish returned OK, did not consume all of the given input";
- } else {
- EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
- << "Encrypt finish failed in an unexpected way when given a large input";
- }
+ EXPECT_EQ(ErrorCode::OK, rc);
+ EXPECT_EQ(plain_message.size(), decrypted_message.size())
+ << "Decrypt finish returned OK, did not consume all of the given input";
}
-
- 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);
+INSTANTIATE_KEYMASTER_HIDL_TEST(TransportLimitTest);
} // namespace test
} // namespace V4_0
diff --git a/keymaster/4.1/default/Android.bp b/keymaster/4.1/default/Android.bp
index b06878b..27297b9 100644
--- a/keymaster/4.1/default/Android.bp
+++ b/keymaster/4.1/default/Android.bp
@@ -31,6 +31,7 @@
"libhidlbase",
"libkeymaster4",
"libkeymaster41",
+ "libkeymaster4_1support",
"liblog",
"libutils",
],
diff --git a/keymaster/4.1/support/Android.bp b/keymaster/4.1/support/Android.bp
index 34b6108..bdd0ca8 100644
--- a/keymaster/4.1/support/Android.bp
+++ b/keymaster/4.1/support/Android.bp
@@ -22,11 +22,25 @@
"-Wextra",
"-Werror",
],
+ srcs: [
+ "attestation_record.cpp",
+ "Keymaster.cpp",
+ "Keymaster3.cpp",
+ "Keymaster4.cpp",
+ ],
export_include_dirs: ["include"],
shared_libs: [
"android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
"android.hardware.keymaster@4.1",
+ "libbase",
+ "libcrypto",
+ "libhidlbase",
"libkeymaster4support",
- ]
+ "libutils",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.keymaster@4.1",
+ "libkeymaster4support",
+ ],
}
diff --git a/keymaster/4.1/support/Keymaster.cpp b/keymaster/4.1/support/Keymaster.cpp
new file mode 100644
index 0000000..ea6604e
--- /dev/null
+++ b/keymaster/4.1/support/Keymaster.cpp
@@ -0,0 +1,197 @@
+/*
+ ** Copyright 2018, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <keymasterV4_1/Keymaster.h>
+
+#include <iomanip>
+
+#include <android-base/logging.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <keymasterV4_0/key_param_output.h>
+#include <keymasterV4_0/keymaster_utils.h>
+#include <keymasterV4_1/Keymaster3.h>
+#include <keymasterV4_1/Keymaster4.h>
+
+namespace android::hardware {
+
+template <class T>
+std::ostream& operator<<(std::ostream& os, const hidl_vec<T>& vec) {
+ os << "{ ";
+ if (vec.size()) {
+ for (size_t i = 0; i < vec.size() - 1; ++i) os << vec[i] << ", ";
+ os << vec[vec.size() - 1];
+ }
+ os << " }";
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, const hidl_vec<uint8_t>& vec) {
+ std::ios_base::fmtflags flags(os.flags());
+ os << std::setw(2) << std::setfill('0') << std::hex;
+ for (uint8_t c : vec) os << static_cast<int>(c);
+ os.flags(flags);
+ return os;
+}
+
+template <size_t N>
+std::ostream& operator<<(std::ostream& os, const hidl_array<uint8_t, N>& vec) {
+ std::ios_base::fmtflags flags(os.flags());
+ os << std::setw(2) << std::setfill('0') << std::hex;
+ for (size_t i = 0; i < N; ++i) os << static_cast<int>(vec[i]);
+ os.flags(flags);
+ return os;
+}
+
+namespace keymaster {
+
+namespace V4_0 {
+
+std::ostream& operator<<(std::ostream& os, const HmacSharingParameters& params) {
+ // Note that by design, although seed and nonce are used to compute a secret, they are
+ // not secrets and it's just fine to log them.
+ os << "(seed: " << params.seed << ", nonce: " << params.nonce << ')';
+ return os;
+}
+
+} // namespace V4_0
+
+namespace V4_1::support {
+
+using ::android::sp;
+using ::android::hidl::manager::V1_2::IServiceManager;
+
+std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster) {
+ auto& version = keymaster.halVersion();
+ os << version.keymasterName << " from " << version.authorName
+ << " SecurityLevel: " << toString(version.securityLevel)
+ << " HAL: " << keymaster.descriptor() << "/" << keymaster.instanceName();
+ return os;
+}
+
+template <typename Wrapper>
+Keymaster::KeymasterSet enumerateDevices(const sp<IServiceManager>& serviceManager) {
+ Keymaster::KeymasterSet result;
+
+ bool foundDefault = false;
+ auto& descriptor = Wrapper::WrappedIKeymasterDevice::descriptor;
+ serviceManager->listManifestByInterface(descriptor, [&](const hidl_vec<hidl_string>& names) {
+ for (auto& name : names) {
+ if (name == "default") foundDefault = true;
+ auto device = Wrapper::WrappedIKeymasterDevice::getService(name);
+ CHECK(device) << "Failed to get service for " << descriptor << " with interface name "
+ << name;
+ result.push_back(new Wrapper(device, name));
+ }
+ });
+
+ if (!foundDefault) {
+ // "default" wasn't provided by listManifestByInterface. Maybe there's a passthrough
+ // implementation.
+ auto device = Wrapper::WrappedIKeymasterDevice::getService("default");
+ if (device) result.push_back(new Wrapper(device, "default"));
+ }
+
+ return result;
+}
+
+void Keymaster::logIfKeymasterVendorError(ErrorCode ec) const {
+ static constexpr int32_t k_keymaster_vendor_error_code_range_max = -10000;
+ if (static_cast<int32_t>(ec) <= k_keymaster_vendor_error_code_range_max) {
+ const auto& versionInfo = halVersion();
+ LOG(ERROR) << "Keymaster reported error: " << static_cast<int32_t>(ec) << "\n"
+ << "NOTE: This is an error in the vendor specific error range.\n"
+ << " Refer to the vendor of the implementation for details.\n"
+ << " Implementation name: " << versionInfo.keymasterName << "\n"
+ << " Vendor name: " << versionInfo.authorName << "\n"
+ << " MajorVersion: " << versionInfo.majorVersion;
+ }
+}
+
+Keymaster::KeymasterSet Keymaster::enumerateAvailableDevices() {
+ auto serviceManager = IServiceManager::getService();
+ CHECK(serviceManager) << "Could not retrieve ServiceManager";
+
+ auto km4s = enumerateDevices<Keymaster4>(serviceManager);
+ auto km3s = enumerateDevices<Keymaster3>(serviceManager);
+
+ auto result = std::move(km4s);
+ result.insert(result.end(), std::make_move_iterator(km3s.begin()),
+ std::make_move_iterator(km3s.end()));
+
+ std::sort(result.begin(), result.end(),
+ [](auto& a, auto& b) { return a->halVersion() > b->halVersion(); });
+
+ size_t i = 1;
+ LOG(INFO) << "List of Keymaster HALs found:";
+ for (auto& hal : result) LOG(INFO) << "Keymaster HAL #" << i++ << ": " << *hal;
+
+ return result;
+}
+
+static hidl_vec<HmacSharingParameters> getHmacParameters(
+ const Keymaster::KeymasterSet& keymasters) {
+ std::vector<HmacSharingParameters> params_vec;
+ params_vec.reserve(keymasters.size());
+ for (auto& keymaster : keymasters) {
+ if (keymaster->halVersion().majorVersion < 4) continue;
+ auto rc = keymaster->getHmacSharingParameters([&](auto error, auto& params) {
+ CHECK(error == V4_0::ErrorCode::OK)
+ << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
+ params_vec.push_back(params);
+ });
+ CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
+ << " error: " << rc.description();
+ }
+ std::sort(params_vec.begin(), params_vec.end());
+
+ return params_vec;
+}
+
+static void computeHmac(const Keymaster::KeymasterSet& keymasters,
+ const hidl_vec<HmacSharingParameters>& params) {
+ if (!params.size()) return;
+
+ hidl_vec<uint8_t> sharingCheck;
+ bool firstKeymaster = true;
+ LOG(DEBUG) << "Computing HMAC with params " << params;
+ for (auto& keymaster : keymasters) {
+ if (keymaster->halVersion().majorVersion < 4) continue;
+ LOG(DEBUG) << "Computing HMAC for " << *keymaster;
+ auto rc = keymaster->computeSharedHmac(
+ params, [&](V4_0::ErrorCode error, const hidl_vec<uint8_t>& curSharingCheck) {
+ CHECK(error == V4_0::ErrorCode::OK) << "Failed to get HMAC parameters from "
+ << *keymaster << " error " << error;
+ if (firstKeymaster) {
+ sharingCheck = curSharingCheck;
+ firstKeymaster = false;
+ }
+ if (curSharingCheck != sharingCheck)
+ LOG(WARNING) << "HMAC computation failed for " << *keymaster //
+ << " Expected: " << sharingCheck //
+ << " got: " << curSharingCheck;
+ });
+ CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
+ << " error: " << rc.description();
+ }
+}
+
+void Keymaster::performHmacKeyAgreement(const KeymasterSet& keymasters) {
+ computeHmac(keymasters, getHmacParameters(keymasters));
+}
+
+} // namespace V4_1::support
+} // namespace keymaster
+} // namespace android::hardware
diff --git a/keymaster/4.1/support/Keymaster3.cpp b/keymaster/4.1/support/Keymaster3.cpp
new file mode 100644
index 0000000..b665689
--- /dev/null
+++ b/keymaster/4.1/support/Keymaster3.cpp
@@ -0,0 +1,286 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <keymasterV4_1/Keymaster3.h>
+
+#include <android-base/logging.h>
+#include <keymasterV4_0/keymaster_utils.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+using android::hardware::details::StatusOf;
+
+namespace {
+
+V4_0::ErrorCode convert(V3_0::ErrorCode error) {
+ return static_cast<V4_0::ErrorCode>(error);
+}
+
+V3_0::KeyPurpose convert(KeyPurpose purpose) {
+ return static_cast<V3_0::KeyPurpose>(purpose);
+}
+
+V3_0::KeyFormat convert(KeyFormat purpose) {
+ return static_cast<V3_0::KeyFormat>(purpose);
+}
+
+V3_0::KeyParameter convert(const KeyParameter& param) {
+ V3_0::KeyParameter converted;
+ converted.tag = static_cast<V3_0::Tag>(param.tag);
+ static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match");
+ memcpy(&converted.f, ¶m.f, sizeof(param.f));
+ converted.blob = param.blob;
+ return converted;
+}
+
+KeyParameter convert(const V3_0::KeyParameter& param) {
+ KeyParameter converted;
+ converted.tag = static_cast<V4_0::Tag>(param.tag);
+ static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match");
+ memcpy(&converted.f, ¶m.f, sizeof(param.f));
+ converted.blob = param.blob;
+ return converted;
+}
+
+hidl_vec<V3_0::KeyParameter> convert(const hidl_vec<KeyParameter>& params) {
+ hidl_vec<V3_0::KeyParameter> converted(params.size());
+ for (size_t i = 0; i < params.size(); ++i) {
+ converted[i] = convert(params[i]);
+ }
+ return converted;
+}
+
+hidl_vec<KeyParameter> convert(const hidl_vec<V3_0::KeyParameter>& params) {
+ hidl_vec<KeyParameter> converted(params.size());
+ for (size_t i = 0; i < params.size(); ++i) {
+ converted[i] = convert(params[i]);
+ }
+ return converted;
+}
+
+template <typename T, typename OutIter>
+inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
+ const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value);
+ return std::copy(value_ptr, value_ptr + sizeof(value), dest);
+}
+
+hidl_vec<V3_0::KeyParameter> convertAndAddAuthToken(const hidl_vec<KeyParameter>& params,
+ const HardwareAuthToken& authToken) {
+ hidl_vec<V3_0::KeyParameter> converted(params.size() + 1);
+ for (size_t i = 0; i < params.size(); ++i) {
+ converted[i] = convert(params[i]);
+ }
+ converted[params.size()].tag = V3_0::Tag::AUTH_TOKEN;
+ converted[params.size()].blob = V4_0::support::authToken2HidlVec(authToken);
+
+ return converted;
+}
+
+KeyCharacteristics convert(const V3_0::KeyCharacteristics& chars) {
+ KeyCharacteristics converted;
+ converted.hardwareEnforced = convert(chars.teeEnforced);
+ converted.softwareEnforced = convert(chars.softwareEnforced);
+ return converted;
+}
+
+} // namespace
+
+void Keymaster3::getVersionIfNeeded() {
+ if (haveVersion_) return;
+
+ auto rc = km3_dev_->getHardwareFeatures(
+ [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
+ bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
+ const hidl_string& keymasterAuthorName) {
+ version_ = {keymasterName,
+ keymasterAuthorName,
+ 0 /* major version, filled below */,
+ 0 /* minor version */,
+ isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
+ supportsEllipticCurve};
+ supportsSymmetricCryptography_ = supportsSymmetricCryptography;
+ supportsAttestation_ = supportsAttestation;
+ supportsAllDigests_ = supportsAllDigests;
+ });
+
+ CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware features";
+
+ if (version_.securityLevel == SecurityLevel::SOFTWARE) {
+ version_.majorVersion = 3;
+ } else if (supportsAttestation_) {
+ version_.majorVersion = 3; // Could be 2, doesn't matter.
+ } else if (supportsSymmetricCryptography_) {
+ version_.majorVersion = 1;
+ } else {
+ version_.majorVersion = 0;
+ }
+}
+
+Return<void> Keymaster3::getHardwareInfo(Keymaster3::getHardwareInfo_cb _hidl_cb) {
+ getVersionIfNeeded();
+ _hidl_cb(version_.securityLevel,
+ std::string(version_.keymasterName) + " (wrapped by keystore::Keymaster3)",
+ version_.authorName);
+ return Void();
+}
+
+Return<V4_0::ErrorCode> Keymaster3::addRngEntropy(const hidl_vec<uint8_t>& data) {
+ auto rc = km3_dev_->addRngEntropy(data);
+ if (!rc.isOk()) {
+ return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
+ }
+ return convert(rc);
+}
+
+Return<void> Keymaster3::generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
+ const V3_0::KeyCharacteristics& characteristics) {
+ _hidl_cb(convert(error), keyBlob, convert(characteristics));
+ };
+ auto rc = km3_dev_->generateKey(convert(keyParams), cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ getKeyCharacteristics_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const V3_0::KeyCharacteristics& chars) {
+ _hidl_cb(convert(error), convert(chars));
+ };
+
+ auto rc = km3_dev_->getKeyCharacteristics(keyBlob, clientId, appData, cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
+ const V3_0::KeyCharacteristics& chars) {
+ _hidl_cb(convert(error), keyBlob, convert(chars));
+ };
+ auto rc = km3_dev_->importKey(convert(params), convert(keyFormat), keyData, cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData, exportKey_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyMaterial) {
+ _hidl_cb(convert(error), keyMaterial);
+ };
+ auto rc = km3_dev_->exportKey(convert(exportFormat), keyBlob, clientId, appData, cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
+ _hidl_cb(convert(error), certChain);
+ };
+ auto rc = km3_dev_->attestKey(keyToAttest, convert(attestParams), cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& upgradedKeyBlob) {
+ _hidl_cb(convert(error), upgradedKeyBlob);
+ };
+ auto rc = km3_dev_->upgradeKey(keyBlobToUpgrade, convert(upgradeParams), cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<V4_0::ErrorCode> Keymaster3::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
+ auto rc = km3_dev_->deleteKey(keyBlob);
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
+ return convert(rc);
+}
+
+Return<V4_0::ErrorCode> Keymaster3::deleteAllKeys() {
+ auto rc = km3_dev_->deleteAllKeys();
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
+ return convert(rc);
+}
+
+Return<V4_0::ErrorCode> Keymaster3::destroyAttestationIds() {
+ auto rc = km3_dev_->destroyAttestationIds();
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
+ return convert(rc);
+}
+
+Return<void> Keymaster3::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams,
+ const HardwareAuthToken& authToken, begin_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<V3_0::KeyParameter>& outParams,
+ OperationHandle operationHandle) {
+ _hidl_cb(convert(error), convert(outParams), operationHandle);
+ };
+
+ auto rc =
+ km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+ const VerificationToken& /* verificationToken */,
+ update_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, uint32_t inputConsumed,
+ const hidl_vec<V3_0::KeyParameter>& outParams, const hidl_vec<uint8_t>& output) {
+ _hidl_cb(convert(error), inputConsumed, convert(outParams), output);
+ };
+
+ auto rc = km3_dev_->update(operationHandle, convertAndAddAuthToken(inParams, authToken), input,
+ cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<void> Keymaster3::finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+ const HardwareAuthToken& authToken,
+ const VerificationToken& /* verificationToken */,
+ finish_cb _hidl_cb) {
+ auto cb = [&](V3_0::ErrorCode error, const hidl_vec<V3_0::KeyParameter>& outParams,
+ const hidl_vec<uint8_t>& output) {
+ _hidl_cb(convert(error), convert(outParams), output);
+ };
+
+ auto rc = km3_dev_->finish(operationHandle, convertAndAddAuthToken(inParams, authToken), input,
+ signature, cb);
+ rc.isOk(); // move ctor prereq
+ return rc;
+}
+
+Return<V4_0::ErrorCode> Keymaster3::abort(uint64_t operationHandle) {
+ auto rc = km3_dev_->abort(operationHandle);
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
+ return convert(rc);
+}
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/Keymaster4.cpp b/keymaster/4.1/support/Keymaster4.cpp
new file mode 100644
index 0000000..33f4bb1
--- /dev/null
+++ b/keymaster/4.1/support/Keymaster4.cpp
@@ -0,0 +1,41 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <keymasterV4_1/Keymaster4.h>
+
+#include <android-base/logging.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+void Keymaster4::getVersionIfNeeded() {
+ if (haveVersion_) return;
+
+ auto rc = km4_0_dev_->getHardwareInfo([&](SecurityLevel securityLevel,
+ const hidl_string& keymasterName,
+ const hidl_string& authorName) {
+ version_ = {keymasterName,
+ authorName,
+ 4 /* major version */,
+ static_cast<uint8_t>((km4_1_dev_) ? 1 : 0) /* minor version */,
+ securityLevel,
+ true /* supportsEc */};
+ haveVersion_ = true;
+ });
+
+ CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
+}
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp
new file mode 100644
index 0000000..9eab1db
--- /dev/null
+++ b/keymaster/4.1/support/attestation_record.cpp
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymasterV4_1/attestation_record.h>
+
+#include <android-base/logging.h>
+#include <assert.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <keymasterV4_0/authorization_set.h>
+#include <keymasterV4_0/openssl_utils.h>
+
+#define AT __FILE__ ":" << __LINE__
+
+/*
+ * NOTE: The contents of this file are *extremely* similar to the contents of the V4_0 copy of the
+ * same support file. Unfortunately, small changes in the scheme mean that the schema types have to
+ * be distinct, which drives almost everything else to be different as well. In the next version we
+ * plan to abandon not just this openssl mechanism for parsing ASN.1, but ASN.1 entirely, so
+ * eventually all of this duplication can be removed.
+ */
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_1 {
+
+struct stack_st_ASN1_TYPE_Delete {
+ void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
+};
+
+struct ASN1_STRING_Delete {
+ void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
+};
+
+struct ASN1_TYPE_Delete {
+ void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
+};
+
+#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
+
+typedef struct km_root_of_trust {
+ ASN1_OCTET_STRING* verified_boot_key;
+ ASN1_BOOLEAN* device_locked;
+ ASN1_ENUMERATED* verified_boot_state;
+ ASN1_OCTET_STRING* verified_boot_hash;
+} KM_ROOT_OF_TRUST;
+
+ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_hash, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+
+typedef struct km_auth_list {
+ ASN1_INTEGER_SET* purpose;
+ ASN1_INTEGER* algorithm;
+ ASN1_INTEGER* key_size;
+ ASN1_INTEGER_SET* digest;
+ ASN1_INTEGER_SET* padding;
+ ASN1_INTEGER* ec_curve;
+ ASN1_INTEGER* rsa_public_exponent;
+ ASN1_INTEGER* active_date_time;
+ ASN1_INTEGER* origination_expire_date_time;
+ ASN1_INTEGER* usage_expire_date_time;
+ ASN1_NULL* no_auth_required;
+ ASN1_INTEGER* user_auth_type;
+ ASN1_INTEGER* auth_timeout;
+ ASN1_NULL* allow_while_on_body;
+ ASN1_NULL* all_applications;
+ ASN1_OCTET_STRING* application_id;
+ ASN1_INTEGER* creation_date_time;
+ ASN1_INTEGER* origin;
+ ASN1_NULL* rollback_resistance;
+ KM_ROOT_OF_TRUST* root_of_trust;
+ ASN1_INTEGER* os_version;
+ ASN1_INTEGER* os_patchlevel;
+ ASN1_OCTET_STRING* attestation_application_id;
+ ASN1_NULL* trusted_user_presence_required;
+ ASN1_NULL* trusted_confirmation_required;
+ ASN1_NULL* unlocked_device_required;
+ ASN1_INTEGER* vendor_patchlevel;
+ ASN1_INTEGER* boot_patchlevel;
+ ASN1_NULL* early_boot_only;
+ ASN1_NULL* device_unique_attestation;
+} KM_AUTH_LIST;
+
+ASN1_SEQUENCE(KM_AUTH_LIST) = {
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+ TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
+ TAG_ROLLBACK_RESISTANCE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+ TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+ TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
+ TAG_ALLOW_WHILE_ON_BODY.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL,
+ TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL,
+ TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL,
+ TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
+ TAG_CREATION_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER,
+ TAG_VENDOR_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
+ TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()),
+} ASN1_SEQUENCE_END(KM_AUTH_LIST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
+
+typedef struct km_key_description {
+ ASN1_INTEGER* attestation_version;
+ ASN1_ENUMERATED* attestation_security_level;
+ ASN1_INTEGER* keymaster_version;
+ ASN1_ENUMERATED* keymaster_security_level;
+ ASN1_OCTET_STRING* attestation_challenge;
+ KM_AUTH_LIST* software_enforced;
+ KM_AUTH_LIST* tee_enforced;
+ ASN1_INTEGER* unique_id;
+} KM_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
+IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
+
+template <V4_0::Tag tag>
+void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag<TagType::ENUM_REP, tag> ttag,
+ AuthorizationSet* auth_list) {
+ typedef typename V4_0::TypedTag2ValueType<decltype(ttag)>::type ValueT;
+ for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
+ auth_list->push_back(
+ ttag, static_cast<ValueT>(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i))));
+ }
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ENUM, tag> ttag,
+ AuthorizationSet* auth_list) {
+ typedef typename V4_0::TypedTag2ValueType<decltype(ttag)>::type ValueT;
+ if (!asn1_int) return;
+ auth_list->push_back(ttag, static_cast<ValueT>(ASN1_INTEGER_get(asn1_int)));
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::UINT, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int));
+}
+
+BIGNUM* construct_uint_max() {
+ BIGNUM* value = BN_new();
+ BIGNUM_Ptr one(BN_new());
+ BN_one(one.get());
+ BN_lshift(value, one.get(), 32);
+ return value;
+}
+
+uint64_t BignumToUint64(BIGNUM* num) {
+ static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)),
+ "This implementation only supports 32 and 64-bit BN_ULONG");
+ if (sizeof(BN_ULONG) == sizeof(uint32_t)) {
+ BIGNUM_Ptr uint_max(construct_uint_max());
+ BIGNUM_Ptr hi(BN_new()), lo(BN_new());
+ BN_CTX_Ptr ctx(BN_CTX_new());
+ BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get());
+ return static_cast<uint64_t>(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get());
+ } else if (sizeof(BN_ULONG) == sizeof(uint64_t)) {
+ return BN_get_word(num);
+ } else {
+ return 0;
+ }
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ULONG, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+ auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::DATE, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+ auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag<TagType::BOOL, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_null) return;
+ auth_list->push_back(ttag);
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag<TagType::BYTES, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_string) return;
+ hidl_vec<uint8_t> buf;
+ buf.setToExternal(asn1_string->data, asn1_string->length);
+ auth_list->push_back(ttag, buf);
+}
+
+// Extract the values from the specified ASN.1 record and place them in auth_list.
+static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) {
+ if (!record) return ErrorCode::OK;
+
+ copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
+ copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
+ copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list);
+ copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
+ copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list);
+ copyAuthTag(record->digest, TAG_DIGEST, auth_list);
+ copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
+ copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
+ copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list);
+ copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
+ copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
+ copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
+ copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
+ copyAuthTag(record->padding, TAG_PADDING, auth_list);
+ copyAuthTag(record->purpose, TAG_PURPOSE, auth_list);
+ copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list);
+ copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
+ copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
+ copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
+ copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
+ copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list);
+ copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list);
+ copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED,
+ auth_list);
+ copyAuthTag(record->trusted_confirmation_required, TAG_TRUSTED_CONFIRMATION_REQUIRED,
+ auth_list);
+ copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list);
+ copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
+ copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
+
+ return ErrorCode::OK;
+}
+
+MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION)
+
+// Parse the DER-encoded attestation record, placing the results in keymaster_version,
+// attestation_challenge, software_enforced, tee_enforced and unique_id.
+std::tuple<ErrorCode, AttestationRecord> parse_attestation_record(const hidl_vec<uint8_t>& cert) {
+ const uint8_t* p = cert.data();
+ X509_Ptr x509(d2i_X509(nullptr, &p, cert.size()));
+
+ ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+ if (!oid.get()) {
+ LOG(ERROR) << "Error parsing OID";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
+
+ int location = X509_get_ext_by_OBJ(x509.get(), oid.get(), -1 /* search from beginning */);
+ if (location == -1) {
+ LOG(ERROR) << "Attestation extension not found in certificate";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
+
+ X509_EXTENSION* attest_rec_ext = X509_get_ext(x509.get(), location);
+ if (!attest_rec_ext) {
+ LOG(ERROR) << "Found extension but couldn't retrieve it. Probably BoringSSL bug.";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
+
+ ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+ if (!attest_rec_ext) {
+ LOG(ERROR) << "Attestation extension contained no data";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
+
+ p = attest_rec->data;
+ KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, attest_rec->length));
+ if (!record.get()) return {ErrorCode::UNKNOWN_ERROR, {}};
+
+ AttestationRecord result;
+
+ result.attestation_version = ASN1_INTEGER_get(record->attestation_version);
+ result.attestation_security_level =
+ static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->attestation_security_level));
+ result.keymaster_version = ASN1_INTEGER_get(record->keymaster_version);
+ result.keymaster_security_level =
+ static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->keymaster_security_level));
+
+ auto& chall = record->attestation_challenge;
+ result.attestation_challenge.resize(chall->length);
+ memcpy(result.attestation_challenge.data(), chall->data, chall->length);
+ auto& uid = record->unique_id;
+ result.unique_id.resize(uid->length);
+ memcpy(result.unique_id.data(), uid->data, uid->length);
+
+ ErrorCode error = extract_auth_list(record->software_enforced, &result.software_enforced);
+ if (error != ErrorCode::OK) return {error, {}};
+
+ error = extract_auth_list(record->tee_enforced, &result.hardware_enforced);
+ if (error != ErrorCode::OK) return {error, {}};
+
+ KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+ if (record->tee_enforced && record->tee_enforced->root_of_trust) {
+ root_of_trust = record->tee_enforced->root_of_trust;
+ } else if (record->software_enforced && record->software_enforced->root_of_trust) {
+ root_of_trust = record->software_enforced->root_of_trust;
+ } else {
+ LOG(ERROR) << AT << " Failed root of trust parsing";
+ return {ErrorCode::INVALID_ARGUMENT, {}};
+ }
+ if (!root_of_trust->verified_boot_key) {
+ LOG(ERROR) << AT << " Failed verified boot key parsing";
+ return {ErrorCode::INVALID_ARGUMENT, {}};
+ }
+
+ RootOfTrust& rot = result.root_of_trust;
+ auto& vb_key = root_of_trust->verified_boot_key;
+ rot.verified_boot_key.resize(vb_key->length);
+ memcpy(rot.verified_boot_key.data(), vb_key->data, vb_key->length);
+
+ rot.verified_boot_state = static_cast<keymaster_verified_boot_t>(
+ ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
+ rot.device_locked = root_of_trust->device_locked;
+
+ auto& vb_hash = root_of_trust->verified_boot_hash;
+ if (!vb_hash) {
+ LOG(ERROR) << AT << " Failed verified boot hash parsing";
+ return {ErrorCode::INVALID_ARGUMENT, {}};
+ }
+ rot.verified_boot_hash.resize(vb_hash->length);
+ memcpy(rot.verified_boot_hash.data(), vb_hash->data, vb_hash->length);
+
+ return {ErrorCode::OK, result};
+}
+
+} // namespace V4_1
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
new file mode 100644
index 0000000..1f49e18
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
@@ -0,0 +1,101 @@
+/*
+ **
+ ** Copyright 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <keymasterV4_1/keymaster_tags.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+/**
+ * Keymaster abstracts the underlying V4_1::IKeymasterDevice. There are two implementations,
+ * Keymaster3 which wraps a V3_0::IKeymasterDevice and Keymaster4, which wraps either a
+ * V4_0::IKeymasterDevice or a V4_1::IKeymasterDevice. There is a V3_0::IKeymasterDevice
+ * implementation that is used to wrap pre-HIDL keymaster implementations, and Keymaster3 will wrap
+ * that.
+ *
+ * The reason for adding this additional layer, rather than simply using the latest HAL directly and
+ * subclassing it to wrap any older HAL, is because this provides a place to put additional methods
+ * which clients can use when they need to distinguish between different underlying HAL versions,
+ * while still having to use only the latest interface. Plus it's a handy place to keep some
+ * convenience methods.
+ */
+class Keymaster : public IKeymasterDevice {
+ public:
+ using KeymasterSet = std::vector<android::sp<Keymaster>>;
+
+ Keymaster(const hidl_string& descriptor, const hidl_string& instanceName)
+ : descriptor_(descriptor), instanceName_(instanceName) {}
+ virtual ~Keymaster() {}
+
+ struct VersionResult {
+ hidl_string keymasterName;
+ hidl_string authorName;
+ uint8_t majorVersion;
+ uint8_t minorVersion;
+ SecurityLevel securityLevel;
+ bool supportsEc;
+
+ bool operator>(const VersionResult& other) const {
+ auto lhs = std::tie(securityLevel, majorVersion, minorVersion, supportsEc);
+ auto rhs = std::tie(other.securityLevel, other.majorVersion, other.minorVersion,
+ other.supportsEc);
+ return lhs > rhs;
+ }
+ };
+
+ virtual const VersionResult& halVersion() const = 0;
+ const hidl_string& descriptor() const { return descriptor_; }
+ const hidl_string& instanceName() const { return instanceName_; }
+
+ /**
+ * If ec is in the vendor error code range (<-10000), logs the fact to logcat.
+ * There are no side effects otherwise.
+ */
+ void logIfKeymasterVendorError(ErrorCode ec) const;
+ void logIfKeymasterVendorError(V4_0::ErrorCode ec) const {
+ logIfKeymasterVendorError(static_cast<ErrorCode>(ec));
+ }
+
+ /**
+ * Returns all available Keymaster3 and Keymaster4 instances, in order of most secure to least
+ * secure (as defined by VersionResult::operator<).
+ */
+ static KeymasterSet enumerateAvailableDevices();
+
+ /**
+ * Ask provided Keymaster instances to compute a shared HMAC key using
+ * getHmacSharingParameters() and computeSharedHmac(). This computation is idempotent as long
+ * as the same set of Keymaster instances is used each time (and if all of the instances work
+ * correctly). It must be performed once per boot, but should do no harm to be repeated.
+ *
+ * If key agreement fails, this method will crash the process (with CHECK).
+ */
+ static void performHmacKeyAgreement(const KeymasterSet& keymasters);
+
+ private:
+ hidl_string descriptor_;
+ hidl_string instanceName_;
+};
+
+std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster);
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h
new file mode 100644
index 0000000..c201e8c
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h
@@ -0,0 +1,148 @@
+/*
+ ** Copyright 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.
+ */
+
+#pragma once
+
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+
+#include "Keymaster.h"
+#include "Operation.h"
+
+namespace android::hardware::keymaster::V4_1::support {
+
+using IKeymaster3Device = ::android::hardware::keymaster::V3_0::IKeymasterDevice;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::details::return_status;
+
+class Keymaster3 : public Keymaster {
+ public:
+ // This definition is used for device enumeration.
+ using WrappedIKeymasterDevice = IKeymaster3Device;
+
+ Keymaster3(sp<IKeymaster3Device> km3_dev, const hidl_string& instanceName)
+ : Keymaster(IKeymaster3Device::descriptor, instanceName),
+ km3_dev_(km3_dev),
+ haveVersion_(false) {}
+
+ const VersionResult& halVersion() const override {
+ const_cast<Keymaster3*>(this)->getVersionIfNeeded();
+ return version_;
+ }
+
+ Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb);
+
+ Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
+ _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {});
+ return Void();
+ }
+
+ Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>&,
+ computeSharedHmac_cb _hidl_cb) override {
+ _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {});
+ return Void();
+ }
+
+ Return<void> verifyAuthorization(uint64_t, const hidl_vec<KeyParameter>&,
+ const HardwareAuthToken&,
+ verifyAuthorization_cb _hidl_cb) override {
+ _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {});
+ return Void();
+ }
+
+ Return<V4_0::ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
+ Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) override;
+ Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ getKeyCharacteristics_cb _hidl_cb) override;
+ Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override;
+
+ Return<void> importWrappedKey(const hidl_vec<uint8_t>& /* wrappedKeyData */,
+ const hidl_vec<uint8_t>& /* wrappingKeyBlob */,
+ const hidl_vec<uint8_t>& /* maskingKey */,
+ const hidl_vec<KeyParameter>& /* unwrappingParams */,
+ uint64_t /* passwordSid */, uint64_t /* biometricSid */,
+ importWrappedKey_cb _hidl_cb) {
+ _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {}, {});
+ return Void();
+ }
+
+ Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+ exportKey_cb _hidl_cb) override;
+ Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) override;
+ Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) override;
+ Return<V4_0::ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
+ Return<V4_0::ErrorCode> deleteAllKeys() override;
+ Return<V4_0::ErrorCode> destroyAttestationIds() override;
+ Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+ begin_cb _hidl_cb) override;
+ Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken, update_cb _hidl_cb) override;
+ Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+ const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken, finish_cb _hidl_cb) override;
+ Return<V4_0::ErrorCode> abort(uint64_t operationHandle) override;
+
+ /**********************************
+ * V4_1::IKeymasterDevice methods *
+ *********************************/
+
+ Return<ErrorCode> deviceLocked(bool /* passwordOnly */,
+ const VerificationToken& /* verificationToken */) override {
+ return ErrorCode::UNIMPLEMENTED;
+ }
+
+ Return<ErrorCode> earlyBootEnded() override { return ErrorCode::UNIMPLEMENTED; }
+
+ Return<void> beginOp(KeyPurpose purpose, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+ beginOp_cb _hidl_cb) override {
+ return begin(purpose, keyBlob, inParams, authToken,
+ [&_hidl_cb](V4_0::ErrorCode errorCode, const hidl_vec<KeyParameter>& outParams,
+ OperationHandle operationHandle) {
+ _hidl_cb(static_cast<ErrorCode>(errorCode), outParams,
+ new Operation(operationHandle));
+ });
+ }
+
+ private:
+ void getVersionIfNeeded();
+
+ sp<IKeymaster3Device> km3_dev_;
+
+ bool haveVersion_;
+ VersionResult version_;
+ bool supportsSymmetricCryptography_;
+ bool supportsAttestation_;
+ bool supportsAllDigests_;
+};
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h
new file mode 100644
index 0000000..6d74d98
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h
@@ -0,0 +1,197 @@
+/*
+ ** Copyright 2020, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#pragma once
+
+#include "Keymaster.h"
+#include "Operation.h"
+
+namespace android::hardware::keymaster::V4_1::support {
+
+using android::sp;
+
+/**
+ * This class can wrap either a V4_0 or V4_1 IKeymasterDevice.
+ */
+class Keymaster4 : public Keymaster {
+ public:
+ // This definition is used for device enumeration; enumerating 4.0 devices will also
+ // enumerate 4.1. devices.
+ using WrappedIKeymasterDevice = V4_0::IKeymasterDevice;
+
+ Keymaster4(sp<V4_1::IKeymasterDevice> km4_1_dev, const hidl_string& instanceName)
+ : Keymaster(V4_1::IKeymasterDevice::descriptor, instanceName),
+ haveVersion_(false),
+ km4_0_dev_(km4_1_dev),
+ km4_1_dev_(km4_1_dev) {}
+
+ Keymaster4(sp<V4_0::IKeymasterDevice> km4_0_dev, const hidl_string& instanceName)
+ : Keymaster(V4_1::IKeymasterDevice::descriptor, instanceName),
+ haveVersion_(false),
+ km4_0_dev_(km4_0_dev),
+ km4_1_dev_() {}
+
+ const VersionResult& halVersion() const override {
+ const_cast<Keymaster4*>(this)->getVersionIfNeeded();
+ return version_;
+ }
+
+ /**********************************
+ * V4_0::IKeymasterDevice methods *
+ *********************************/
+
+ Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
+ return km4_0_dev_->getHardwareInfo(_hidl_cb);
+ }
+
+ Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
+ return km4_0_dev_->getHmacSharingParameters(_hidl_cb);
+ }
+
+ Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>& params,
+ computeSharedHmac_cb _hidl_cb) override {
+ return km4_0_dev_->computeSharedHmac(params, _hidl_cb);
+ }
+
+ Return<void> verifyAuthorization(uint64_t operationHandle, const hidl_vec<KeyParameter>& params,
+ const HardwareAuthToken& authToken,
+ verifyAuthorization_cb _hidl_cb) override {
+ return km4_0_dev_->verifyAuthorization(operationHandle, params, authToken, _hidl_cb);
+ }
+
+ Return<V4_0::ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override {
+ return km4_0_dev_->addRngEntropy(data);
+ }
+
+ Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) override {
+ return km4_0_dev_->generateKey(keyParams, _hidl_cb);
+ }
+
+ Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ getKeyCharacteristics_cb _hidl_cb) override {
+ return km4_0_dev_->getKeyCharacteristics(keyBlob, clientId, appData, _hidl_cb);
+ }
+
+ Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override {
+ return km4_0_dev_->importKey(params, keyFormat, keyData, _hidl_cb);
+ }
+
+ Return<void> importWrappedKey(const hidl_vec<uint8_t>& wrappedKeyData,
+ const hidl_vec<uint8_t>& wrappingKeyBlob,
+ const hidl_vec<uint8_t>& maskingKey,
+ const hidl_vec<KeyParameter>& unwrappingParams,
+ uint64_t passwordSid, uint64_t biometricSid,
+ importWrappedKey_cb _hidl_cb) {
+ return km4_0_dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey,
+ unwrappingParams, passwordSid, biometricSid, _hidl_cb);
+ }
+
+ Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+ exportKey_cb _hidl_cb) override {
+ return km4_0_dev_->exportKey(exportFormat, keyBlob, clientId, appData, _hidl_cb);
+ }
+
+ Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) override {
+ return km4_0_dev_->attestKey(keyToAttest, attestParams, _hidl_cb);
+ }
+
+ Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) override {
+ return km4_0_dev_->upgradeKey(keyBlobToUpgrade, upgradeParams, _hidl_cb);
+ }
+
+ Return<V4_0::ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override {
+ return km4_0_dev_->deleteKey(keyBlob);
+ }
+
+ Return<V4_0::ErrorCode> deleteAllKeys() override { return km4_0_dev_->deleteAllKeys(); }
+
+ Return<V4_0::ErrorCode> destroyAttestationIds() override {
+ return km4_0_dev_->destroyAttestationIds();
+ }
+
+ Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+ begin_cb _hidl_cb) override {
+ return km4_0_dev_->begin(purpose, key, inParams, authToken, _hidl_cb);
+ }
+
+ Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken, update_cb _hidl_cb) override {
+ return km4_0_dev_->update(operationHandle, inParams, input, authToken, verificationToken,
+ _hidl_cb);
+ }
+
+ Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+ const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken, finish_cb _hidl_cb) override {
+ return km4_0_dev_->finish(operationHandle, inParams, input, signature, authToken,
+ verificationToken, _hidl_cb);
+ }
+
+ Return<V4_0::ErrorCode> abort(uint64_t operationHandle) override {
+ return km4_0_dev_->abort(operationHandle);
+ }
+
+ /**********************************
+ * V4_1::IKeymasterDevice methods *
+ *********************************/
+
+ Return<ErrorCode> deviceLocked(bool passwordOnly,
+ const VerificationToken& verificationToken) override {
+ if (km4_1_dev_) return km4_1_dev_->deviceLocked(passwordOnly, verificationToken);
+ return ErrorCode::UNIMPLEMENTED;
+ }
+
+ Return<ErrorCode> earlyBootEnded() override {
+ if (km4_1_dev_) return km4_1_dev_->earlyBootEnded();
+ return ErrorCode::UNIMPLEMENTED;
+ }
+
+ Return<void> beginOp(KeyPurpose purpose, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+ beginOp_cb _hidl_cb) override {
+ if (km4_1_dev_) return km4_1_dev_->beginOp(purpose, keyBlob, inParams, authToken, _hidl_cb);
+
+ return km4_0_dev_->begin(
+ purpose, keyBlob, inParams, authToken,
+ [&_hidl_cb](V4_0::ErrorCode errorCode, const hidl_vec<KeyParameter>& outParams,
+ OperationHandle operationHandle) {
+ _hidl_cb(static_cast<ErrorCode>(errorCode), outParams,
+ new Operation(operationHandle));
+ });
+ }
+
+ private:
+ void getVersionIfNeeded();
+
+ bool haveVersion_;
+ VersionResult version_;
+ sp<V4_0::IKeymasterDevice> km4_0_dev_;
+ sp<V4_1::IKeymasterDevice> km4_1_dev_;
+}; // namespace android::hardware::keymaster::V4_1::support
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/Operation.h b/keymaster/4.1/support/include/keymasterV4_1/Operation.h
new file mode 100644
index 0000000..902d49a
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/Operation.h
@@ -0,0 +1,38 @@
+/*
+ ** Copyright 2020, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/keymaster/4.1/IOperation.h>
+
+#include <keymasterV4_1/keymaster_tags.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+class Operation : public IOperation {
+ public:
+ Operation(OperationHandle handle) : handle_(handle) {}
+
+ Return<void> getOperationChallenge(getOperationChallenge_cb _hidl_cb) override {
+ _hidl_cb(V4_1::ErrorCode::OK, handle_);
+ return Void();
+ }
+
+ private:
+ OperationHandle handle_;
+};
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h b/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h
new file mode 100644
index 0000000..b543bdd
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <keymasterV4_0/attestation_record.h>
+#include <keymasterV4_0/openssl_utils.h>
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_1 {
+
+using V4_0::kAttestionRecordOid;
+using V4_0::keymaster_verified_boot_t;
+
+struct RootOfTrust {
+ SecurityLevel security_level;
+ hidl_vec<uint8_t> verified_boot_key;
+ hidl_vec<uint8_t> verified_boot_hash;
+ keymaster_verified_boot_t verified_boot_state;
+ bool device_locked;
+};
+
+struct AttestationRecord {
+ RootOfTrust root_of_trust;
+ uint32_t attestation_version;
+ SecurityLevel attestation_security_level;
+ uint32_t keymaster_version;
+ SecurityLevel keymaster_security_level;
+ hidl_vec<uint8_t> attestation_challenge;
+ AuthorizationSet software_enforced;
+ AuthorizationSet hardware_enforced;
+ hidl_vec<uint8_t> unique_id;
+};
+
+std::tuple<ErrorCode, AttestationRecord> parse_attestation_record(const hidl_vec<uint8_t>& cert);
+
+} // namespace V4_1
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
index afc0eaf..01605b7 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
-#define HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
+#pragma once
#include <keymasterV4_0/authorization_set.h>
@@ -28,5 +27,3 @@
using V4_0::KeyParameter;
} // namespace android::hardware::keymaster::V4_1
-
-#endif // HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
index 6ffe8e1..6c186f6 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
@@ -23,16 +23,26 @@
namespace android::hardware::keymaster::V4_1 {
+using V4_0::Algorithm;
using V4_0::BlockMode;
using V4_0::Digest;
using V4_0::EcCurve;
-using V4_0::ErrorCode;
+using V4_0::HardwareAuthenticatorType;
using V4_0::HardwareAuthToken;
+using V4_0::HmacSharingParameters;
+using V4_0::KeyBlobUsageRequirements;
+using V4_0::KeyCharacteristics;
+using V4_0::KeyFormat;
+using V4_0::KeyOrigin;
using V4_0::KeyParameter;
+using V4_0::KeyPurpose;
+using V4_0::OperationHandle;
using V4_0::PaddingMode;
+using V4_0::SecurityLevel;
using V4_0::TagType;
using V4_0::VerificationToken;
+using V4_0::NullOr;
using V4_0::TypedTag;
using V4_0::TAG_ACTIVE_DATETIME;
@@ -90,6 +100,7 @@
DECLARE_KM_4_1_TYPED_TAG(EARLY_BOOT_ONLY);
DECLARE_KM_4_1_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION);
+DECLARE_KM_4_1_TYPED_TAG(STORAGE_KEY);
} // namespace android::hardware::keymaster::V4_1
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h
new file mode 100644
index 0000000..2e28002
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <keymasterV4_0/keymaster_utils.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+using V4_0::support::blob2hidlVec;
+using V4_0::support::hidlVec2AuthToken;
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/types.hal b/keymaster/4.1/types.hal
index 9e8b30e..f3bdcc6 100644
--- a/keymaster/4.1/types.hal
+++ b/keymaster/4.1/types.hal
@@ -50,10 +50,29 @@
* HAL attests to Credential Keys. IIdentityCredential produces Keymaster-style attestations.
*/
IDENTITY_CREDENTIAL_KEY = TagType:BOOL | 721,
+
+ /**
+ * To prevent keys from being compromised if an attacker acquires read access to system / kernel
+ * memory, some inline encryption hardware supports protecting storage encryption keys in hardware
+ * without software having access to or the ability to set the plaintext keys. Instead, software
+ * only sees wrapped version of these keys.
+ *
+ * STORAGE_KEY is used to denote that a key generated or imported is a key used for storage
+ * encryption. Keys of this type can either be generated or imported or secure imported using
+ * keymaster. exportKey() can be used to re-wrap storage key with a per-boot ephemeral key wrapped
+ * key once the key characteristics are enforced.
+ *
+ * Keys with this tag cannot be used for any operation within keymaster.
+ * ErrorCode::INVALID_OPERATION is returned when a key with Tag::STORAGE_KEY is provided to
+ * begin().
+ */
+ STORAGE_KEY = TagType:BOOL | 722,
};
enum ErrorCode : @4.0::ErrorCode {
EARLY_BOOT_ENDED = -73,
ATTESTATION_KEYS_NOT_PROVISIONED = -74,
ATTESTATION_IDS_NOT_PROVISIONED = -75,
+ INVALID_OPERATION = -76,
+ STORAGE_KEY_UNSUPPORTED = -77,
};
diff --git a/keymaster/4.1/vts/functional/Android.bp b/keymaster/4.1/vts/functional/Android.bp
index f5a0c9c..c2d7fa3 100644
--- a/keymaster/4.1/vts/functional/Android.bp
+++ b/keymaster/4.1/vts/functional/Android.bp
@@ -19,12 +19,24 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"EarlyBootKeyTest.cpp",
+ "DeviceUniqueAttestationTest.cpp",
+ "Keymaster4_1HidlTest.cpp",
+ "UnlockedDeviceRequiredTest.cpp",
],
static_libs: [
"android.hardware.keymaster@4.0",
"android.hardware.keymaster@4.1",
- "libkeymaster4support",
+ "libcrypto_static",
"libkeymaster4_1support",
+ "libkeymaster4support",
+ "libkeymaster4vtstest",
],
- test_suites: ["vts-core"],
+ cflags: [
+ "-Wall",
+ "-O0",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
new file mode 100644
index 0000000..7ea3275
--- /dev/null
+++ b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Keymaster4_1HidlTest.h"
+
+#include <cutils/properties.h>
+
+#include <openssl/x509.h>
+
+#include <keymasterV4_1/attestation_record.h>
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_0 {
+
+bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
+ return std::equal(a.begin(), a.end(), b.begin(), b.end());
+}
+
+} // namespace android::hardware::keymaster::V4_0
+
+namespace android::hardware::keymaster::V4_1 {
+
+inline ::std::ostream& operator<<(::std::ostream& os, Tag tag) {
+ return os << toString(tag);
+}
+
+namespace test {
+
+using std::string;
+using std::tuple;
+
+namespace {
+
+char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+string bin2hex(const hidl_vec<uint8_t>& data) {
+ string retval;
+ retval.reserve(data.size() * 2 + 1);
+ for (uint8_t byte : data) {
+ retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
+ retval.push_back(nibble2hex[0x0F & byte]);
+ }
+ return retval;
+}
+
+struct AuthorizationSetDifferences {
+ string aName;
+ string bName;
+ AuthorizationSet aWhackB;
+ AuthorizationSet bWhackA;
+};
+
+std::ostream& operator<<(std::ostream& o, const AuthorizationSetDifferences& diffs) {
+ if (!diffs.aWhackB.empty()) {
+ o << "Set " << diffs.aName << " contains the following that " << diffs.bName << " does not"
+ << diffs.aWhackB;
+ if (!diffs.bWhackA.empty()) o << std::endl;
+ }
+
+ if (!diffs.bWhackA.empty()) {
+ o << "Set " << diffs.bName << " contains the following that " << diffs.aName << " does not"
+ << diffs.bWhackA;
+ }
+ return o;
+}
+
+// Computes and returns a \ b and b \ a ('\' is the set-difference operator, a \ b means all the
+// elements that are in a but not b, i.e. take a and whack all the elements in b) to the provided
+// stream. The sets must be sorted.
+//
+// This provides a simple and clear view of how the two sets differ, generally much
+// easier than scrutinizing printouts of the two sets.
+AuthorizationSetDifferences difference(string aName, const AuthorizationSet& a, string bName,
+ const AuthorizationSet& b) {
+ AuthorizationSetDifferences diffs = {std::move(aName), std::move(bName), {}, {}};
+ std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(diffs.aWhackB));
+ std::set_difference(b.begin(), b.end(), a.begin(), a.end(), std::back_inserter(diffs.bWhackA));
+ return diffs;
+}
+
+#define DIFFERENCE(a, b) difference(#a, a, #b, b)
+
+void check_root_of_trust(const RootOfTrust& root_of_trust) {
+ char vb_meta_device_state[PROPERTY_VALUE_MAX];
+ if (property_get("ro.boot.vbmeta.device_state", vb_meta_device_state, "") == 0) return;
+
+ char vb_meta_digest[PROPERTY_VALUE_MAX];
+ EXPECT_GT(property_get("ro.boot.vbmeta.digest", vb_meta_digest, ""), 0);
+ EXPECT_EQ(vb_meta_digest, bin2hex(root_of_trust.verified_boot_hash));
+
+ // Verified boot key should be all 0's if the boot state is not verified or self signed
+ HidlBuf empty_boot_key(string(32, '\0'));
+
+ char vb_meta_bootstate[PROPERTY_VALUE_MAX];
+ auto& verified_boot_key = root_of_trust.verified_boot_key;
+ auto& verified_boot_state = root_of_trust.verified_boot_state;
+ EXPECT_GT(property_get("ro.boot.verifiedbootstate", vb_meta_bootstate, ""), 0);
+ if (!strcmp(vb_meta_bootstate, "green")) {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_VERIFIED);
+ EXPECT_NE(verified_boot_key, empty_boot_key);
+ } else if (!strcmp(vb_meta_bootstate, "yellow")) {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_SELF_SIGNED);
+ EXPECT_NE(verified_boot_key, empty_boot_key);
+ } else if (!strcmp(vb_meta_bootstate, "orange")) {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_UNVERIFIED);
+ EXPECT_EQ(verified_boot_key, empty_boot_key);
+ } else if (!strcmp(vb_meta_bootstate, "red")) {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_FAILED);
+ } else {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_UNVERIFIED);
+ EXPECT_EQ(verified_boot_key, empty_boot_key);
+ }
+}
+
+void check_attestation_record(AttestationRecord attestation, const HidlBuf& challenge,
+ AuthorizationSet expected_sw_enforced,
+ AuthorizationSet expected_hw_enforced,
+ SecurityLevel expected_security_level) {
+ EXPECT_EQ(41U, attestation.keymaster_version);
+ EXPECT_EQ(4U, attestation.attestation_version);
+ EXPECT_EQ(expected_security_level, attestation.attestation_security_level);
+ EXPECT_EQ(expected_security_level, attestation.keymaster_security_level);
+ EXPECT_EQ(challenge, attestation.attestation_challenge);
+
+ check_root_of_trust(attestation.root_of_trust);
+
+ // Sort all of the authorization lists, so that equality matching works.
+ expected_sw_enforced.Sort();
+ expected_hw_enforced.Sort();
+ attestation.software_enforced.Sort();
+ attestation.hardware_enforced.Sort();
+
+ EXPECT_EQ(expected_sw_enforced, attestation.software_enforced)
+ << DIFFERENCE(expected_sw_enforced, attestation.software_enforced);
+ EXPECT_EQ(expected_hw_enforced, attestation.hardware_enforced)
+ << DIFFERENCE(expected_hw_enforced, attestation.hardware_enforced);
+}
+
+} // namespace
+
+using std::string;
+using DeviceUniqueAttestationTest = Keymaster4_1HidlTest;
+
+TEST_P(DeviceUniqueAttestationTest, StrongBoxOnly) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+
+ ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID))));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ EXPECT_EQ(ErrorCode::UNIMPLEMENTED,
+ convert(AttestKey(
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+ &cert_chain)));
+ CheckedDeleteKey();
+
+ ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID))));
+
+ EXPECT_EQ(ErrorCode::UNIMPLEMENTED,
+ convert(AttestKey(
+ AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+ &cert_chain)));
+}
+
+TEST_P(DeviceUniqueAttestationTest, Rsa) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+ ASSERT_EQ(ErrorCode::OK,
+ convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Authorization(TAG_CREATION_DATETIME, 1))));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ HidlBuf challenge("challenge");
+ HidlBuf app_id("foo");
+ EXPECT_EQ(ErrorCode::OK,
+ convert(AttestKey(AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ &cert_chain)));
+
+ EXPECT_EQ(1U, cert_chain.size());
+ auto [err, attestation] = parse_attestation_record(cert_chain[0]);
+ EXPECT_EQ(ErrorCode::OK, err);
+
+ check_attestation_record(attestation, challenge,
+ /* sw_enforced */
+ AuthorizationSetBuilder()
+ .Authorization(TAG_CREATION_DATETIME, 1)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ /* hw_enforced */
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+ .Authorization(TAG_OS_VERSION, os_version())
+ .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()),
+ SecLevel());
+}
+
+TEST_P(DeviceUniqueAttestationTest, Ecdsa) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+ ASSERT_EQ(ErrorCode::OK,
+ convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_CREATION_DATETIME, 1))));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ HidlBuf challenge("challenge");
+ HidlBuf app_id("foo");
+ EXPECT_EQ(ErrorCode::OK,
+ convert(AttestKey(AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ &cert_chain)));
+
+ EXPECT_EQ(1U, cert_chain.size());
+ auto [err, attestation] = parse_attestation_record(cert_chain[0]);
+ EXPECT_EQ(ErrorCode::OK, err);
+
+ check_attestation_record(attestation, challenge,
+ /* sw_enforced */
+ AuthorizationSetBuilder()
+ .Authorization(TAG_CREATION_DATETIME, 1)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ /* hw_enforced */
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_EC_CURVE, EcCurve::P_256)
+ .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+ .Authorization(TAG_OS_VERSION, os_version())
+ .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()),
+ SecLevel());
+}
+
+INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(DeviceUniqueAttestationTest);
+
+} // namespace test
+} // namespace android::hardware::keymaster::V4_1
diff --git a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
index 4a19010..a26c688 100644
--- a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
+++ b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
@@ -14,8 +14,78 @@
* limitations under the License.
*/
+#include "Keymaster4_1HidlTest.h"
+
+#include <keymasterV4_1/authorization_set.h>
+
namespace android::hardware::keymaster::V4_1::test {
-// TODO(swillden): Put tests here.
+using std::string;
+
+using EarlyBootKeyTest = Keymaster4_1HidlTest;
+
+// Because VTS tests are run on fully-booted machines, we can only run negative tests for early boot
+// keys, which cannot be created or used after /data is mounted. This is the only test we can run
+// in the normal case. The positive test will have to be done by the Android system, when it
+// creates/uses early boot keys during boot. It should fail to boot if the early boot key usage
+// fails.
+TEST_P(EarlyBootKeyTest, CannotCreateEarlyBootKeys) {
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED);
+
+ CheckedDeleteKeyData(&aesKeyData);
+ CheckedDeleteKeyData(&hmacKeyData);
+ CheckedDeleteKeyData(&rsaKeyData);
+ CheckedDeleteKeyData(&ecdsaKeyData);
+}
+
+// This is a more comprenhensive test, but it can only be run on a machine which is still in early
+// boot stage, which no proper Android device is by the time we can run VTS. To use this,
+// un-disable it and modify vold to remove the call to earlyBootEnded(). Running the test will end
+// early boot, so you'll have to reboot between runs.
+TEST_P(EarlyBootKeyTest, DISABLED_FullTest) {
+ // Should be able to create keys, since early boot has not ended
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK);
+
+ // TAG_EARLY_BOOT_ONLY should be in hw-enforced.
+ EXPECT_TRUE(contains(aesKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+ EXPECT_TRUE(contains(hmacKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+ EXPECT_TRUE(contains(rsaKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+ EXPECT_TRUE(contains(ecdsaKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+
+ // Should be able to use keys, since early boot has not ended
+ EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
+
+ // End early boot
+ Return<ErrorCode> earlyBootResult = keymaster().earlyBootEnded();
+ EXPECT_TRUE(earlyBootResult.isOk());
+ EXPECT_EQ(earlyBootResult, ErrorCode::OK);
+
+ // Should not be able to use already-created keys.
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseEcdsaKey(ecdsaKeyData.blob));
+
+ CheckedDeleteKeyData(&aesKeyData);
+ CheckedDeleteKeyData(&hmacKeyData);
+ CheckedDeleteKeyData(&rsaKeyData);
+ CheckedDeleteKeyData(&ecdsaKeyData);
+
+ // Should not be able to create new keys
+ std::tie(aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData) =
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED);
+
+ CheckedDeleteKeyData(&aesKeyData);
+ CheckedDeleteKeyData(&hmacKeyData);
+ CheckedDeleteKeyData(&rsaKeyData);
+ CheckedDeleteKeyData(&ecdsaKeyData);
+}
+
+INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(EarlyBootKeyTest);
} // namespace android::hardware::keymaster::V4_1::test
diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp
new file mode 100644
index 0000000..efedf28
--- /dev/null
+++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Keymaster4_1HidlTest.h"
+
+namespace android::hardware::keymaster::V4_1::test {
+
+using std::string;
+
+void Keymaster4_1HidlTest::SetUp() {
+ keymaster41_ = IKeymasterDevice::getService(GetParam());
+ InitializeKeymaster(keymaster41_);
+}
+
+auto Keymaster4_1HidlTest::ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation,
+ const string& message, const AuthorizationSet& in_params)
+ -> std::tuple<ErrorCode, string, AuthorizationSet /* out_params */> {
+ AuthorizationSet begin_out_params;
+ V4_0::ErrorCode result = Begin(operation, key_blob, in_params, &begin_out_params, &op_handle_);
+ AuthorizationSet out_params(std::move(begin_out_params));
+ if (result != V4_0::ErrorCode::OK) {
+ return {convert(result), {}, out_params};
+ }
+
+ string output;
+ size_t consumed = 0;
+ AuthorizationSet update_params;
+ AuthorizationSet update_out_params;
+ result = Update(op_handle_, update_params, message, &update_out_params, &output, &consumed);
+ out_params.push_back(update_out_params);
+ if (result != V4_0::ErrorCode::OK) {
+ return {convert(result), output, out_params};
+ }
+
+ string unused;
+ AuthorizationSet finish_params;
+ AuthorizationSet finish_out_params;
+ result = Finish(op_handle_, finish_params, message.substr(consumed), unused, &finish_out_params,
+ &output);
+ op_handle_ = V4_0::test::kOpHandleSentinel;
+ out_params.push_back(finish_out_params);
+
+ return {convert(result), output, out_params};
+}
+
+} // namespace android::hardware::keymaster::V4_1::test
diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
new file mode 100644
index 0000000..6332c43
--- /dev/null
+++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
@@ -0,0 +1,158 @@
+/*
+ * 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/keymaster/4.1/IKeymasterDevice.h>
+
+#include <KeymasterHidlTest.h>
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_1::test {
+
+using V4_0::test::HidlBuf;
+
+class Keymaster4_1HidlTest : public V4_0::test::KeymasterHidlTest {
+ public:
+ using super = V4_0::test::KeymasterHidlTest;
+
+ ErrorCode convert(V4_0::ErrorCode error_code) { return static_cast<ErrorCode>(error_code); }
+
+ // These methods hide the base class versions.
+ void SetUp();
+ IKeymasterDevice& keymaster() { return *keymaster41_; };
+
+ struct KeyData {
+ HidlBuf blob;
+ KeyCharacteristics characteristics;
+ };
+
+ std::tuple<ErrorCode, KeyData> GenerateKeyData(const AuthorizationSet& keyDescription) {
+ KeyData keyData;
+ ErrorCode errorCode = convert(
+ super::GenerateKey(keyDescription, &keyData.blob, &keyData.characteristics));
+ return {errorCode, keyData};
+ }
+
+ void CheckedDeleteKeyData(KeyData* keyData) { CheckedDeleteKey(&keyData->blob); }
+
+ template <typename TagType>
+ std::tuple<KeyData /* aesKey */, KeyData /* hmacKey */, KeyData /* rsaKey */,
+ KeyData /* ecdsaKey */>
+ CreateTestKeys(TagType tagToTest, ErrorCode expectedReturn) {
+ ErrorCode errorCode;
+
+ /* AES */
+ KeyData aesKeyData;
+ std::tie(errorCode, aesKeyData) =
+ GenerateKeyData(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(tagToTest)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED));
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ /* HMAC */
+ KeyData hmacKeyData;
+ std::tie(errorCode, hmacKeyData) =
+ GenerateKeyData(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Authorization(tagToTest)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)
+ .Authorization(TAG_NO_AUTH_REQUIRED));
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ /* RSA */
+ KeyData rsaKeyData;
+ std::tie(errorCode, rsaKeyData) =
+ GenerateKeyData(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(tagToTest)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED));
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ /* ECDSA */
+ KeyData ecdsaKeyData;
+ std::tie(errorCode, ecdsaKeyData) =
+ GenerateKeyData(AuthorizationSetBuilder()
+ .EcdsaSigningKey(256)
+ .Authorization(tagToTest)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED));
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ return {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData};
+ }
+
+ std::tuple<ErrorCode, std::string /* processedMessage */, AuthorizationSet /* out_params */>
+ ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, const std::string& message,
+ const AuthorizationSet& in_params);
+
+ ErrorCode UseAesKey(const HidlBuf& aesKeyBlob) {
+ auto [result, ciphertext, out_params] = ProcessMessage(
+ aesKeyBlob, KeyPurpose::ENCRYPT, "1234567890123456",
+ AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE));
+ return result;
+ }
+
+ ErrorCode UseHmacKey(const HidlBuf& hmacKeyBlob) {
+ auto [result, mac, out_params] =
+ ProcessMessage(hmacKeyBlob, KeyPurpose::SIGN, "1234567890123456",
+ AuthorizationSetBuilder().Authorization(TAG_MAC_LENGTH, 128));
+ return result;
+ }
+
+ ErrorCode UseRsaKey(const HidlBuf& rsaKeyBlob) {
+ std::string message(2048 / 8, 'a');
+ auto [result, signature, out_params] = ProcessMessage(
+ rsaKeyBlob, KeyPurpose::SIGN, message,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+ return result;
+ }
+
+ ErrorCode UseEcdsaKey(const HidlBuf& ecdsaKeyBlob) {
+ auto [result, signature, out_params] =
+ ProcessMessage(ecdsaKeyBlob, KeyPurpose::SIGN, "a",
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+ return result;
+ }
+
+ static std::vector<std::string> build_params() {
+ auto params = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
+ return params;
+ }
+
+ private:
+ sp<IKeymasterDevice> keymaster41_;
+};
+
+template <typename TypedTag>
+bool contains(hidl_vec<KeyParameter>& set, TypedTag typedTag) {
+ return std::find_if(set.begin(), set.end(), [&](const KeyParameter& param) {
+ return param.tag == static_cast<V4_0::Tag>(typedTag);
+ }) != set.end();
+}
+
+#define INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(name) \
+ INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
+ testing::ValuesIn(Keymaster4_1HidlTest::build_params()), \
+ android::hardware::PrintInstanceNameToString)
+
+} // namespace android::hardware::keymaster::V4_1::test
diff --git a/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp b/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp
new file mode 100644
index 0000000..671bbbf
--- /dev/null
+++ b/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Keymaster4_1HidlTest.h"
+
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_1::test {
+
+using UnlockedDeviceRequiredTest = Keymaster4_1HidlTest;
+
+// This may be a problematic test. It can't be run repeatedly without unlocking the device in
+// between runs... and on most test devices there are no enrolled credentials so it can't be
+// unlocked at all, meaning the only way to get the test to pass again on a properly-functioning
+// device is to reboot it. For that reason, this is disabled by default. It can be used as part of
+// a manual test process, which includes unlocking between runs, which is why it's included here.
+// Well, that and the fact that it's the only test we can do without also making calls into the
+// Gatekeeper HAL. We haven't written any cross-HAL tests, and don't know what all of the
+// implications might be, so that may or may not be a solution.
+//
+// TODO(swillden): Use the Gatekeeper HAL to enroll some test credentials which we can verify to get
+// an unlock auth token. If that works, enable the improved test.
+TEST_P(UnlockedDeviceRequiredTest, DISABLED_KeysBecomeUnusable) {
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+ CreateTestKeys(TAG_UNLOCKED_DEVICE_REQUIRED, ErrorCode::OK);
+
+ EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
+
+ Return<ErrorCode> rc =
+ keymaster().deviceLocked(false /* passwordOnly */, {} /* verificationToken */);
+ ASSERT_TRUE(rc.isOk());
+ ASSERT_EQ(ErrorCode::OK, static_cast<ErrorCode>(rc));
+
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseEcdsaKey(ecdsaKeyData.blob));
+
+ CheckedDeleteKeyData(&aesKeyData);
+ CheckedDeleteKeyData(&hmacKeyData);
+ CheckedDeleteKeyData(&rsaKeyData);
+ CheckedDeleteKeyData(&ecdsaKeyData);
+}
+
+INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(UnlockedDeviceRequiredTest);
+
+} // namespace android::hardware::keymaster::V4_1::test
diff --git a/light/aidl/Android.bp b/light/aidl/Android.bp
new file mode 100644
index 0000000..916a857
--- /dev/null
+++ b/light/aidl/Android.bp
@@ -0,0 +1,18 @@
+aidl_interface {
+ name: "android.hardware.light",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/light/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ },
+}
diff --git a/light/aidl/android/hardware/light/BrightnessMode.aidl b/light/aidl/android/hardware/light/BrightnessMode.aidl
new file mode 100644
index 0000000..bc29699
--- /dev/null
+++ b/light/aidl/android/hardware/light/BrightnessMode.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.light;
+
+@VintfStability
+enum BrightnessMode {
+ /**
+ * Light brightness is managed by a user setting.
+ */
+ USER = 0,
+
+ /**
+ * Light brightness is managed by a light sensor. This is typically used
+ * to control the display backlight, but not limited to it. HALs and
+ * hardware implementations are free to support sensor for other lights or
+ * none whatsoever.
+ */
+ SENSOR = 1,
+
+ /**
+ * Use a low-persistence mode for display backlights, where the pixel
+ * color transition times are lowered.
+ *
+ * When set, the device driver must switch to a mode optimized for low display
+ * persistence that is intended to be used when the device is being treated as a
+ * head mounted display (HMD). The actual display brightness in this mode is
+ * implementation dependent, and any value set for color in LightState may be
+ * overridden by the HAL implementation.
+ *
+ * For an optimal HMD viewing experience, the display must meet the following
+ * criteria in this mode:
+ * - Gray-to-Gray, White-to-Black, and Black-to-White switching time must be ≤ 3 ms.
+ * - The display must support low-persistence with ≤ 3.5 ms persistence.
+ * Persistence is defined as the amount of time for which a pixel is
+ * emitting light for a single frame.
+ * - Any "smart panel" or other frame buffering options that increase display
+ * latency are disabled.
+ * - Display brightness is set so that the display is still visible to the user
+ * under normal indoor lighting.
+ * - The display must update at 60 Hz at least, but higher refresh rates are
+ * recommended for low latency.
+ *
+ */
+ LOW_PERSISTENCE = 2,
+}
diff --git a/light/aidl/android/hardware/light/FlashMode.aidl b/light/aidl/android/hardware/light/FlashMode.aidl
new file mode 100644
index 0000000..00c6b6a
--- /dev/null
+++ b/light/aidl/android/hardware/light/FlashMode.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.light;
+
+@VintfStability
+enum FlashMode {
+ /**
+ * Keep the light steady on or off.
+ */
+ NONE = 0,
+ /**
+ * Flash the light at specified rate, potentially using a software-based
+ * implementation.
+ */
+ TIMED = 1,
+ /**
+ * Flash the light using hardware flashing support. This may or may not
+ * support a user-defined flashing rate or other features.
+ */
+ HARDWARE = 2,
+}
diff --git a/light/aidl/android/hardware/light/HwLight.aidl b/light/aidl/android/hardware/light/HwLight.aidl
new file mode 100644
index 0000000..43fdb4b
--- /dev/null
+++ b/light/aidl/android/hardware/light/HwLight.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.light;
+
+import android.hardware.light.LightType;
+
+/**
+ * A description of a single light. Multiple lights can map to the same physical
+ * LED. Separate physical LEDs are always represented by separate instances.
+ */
+@VintfStability
+parcelable HwLight {
+ /**
+ * Integer ID used for controlling this light
+ */
+ int id;
+
+ /**
+ * For a group of lights of the same logical type, sorting by ordinal should
+ * be give their physical order. No other meaning is carried by it.
+ */
+ int ordinal;
+
+ /**
+ * Logical type use of this light.
+ */
+ LightType type;
+}
diff --git a/light/aidl/android/hardware/light/HwLightState.aidl b/light/aidl/android/hardware/light/HwLightState.aidl
new file mode 100644
index 0000000..24d3250
--- /dev/null
+++ b/light/aidl/android/hardware/light/HwLightState.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.light;
+
+import android.hardware.light.BrightnessMode;
+import android.hardware.light.FlashMode;
+
+/**
+ * The parameters that can be set for a given light.
+ *
+ * Not all lights must support all parameters. If you
+ * can do something backward-compatible, do it.
+ */
+@VintfStability
+parcelable HwLightState {
+ /**
+ * The color of the LED in ARGB.
+ *
+ * The implementation of this in the HAL and hardware is a best-effort one.
+ * - If a light can only do red or green and blue is requested, green
+ * should be shown.
+ * - If only a brightness ramp is supported, then this formula applies:
+ * unsigned char brightness = ((77*((color>>16)&0x00ff))
+ * + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
+ * - If only on and off are supported, 0 is off, anything else is on.
+ *
+ * The high byte should be ignored. Callers should set it to 0xff (which
+ * would correspond to 255 alpha).
+ */
+ int color;
+
+ /**
+ * To flash the light at a given rate, set flashMode to FLASH_TIMED.
+ */
+ FlashMode flashMode;
+
+ /**
+ * flashOnMs should be set to the number of milliseconds to turn the
+ * light on, before it's turned off.
+ */
+ int flashOnMs;
+
+ /**
+ * flashOfMs should be set to the number of milliseconds to turn the
+ * light off, before it's turned back on.
+ */
+ int flashOffMs;
+
+ BrightnessMode brightnessMode;
+}
diff --git a/light/aidl/android/hardware/light/ILights.aidl b/light/aidl/android/hardware/light/ILights.aidl
new file mode 100644
index 0000000..2253f73
--- /dev/null
+++ b/light/aidl/android/hardware/light/ILights.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.light;
+
+import android.hardware.light.HwLightState;
+import android.hardware.light.HwLight;
+
+/**
+ * Allows controlling logical lights/indicators, mapped to LEDs in a
+ * hardware-specific manner by the HAL implementation.
+ */
+@VintfStability
+interface ILights {
+ /**
+ * Set light identified by id to the provided state.
+ *
+ * If control over an invalid light is requested, this method exists with
+ * EX_UNSUPPORTED_OPERATION. Control over supported lights is done on a
+ * device-specific best-effort basis and unsupported sub-features will not
+ * be reported.
+ *
+ * @param id ID of logical light to set as returned by getLights()
+ * @param state describes what the light should look like.
+ */
+ void setLightState(in int id, in HwLightState state);
+
+ /**
+ * Discover what lights are supported by the HAL implementation.
+ *
+ * @return List of available lights
+ */
+ HwLight[] getLights();
+}
diff --git a/light/aidl/android/hardware/light/LightType.aidl b/light/aidl/android/hardware/light/LightType.aidl
new file mode 100644
index 0000000..9a7f656
--- /dev/null
+++ b/light/aidl/android/hardware/light/LightType.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.light;
+
+/**
+ * These light IDs correspond to logical lights, not physical.
+ * So for example, if your INDICATOR light is in line with your
+ * BUTTONS, it might make sense to also light the INDICATOR
+ * light to a reasonable color when the BUTTONS are lit.
+ */
+@VintfStability
+enum LightType {
+ BACKLIGHT = 0,
+ KEYBOARD = 1,
+ BUTTONS = 2,
+ BATTERY = 3,
+ NOTIFICATIONS = 4,
+ ATTENTION = 5,
+ BLUETOOTH = 6,
+ WIFI = 7,
+ MICROPHONE = 8,
+}
diff --git a/light/aidl/default/Android.bp b/light/aidl/default/Android.bp
new file mode 100644
index 0000000..ae3f463
--- /dev/null
+++ b/light/aidl/default/Android.bp
@@ -0,0 +1,16 @@
+cc_binary {
+ name: "android.hardware.lights-service.example",
+ relative_install_path: "hw",
+ init_rc: ["lights-default.rc"],
+ vintf_fragments: ["lights-default.xml"],
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.light-ndk_platform",
+ ],
+ srcs: [
+ "Lights.cpp",
+ "main.cpp",
+ ],
+}
diff --git a/light/aidl/default/Lights.cpp b/light/aidl/default/Lights.cpp
new file mode 100644
index 0000000..74747d5
--- /dev/null
+++ b/light/aidl/default/Lights.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Lights.h"
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace light {
+
+ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) {
+ LOG(INFO) << "Lights setting state for id=" << id << " to color " << std::hex << state.color;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Lights::getLights(std::vector<HwLight>* /*lights*/) {
+ LOG(INFO) << "Lights reporting supported lights";
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace light
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/light/aidl/default/Lights.h b/light/aidl/default/Lights.h
new file mode 100644
index 0000000..8cba5a1
--- /dev/null
+++ b/light/aidl/default/Lights.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/light/BnLights.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace light {
+
+// Default implementation that reports no supported lights.
+class Lights : public BnLights {
+ ndk::ScopedAStatus setLightState(int id, const HwLightState& state) override;
+ ndk::ScopedAStatus getLights(std::vector<HwLight>* types) override;
+};
+
+} // namespace light
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/light/aidl/default/lights-default.rc b/light/aidl/default/lights-default.rc
new file mode 100644
index 0000000..687ec97
--- /dev/null
+++ b/light/aidl/default/lights-default.rc
@@ -0,0 +1,5 @@
+service vendor.light-default /vendor/bin/hw/android.hardware.lights-service.example
+ class hal
+ user nobody
+ group nobody
+ shutdown critical
diff --git a/light/aidl/default/lights-default.xml b/light/aidl/default/lights-default.xml
new file mode 100644
index 0000000..db604d6
--- /dev/null
+++ b/light/aidl/default/lights-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.light</name>
+ <fqname>ILights/default</fqname>
+ </hal>
+</manifest>
diff --git a/light/aidl/default/main.cpp b/light/aidl/default/main.cpp
new file mode 100644
index 0000000..a860bf4
--- /dev/null
+++ b/light/aidl/default/main.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Lights.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::aidl::android::hardware::light::Lights;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<Lights> lights = ndk::SharedRefBase::make<Lights>();
+
+ const std::string instance = std::string() + Lights::descriptor + "/default";
+ binder_status_t status = AServiceManager_addService(lights->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reached
+}
diff --git a/light/aidl/vts/functional/Android.bp b/light/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..3dd8cf6
--- /dev/null
+++ b/light/aidl/vts/functional/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalLightTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "VtsHalLightTargetTest.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ ],
+ static_libs: [
+ "android.hardware.light-cpp",
+ ],
+ test_suites: [
+ "vts-core",
+ ],
+}
diff --git a/light/aidl/vts/functional/VtsHalLightTargetTest.cpp b/light/aidl/vts/functional/VtsHalLightTargetTest.cpp
new file mode 100644
index 0000000..3c26278
--- /dev/null
+++ b/light/aidl/vts/functional/VtsHalLightTargetTest.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "light_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android-base/logging.h>
+#include <android/hardware/light/ILights.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <unistd.h>
+#include <set>
+
+using android::ProcessState;
+using android::sp;
+using android::String16;
+using android::binder::Status;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::light::BrightnessMode;
+using android::hardware::light::FlashMode;
+using android::hardware::light::HwLight;
+using android::hardware::light::HwLightState;
+using android::hardware::light::ILights;
+using android::hardware::light::LightType;
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+const std::set<LightType> kAllTypes{android::enum_range<LightType>().begin(),
+ android::enum_range<LightType>().end()};
+
+class LightsAidl : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ lights = android::waitForDeclaredService<ILights>(String16(GetParam().c_str()));
+ ASSERT_NE(lights, nullptr);
+ ASSERT_TRUE(lights->getLights(&supportedLights).isOk());
+ }
+
+ sp<ILights> lights;
+ std::vector<HwLight> supportedLights;
+
+ virtual void TearDown() override {
+ for (const HwLight& light : supportedLights) {
+ HwLightState off;
+ off.color = 0x00000000;
+ off.flashMode = FlashMode::NONE;
+ off.brightnessMode = BrightnessMode::USER;
+ EXPECT_TRUE(lights->setLightState(light.id, off).isOk());
+ }
+
+ // must leave the device in a useable condition
+ for (const HwLight& light : supportedLights) {
+ if (light.type == LightType::BACKLIGHT) {
+ HwLightState backlightOn;
+ backlightOn.color = 0xFFFFFFFF;
+ backlightOn.flashMode = FlashMode::TIMED;
+ backlightOn.brightnessMode = BrightnessMode::USER;
+ EXPECT_TRUE(lights->setLightState(light.id, backlightOn).isOk());
+ }
+ }
+ }
+};
+
+/**
+ * Ensure all reported lights actually work.
+ */
+TEST_P(LightsAidl, TestSupported) {
+ HwLightState whiteFlashing;
+ whiteFlashing.color = 0xFFFFFFFF;
+ whiteFlashing.flashMode = FlashMode::TIMED;
+ whiteFlashing.flashOnMs = 100;
+ whiteFlashing.flashOffMs = 50;
+ whiteFlashing.brightnessMode = BrightnessMode::USER;
+ for (const HwLight& light : supportedLights) {
+ EXPECT_TRUE(lights->setLightState(light.id, whiteFlashing).isOk());
+ }
+}
+
+/**
+ * Ensure all reported lights have one of the supported types.
+ */
+TEST_P(LightsAidl, TestSupportedLightTypes) {
+ for (const HwLight& light : supportedLights) {
+ EXPECT_TRUE(kAllTypes.find(light.type) != kAllTypes.end());
+ }
+}
+
+/**
+ * Ensure all lights have a unique id.
+ */
+TEST_P(LightsAidl, TestUniqueIds) {
+ std::set<int> ids;
+ for (const HwLight& light : supportedLights) {
+ EXPECT_TRUE(ids.find(light.id) == ids.end());
+ ids.insert(light.id);
+ }
+}
+
+/**
+ * Ensure all lights have a unique ordinal for a given type.
+ */
+TEST_P(LightsAidl, TestUniqueOrdinalsForType) {
+ std::map<int, std::set<int>> ordinalsByType;
+ for (const HwLight& light : supportedLights) {
+ auto& ordinals = ordinalsByType[(int)light.type];
+ EXPECT_TRUE(ordinals.find(light.ordinal) == ordinals.end());
+ ordinals.insert(light.ordinal);
+ }
+}
+
+/**
+ * Ensure EX_UNSUPPORTED_OPERATION is returned if LOW_PERSISTENCE is not supported.
+ */
+TEST_P(LightsAidl, TestLowPersistence) {
+ HwLightState lowPersistence;
+ lowPersistence.color = 0xFF123456;
+ lowPersistence.flashMode = FlashMode::TIMED;
+ lowPersistence.flashOnMs = 100;
+ lowPersistence.flashOffMs = 50;
+ lowPersistence.brightnessMode = BrightnessMode::LOW_PERSISTENCE;
+ for (const HwLight& light : supportedLights) {
+ Status status = lights->setLightState(light.id, lowPersistence);
+ EXPECT_TRUE(status.isOk() || Status::EX_UNSUPPORTED_OPERATION == status.exceptionCode());
+ }
+}
+
+/**
+ * Ensure EX_UNSUPPORTED_OPERATION is returns for an invalid light id.
+ */
+TEST_P(LightsAidl, TestInvalidLightIdUnsupported) {
+ int maxId = INT_MIN;
+ for (const HwLight& light : supportedLights) {
+ maxId = std::max(maxId, light.id);
+ }
+
+ Status status = lights->setLightState(maxId + 1, HwLightState());
+ EXPECT_TRUE(status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION);
+}
+
+INSTANTIATE_TEST_SUITE_P(Lights, LightsAidl,
+ testing::ValuesIn(android::getAidlHalInstanceNames(ILights::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ ProcessState::self()->startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/light/utils/Android.bp b/light/utils/Android.bp
index 4c287e4..e901129 100644
--- a/light/utils/Android.bp
+++ b/light/utils/Android.bp
@@ -23,7 +23,11 @@
shared_libs: [
"android.hardware.light@2.0",
"libbase",
+ "libbinder",
"libhidlbase",
"libutils",
],
+ static_libs: [
+ "android.hardware.light-cpp",
+ ],
}
diff --git a/light/utils/main.cpp b/light/utils/main.cpp
index b834132..b9b6489 100644
--- a/light/utils/main.cpp
+++ b/light/utils/main.cpp
@@ -19,34 +19,23 @@
#include <android-base/logging.h>
#include <android/hardware/light/2.0/ILight.h>
+#include <android/hardware/light/ILights.h>
+#include <binder/IServiceManager.h>
+
+using android::sp;
+using android::waitForVintfService;
+using android::binder::Status;
+using android::hardware::hidl_vec;
+
+namespace V2_0 = android::hardware::light::V2_0;
+namespace aidl = android::hardware::light;
void error(const std::string& msg) {
LOG(ERROR) << msg;
std::cerr << msg << std::endl;
}
-int main(int argc, char* argv[]) {
- using ::android::hardware::hidl_vec;
- using ::android::hardware::light::V2_0::Brightness;
- using ::android::hardware::light::V2_0::Flash;
- using ::android::hardware::light::V2_0::ILight;
- using ::android::hardware::light::V2_0::LightState;
- using ::android::hardware::light::V2_0::Status;
- using ::android::hardware::light::V2_0::Type;
- using ::android::sp;
-
- sp<ILight> service = ILight::getService();
- if (service == nullptr) {
- error("Could not retrieve light service.");
- return -1;
- }
-
- static LightState off = {
- .color = 0u,
- .flashMode = Flash::NONE,
- .brightnessMode = Brightness::USER,
- };
-
+int parseArgs(int argc, char* argv[], unsigned int* color) {
if (argc > 2) {
error("Usage: blank_screen [color]");
return -1;
@@ -54,25 +43,78 @@
if (argc > 1) {
char* col_ptr;
- unsigned int col_new;
- col_new = strtoul(argv[1], &col_ptr, 0);
+ *color = strtoul(argv[1], &col_ptr, 0);
if (*col_ptr != '\0') {
error("Failed to convert " + std::string(argv[1]) + " to number");
return -1;
}
- off.color = col_new;
+
+ return 0;
}
- service->getSupportedTypes([&](const hidl_vec<Type>& types) {
- for (Type type : types) {
- Status ret = service->setLight(type, off);
- if (ret != Status::SUCCESS) {
- error("Failed to shut off screen for type " +
+ *color = 0u;
+ return 0;
+}
+
+void setToColorAidl(sp<aidl::ILights> hal, unsigned int color) {
+ static aidl::HwLightState off;
+ off.color = color;
+ off.flashMode = aidl::FlashMode::NONE;
+ off.brightnessMode = aidl::BrightnessMode::USER;
+
+ std::vector<aidl::HwLight> lights;
+ Status status = hal->getLights(&lights);
+ if (!status.isOk()) {
+ error("Failed to list lights");
+ return;
+ }
+
+ for (auto light : lights) {
+ Status setStatus = hal->setLightState(light.id, off);
+ if (!setStatus.isOk()) {
+ error("Failed to shut off light id " + std::to_string(light.id));
+ }
+ }
+}
+
+void setToColorHidl(sp<V2_0::ILight> hal, unsigned int color) {
+ static V2_0::LightState off = {
+ .color = color,
+ .flashMode = V2_0::Flash::NONE,
+ .brightnessMode = V2_0::Brightness::USER,
+ };
+
+ hal->getSupportedTypes([&](const hidl_vec<V2_0::Type>& types) {
+ for (auto type : types) {
+ V2_0::Status ret = hal->setLight(type, off);
+ if (ret != V2_0::Status::SUCCESS) {
+ error("Failed to shut off light for type " +
std::to_string(static_cast<int>(type)));
}
}
});
+}
- return 0;
+int main(int argc, char* argv[]) {
+ unsigned int inputColor;
+ int result = parseArgs(argc, argv, &inputColor);
+ if (result != 0) {
+ return result;
+ }
+
+ auto aidlHal = waitForVintfService<aidl::ILights>();
+ if (aidlHal != nullptr) {
+ setToColorAidl(aidlHal, inputColor);
+ return 0;
+ }
+
+ sp<V2_0::ILight> hidlHal = V2_0::ILight::getService();
+ if (hidlHal != nullptr) {
+ setToColorHidl(hidlHal, inputColor);
+ return 0;
+ }
+
+ error("Could not retrieve light service.");
+ return -1;
}
diff --git a/media/c2/1.1/Android.bp b/media/c2/1.1/Android.bp
new file mode 100644
index 0000000..c3e30b2
--- /dev/null
+++ b/media/c2/1.1/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.media.c2@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "IComponent.hal",
+ "IComponentStore.hal",
+ ],
+ interfaces: [
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.bufferqueue@2.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.media.bufferpool@2.0",
+ "android.hardware.media.c2@1.0",
+ "android.hardware.media.omx@1.0",
+ "android.hardware.media@1.0",
+ "android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/media/c2/1.1/IComponent.hal b/media/c2/1.1/IComponent.hal
new file mode 100644
index 0000000..97382dd
--- /dev/null
+++ b/media/c2/1.1/IComponent.hal
@@ -0,0 +1,72 @@
+/*
+ * 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.media.c2@1.1;
+
+import android.hardware.media.c2@1.0::IComponent;
+import android.hardware.media.c2@1.0::Status;
+
+/**
+ * Interface for a Codec2 component corresponding to API level 1.0 or below.
+ * Components have two states: stopped and running. The running state has three
+ * sub-states: executing, tripped and error.
+ *
+ * All methods in `IComponent` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status.
+ *
+ * @note This is an extension of version 1.0 of `IComponent`. The purpose of the
+ * extension is to add support for tunneling.
+ */
+interface IComponent extends @1.0::IComponent {
+ /**
+ * Configures a component for a tunneled playback mode.
+ *
+ * A successful call to this method puts the component in the *tunneled*
+ * mode. In this mode, the output `Worklet`s returned in
+ * IComponentListener::onWorkDone() may not contain any buffers. The output
+ * buffers are passed directly to the consumer end of a buffer queue whose
+ * producer side is configured with the returned @p sidebandStream passed
+ * to IGraphicBufferProducer::setSidebandStream().
+ *
+ * The component is initially in the non-tunneled mode by default. The
+ * tunneled mode can be toggled on only before the component starts
+ * processing. Once the component is put into the tunneled mode, it shall
+ * stay in the tunneled mode until and only until reset() is called.
+ *
+ * @param avSyncHwId A resource ID for hardware sync. The generator of sync
+ * IDs must ensure that this number is unique among all services at any
+ * given time. For example, if both the audio HAL and the tuner HAL
+ * support this feature, sync IDs from the audio HAL must not clash
+ * with sync IDs from the tuner HAL.
+ * @return status Status of the call, which may be
+ * - `OK` - The operation completed successfully. In this case,
+ * @p sidebandHandle shall not be a null handle.
+ * - `OMITTED` - The component does not support video tunneling.
+ * - `BAD_STATE` - The component is already running.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return sidebandHandle Codec-allocated sideband stream handle. This can
+ * be passed to IGraphicBufferProducer::setSidebandStream() to
+ * establish a direct channel to the consumer.
+ */
+ configureVideoTunnel(
+ uint32_t avSyncHwId
+ ) generates (
+ Status status,
+ handle sidebandHandle
+ );
+};
diff --git a/media/c2/1.1/IComponentStore.hal b/media/c2/1.1/IComponentStore.hal
new file mode 100644
index 0000000..38e0fc6
--- /dev/null
+++ b/media/c2/1.1/IComponentStore.hal
@@ -0,0 +1,64 @@
+/*
+ * 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.media.c2@1.1;
+
+import android.hardware.media.bufferpool@2.0::IClientManager;
+import android.hardware.media.c2@1.0::IComponentListener;
+import android.hardware.media.c2@1.0::IComponentStore;
+import android.hardware.media.c2@1.0::Status;
+
+import IComponent;
+
+/**
+ * Entry point for Codec2 HAL.
+ *
+ * All methods in `IComponentStore` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status. The only exceptions are getPoolClientManager() and getConfigurable(),
+ * which must always return immediately.
+ *
+ * @note This is an extension of version 1.0 of `IComponentStore`. The purpose
+ * of the extension is to add support for tunneling.
+ */
+interface IComponentStore extends @1.0::IComponentStore {
+ /**
+ * Creates a component by name.
+ *
+ * @param name Name of the component to create. This must match one of the
+ * names returned by listComponents().
+ * @param listener Callback receiver.
+ * @param pool `IClientManager` object of the BufferPool in the client
+ * process. This may be null if the client does not own a BufferPool.
+ * @return status Status of the call, which may be
+ * - `OK` - The component was created successfully.
+ * - `NOT_FOUND` - There is no component with the given name.
+ * - `NO_MEMORY` - Not enough memory to create the component.
+ * - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+ * - `CORRUPTED` - Some unknown error occurred.
+ * @return comp The created component if @p status is `OK`.
+ *
+ * @sa IComponentListener.
+ */
+ createComponent_1_1(
+ string name,
+ IComponentListener listener,
+ IClientManager pool
+ ) generates (
+ Status status,
+ IComponent comp
+ );
+};
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
index 4909214..599fd1d 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -272,7 +272,7 @@
int n;
std::tie(n, outputShapes, timing, std::ignore) =
controller->compute(request, testConfig.measureTiming, keys);
- executionStatus = nn::convertResultCodeToErrorStatus(n);
+ executionStatus = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(n));
break;
}
diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
index 416744f..ec9629b 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
@@ -296,7 +296,8 @@
// collect serialized result by running regular burst
const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] =
controllerRegular->compute(request, MeasureTiming::NO, keys);
- const ErrorStatus statusRegular = nn::convertResultCodeToErrorStatus(nRegular);
+ const ErrorStatus statusRegular =
+ nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nRegular));
EXPECT_FALSE(fallbackRegular);
// skip test if regular burst output isn't useful for testing a failure
@@ -312,7 +313,7 @@
// large enough to return the serialized result
const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] =
controllerSmall->compute(request, MeasureTiming::NO, keys);
- const ErrorStatus statusSmall = nn::convertResultCodeToErrorStatus(nSmall);
+ const ErrorStatus statusSmall = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nSmall));
EXPECT_NE(ErrorStatus::NONE, statusSmall);
EXPECT_EQ(0u, outputShapesSmall.size());
EXPECT_TRUE(badTiming(timingSmall));
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index a14b86b..30530be 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -216,7 +216,7 @@
case OperandType::TENSOR_QUANT8_ASYMM:
return {-1, 256};
case OperandType::TENSOR_QUANT8_SYMM:
- return {-129, -1, 1, 128};
+ return {-129, -1, 1, 128};
case OperandType::TENSOR_QUANT16_ASYMM:
return {-1, 65536};
case OperandType::TENSOR_QUANT16_SYMM:
@@ -482,15 +482,15 @@
}
}
}
- // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have
- // either one or two outputs depending on their mergeOutputs parameter.
+ // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have either one or two
+ // outputs depending on their mergeOutputs parameter.
if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM ||
operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) {
- for (const size_t outOprand : operation.outputs) {
- if (operand == outOprand) {
- return true;
+ for (const size_t outOprand : operation.outputs) {
+ if (operand == outOprand) {
+ return true;
+ }
}
- }
}
}
return false;
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index 2d83b81..7b5ff9b 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -107,7 +107,7 @@
// execute and verify
const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys);
- const ErrorStatus status = nn::convertResultCodeToErrorStatus(n);
+ const ErrorStatus status = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(n));
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
EXPECT_EQ(outputShapes.size(), 0);
EXPECT_TRUE(badTiming(timing));
diff --git a/neuralnetworks/1.3/Android.bp b/neuralnetworks/1.3/Android.bp
index 0b07a58..7b02cc5 100644
--- a/neuralnetworks/1.3/Android.bp
+++ b/neuralnetworks/1.3/Android.bp
@@ -8,7 +8,10 @@
},
srcs: [
"types.hal",
+ "IBuffer.hal",
"IDevice.hal",
+ "IExecutionCallback.hal",
+ "IFencedExecutionCallback.hal",
"IPreparedModel.hal",
"IPreparedModelCallback.hal",
],
diff --git a/neuralnetworks/1.3/IBuffer.hal b/neuralnetworks/1.3/IBuffer.hal
new file mode 100644
index 0000000..dfc57fe
--- /dev/null
+++ b/neuralnetworks/1.3/IBuffer.hal
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.neuralnetworks@1.3;
+
+import ErrorStatus;
+
+/**
+ * This interface represents a device memory buffer.
+ */
+interface IBuffer {
+ /**
+ * Retrieves the content of this buffer to a shared memory region.
+ *
+ * The IBuffer object must have been initialized before the call to IBuffer::copyTo.
+ * For more information on the state of the IBuffer object, refer to IDevice::allocate.
+ *
+ * @param dst The destination shared memory region.
+ * @return status Error status of the call, must be:
+ * - NONE if successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if the IBuffer object is uninitialized, or there is an unspecified
+ * error
+ * - INVALID_ARGUMENT if provided memory is invalid
+ */
+ copyTo(memory dst) generates (ErrorStatus status);
+
+ /**
+ * Sets the content of this buffer from a shared memory region.
+ *
+ * @param src The source shared memory region.
+ * @param dimensions Updated dimensional information. If the dimensions of the IBuffer object
+ * are not fully specified, then the dimensions must be fully specified here. If the
+ * dimensions of the IBuffer object are fully specified, then the dimensions may be empty
+ * here. If dimensions.size() > 0, then all dimensions must be specified here, and any
+ * dimension that was specified in the IBuffer object must have the same value here.
+ * @return status Error status of the call, must be:
+ * - NONE if successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if provided memory is invalid, or if the dimensions is invalid
+ */
+ copyFrom(memory src, vec<uint32_t> dimensions) generates (ErrorStatus status);
+};
diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal
index 1295d6a..610db79 100644
--- a/neuralnetworks/1.3/IDevice.hal
+++ b/neuralnetworks/1.3/IDevice.hal
@@ -16,12 +16,20 @@
package android.hardware.neuralnetworks@1.3;
-import @1.0::ErrorStatus;
import @1.1::ExecutionPreference;
import @1.2::Constant;
import @1.2::DeviceType;
import @1.2::Extension;
import @1.2::IDevice;
+import BufferDesc;
+import BufferRole;
+import Capabilities;
+import ErrorStatus;
+import Model;
+import OptionalTimePoint;
+import Priority;
+import IBuffer;
+import IPreparedModel;
import IPreparedModelCallback;
/**
@@ -40,11 +48,29 @@
getCapabilities_1_3() generates (ErrorStatus status, Capabilities capabilities);
/**
+ * Returns whether the device is able to complete or abort a task within a
+ * specified duration.
+ *
+ * @return prepareModelDeadline 'true' if the device supports completing or
+ * aborting model preparation by the deadline when the deadline is supplied,
+ * 'false' otherwise.
+ * @return executionDeadline 'true' if the device supports completing or
+ * aborting an execution by the deadline when the deadline is supplied,
+ * 'false' otherwise.
+ */
+ supportsDeadlines() generates (bool prepareModelDeadline, bool executionDeadline);
+
+ /**
* Gets the supported operations in a model.
*
- * getSupportedOperations indicates which operations of a model are fully
- * supported by the vendor driver. If an operation may not be supported for
- * any reason, getSupportedOperations must return false for that operation.
+ * getSupportedOperations indicates which operations of the top-level
+ * subgraph are fully supported by the vendor driver. If an operation may
+ * not be supported for any reason, getSupportedOperations must return
+ * false for that operation.
+ *
+ * The {@link OperationType::IF} and {@link OperationType::WHILE}
+ * operations may only be fully supported if the vendor driver fully
+ * supports all operations in the referenced subgraphs.
*
* @param model A model whose operations--and their corresponding operands--
* are to be verified by the driver.
@@ -107,6 +133,22 @@
* the callback object must be invoked with the appropriate ErrorStatus
* value and nullptr for the IPreparedModel.
*
+ * The model is prepared with a priority. This priority is relative to other
+ * prepared models owned by the same client. Higher priority executions may
+ * use more compute resources than lower priority executions, and may
+ * preempt or starve lower priority executions.
+ *
+ * prepareModel_1_3 can be called with an optional deadline. If the model
+ * is not able to be prepared before the provided deadline, the model
+ * preparation must be aborted, and either {@link
+ * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
+ * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
+ * to an abort must be sent the same way as other errors, described above.
+ * If the service reports that it does not support preparation deadlines via
+ * IDevice::supportsDeadlines, and prepareModel_1_3 is called with a
+ * deadline, then the argument is invalid, and {@link
+ * ErrorStatus::INVALID_ARGUMENT} must be returned.
+ *
* Optionally, the driver may save the prepared model to cache during the
* asynchronous preparation. Any error that occurs when saving to cache must
* not affect the status of preparing the model. Even if the input arguments
@@ -128,6 +170,11 @@
* @param model The model to be prepared for execution.
* @param preference Indicates the intended execution behavior of a prepared
* model.
+ * @param priority The priority of the prepared model relative to other
+ * prepared models owned by the client.
+ * @param deadline The time by which the model must be prepared. If the
+ * model cannot be prepared by the deadline, the preparation must be
+ * aborted.
* @param modelCache A vector of handles with each entry holding exactly one
* cache file descriptor for the security-sensitive cache. The length of
* the vector must either be 0 indicating that caching information is
@@ -162,8 +209,12 @@
* - GENERAL_FAILURE if there is an unspecified error
* - INVALID_ARGUMENT if one of the input arguments related to preparing
* the model is invalid
+ * - MISSED_DEADLINE_* if the deadline for preparing a model cannot be
+ * met
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
prepareModel_1_3(Model model, ExecutionPreference preference,
+ Priority priority, OptionalTimePoint deadline,
vec<handle> modelCache, vec<handle> dataCache,
uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token,
IPreparedModelCallback callback)
@@ -209,6 +260,22 @@
* the model, the callback object must be invoked with the appropriate
* ErrorStatus value and nullptr for the IPreparedModel.
*
+ * The model is prepared with a priority. This priority is relative to other
+ * prepared models owned by the same client. Higher priority executions may
+ * use more compute resources than lower priority executions, and may
+ * preempt or starve lower priority executions.
+ *
+ * prepareModelFromCache_1_3 can be called with an optional deadline. If the
+ * model is not able to prepared before the provided deadline, the model
+ * preparation must be aborted, and either {@link
+ * ErrorStatus::MISSED_DEADLINE_TRANSIENT}
+ * or {@link ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The
+ * error due to an abort must be sent the same way as other errors,
+ * described above. If the service reports that it does not support
+ * preparation deadlines via IDevice::supportsDeadlines, and
+ * prepareModelFromCache_1_3 is called with a deadline, then the argument is
+ * invalid, and {@link ErrorStatus::INVALID_ARGUMENT} must be returned.
+ *
* The only information that may be unknown to the model at this stage is
* the shape of the tensors, which may only be known at execution time. As
* such, some driver services may return partially prepared models, where
@@ -217,6 +284,11 @@
* used with different shapes of inputs on different (possibly concurrent)
* executions.
*
+ * @param priority The priority of the prepared model relative to other
+ * prepared models owned by the client.
+ * @param deadline The time by which the model must be prepared. If the
+ * model cannot be prepared by the deadline, the preparation must be
+ * aborted.
* @param modelCache A vector of handles with each entry holding exactly one
* cache file descriptor for the security-sensitive cache. The length of
* the vector must match the numModelCache returned from getNumberOfCacheFilesNeeded.
@@ -242,9 +314,70 @@
* - GENERAL_FAILURE if caching is not supported or if there is an
* unspecified error
* - INVALID_ARGUMENT if one of the input arguments is invalid
+ * - MISSED_DEADLINE_* if the deadline for preparing a model cannot be
+ * met
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
- prepareModelFromCache_1_3(vec<handle> modelCache, vec<handle> dataCache,
+ prepareModelFromCache_1_3(Priority priority, OptionalTimePoint deadline,
+ vec<handle> modelCache, vec<handle> dataCache,
uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token,
IPreparedModelCallback callback)
generates (ErrorStatus status);
+
+ /**
+ * Allocates a driver-managed buffer with the properties specified by the buffer descriptor
+ * as well as the input and output roles.
+ *
+ * The allocate function must verify its inputs are correct. If there is an error, or if a
+ * certain role or property is not supported by the driver, the allocate
+ * function must return with an appropriate ErrorStatus, a nullptr as the IBuffer, and 0 as the
+ * buffer token. If the allocation is successful, this method must return with ErrorStatus::NONE
+ * and the produced IBuffer with a positive token identifying the allocated buffer. A successful
+ * allocation must accommodate all of the specified roles and buffer properties.
+ *
+ * The buffer is allocated to an uninitialized state. An uninitialized buffer may only be used
+ * in ways that are specified by outputRoles. A buffer is initialized after it is used as an
+ * output in a successful execution, or after a successful invocation of IBuffer::copyFrom on
+ * the buffer. An initialized buffer may be used according to all roles specified in inputRoles
+ * and outputRoles. A buffer will return to the uninitialized state if it is used as an output
+ * in a failed execution, or after a failed invocation of IBuffer::copyFrom on the buffer.
+ *
+ * The dimensions of the buffer can be deduced from the buffer descriptor as well as the
+ * dimensions of the corresponding model operands of the input and output roles. The dimensions
+ * or rank of the buffer may be unknown at this stage. As such, some driver services may only
+ * create a placeholder and defer the actual allocation until execution time. Note that the
+ * same buffer may be used for different shapes of outputs on different executions. When the
+ * buffer is used as an input, the input shape must be the same as the output shape from the
+ * last execution using this buffer as an output.
+ *
+ * The driver must apply proper validatation upon every usage of the buffer, and must fail the
+ * execution immediately if the usage is illegal.
+ *
+ * @param desc A buffer descriptor specifying the properties of the buffer to allocate.
+ * @param preparedModels A vector of IPreparedModel objects. Must only contain IPreparedModel
+ * objects from the same IDevice as this method is being invoked on.
+ * @param inputRoles A vector of roles with each specifying an input to a prepared model.
+ * @param outputRoles A vector of roles with each specifying an output to a prepared model.
+ * Each role specified in inputRoles and outputRoles must be unique. The corresponding
+ * model operands of the roles must have the same OperandType, scale, zero point, and
+ * ExtraParams. The dimensions of the operands and the dimensions specified in the buffer
+ * descriptor must be compatible with each other. Two dimensions are incompatible if there
+ * is at least one axis that is fully specified in both but has different values.
+ * @return status Error status of the buffer allocation. Must be:
+ * - NONE if successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if a certain buffer property or a certain role is not supported,
+ * or if there is an unspecified error
+ * - INVALID_ARGUMENT if one of the input arguments is invalid
+ * @return buffer The allocated IBuffer object. If the buffer was unable to be allocated
+ * due to an error, nullptr must be returned.
+ * @return token A positive token identifying the allocated buffer. The same token will be
+ * provided when referencing the buffer as one of the memory pools in the request of an
+ * execution. The token must not collide with the tokens of other IBuffer objects that are
+ * currently alive in the same driver service. If the buffer was unable to be allocated
+ * due to an error, the token must be 0.
+ */
+ allocate(BufferDesc desc, vec<IPreparedModel> preparedModels, vec<BufferRole> inputRoles,
+ vec<BufferRole> outputRoles)
+ generates (ErrorStatus status, IBuffer buffer, int32_t token);
};
diff --git a/neuralnetworks/1.3/IExecutionCallback.hal b/neuralnetworks/1.3/IExecutionCallback.hal
new file mode 100644
index 0000000..439428a
--- /dev/null
+++ b/neuralnetworks/1.3/IExecutionCallback.hal
@@ -0,0 +1,64 @@
+/*
+ * 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.neuralnetworks@1.3;
+
+import @1.2::IExecutionCallback;
+import @1.2::OutputShape;
+import @1.2::Timing;
+
+/**
+ * IExecutionCallback must be used to return the error status result from an
+ * execution asynchronously launched from IPreparedModel::execute*.
+ */
+interface IExecutionCallback extends @1.2::IExecutionCallback {
+
+ /**
+ * There are three notify methods declared for the IExecutionCallback
+ * interface: notify_1_3, notify_1_2, and notify. One of the three notify
+ * methods must be invoked immediately after the asynchronous task has
+ * finished performing the execution. One of the notify methods must be
+ * provided with the ErrorStatus from the execution. If the asynchronous
+ * task is not launched, one of the notify methods must be invoked with the
+ * appropriate error.
+ *
+ * @param status Error status returned from launching the asynchronous task
+ * (if the launch fails) or from the asynchronous task itself
+ * (if the launch succeeds). Must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if the asynchronous task resulted in an
+ * unspecified error
+ * - OUTPUT_INSUFFICIENT_SIZE if at least one output
+ * operand buffer is not large enough to store the
+ * corresponding output
+ * - INVALID_ARGUMENT if one of the input arguments to
+ * prepareModel is invalid
+ * - MISSED_DEADLINE_* if the deadline could not be met
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
+ * @param outputShapes A list of shape information of model output operands.
+ * The index into "outputShapes" corresponds with to index
+ * of the output operand in the Request outputs vector.
+ * outputShapes must be empty unless the status is either
+ * NONE or OUTPUT_INSUFFICIENT_SIZE.
+ * @param timing Duration of execution. Unless MeasureTiming::YES was passed when
+ * launching the execution and status is NONE, all times must
+ * be reported as UINT64_MAX. A driver may choose to report
+ * any time as UINT64_MAX, indicating that particular measurement is
+ * not available.
+ */
+ oneway notify_1_3(ErrorStatus status, vec<OutputShape> outputShapes, Timing timing);
+};
diff --git a/neuralnetworks/1.3/IFencedExecutionCallback.hal b/neuralnetworks/1.3/IFencedExecutionCallback.hal
new file mode 100644
index 0000000..39076b9
--- /dev/null
+++ b/neuralnetworks/1.3/IFencedExecutionCallback.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.neuralnetworks@1.3;
+
+import @1.2::Timing;
+import ErrorStatus;
+
+/**
+ * IFencedExecutionCallback can be used to query the error status result
+ * and duration information from an IPreparedModel::executeFenced call.
+ */
+interface IFencedExecutionCallback {
+
+ /**
+ * The getExecutionInfo method is used by the clients to query error status
+ * result and duration information. The method must only be called after the actual
+ * evaluation has finished or resulted in an runtime error, as indicated by the status
+ * of the sync fence returned by the IPreparedModel::executeFenced call, otherwise
+ * GENERAL_FAILURE must be returned.
+ *
+ * @return status Error status returned from the asynchronously dispatched execution
+ * must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if the asynchronous task resulted in an
+ * unspecified error
+ * @return timing Duration of execution. Unless MeasureTiming::YES was passed when
+ * launching the execution and status is NONE, all times must
+ * be reported as UINT64_MAX. A driver may choose to report
+ * any time as UINT64_MAX, indicating that particular measurement is
+ * not available.
+ */
+ getExecutionInfo() generates (ErrorStatus status, Timing timing);
+};
diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal
index 7aea416..f84bcf4 100644
--- a/neuralnetworks/1.3/IPreparedModel.hal
+++ b/neuralnetworks/1.3/IPreparedModel.hal
@@ -16,13 +16,15 @@
package android.hardware.neuralnetworks@1.3;
-import @1.0::ErrorStatus;
-import @1.0::Request;
-import @1.2::IExecutionCallback;
import @1.2::IPreparedModel;
import @1.2::MeasureTiming;
import @1.2::OutputShape;
import @1.2::Timing;
+import ErrorStatus;
+import OptionalTimePoint;
+import Request;
+import IExecutionCallback;
+import IFencedExecutionCallback;
/**
* IPreparedModel describes a model that has been prepared for execution and
@@ -33,7 +35,8 @@
* Launches an asynchronous execution on a prepared model.
*
* The execution is performed asynchronously with respect to the caller.
- * execute_1_3 must verify the inputs to the function are correct. If there is
+ * execute_1_3 must verify the inputs to the function are correct, and the usages
+ * of memory pools allocated by IDevice::allocate are valid. If there is
* an error, execute_1_3 must immediately invoke the callback with the
* appropriate ErrorStatus value, then return with the same ErrorStatus. If
* the inputs to the function are valid and there is no error, execute_1_3 must
@@ -64,6 +67,17 @@
* values, the execution should complete successfully (ErrorStatus::NONE):
* There must be no failure unless the device itself is in a bad state.
*
+ * execute_1_3 can be called with an optional deadline. If the execution
+ * is not able to completed before the provided deadline, the execution
+ * must be aborted, and either {@link
+ * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
+ * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
+ * to an abort must be sent the same way as other errors, described above.
+ * If the service reports that it does not support execution deadlines via
+ * IDevice::supportsDeadlines, and execute_1_3 is called with a deadline,
+ * then the argument is invalid, and {@link ErrorStatus::INVALID_ARGUMENT}
+ * must be returned.
+ *
* Any number of calls to the execute* and executeSynchronously* functions,
* in any combination, may be made concurrently, even on the same
* IPreparedModel object.
@@ -74,8 +88,12 @@
* The duration runs from the time the driver sees the call
* to the execute_1_3 function to the time the driver invokes
* the callback.
+ * @param deadline The time by which execution must complete. If the
+ * execution cannot be finished by the deadline, the
+ * execution must be aborted.
* @param callback A callback object used to return the error status of
- * the execution. The callback object's notify function must
+ * the execution, shape information of model output operands, and
+ * duration of execution. The callback object's notify function must
* be called exactly once, even if the execution was
* unsuccessful.
* @return status Error status of the call, must be:
@@ -86,8 +104,13 @@
* not large enough to store the resultant values
* - INVALID_ARGUMENT if one of the input arguments is
* invalid
+ * - MISSED_DEADLINE_* if the deadline for executing a model
+ * cannot be met
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the
+ * driver
*/
- execute_1_3(Request request, MeasureTiming measure, IExecutionCallback callback)
+ execute_1_3(Request request, MeasureTiming measure, OptionalTimePoint deadline,
+ IExecutionCallback callback)
generates (ErrorStatus status);
/**
@@ -95,7 +118,8 @@
*
* 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
+ * correct, and the usages of memory pools allocated by IDevice::allocate
+ * are valid. 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
@@ -114,6 +138,17 @@
* (ErrorStatus::NONE): There must be no failure unless the device itself is
* in a bad state.
*
+ * executeSynchronously_1_3 can be called with an optional deadline. If the
+ * execution is not able to completed before the provided deadline, the
+ * execution must be aborted, and either {@link
+ * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
+ * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
+ * to an abort must be sent the same way as other errors, described above.
+ * If the service reports that it does not support execution deadlines via
+ * IDevice::supportsDeadlines, and executeSynchronously_1_3 is called with a
+ * deadline, then the argument is invalid, and
+ * {@link ErrorStatus::INVALID_ARGUMENT} must be returned.
+ *
* Any number of calls to the execute* and executeSynchronously* functions,
* in any combination, may be made concurrently, even on the same
* IPreparedModel object.
@@ -124,6 +159,9 @@
* The duration runs from the time the driver sees the call
* to the executeSynchronously_1_3 function to the time the driver
* returns from the function.
+ * @param deadline The time by which execution must complete. If the
+ * execution cannot be finished by the deadline, the
+ * execution must be aborted.
* @return status Error status of the execution, must be:
* - NONE if execution is performed successfully
* - DEVICE_UNAVAILABLE if driver is offline or busy
@@ -133,16 +171,75 @@
* corresponding output
* - INVALID_ARGUMENT if one of the input arguments is
* invalid
+ * - MISSED_DEADLINE_* if the deadline for executing a model
+ * cannot be met
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the
+ * driver
* @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
+ * @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);
+ executeSynchronously_1_3(Request request, MeasureTiming measure,
+ OptionalTimePoint deadline)
+ generates (ErrorStatus status, vec<OutputShape> outputShapes,
+ Timing timing);
+
+ /**
+ * Launch a fenced asynchronous execution on a prepared model.
+ *
+ * The execution is performed asynchronously with respect to the caller.
+ * executeFenced must fully validate the request, and only accept one that is
+ * guaranteed to be completed, unless a hardware failure or kernel panic happens on the device.
+ * If there is an error during validation, executeFenced must immediately return with
+ * the corresponding ErrorStatus. If the request is valid and there is no error launching,
+ * executeFenced must dispatch an asynchronous task to perform the execution in the
+ * background, and immediately return with ErrorStatus::NONE, a sync_fence that will be
+ * signaled once the execution is completed, and a callback that can be used by the client
+ * to query the duration and runtime error status. If the task has finished
+ * before the call returns, empty handle may be returned for the sync fence. If the
+ * asynchronous task fails to launch, executeFenced must immediately return with
+ * ErrorStatus::GENERAL_FAILURE, and empty handle for the sync fence and nullptr
+ * for callback. The execution must wait for all the sync fences (if any) in wait_for to be
+ * signaled before starting the actual execution.
+ *
+ * If any of sync fences in wait_for changes to error status after the executeFenced
+ * call succeeds, the driver must immediately set the returned sync fence to error status.
+ *
+ * When the asynchronous task has finished its execution, it must
+ * immediately signal the sync_fence created when dispatching. After
+ * the sync_fence is signaled, the task must not modify the content of
+ * any data object referenced by 'request' (described by the
+ * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}).
+ *
+ * Any number of calls to the executeFenced, execute* and executeSynchronously*
+ * functions, in any combination, may be made concurrently, even on the same
+ * IPreparedModel object.
+ *
+ * @param request The input and output information on which the prepared
+ * model is to be executed.
+ * @param waitFor A vector of sync fence file descriptors.
+ * Execution must not start until all sync fences have been signaled.
+ * @param measure Specifies whether or not to measure duration of the execution.
+ * The duration runs from the time the driver sees the call
+ * to the executeFenced function to the time sync_fence is triggered.
+ * @return status Error status of the call, must be:
+ * - NONE if task is successfully launched
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if one of the input arguments is invalid, including
+ * fences in error states.
+ * @return syncFence The sync fence that will be triggered when the task is completed.
+ * The sync fence will be set to error if a critical error,
+ * e.g. hardware failure or kernel panic, occurs when doing execution.
+ * @return callback The IFencedExecutionCallback can be used to query information like duration
+ * and error status when the execution is completed.
+ */
+ executeFenced(Request request, vec<handle> waitFor, MeasureTiming measure)
+ generates (ErrorStatus status, handle syncFence, IFencedExecutionCallback callback);
};
diff --git a/neuralnetworks/1.3/IPreparedModelCallback.hal b/neuralnetworks/1.3/IPreparedModelCallback.hal
index ff295a2..11ebbf4 100644
--- a/neuralnetworks/1.3/IPreparedModelCallback.hal
+++ b/neuralnetworks/1.3/IPreparedModelCallback.hal
@@ -16,7 +16,6 @@
package android.hardware.neuralnetworks@1.3;
-import @1.0::ErrorStatus;
import @1.2::IPreparedModelCallback;
import IPreparedModel;
@@ -48,6 +47,10 @@
* unspecified error
* - INVALID_ARGUMENT if one of the input arguments to
* prepareModel is invalid
+ * - MISSED_DEADLINE_* if the deadline for executing a model
+ * cannot be met
+ * - RESOURCE_EXHAUSTED_* if the task was aborted by the
+ * driver
* @param preparedModel A model that has been asynchronously prepared for
* execution. If the model was unable to be prepared
* due to an error, nullptr must be passed in place of
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index 62c5833..abc33e7 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -17,8 +17,11 @@
package android.hardware.neuralnetworks@1.3;
import @1.0::DataLocation;
-import @1.0::OperandLifeTime;
+import @1.0::ErrorStatus;
import @1.0::PerformanceInfo;
+import @1.0::RequestArgument;
+import @1.2::Model.ExtensionNameAndPrefix;
+import @1.2::Model.ExtensionTypeEncoding;
import @1.2::OperandType;
import @1.2::OperationType;
import @1.2::SymmPerChannelQuantParams;
@@ -39,6 +42,13 @@
*/
TENSOR_QUANT8_ASYMM_SIGNED = 14,
+ /**
+ * A reference to a subgraph.
+ *
+ * Must have the lifetime {@link OperandLifeTime::SUBGRAPH}.
+ */
+ SUBGRAPH = 15,
+
/*
* DEPRECATED. Since HAL version 1.2, extensions are the preferred
* alternative to OEM operation and data types.
@@ -67,7 +77,7 @@
enum OperandTypeRange : uint32_t {
BASE_MIN = 0,
FUNDAMENTAL_MIN = 0,
- FUNDAMENTAL_MAX = 14,
+ FUNDAMENTAL_MAX = 15,
OEM_MIN = 10000,
OEM_MAX = 10001,
BASE_MAX = 0xFFFF,
@@ -1405,6 +1415,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
*
@@ -1415,6 +1426,8 @@
* * 2: An {@link OperandType::INT32} scalar, and has to be one of the
* {@link FusedActivationFunc} values. Specifies the activation to
* invoke on the result.
+ * For a {@link OperandType::TENSOR_INT32} tensor,
+ * the {@link FusedActivationFunc} must be "NONE".
*
* Outputs:
* * 0: The product, a tensor of the same {@link OperandType} as input0.
@@ -1895,6 +1908,11 @@
* dimensions. The output is the result of dividing the first input tensor
* by the second, optionally modified by an activation function.
*
+ * For inputs of {@link OperandType::TENSOR_INT32}, performs
+ * "floor division" ("//" in Python). For example,
+ * 5 // 2 = 2
+ * -5 // 2 = -3
+ *
* Two dimensions are compatible when:
* 1. they are equal, or
* 2. one of them is 1
@@ -1915,6 +1933,7 @@
* Supported tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
* * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
*
* Supported tensor rank: up to 4
*
@@ -1925,6 +1944,8 @@
* * 2: An {@link OperandType::INT32} scalar, and has to be one of the
* {@link FusedActivationFunc} values. Specifies the activation to
* invoke on the result.
+ * For a {@link OperandType::TENSOR_INT32} tensor,
+ * the {@link FusedActivationFunc} must be "NONE".
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
@@ -2176,6 +2197,7 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
* * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+ * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
*
* Supported tensor rank: up to 4
*
@@ -2186,6 +2208,8 @@
* * 2: An {@link OperandType::INT32} scalar, and has to be one of the
* {@link FusedActivationFunc} values. Specifies the activation to
* invoke on the result.
+ * For a {@link OperandType::TENSOR_INT32} tensor,
+ * the {@link FusedActivationFunc} must be "NONE".
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
@@ -2232,6 +2256,7 @@
* Supported tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
*
* Supported tensor rank: from 1.
*
@@ -4876,6 +4901,192 @@
QUANTIZED_LSTM = 95,
/**
+ * Executes one of the two referenced subgraphs as determined by a boolean
+ * value.
+ *
+ * The inputs and outputs of the two referenced subgraphs must agree with the
+ * signature of this operation. That is, if the operation has (3 + n) inputs
+ * and m outputs, both subgraphs must have n inputs and m outputs with the same
+ * types as the corresponding operation inputs and outputs.
+ *
+ * Inputs:
+ * * 0: A value of type {@link OperandType::TENSOR_BOOL8} and shape [1]
+ * that determines which of the two referenced subgraphs to execute.
+ * * 1: A {@link OperandType::SUBGRAPH} reference to the subgraph to be
+ * executed if the condition is true.
+ * * 2: A {@link OperandType::SUBGRAPH} reference to the subgraph to be
+ * executed if the condition is false.
+ * * 3 ~ (n + 2): Inputs to be passed to the subgraph selected for execution.
+ *
+ * Outputs:
+ * * 0 ~ (m - 1): Outputs produced by the selected subgraph.
+ */
+ IF = 96,
+
+ /**
+ * Executes the body subgraph until the condition subgraph outputs false.
+ *
+ * The inputs to this operation are the condition subgraph, the body subgraph,
+ * and operand values for the first iteration of the loop. The values are
+ * implicitly split into three groups of input-output, state-only, and
+ * input-only values, as described below.
+ *
+ * The outputs of this operation are the final values of input-output
+ * operands.
+ *
+ * Both the condition and body subgraph receive (m + k + n) inputs.
+ * * The first m (m >= 1) inputs are input-output operands. For the first
+ * iteration, these are initialized from the corresponding inputs of the
+ * WHILE operation. In subsequent iterations, their values come from the
+ * corresponding outputs of the body subgraph produced during the previous
+ * iteration.
+ * * The next k (k >= 0) inputs are state-only operands. They are similar to
+ * the input-output operands, except that their values are no longer
+ * available after the loop terminates.
+ * * The last n (n >= 0) inputs are input-only operands. Their values come
+ * from the corresponding inputs of the WHILE operation.
+ *
+ * The body subgraph produces (m + k) outputs.
+ * * The first m outputs are input-output operands. They become the outputs
+ * of the WHILE operation when a termination condition is reached.
+ * * The last k outputs are state-only operands. Their values are no longer
+ * available after the loop terminates.
+ *
+ * The numbers m, k, and n are inferred by the driver as follows:
+ * m = (WHILE operation output count)
+ * k = (body subgraph output count) - m
+ * n = (body subgraph input count) - m - k
+ *
+ * The pseudo-code below illustrates the flow of a WHILE operation with
+ * inputs condition, body, initial_input_output, initial_state, input_only
+ * (m = 1, k = 1, n = 1):
+ *
+ * input_output = initial_input_output
+ * state = initial_state
+ * while condition(input_output, state, input_only):
+ * input_output, state = body(input_output, state, input_only)
+ * return input_output
+ *
+ * Inputs:
+ * * 0: A {@link OperandType::SUBGRAPH} reference to the condition
+ * subgraph. The subgraph must have (m + k + n) inputs with
+ * the same types as the corresponding inputs of the WHILE operation
+ * and exactly one output of {@link OperandType::TENSOR_BOOL8}
+ * and shape [1].
+ * * 1: A {@link OperandType::SUBGRAPH} reference to the body subgraph.
+ * The subgraph must have (m + k + n) inputs and (m + k) outputs with
+ * the same types as the corresponding inputs and outputs of the WHILE
+ * operation.
+ * * (m inputs): Initial values for input-output operands.
+ * * (k inputs): Initial values for state-only operands.
+ * * (n inputs): Values for input-only operands.
+ *
+ * Outputs:
+ * * 0 ~ (m - 1): Outputs produced by the loop.
+ */
+ WHILE = 97,
+
+ /**
+ * Computes exponential linear activation on the input tensor element-wise.
+ *
+ * The output is calculated using the following formula:
+ *
+ * ELU(x) = max(0, x) + min(0, alpha * (exp(x) - 1))
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT16}
+ * * {@link OperandType::TENSOR_FLOAT32}
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input. May be zero-sized.
+ * * 1: A scalar, specifying the alpha parameter.
+ * For input tensor of {@link OperandType::TENSOR_FLOAT16},
+ * the alpha value must be of {@link OperandType::FLOAT16}.
+ * For input tensor of {@link OperandType::TENSOR_FLOAT32},
+ * the alpha value must be of {@link OperandType::FLOAT32}.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape and type as input0.
+ */
+ ELU = 98,
+
+ /**
+ * Computes hard-swish activation on the input tensor element-wise.
+ *
+ * Hard swish activation is introduced in
+ * https://arxiv.org/pdf/1905.02244.pdf
+ *
+ * The output is calculated using the following formula:
+ *
+ * h-swish(x) = x * max(0, min(6, (x + 3))) / 6
+
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT16}
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input. May be zero-sized.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape and type as input0.
+ * Scale and zero point of this tensor may be different from the input
+ * tensor's parameters.
+ */
+ HARD_SWISH = 99,
+
+ /**
+ * Creates a tensor filled with a scalar value.
+ *
+ * Supported output tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT16}
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_INT32}
+ *
+ * Inputs:
+ * * 0: A 1-D tensor, specifying the desired output tensor shape.
+ * * 1: A scalar, specifying the value to fill the output tensors with.
+ * For output tensor of {@link OperandType::TENSOR_FLOAT16},
+ * the scalar must be of {@link OperandType::FLOAT16}.
+ * For output tensor of {@link OperandType::TENSOR_FLOAT32},
+ * the scalar must be of {@link OperandType::FLOAT32}.
+ * For output tensor of {@link OperandType::TENSOR_INT32},
+ * the scalar must be of {@link OperandType::INT32}.
+ *
+ * Outputs:
+ * * 0: The output tensor.
+ */
+ FILL = 100,
+
+ /**
+ * Returns the rank of a tensor.
+ *
+ * The rank of a tensor is the number of dimensions in it. Also known as
+ * "order", "degree", "ndims".
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT16}
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_INT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT16_SYMM}
+ * * {@link OperandType::TENSOR_BOOL8}
+ * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
+ * * {@link OperandType::TENSOR_QUANT16_ASYMM}
+ * * {@link OperandType::TENSOR_QUANT8_SYMM}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+ *
+ * Inputs:
+ * * 0: The input tensor.
+ *
+ * Outputs:
+ * * 0: A scalar of {@link OperandType::INT32}, specifying the rank
+ * of the input tensor.
+ */
+ RANK = 101,
+
+ /**
* DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
* OEM operation and data types.
*
@@ -4897,12 +5108,21 @@
enum OperationTypeRange : uint32_t {
BASE_MIN = 0,
FUNDAMENTAL_MIN = 0,
- FUNDAMENTAL_MAX = 95,
+ FUNDAMENTAL_MAX = 101,
OEM_MIN = 10000,
OEM_MAX = 10000,
BASE_MAX = 0xFFFF,
};
+/**
+ * Priority given to a prepared model for execution.
+ */
+enum Priority : int32_t {
+ LOW,
+ MEDIUM,
+ HIGH,
+};
+
/**
* The capabilities of a driver.
@@ -4965,6 +5185,59 @@
};
/**
+ * How an operand is used.
+ */
+enum OperandLifeTime : int32_t {
+ /**
+ * The operand is internal to the model. It's created by an operation and
+ * consumed by other operations. It must be an output operand of
+ * exactly one operation.
+ */
+ TEMPORARY_VARIABLE,
+
+ /**
+ * The operand is an input of a subgraph. It must not be an output
+ * operand of any operation.
+ *
+ * An operand can't be both input and output of a subgraph.
+ */
+ SUBGRAPH_INPUT,
+
+ /**
+ * The operand is an output of a subgraph. It must be an output
+ * operand of exactly one operation.
+ *
+ * An operand can't be both input and output of a subgraph.
+ */
+ SUBGRAPH_OUTPUT,
+
+ /**
+ * The operand is a constant found in Model.operandValues. It must
+ * not be an output operand of any operation.
+ */
+ CONSTANT_COPY,
+
+ /**
+ * The operand is a constant that was specified via a Memory
+ * object. It must not be an output operand of any operation.
+ */
+ CONSTANT_REFERENCE,
+
+ /**
+ * The operand does not have a value. This is valid only for optional
+ * arguments of operations.
+ */
+ NO_VALUE,
+
+ /**
+ * The operand is a reference to a subgraph. It must be an input to one
+ * or more {@link OperationType::IF} or {@link OperationType::WHILE}
+ * operations.
+ */
+ SUBGRAPH,
+};
+
+/**
* Describes one operand of the model's graph.
*/
struct Operand {
@@ -5000,7 +5273,7 @@
* . The operand has lifetime CONSTANT_COPY or
* CONSTANT_REFERENCE.
*
- * . The operand has lifetime MODEL_INPUT. Fully
+ * . The operand has lifetime SUBGRAPH_INPUT. Fully
* specified dimensions must either be present in the
* Operand or they must be provided in the corresponding
* RequestArgument.
@@ -5048,8 +5321,8 @@
/**
* Where to find the data for this operand.
- * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
- * NO_VALUE:
+ * If the lifetime is TEMPORARY_VARIABLE, SUBGRAPH_INPUT, SUBGRAPH_OUTPUT,
+ * or NO_VALUE:
* - All the fields must be 0.
* If the lifetime is CONSTANT_COPY:
* - location.poolIndex is 0.
@@ -5059,6 +5332,11 @@
* - location.poolIndex is set.
* - location.offset is the offset in bytes into the specified pool.
* - location.length is set.
+ * If the lifetime is SUBGRAPH:
+ * - location.poolIndex is 0.
+ * - location.offset is the index of the referenced subgraph in
+ * {@link Model::referenced}.
+ * - location.length is 0.
*/
DataLocation location;
@@ -5097,32 +5375,19 @@
*/
struct Model {
/**
- * All operands included in the model.
+ * The top-level subgraph.
*/
- vec<Operand> operands;
+ Subgraph main;
/**
- * All operations included in the model.
+ * Referenced subgraphs.
*
- * The operations are sorted into execution order. Every operand
- * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
- * written before it is read.
- */
- vec<Operation> operations;
-
- /**
- * Input indexes of the model. There must be at least one.
+ * Each subgraph is referenced by the main subgraph or at least one other
+ * referenced subgraph.
*
- * Each value corresponds to the index of the operand in "operands".
+ * There must be no reference cycles.
*/
- vec<uint32_t> inputIndexes;
-
- /**
- * Output indexes of the model. There must be at least one.
- *
- * Each value corresponds to the index of the operand in "operands".
- */
- vec<uint32_t> outputIndexes;
+ vec<Subgraph> referenced;
/**
* A byte buffer containing operand data that were copied into the model.
@@ -5156,9 +5421,9 @@
* {@link OperandTypeRange::BASE_MAX} or
* {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
* as an extension operand. The low
- * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
- * correspond to the type ID within the extension and the high
- * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+ * {@link @1.2::Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the
+ * value correspond to the type ID within the extension and the high
+ * {@link @1.2::Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
* the "prefix", which maps uniquely to the extension name.
*
* For example, if a model contains an operation whose value is
@@ -5171,37 +5436,173 @@
* prefix corresponding to each extension name and at most one extension
* name corresponding to each prefix.
*/
- vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+ vec<@1.2::Model.ExtensionNameAndPrefix> extensionNameToPrefix;
+};
+
+/**
+ * An excerpt of the execution graph.
+ */
+struct Subgraph {
+ /**
+ * All operands included in the subgraph.
+ */
+ vec<Operand> operands;
/**
- * A correspondence between an extension name and a prefix of operand and
- * operation type values.
+ * All operations included in the subgraph.
+ *
+ * The operations are sorted into execution order. Every operand
+ * with lifetime SUBGRAPH_OUTPUT or TEMPORARY_VARIABLE must be
+ * written before it is read.
*/
- struct ExtensionNameAndPrefix {
+ vec<Operation> operations;
+
+ /**
+ * Input indexes of the subgraph. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
+ */
+ vec<uint32_t> inputIndexes;
+
+ /**
+ * Output indexes of the subgraph. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
+ */
+ vec<uint32_t> outputIndexes;
+};
+
+/**
+ * A buffer descriptor. Describes the properties of a buffer.
+ */
+struct BufferDesc {
+ /**
+ * Dimensions of the buffer. May have unknown dimensions or rank. A buffer with some number
+ * of unspecified dimensions is represented by setting each unspecified dimension to 0. A
+ * buffer with unspecified rank is represented by providing an empty dimensions vector.
+ */
+ vec<uint32_t> dimensions;
+};
+
+/**
+ * Describes a role of an input or output to a prepared model.
+ */
+struct BufferRole {
+ /**
+ * The index of the IPreparedModel within the "preparedModel" argument passed in
+ * IDevice::allocate.
+ */
+ uint32_t modelIndex;
+
+ /**
+ * The index of the input or output operand.
+ */
+ uint32_t ioIndex;
+
+ /**
+ * A floating-point value within the range (0.0, 1.0]. Describes how likely the
+ * buffer is to be used in the specified role. This is provided as a hint to
+ * optimize the case when multiple roles prefer different buffer locations or data
+ * layouts.
+ */
+ float frequency;
+};
+
+/**
+ * Inputs to be sent to and outputs to be retrieved from a prepared model.
+ *
+ * A Request serves two primary tasks:
+ * 1) Provides the input and output data to be used when executing the model.
+ * 2) Specifies any updates to the input operand metadata that were left
+ * unspecified at model preparation time.
+ *
+ * An output must not overlap with any other output, with an input, or
+ * with an operand of lifetime CONSTANT_REFERENCE.
+ */
+struct Request {
+ /**
+ * Input data and information to be used in the execution of a prepared
+ * model.
+ *
+ * The index of the input corresponds to the index in Model.inputIndexes.
+ * E.g., input[i] corresponds to Model.inputIndexes[i].
+ */
+ vec<RequestArgument> inputs;
+
+ /**
+ * Output data and information to be used in the execution of a prepared
+ * model.
+ *
+ * The index of the output corresponds to the index in Model.outputIndexes.
+ * E.g., output[i] corresponds to Model.outputIndexes[i].
+ */
+ vec<RequestArgument> outputs;
+
+ /**
+ * A memory pool.
+ */
+ safe_union MemoryPool {
/**
- * The extension name.
- *
- * See {@link Extension::name} for the format specification.
+ * Specifies a client-managed shared memory pool.
*/
- string name;
+ memory hidlMemory;
/**
- * The unique extension identifier within the model.
- *
- * See {@link Model::extensionNameToPrefix}.
+ * Specifies a driver-managed buffer. It is the token returned from IDevice::allocate,
+ * and is specific to the IDevice object.
*/
- uint16_t prefix;
+ int32_t token;
};
/**
- * Numeric values of extension operand and operation types have the
- * following structure:
- * - 16 high bits represent the "prefix", which corresponds uniquely to the
- * extension name.
- * - 16 low bits represent the type ID within the extension.
+ * A collection of memory pools containing operand data for both the
+ * inputs and the outputs to a model.
*/
- enum ExtensionTypeEncoding : uint8_t {
- HIGH_BITS_PREFIX = 16,
- LOW_BITS_TYPE = 16,
- };
+ vec<MemoryPool> pools;
+};
+
+/**
+ * Optional time point of the steady clock (as from std::chrono::steady_clock)
+ * measured in nanoseconds.
+ */
+safe_union OptionalTimePoint {
+ /** No time point provided. */
+ Monostate none;
+
+ /**
+ * Time point of the steady clock (as from std::chrono::steady_clock)
+ * measured in nanoseconds.
+ */
+ uint64_t nanoseconds;
+};
+
+/**
+ * Return status of a function.
+ */
+enum ErrorStatus : @1.0::ErrorStatus {
+ /**
+ * Failure because a deadline could not be met for a task, but future
+ * deadlines may still be met for the same task after a short delay.
+ */
+ MISSED_DEADLINE_TRANSIENT,
+
+ /**
+ * Failure because a deadline could not be met for a task, and future
+ * deadlines will likely also not be met for the same task even after a
+ * short delay.
+ */
+ MISSED_DEADLINE_PERSISTENT,
+
+ /**
+ * Failure because of a resource limitation within the driver, but future
+ * calls for the same task may still succeed after a short delay.
+ */
+ RESOURCE_EXHAUSTED_TRANSIENT,
+
+ /**
+ * Failure because of a resource limitation within the driver, and future
+ * calls for the same task will likely also fail even after a short
+ * delay.
+ */
+ RESOURCE_EXHAUSTED_PERSISTENT,
};
diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t
index 0d20d06..a973923 100644
--- a/neuralnetworks/1.3/types.t
+++ b/neuralnetworks/1.3/types.t
@@ -19,8 +19,11 @@
package android.hardware.neuralnetworks@1.3;
import @1.0::DataLocation;
-import @1.0::OperandLifeTime;
+import @1.0::ErrorStatus;
import @1.0::PerformanceInfo;
+import @1.0::RequestArgument;
+import @1.2::Model.ExtensionNameAndPrefix;
+import @1.2::Model.ExtensionTypeEncoding;
import @1.2::OperandType;
import @1.2::OperationType;
import @1.2::SymmPerChannelQuantParams;
@@ -87,6 +90,15 @@
BASE_MAX = 0xFFFF,
};
+/**
+ * Priority given to a prepared model for execution.
+ */
+enum Priority : int32_t {
+ LOW,
+ MEDIUM,
+ HIGH,
+};
+
/**
* The capabilities of a driver.
@@ -149,6 +161,59 @@
};
/**
+ * How an operand is used.
+ */
+enum OperandLifeTime : int32_t {
+ /**
+ * The operand is internal to the model. It's created by an operation and
+ * consumed by other operations. It must be an output operand of
+ * exactly one operation.
+ */
+ TEMPORARY_VARIABLE,
+
+ /**
+ * The operand is an input of a subgraph. It must not be an output
+ * operand of any operation.
+ *
+ * An operand can't be both input and output of a subgraph.
+ */
+ SUBGRAPH_INPUT,
+
+ /**
+ * The operand is an output of a subgraph. It must be an output
+ * operand of exactly one operation.
+ *
+ * An operand can't be both input and output of a subgraph.
+ */
+ SUBGRAPH_OUTPUT,
+
+ /**
+ * The operand is a constant found in Model.operandValues. It must
+ * not be an output operand of any operation.
+ */
+ CONSTANT_COPY,
+
+ /**
+ * The operand is a constant that was specified via a Memory
+ * object. It must not be an output operand of any operation.
+ */
+ CONSTANT_REFERENCE,
+
+ /**
+ * The operand does not have a value. This is valid only for optional
+ * arguments of operations.
+ */
+ NO_VALUE,
+
+ /**
+ * The operand is a reference to a subgraph. It must be an input to one
+ * or more {@link OperationType::IF} or {@link OperationType::WHILE}
+ * operations.
+ */
+ SUBGRAPH,
+};
+
+/**
* Describes one operand of the model's graph.
*/
struct Operand {
@@ -184,7 +249,7 @@
* . The operand has lifetime CONSTANT_COPY or
* CONSTANT_REFERENCE.
*
- * . The operand has lifetime MODEL_INPUT. Fully
+ * . The operand has lifetime SUBGRAPH_INPUT. Fully
* specified dimensions must either be present in the
* Operand or they must be provided in the corresponding
* RequestArgument.
@@ -232,8 +297,8 @@
/**
* Where to find the data for this operand.
- * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
- * NO_VALUE:
+ * If the lifetime is TEMPORARY_VARIABLE, SUBGRAPH_INPUT, SUBGRAPH_OUTPUT,
+ * or NO_VALUE:
* - All the fields must be 0.
* If the lifetime is CONSTANT_COPY:
* - location.poolIndex is 0.
@@ -243,6 +308,11 @@
* - location.poolIndex is set.
* - location.offset is the offset in bytes into the specified pool.
* - location.length is set.
+ * If the lifetime is SUBGRAPH:
+ * - location.poolIndex is 0.
+ * - location.offset is the index of the referenced subgraph in
+ * {@link Model::referenced}.
+ * - location.length is 0.
*/
DataLocation location;
@@ -281,32 +351,19 @@
*/
struct Model {
/**
- * All operands included in the model.
+ * The top-level subgraph.
*/
- vec<Operand> operands;
+ Subgraph main;
/**
- * All operations included in the model.
+ * Referenced subgraphs.
*
- * The operations are sorted into execution order. Every operand
- * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
- * written before it is read.
- */
- vec<Operation> operations;
-
- /**
- * Input indexes of the model. There must be at least one.
+ * Each subgraph is referenced by the main subgraph or at least one other
+ * referenced subgraph.
*
- * Each value corresponds to the index of the operand in "operands".
+ * There must be no reference cycles.
*/
- vec<uint32_t> inputIndexes;
-
- /**
- * Output indexes of the model. There must be at least one.
- *
- * Each value corresponds to the index of the operand in "operands".
- */
- vec<uint32_t> outputIndexes;
+ vec<Subgraph> referenced;
/**
* A byte buffer containing operand data that were copied into the model.
@@ -340,9 +397,9 @@
* {@link OperandTypeRange::BASE_MAX} or
* {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
* as an extension operand. The low
- * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
- * correspond to the type ID within the extension and the high
- * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+ * {@link @1.2::Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the
+ * value correspond to the type ID within the extension and the high
+ * {@link @1.2::Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
* the "prefix", which maps uniquely to the extension name.
*
* For example, if a model contains an operation whose value is
@@ -355,37 +412,173 @@
* prefix corresponding to each extension name and at most one extension
* name corresponding to each prefix.
*/
- vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+ vec<@1.2::Model.ExtensionNameAndPrefix> extensionNameToPrefix;
+};
+
+/**
+ * An excerpt of the execution graph.
+ */
+struct Subgraph {
+ /**
+ * All operands included in the subgraph.
+ */
+ vec<Operand> operands;
/**
- * A correspondence between an extension name and a prefix of operand and
- * operation type values.
+ * All operations included in the subgraph.
+ *
+ * The operations are sorted into execution order. Every operand
+ * with lifetime SUBGRAPH_OUTPUT or TEMPORARY_VARIABLE must be
+ * written before it is read.
*/
- struct ExtensionNameAndPrefix {
+ vec<Operation> operations;
+
+ /**
+ * Input indexes of the subgraph. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
+ */
+ vec<uint32_t> inputIndexes;
+
+ /**
+ * Output indexes of the subgraph. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
+ */
+ vec<uint32_t> outputIndexes;
+};
+
+/**
+ * A buffer descriptor. Describes the properties of a buffer.
+ */
+struct BufferDesc {
+ /**
+ * Dimensions of the buffer. May have unknown dimensions or rank. A buffer with some number
+ * of unspecified dimensions is represented by setting each unspecified dimension to 0. A
+ * buffer with unspecified rank is represented by providing an empty dimensions vector.
+ */
+ vec<uint32_t> dimensions;
+};
+
+/**
+ * Describes a role of an input or output to a prepared model.
+ */
+struct BufferRole {
+ /**
+ * The index of the IPreparedModel within the "preparedModel" argument passed in
+ * IDevice::allocate.
+ */
+ uint32_t modelIndex;
+
+ /**
+ * The index of the input or output operand.
+ */
+ uint32_t ioIndex;
+
+ /**
+ * A floating-point value within the range (0.0, 1.0]. Describes how likely the
+ * buffer is to be used in the specified role. This is provided as a hint to
+ * optimize the case when multiple roles prefer different buffer locations or data
+ * layouts.
+ */
+ float frequency;
+};
+
+/**
+ * Inputs to be sent to and outputs to be retrieved from a prepared model.
+ *
+ * A Request serves two primary tasks:
+ * 1) Provides the input and output data to be used when executing the model.
+ * 2) Specifies any updates to the input operand metadata that were left
+ * unspecified at model preparation time.
+ *
+ * An output must not overlap with any other output, with an input, or
+ * with an operand of lifetime CONSTANT_REFERENCE.
+ */
+struct Request {
+ /**
+ * Input data and information to be used in the execution of a prepared
+ * model.
+ *
+ * The index of the input corresponds to the index in Model.inputIndexes.
+ * E.g., input[i] corresponds to Model.inputIndexes[i].
+ */
+ vec<RequestArgument> inputs;
+
+ /**
+ * Output data and information to be used in the execution of a prepared
+ * model.
+ *
+ * The index of the output corresponds to the index in Model.outputIndexes.
+ * E.g., output[i] corresponds to Model.outputIndexes[i].
+ */
+ vec<RequestArgument> outputs;
+
+ /**
+ * A memory pool.
+ */
+ safe_union MemoryPool {
/**
- * The extension name.
- *
- * See {@link Extension::name} for the format specification.
+ * Specifies a client-managed shared memory pool.
*/
- string name;
+ memory hidlMemory;
/**
- * The unique extension identifier within the model.
- *
- * See {@link Model::extensionNameToPrefix}.
+ * Specifies a driver-managed buffer. It is the token returned from IDevice::allocate,
+ * and is specific to the IDevice object.
*/
- uint16_t prefix;
+ int32_t token;
};
/**
- * Numeric values of extension operand and operation types have the
- * following structure:
- * - 16 high bits represent the "prefix", which corresponds uniquely to the
- * extension name.
- * - 16 low bits represent the type ID within the extension.
+ * A collection of memory pools containing operand data for both the
+ * inputs and the outputs to a model.
*/
- enum ExtensionTypeEncoding : uint8_t {
- HIGH_BITS_PREFIX = 16,
- LOW_BITS_TYPE = 16,
- };
+ vec<MemoryPool> pools;
+};
+
+/**
+ * Optional time point of the steady clock (as from std::chrono::steady_clock)
+ * measured in nanoseconds.
+ */
+safe_union OptionalTimePoint {
+ /** No time point provided. */
+ Monostate none;
+
+ /**
+ * Time point of the steady clock (as from std::chrono::steady_clock)
+ * measured in nanoseconds.
+ */
+ uint64_t nanoseconds;
+};
+
+/**
+ * Return status of a function.
+ */
+enum ErrorStatus : @1.0::ErrorStatus {
+ /**
+ * Failure because a deadline could not be met for a task, but future
+ * deadlines may still be met for the same task after a short delay.
+ */
+ MISSED_DEADLINE_TRANSIENT,
+
+ /**
+ * Failure because a deadline could not be met for a task, and future
+ * deadlines will likely also not be met for the same task even after a
+ * short delay.
+ */
+ MISSED_DEADLINE_PERSISTENT,
+
+ /**
+ * Failure because of a resource limitation within the driver, but future
+ * calls for the same task may still succeed after a short delay.
+ */
+ RESOURCE_EXHAUSTED_TRANSIENT,
+
+ /**
+ * Failure because of a resource limitation within the driver, and future
+ * calls for the same task will likely also fail even after a short
+ * delay.
+ */
+ RESOURCE_EXHAUSTED_PERSISTENT,
};
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index e2795de..8e7e9b9 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -15,11 +15,12 @@
//
cc_library_static {
- name: "VtsHalNeuralNetworksV1_3Callbacks",
+ name: "VtsHalNeuralNetworksV1_3_utils",
defaults: ["VtsHalTargetTestDefaults"],
export_include_dirs: ["include"],
srcs: [
"Callbacks.cpp",
+ "Utils.cpp",
],
static_libs: [
"android.hardware.neuralnetworks@1.0",
@@ -29,7 +30,7 @@
],
header_libs: [
"libbase_headers",
- ]
+ ],
}
cc_test {
@@ -39,6 +40,7 @@
"BasicTests.cpp",
"CompilationCachingTests.cpp",
"GeneratedTestHarness.cpp",
+ "QualityOfServiceTests.cpp",
"TestAssertions.cpp",
"ValidateBurst.cpp",
"ValidateModel.cpp",
@@ -50,6 +52,9 @@
"libnativewindow",
],
static_libs: [
+ "VtsHalNeuralNetworksV1_0_utils",
+ "VtsHalNeuralNetworksV1_2Callbacks",
+ "VtsHalNeuralNetworksV1_3_utils",
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
@@ -60,9 +65,7 @@
"libhidlmemory",
"libneuralnetworks_generated_test_harness",
"libneuralnetworks_utils",
- "VtsHalNeuralNetworksV1_0_utils",
- "VtsHalNeuralNetworksV1_2Callbacks",
- "VtsHalNeuralNetworksV1_3Callbacks",
+ "libsync",
],
whole_static_libs: [
"neuralnetworks_generated_V1_0_example",
diff --git a/neuralnetworks/1.3/vts/functional/BasicTests.cpp b/neuralnetworks/1.3/vts/functional/BasicTests.cpp
index b64dc2f..891850c 100644
--- a/neuralnetworks/1.3/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/BasicTests.cpp
@@ -21,7 +21,6 @@
namespace android::hardware::neuralnetworks::V1_3::vts::functional {
using V1_0::DeviceStatus;
-using V1_0::ErrorStatus;
using V1_0::PerformanceInfo;
using V1_2::Constant;
using V1_2::DeviceType;
diff --git a/neuralnetworks/1.3/vts/functional/Callbacks.cpp b/neuralnetworks/1.3/vts/functional/Callbacks.cpp
index 4f08e72..5768e37 100644
--- a/neuralnetworks/1.3/vts/functional/Callbacks.cpp
+++ b/neuralnetworks/1.3/vts/functional/Callbacks.cpp
@@ -24,12 +24,16 @@
namespace android::hardware::neuralnetworks::V1_3::implementation {
-using V1_0::ErrorStatus;
+using V1_2::OutputShape;
+using V1_2::Timing;
+
+constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits<uint64_t>::max(),
+ .timeInDriver = std::numeric_limits<uint64_t>::max()};
// PreparedModelCallback methods begin here
-Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus,
- const sp<V1_0::IPreparedModel>& preparedModel) {
+Return<void> PreparedModelCallback::notifyInternal(ErrorStatus errorStatus,
+ const sp<V1_0::IPreparedModel>& preparedModel) {
{
std::lock_guard<std::mutex> hold(mMutex);
@@ -48,14 +52,19 @@
return Void();
}
-Return<void> PreparedModelCallback::notify_1_2(ErrorStatus errorStatus,
- const sp<V1_2::IPreparedModel>& preparedModel) {
- return notify(errorStatus, preparedModel);
+Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus errorStatus,
+ const sp<V1_0::IPreparedModel>& preparedModel) {
+ return notifyInternal(static_cast<ErrorStatus>(errorStatus), preparedModel);
}
-Return<void> PreparedModelCallback::notify_1_3(ErrorStatus errorStatus,
+Return<void> PreparedModelCallback::notify_1_2(V1_0::ErrorStatus errorStatus,
+ const sp<V1_2::IPreparedModel>& preparedModel) {
+ return notifyInternal(static_cast<ErrorStatus>(errorStatus), preparedModel);
+}
+
+Return<void> PreparedModelCallback::notify_1_3(V1_3::ErrorStatus errorStatus,
const sp<V1_3::IPreparedModel>& preparedModel) {
- return notify(errorStatus, preparedModel);
+ return notifyInternal(errorStatus, preparedModel);
}
void PreparedModelCallback::wait() const {
@@ -73,4 +82,82 @@
return mPreparedModel;
}
+// ExecutionCallback methods begin here
+
+Return<void> ExecutionCallback::notify(V1_0::ErrorStatus errorStatus) {
+ return notifyInternal(static_cast<ErrorStatus>(errorStatus), {}, kNoTiming);
+}
+
+Return<void> ExecutionCallback::notify_1_2(V1_0::ErrorStatus errorStatus,
+ const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing) {
+ return notifyInternal(static_cast<ErrorStatus>(errorStatus), outputShapes, timing);
+}
+
+Return<void> ExecutionCallback::notify_1_3(V1_3::ErrorStatus errorStatus,
+ const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing) {
+ return notifyInternal(errorStatus, outputShapes, timing);
+}
+
+void ExecutionCallback::wait() const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondition.wait(lock, [this] { return mNotified; });
+}
+
+ErrorStatus ExecutionCallback::getStatus() const {
+ wait();
+ return mErrorStatus;
+}
+
+const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() const {
+ wait();
+ return mOutputShapes;
+}
+
+Timing ExecutionCallback::getTiming() const {
+ wait();
+ return mTiming;
+}
+
+Return<void> ExecutionCallback::notifyInternal(ErrorStatus errorStatus,
+ hidl_vec<OutputShape> outputShapes, Timing timing) {
+ // check results
+ if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
+ // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE.
+ if (outputShapes.size() == 0) {
+ LOG(ERROR) << "Notifid with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE";
+ errorStatus = ErrorStatus::GENERAL_FAILURE;
+ outputShapes = {};
+ timing = kNoTiming;
+ }
+ } else if (errorStatus != ErrorStatus::NONE) {
+ // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE.
+ if (outputShapes.size() != 0) {
+ LOG(ERROR) << "Notified with non-empty output shape vector when error status is "
+ "neither NONE nor OUTPUT_INSUFFICIENT_SIZE";
+ errorStatus = ErrorStatus::GENERAL_FAILURE;
+ outputShapes = {};
+ timing = kNoTiming;
+ }
+ }
+
+ // store results
+ {
+ std::lock_guard<std::mutex> hold(mMutex);
+
+ // quick-return if object has already been notified
+ if (mNotified) {
+ return Void();
+ }
+
+ mErrorStatus = errorStatus;
+ mOutputShapes = std::move(outputShapes);
+ mTiming = timing;
+ mNotified = true;
+ }
+ mCondition.notify_all();
+ return Void();
+}
+
} // namespace android::hardware::neuralnetworks::V1_3::implementation
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index 60992d5..576e524 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -29,6 +29,7 @@
#include <thread>
#include "1.3/Callbacks.h"
+#include "1.3/Utils.h"
#include "GeneratedTestHarness.h"
#include "MemoryUtils.h"
#include "TestHarness.h"
@@ -49,7 +50,6 @@
using namespace test_helper;
using implementation::PreparedModelCallback;
-using V1_0::ErrorStatus;
using V1_1::ExecutionPreference;
using V1_2::Constant;
using V1_2::OperationType;
@@ -238,8 +238,8 @@
mCacheDir.push_back('/');
Return<void> ret = kDevice->getNumberOfCacheFilesNeeded(
- [this](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) {
- EXPECT_EQ(ErrorStatus::NONE, status);
+ [this](V1_0::ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) {
+ EXPECT_EQ(V1_0::ErrorStatus::NONE, status);
mNumModelCache = numModelCache;
mNumDataCache = numDataCache;
});
@@ -308,7 +308,7 @@
model,
[&fullySupportsModel, &model](ErrorStatus status, const hidl_vec<bool>& supported) {
ASSERT_EQ(ErrorStatus::NONE, status);
- ASSERT_EQ(supported.size(), model.operations.size());
+ ASSERT_EQ(supported.size(), model.main.operations.size());
fullySupportsModel = std::all_of(supported.begin(), supported.end(),
[](bool valid) { return valid; });
});
@@ -324,9 +324,9 @@
// Launch prepare model.
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
- Return<ErrorStatus> prepareLaunchStatus =
- kDevice->prepareModel_1_3(model, ExecutionPreference::FAST_SINGLE_ANSWER,
- modelCache, dataCache, cacheToken, preparedModelCallback);
+ Return<ErrorStatus> prepareLaunchStatus = kDevice->prepareModel_1_3(
+ model, ExecutionPreference::FAST_SINGLE_ANSWER, kDefaultPriority, {}, modelCache,
+ dataCache, cacheToken, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
ASSERT_EQ(static_cast<ErrorStatus>(prepareLaunchStatus), ErrorStatus::NONE);
@@ -370,7 +370,7 @@
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
Return<ErrorStatus> prepareLaunchStatus = kDevice->prepareModelFromCache_1_3(
- modelCache, dataCache, cacheToken, preparedModelCallback);
+ kDefaultPriority, {}, modelCache, dataCache, cacheToken, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
if (static_cast<ErrorStatus>(prepareLaunchStatus) != ErrorStatus::NONE) {
*preparedModel = nullptr;
@@ -456,7 +456,7 @@
}
// Execute and verify results.
- EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
}
TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) {
@@ -518,7 +518,7 @@
}
// Execute and verify results.
- EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
}
TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) {
@@ -539,7 +539,7 @@
saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
ErrorStatus status;
@@ -563,7 +563,7 @@
saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
ErrorStatus status;
@@ -586,7 +586,7 @@
saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
ErrorStatus status;
@@ -610,7 +610,7 @@
saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
ErrorStatus status;
@@ -721,7 +721,7 @@
saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
ErrorStatus status;
@@ -745,7 +745,7 @@
saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
ErrorStatus status;
@@ -768,7 +768,7 @@
saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
ErrorStatus status;
@@ -792,7 +792,7 @@
saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
ErrorStatus status;
@@ -904,7 +904,7 @@
saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
ErrorStatus status;
@@ -926,7 +926,7 @@
saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
ErrorStatus status;
@@ -1070,7 +1070,8 @@
ASSERT_EQ(preparedModel, nullptr);
} else {
ASSERT_NE(preparedModel, nullptr);
- EvaluatePreparedModel(preparedModel, testModelAdd, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModelAdd,
+ /*testKind=*/TestKind::GENERAL);
}
}
}
@@ -1131,7 +1132,8 @@
ASSERT_EQ(preparedModel, nullptr);
} else {
ASSERT_NE(preparedModel, nullptr);
- EvaluatePreparedModel(preparedModel, testModelAdd, /*testKind=*/TestKind::GENERAL);
+ EvaluatePreparedModel(kDevice, preparedModel, testModelAdd,
+ /*testKind=*/TestKind::GENERAL);
}
}
}
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index eced063..88837db 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -29,11 +29,13 @@
#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
#include <android/hardware/neuralnetworks/1.2/types.h>
#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
#include <android/hardware/neuralnetworks/1.3/types.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
+#include <android/sync.h>
#include <gtest/gtest.h>
#include <hidlmemory/mapping.h>
@@ -44,8 +46,8 @@
#include <vector>
#include "1.0/Utils.h"
-#include "1.2/Callbacks.h"
#include "1.3/Callbacks.h"
+#include "1.3/Utils.h"
#include "ExecutionBurstController.h"
#include "MemoryUtils.h"
#include "TestHarness.h"
@@ -56,47 +58,136 @@
using namespace test_helper;
using hidl::memory::V1_0::IMemory;
+using implementation::ExecutionCallback;
using implementation::PreparedModelCallback;
using V1_0::DataLocation;
-using V1_0::ErrorStatus;
-using V1_0::OperandLifeTime;
-using V1_0::Request;
+using V1_0::RequestArgument;
using V1_1::ExecutionPreference;
using V1_2::Constant;
using V1_2::MeasureTiming;
using V1_2::OutputShape;
using V1_2::SymmPerChannelQuantParams;
using V1_2::Timing;
-using V1_2::implementation::ExecutionCallback;
using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
namespace {
-enum class Executor { ASYNC, SYNC, BURST };
+enum class Executor { ASYNC, SYNC, BURST, FENCED };
enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
+enum class MemoryType { SHARED, DEVICE };
+
+enum class IOType { INPUT, OUTPUT };
+
struct TestConfig {
Executor executor;
MeasureTiming measureTiming;
OutputType outputType;
+ MemoryType memoryType;
// `reportSkipping` indicates if a test should print an info message in case
// it is skipped. The field is set to true by default and is set to false in
// quantization coupling tests to suppress skipping a test
bool reportSkipping;
- TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType)
+ TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType,
+ MemoryType memoryType)
: executor(executor),
measureTiming(measureTiming),
outputType(outputType),
+ memoryType(memoryType),
reportSkipping(true) {}
TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType,
- bool reportSkipping)
+ MemoryType memoryType, bool reportSkipping)
: executor(executor),
measureTiming(measureTiming),
outputType(outputType),
+ memoryType(memoryType),
reportSkipping(reportSkipping) {}
};
+class DeviceMemoryAllocator {
+ public:
+ DeviceMemoryAllocator(const sp<IDevice>& device, const sp<IPreparedModel>& preparedModel,
+ const TestModel& testModel)
+ : kDevice(device), kPreparedModel(preparedModel), kTestModel(testModel) {}
+
+ // Allocate device memory for a target input/output operand.
+ // Return {IBuffer object, token} if successful.
+ // Return {nullptr, 0} if device memory is not supported.
+ template <IOType ioType>
+ std::pair<sp<IBuffer>, int32_t> allocate(uint32_t index) {
+ std::pair<sp<IBuffer>, int32_t> buffer;
+ allocateInternal<ioType>(index, &buffer);
+ return buffer;
+ }
+
+ private:
+ template <IOType ioType>
+ void allocateInternal(uint32_t index, std::pair<sp<IBuffer>, int32_t>* result) {
+ ASSERT_NE(result, nullptr);
+
+ // Prepare arguments.
+ BufferRole role = {.modelIndex = 0, .ioIndex = index, .frequency = 1.0f};
+ hidl_vec<BufferRole> inputRoles, outputRoles;
+ if constexpr (ioType == IOType::INPUT) {
+ inputRoles = {role};
+ } else {
+ outputRoles = {role};
+ }
+
+ // Allocate device memory.
+ ErrorStatus status;
+ sp<IBuffer> buffer;
+ int32_t token;
+ const auto ret = kDevice->allocate(
+ {}, {kPreparedModel}, inputRoles, outputRoles,
+ [&status, &buffer, &token](ErrorStatus error, const sp<IBuffer>& buf, int32_t tok) {
+ status = error;
+ buffer = buf;
+ token = tok;
+ });
+
+ // Check allocation results.
+ ASSERT_TRUE(ret.isOk());
+ if (status == ErrorStatus::NONE) {
+ ASSERT_NE(buffer, nullptr);
+ ASSERT_GT(token, 0);
+ } else {
+ ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+ ASSERT_EQ(buffer, nullptr);
+ ASSERT_EQ(token, 0);
+ }
+
+ // Initialize input data from TestBuffer.
+ if constexpr (ioType == IOType::INPUT) {
+ if (buffer != nullptr) {
+ // TestBuffer -> Shared memory.
+ const auto& testBuffer = kTestModel.operands[kTestModel.inputIndexes[index]].data;
+ ASSERT_GT(testBuffer.size(), 0);
+ hidl_memory tmp = nn::allocateSharedMemory(testBuffer.size());
+ sp<IMemory> inputMemory = mapMemory(tmp);
+ ASSERT_NE(inputMemory.get(), nullptr);
+ uint8_t* inputPtr =
+ static_cast<uint8_t*>(static_cast<void*>(inputMemory->getPointer()));
+ ASSERT_NE(inputPtr, nullptr);
+ const uint8_t* begin = testBuffer.get<uint8_t>();
+ const uint8_t* end = begin + testBuffer.size();
+ std::copy(begin, end, inputPtr);
+
+ // Shared memory -> IBuffer.
+ auto ret = buffer->copyFrom(tmp, {});
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(static_cast<ErrorStatus>(ret), ErrorStatus::NONE);
+ }
+ }
+ *result = {std::move(buffer), token};
+ }
+
+ const sp<IDevice> kDevice;
+ const sp<IPreparedModel> kPreparedModel;
+ const TestModel& kTestModel;
+};
+
} // namespace
Model createModel(const TestModel& testModel) {
@@ -178,10 +269,10 @@
}
}
- return {.operands = std::move(operands),
- .operations = std::move(operations),
- .inputIndexes = testModel.inputIndexes,
- .outputIndexes = testModel.outputIndexes,
+ return {.main = {.operands = std::move(operands),
+ .operations = std::move(operations),
+ .inputIndexes = testModel.inputIndexes,
+ .outputIndexes = testModel.outputIndexes},
.operandValues = std::move(operandValues),
.pools = std::move(pools),
.relaxComputationFloat32toFloat16 = testModel.isRelaxed};
@@ -199,16 +290,171 @@
}
static void makeOutputDimensionsUnspecified(Model* model) {
- for (auto i : model->outputIndexes) {
- auto& dims = model->operands[i].dimensions;
+ for (auto i : model->main.outputIndexes) {
+ auto& dims = model->main.operands[i].dimensions;
std::fill(dims.begin(), dims.end(), 0);
}
}
+constexpr uint32_t kInputPoolIndex = 0;
+constexpr uint32_t kOutputPoolIndex = 1;
+constexpr uint32_t kDeviceMemoryBeginIndex = 2;
+
+static std::pair<Request, std::vector<sp<IBuffer>>> createRequest(
+ const sp<IDevice>& device, const sp<IPreparedModel>& preparedModel,
+ const TestModel& testModel, bool preferDeviceMemory) {
+ // Memory pools are organized as:
+ // - 0: Input shared memory pool
+ // - 1: Output shared memory pool
+ // - [2, 2+i): Input device memories
+ // - [2+i, 2+i+o): Output device memories
+ DeviceMemoryAllocator allocator(device, preparedModel, testModel);
+ std::vector<sp<IBuffer>> buffers;
+ std::vector<int32_t> tokens;
+
+ // Model inputs.
+ hidl_vec<RequestArgument> inputs(testModel.inputIndexes.size());
+ size_t inputSize = 0;
+ for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
+ const auto& op = testModel.operands[testModel.inputIndexes[i]];
+ if (op.data.size() == 0) {
+ // Omitted input.
+ inputs[i] = {.hasNoValue = true};
+ continue;
+ } else if (preferDeviceMemory) {
+ SCOPED_TRACE("Input index = " + std::to_string(i));
+ auto [buffer, token] = allocator.allocate<IOType::INPUT>(i);
+ if (buffer != nullptr) {
+ DataLocation loc = {.poolIndex = static_cast<uint32_t>(buffers.size() +
+ kDeviceMemoryBeginIndex)};
+ buffers.push_back(std::move(buffer));
+ tokens.push_back(token);
+ inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
+ continue;
+ }
+ }
+
+ // Reserve shared memory for input.
+ DataLocation loc = {.poolIndex = kInputPoolIndex,
+ .offset = static_cast<uint32_t>(inputSize),
+ .length = static_cast<uint32_t>(op.data.size())};
+ inputSize += op.data.alignedSize();
+ inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
+ }
+
+ // Model outputs.
+ hidl_vec<RequestArgument> outputs(testModel.outputIndexes.size());
+ size_t outputSize = 0;
+ for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) {
+ const auto& op = testModel.operands[testModel.outputIndexes[i]];
+ if (preferDeviceMemory) {
+ SCOPED_TRACE("Output index = " + std::to_string(i));
+ auto [buffer, token] = allocator.allocate<IOType::OUTPUT>(i);
+ if (buffer != nullptr) {
+ DataLocation loc = {.poolIndex = static_cast<uint32_t>(buffers.size() +
+ kDeviceMemoryBeginIndex)};
+ buffers.push_back(std::move(buffer));
+ tokens.push_back(token);
+ outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
+ continue;
+ }
+ }
+
+ // In the case of zero-sized output, we should at least provide a one-byte buffer.
+ // This is because zero-sized tensors are only supported internally to the driver, or
+ // reported in output shapes. It is illegal for the client to pre-specify a zero-sized
+ // tensor as model output. Otherwise, we will have two semantic conflicts:
+ // - "Zero dimension" conflicts with "unspecified dimension".
+ // - "Omitted operand buffer" conflicts with "zero-sized operand buffer".
+ size_t bufferSize = std::max<size_t>(op.data.size(), 1);
+
+ // Reserve shared memory for output.
+ DataLocation loc = {.poolIndex = kOutputPoolIndex,
+ .offset = static_cast<uint32_t>(outputSize),
+ .length = static_cast<uint32_t>(bufferSize)};
+ outputSize += op.data.size() == 0 ? TestBuffer::kAlignment : op.data.alignedSize();
+ outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
+ }
+
+ // Memory pools.
+ hidl_vec<Request::MemoryPool> pools(kDeviceMemoryBeginIndex + buffers.size());
+ pools[kInputPoolIndex].hidlMemory(nn::allocateSharedMemory(std::max<size_t>(inputSize, 1)));
+ pools[kOutputPoolIndex].hidlMemory(nn::allocateSharedMemory(std::max<size_t>(outputSize, 1)));
+ CHECK_NE(pools[kInputPoolIndex].hidlMemory().size(), 0u);
+ CHECK_NE(pools[kOutputPoolIndex].hidlMemory().size(), 0u);
+ for (uint32_t i = 0; i < buffers.size(); i++) {
+ pools[kDeviceMemoryBeginIndex + i].token(tokens[i]);
+ }
+
+ // Copy input data to the input shared memory pool.
+ sp<IMemory> inputMemory = mapMemory(pools[kInputPoolIndex].hidlMemory());
+ CHECK(inputMemory.get() != nullptr);
+ uint8_t* inputPtr = static_cast<uint8_t*>(static_cast<void*>(inputMemory->getPointer()));
+ CHECK(inputPtr != nullptr);
+ for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
+ if (!inputs[i].hasNoValue && inputs[i].location.poolIndex == kInputPoolIndex) {
+ const auto& op = testModel.operands[testModel.inputIndexes[i]];
+ const uint8_t* begin = op.data.get<uint8_t>();
+ const uint8_t* end = begin + op.data.size();
+ std::copy(begin, end, inputPtr + inputs[i].location.offset);
+ }
+ }
+
+ Request request = {
+ .inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)};
+ return {std::move(request), std::move(buffers)};
+}
+
+// Get a TestBuffer with data copied from an IBuffer object.
+static void getBuffer(const sp<IBuffer>& buffer, size_t size, TestBuffer* testBuffer) {
+ // IBuffer -> Shared memory.
+ hidl_memory tmp = nn::allocateSharedMemory(size);
+ const auto ret = buffer->copyTo(tmp);
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(static_cast<ErrorStatus>(ret), ErrorStatus::NONE);
+
+ // Shared memory -> TestBuffer.
+ sp<IMemory> outputMemory = mapMemory(tmp);
+ ASSERT_NE(outputMemory.get(), nullptr);
+ uint8_t* outputPtr = static_cast<uint8_t*>(static_cast<void*>(outputMemory->getPointer()));
+ ASSERT_NE(outputPtr, nullptr);
+ ASSERT_NE(testBuffer, nullptr);
+ *testBuffer = TestBuffer(size, outputPtr);
+}
+
+static std::vector<TestBuffer> getOutputBuffers(const TestModel& testModel, const Request& request,
+ const std::vector<sp<IBuffer>>& buffers) {
+ sp<IMemory> outputMemory = mapMemory(request.pools[kOutputPoolIndex].hidlMemory());
+ CHECK(outputMemory.get() != nullptr);
+ uint8_t* outputPtr = static_cast<uint8_t*>(static_cast<void*>(outputMemory->getPointer()));
+ CHECK(outputPtr != nullptr);
+
+ // Copy out output results.
+ std::vector<TestBuffer> outputBuffers;
+ for (uint32_t i = 0; i < request.outputs.size(); i++) {
+ const auto& outputLoc = request.outputs[i].location;
+ if (outputLoc.poolIndex == kOutputPoolIndex) {
+ outputBuffers.emplace_back(outputLoc.length, outputPtr + outputLoc.offset);
+ } else {
+ const auto& op = testModel.operands[testModel.outputIndexes[i]];
+ if (op.data.size() == 0) {
+ outputBuffers.emplace_back();
+ } else {
+ SCOPED_TRACE("Output index = " + std::to_string(i));
+ const uint32_t bufferIndex = outputLoc.poolIndex - kDeviceMemoryBeginIndex;
+ TestBuffer buffer;
+ getBuffer(buffers[bufferIndex], op.data.size(), &buffer);
+ outputBuffers.push_back(std::move(buffer));
+ }
+ }
+ }
+ return outputBuffers;
+}
+
static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
const Request& request, MeasureTiming measure,
sp<ExecutionCallback>& callback) {
- return preparedModel->execute_1_3(request, measure, callback);
+ return preparedModel->execute_1_3(request, measure, {}, callback);
}
static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
const Request& request, MeasureTiming measure,
@@ -216,7 +462,7 @@
Timing* timing) {
ErrorStatus result;
Return<void> ret = preparedModel->executeSynchronously_1_3(
- request, measure,
+ request, measure, {},
[&result, outputShapes, timing](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
const Timing& time) {
result = error;
@@ -234,8 +480,9 @@
std::chrono::microseconds{0});
}
-void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
- const TestConfig& testConfig, bool* skipped = nullptr) {
+void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>& preparedModel,
+ const TestModel& testModel, const TestConfig& testConfig,
+ bool* skipped = nullptr) {
if (skipped != nullptr) {
*skipped = false;
}
@@ -245,7 +492,13 @@
return;
}
- Request request = createRequest(testModel);
+ auto [request, buffers] =
+ createRequest(device, preparedModel, testModel,
+ /*preferDeviceMemory=*/testConfig.memoryType == MemoryType::DEVICE);
+ // Skip if testing memory domain but no device memory has been allocated.
+ if (testConfig.memoryType == MemoryType::DEVICE && buffers.empty()) {
+ return;
+ }
if (testConfig.outputType == OutputType::INSUFFICIENT) {
makeOutputInsufficientSize(/*outputIndex=*/0, &request);
}
@@ -284,30 +537,75 @@
break;
}
case Executor::BURST: {
+ // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains
+ // V1_2.
SCOPED_TRACE("burst");
+ // check compliance
+ ASSERT_TRUE(nn::compliantWithV1_0(request));
+ V1_0::Request request10 = nn::convertToV1_0(request);
+
// create burst
const std::shared_ptr<::android::nn::ExecutionBurstController> controller =
CreateBurst(preparedModel);
ASSERT_NE(nullptr, controller.get());
// create memory keys
- std::vector<intptr_t> keys(request.pools.size());
+ std::vector<intptr_t> keys(request10.pools.size());
for (size_t i = 0; i < keys.size(); ++i) {
- keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
+ keys[i] = reinterpret_cast<intptr_t>(&request10.pools[i]);
}
// execute burst
int n;
std::tie(n, outputShapes, timing, std::ignore) =
- controller->compute(request, testConfig.measureTiming, keys);
+ controller->compute(request10, testConfig.measureTiming, keys);
executionStatus = nn::convertResultCodeToErrorStatus(n);
break;
}
+ case Executor::FENCED: {
+ SCOPED_TRACE("fenced");
+ ErrorStatus result;
+ hidl_handle sync_fence_handle;
+ sp<IFencedExecutionCallback> fenced_callback;
+ Return<void> ret = preparedModel->executeFenced(
+ request, {}, testConfig.measureTiming,
+ [&result, &sync_fence_handle, &fenced_callback](
+ ErrorStatus error, const hidl_handle& handle,
+ const sp<IFencedExecutionCallback>& callback) {
+ result = error;
+ sync_fence_handle = handle;
+ fenced_callback = callback;
+ });
+ ASSERT_TRUE(ret.isOk());
+ if (result != ErrorStatus::NONE) {
+ ASSERT_EQ(sync_fence_handle.getNativeHandle(), nullptr);
+ ASSERT_EQ(fenced_callback, nullptr);
+ executionStatus = ErrorStatus::GENERAL_FAILURE;
+ } else if (sync_fence_handle.getNativeHandle()) {
+ constexpr int kInfiniteTimeout = -1;
+ int sync_fd = sync_fence_handle.getNativeHandle()->data[0];
+ ASSERT_GT(sync_fd, 0);
+ int r = sync_wait(sync_fd, kInfiniteTimeout);
+ ASSERT_GE(r, 0);
+ }
+ if (result == ErrorStatus::NONE) {
+ ASSERT_NE(fenced_callback, nullptr);
+ Return<void> ret = fenced_callback->getExecutionInfo(
+ [&executionStatus, &timing](ErrorStatus error, Timing t) {
+ executionStatus = error;
+ timing = t;
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ break;
+ }
}
- if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
+ // The driver is allowed to reject executeFenced, and if they do, we should skip.
+ if ((testConfig.outputType != OutputType::FULLY_SPECIFIED ||
+ testConfig.executor == Executor::FENCED) &&
executionStatus == ErrorStatus::GENERAL_FAILURE) {
if (skipped != nullptr) {
*skipped = true;
@@ -361,17 +659,18 @@
}
// Retrieve execution results.
- const std::vector<TestBuffer> outputs = getOutputBuffers(request);
+ const std::vector<TestBuffer> outputs = getOutputBuffers(testModel, request, buffers);
// We want "close-enough" results.
checkResults(testModel, outputs);
}
-void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
- TestKind testKind) {
+void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>& preparedModel,
+ const TestModel& testModel, TestKind testKind) {
std::vector<OutputType> outputTypesList;
std::vector<MeasureTiming> measureTimingList;
std::vector<Executor> executorList;
+ MemoryType memoryType = MemoryType::SHARED;
switch (testKind) {
case TestKind::GENERAL: {
@@ -384,6 +683,17 @@
measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
} break;
+ case TestKind::MEMORY_DOMAIN: {
+ outputTypesList = {OutputType::FULLY_SPECIFIED};
+ measureTimingList = {MeasureTiming::NO};
+ executorList = {Executor::ASYNC, Executor::SYNC};
+ memoryType = MemoryType::DEVICE;
+ } break;
+ case TestKind::FENCED_COMPUTE: {
+ outputTypesList = {OutputType::FULLY_SPECIFIED};
+ measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+ executorList = {Executor::FENCED};
+ } break;
case TestKind::QUANTIZATION_COUPLING: {
LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel";
return;
@@ -393,30 +703,32 @@
for (const OutputType outputType : outputTypesList) {
for (const MeasureTiming measureTiming : measureTimingList) {
for (const Executor executor : executorList) {
- const TestConfig testConfig(executor, measureTiming, outputType);
- EvaluatePreparedModel(preparedModel, testModel, testConfig);
+ const TestConfig testConfig(executor, measureTiming, outputType, memoryType);
+ EvaluatePreparedModel(device, preparedModel, testModel, testConfig);
}
}
}
}
-void EvaluatePreparedCoupledModels(const sp<IPreparedModel>& preparedModel,
+void EvaluatePreparedCoupledModels(const sp<IDevice>& device,
+ const sp<IPreparedModel>& preparedModel,
const TestModel& testModel,
const sp<IPreparedModel>& preparedCoupledModel,
const TestModel& coupledModel) {
const std::vector<OutputType> outputTypesList = {OutputType::FULLY_SPECIFIED};
const std::vector<MeasureTiming> measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
- const std::vector<Executor> executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+ const std::vector<Executor> executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST,
+ Executor::FENCED};
for (const OutputType outputType : outputTypesList) {
for (const MeasureTiming measureTiming : measureTimingList) {
for (const Executor executor : executorList) {
- const TestConfig testConfig(executor, measureTiming, outputType,
+ const TestConfig testConfig(executor, measureTiming, outputType, MemoryType::SHARED,
/*reportSkipping=*/false);
bool baseSkipped = false;
- EvaluatePreparedModel(preparedModel, testModel, testConfig, &baseSkipped);
+ EvaluatePreparedModel(device, preparedModel, testModel, testConfig, &baseSkipped);
bool coupledSkipped = false;
- EvaluatePreparedModel(preparedCoupledModel, coupledModel, testConfig,
+ EvaluatePreparedModel(device, preparedCoupledModel, coupledModel, testConfig,
&coupledSkipped);
ASSERT_EQ(baseSkipped, coupledSkipped);
if (baseSkipped) {
@@ -441,19 +753,18 @@
sp<IPreparedModel> preparedModel;
switch (testKind) {
- case TestKind::GENERAL: {
+ case TestKind::GENERAL:
+ case TestKind::DYNAMIC_SHAPE:
+ case TestKind::MEMORY_DOMAIN:
+ case TestKind::FENCED_COMPUTE: {
createPreparedModel(device, model, &preparedModel);
if (preparedModel == nullptr) return;
- EvaluatePreparedModel(preparedModel, testModel, TestKind::GENERAL);
- } break;
- case TestKind::DYNAMIC_SHAPE: {
- createPreparedModel(device, model, &preparedModel);
- if (preparedModel == nullptr) return;
- EvaluatePreparedModel(preparedModel, testModel, TestKind::DYNAMIC_SHAPE);
+ EvaluatePreparedModel(device, preparedModel, testModel, testKind);
} break;
case TestKind::QUANTIZATION_COUPLING: {
ASSERT_TRUE(testModel.hasQuant8CoupledOperands());
- createPreparedModel(device, model, &preparedModel, /*reportSkipping*/ false);
+ createPreparedModel(device, model, &preparedModel,
+ /*reportSkipping*/ false);
TestModel signedQuantizedModel = convertQuant8AsymmOperandsToSigned(testModel);
sp<IPreparedModel> preparedCoupledModel;
createPreparedModel(device, createModel(signedQuantizedModel), &preparedCoupledModel,
@@ -473,7 +784,7 @@
GTEST_SKIP();
}
ASSERT_NE(preparedCoupledModel, nullptr);
- EvaluatePreparedCoupledModels(preparedModel, testModel, preparedCoupledModel,
+ EvaluatePreparedCoupledModels(device, preparedModel, testModel, preparedCoupledModel,
signedQuantizedModel);
} break;
}
@@ -482,6 +793,12 @@
void GeneratedTestBase::SetUp() {
testing::TestWithParam<GeneratedTestParam>::SetUp();
ASSERT_NE(kDevice, nullptr);
+
+ const Return<void> ret =
+ kDevice->supportsDeadlines([this](bool prepareModelDeadline, bool executionDeadline) {
+ mSupportsDeadlines = {prepareModelDeadline, executionDeadline};
+ });
+ ASSERT_TRUE(ret.isOk());
}
std::vector<NamedModel> getNamedModels(const FilterFn& filter) {
@@ -499,6 +816,12 @@
// Tag for the dynamic output shape tests
class DynamicOutputShapeTest : public GeneratedTest {};
+// Tag for the memory domain tests
+class MemoryDomainTest : public GeneratedTest {};
+
+// Tag for the fenced compute tests
+class FencedComputeTest : public GeneratedTest {};
+
// Tag for the dynamic output shape tests
class QuantizationCouplingTest : public GeneratedTest {};
@@ -510,6 +833,14 @@
Execute(kDevice, kTestModel, /*testKind=*/TestKind::DYNAMIC_SHAPE);
}
+TEST_P(MemoryDomainTest, Test) {
+ Execute(kDevice, kTestModel, /*testKind=*/TestKind::MEMORY_DOMAIN);
+}
+
+TEST_P(FencedComputeTest, Test) {
+ Execute(kDevice, kTestModel, /*testKind=*/TestKind::FENCED_COMPUTE);
+}
+
TEST_P(QuantizationCouplingTest, Test) {
Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING);
}
@@ -517,7 +848,14 @@
INSTANTIATE_GENERATED_TEST(GeneratedTest,
[](const TestModel& testModel) { return !testModel.expectFailure; });
-INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest,
+INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) {
+ return !testModel.expectFailure && !testModel.hasScalarOutputs();
+});
+
+INSTANTIATE_GENERATED_TEST(MemoryDomainTest,
+ [](const TestModel& testModel) { return !testModel.expectFailure; });
+
+INSTANTIATE_GENERATED_TEST(FencedComputeTest,
[](const TestModel& testModel) { return !testModel.expectFailure; });
INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) {
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
index ad6323f..e597fac 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
@@ -36,6 +36,7 @@
void SetUp() override;
const sp<IDevice> kDevice = getData(std::get<NamedDevice>(GetParam()));
const test_helper::TestModel& kTestModel = *getData(std::get<NamedModel>(GetParam()));
+ std::pair<bool, bool> mSupportsDeadlines;
};
using FilterFn = std::function<bool(const test_helper::TestModel&)>;
@@ -62,13 +63,17 @@
GENERAL,
// Same as GENERAL but sets dimensions for the output tensors to zeros
DYNAMIC_SHAPE,
+ // Same as GENERAL but use device memories for inputs and outputs
+ MEMORY_DOMAIN,
+ // Same as GENERAL but use executeFenced for exeuction
+ FENCED_COMPUTE,
// Tests if quantized model with TENSOR_QUANT8_ASYMM produces the same result
// (OK/SKIPPED/FAILED) as the model with all such tensors converted to
// TENSOR_QUANT8_ASYMM_SIGNED.
QUANTIZATION_COUPLING
};
-void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel,
+void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>& preparedModel,
const test_helper::TestModel& testModel, TestKind testKind);
} // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
new file mode 100644
index 0000000..62ffcda
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
@@ -0,0 +1,299 @@
+/*
+ * 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 "1.0/Utils.h"
+#include "1.3/Callbacks.h"
+#include "1.3/Utils.h"
+#include "GeneratedTestHarness.h"
+#include "Utils.h"
+
+namespace android::hardware::neuralnetworks::V1_3::vts::functional {
+
+using implementation::ExecutionCallback;
+using implementation::PreparedModelCallback;
+using test_helper::TestBuffer;
+using test_helper::TestModel;
+using V1_1::ExecutionPreference;
+using V1_2::MeasureTiming;
+using V1_2::OutputShape;
+using V1_2::Timing;
+
+using HidlToken =
+ hidl_array<uint8_t, static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
+
+enum class DeadlineBoundType { NOW, UNLIMITED };
+constexpr std::array<DeadlineBoundType, 2> deadlineBounds = {DeadlineBoundType::NOW,
+ DeadlineBoundType::UNLIMITED};
+std::string toString(DeadlineBoundType type) {
+ switch (type) {
+ case DeadlineBoundType::NOW:
+ return "NOW";
+ case DeadlineBoundType::UNLIMITED:
+ return "UNLIMITED";
+ }
+ LOG(FATAL) << "Unrecognized DeadlineBoundType: " << static_cast<int>(type);
+ return {};
+}
+
+using Results = std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing>;
+using MaybeResults = std::optional<Results>;
+
+using ExecutionFunction =
+ std::function<MaybeResults(const sp<IPreparedModel>& preparedModel, const Request& request,
+ DeadlineBoundType deadlineBound)>;
+
+static OptionalTimePoint makeOptionalTimePoint(DeadlineBoundType deadlineBoundType) {
+ OptionalTimePoint deadline;
+ switch (deadlineBoundType) {
+ case DeadlineBoundType::NOW: {
+ const auto currentTime = std::chrono::steady_clock::now();
+ const auto currentTimeInNanoseconds =
+ std::chrono::time_point_cast<std::chrono::nanoseconds>(currentTime);
+ const uint64_t nanosecondsSinceEpoch =
+ currentTimeInNanoseconds.time_since_epoch().count();
+ deadline.nanoseconds(nanosecondsSinceEpoch);
+ } break;
+ case DeadlineBoundType::UNLIMITED: {
+ uint64_t unlimited = std::numeric_limits<uint64_t>::max();
+ deadline.nanoseconds(unlimited);
+ } break;
+ }
+ return deadline;
+}
+
+void runPrepareModelTest(const sp<IDevice>& device, const Model& model, Priority priority,
+ std::optional<DeadlineBoundType> deadlineBound) {
+ OptionalTimePoint deadline;
+ if (deadlineBound.has_value()) {
+ deadline = makeOptionalTimePoint(deadlineBound.value());
+ }
+
+ // see if service can handle model
+ bool fullySupportsModel = false;
+ const Return<void> supportedCall = device->getSupportedOperations_1_3(
+ model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
+ ASSERT_EQ(ErrorStatus::NONE, status);
+ ASSERT_NE(0ul, supported.size());
+ fullySupportsModel = std::all_of(supported.begin(), supported.end(),
+ [](bool valid) { return valid; });
+ });
+ ASSERT_TRUE(supportedCall.isOk());
+
+ // launch prepare model
+ const sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+ const Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_3(
+ model, ExecutionPreference::FAST_SINGLE_ANSWER, priority, deadline,
+ hidl_vec<hidl_handle>(), hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
+ ASSERT_TRUE(prepareLaunchStatus.isOk());
+ ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+ // retrieve prepared model
+ preparedModelCallback->wait();
+ const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+ const sp<V1_0::IPreparedModel> preparedModelV1_0 = preparedModelCallback->getPreparedModel();
+ const sp<IPreparedModel> preparedModel =
+ IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr);
+
+ // The getSupportedOperations_1_3 call returns a list of operations that are
+ // guaranteed not to fail if prepareModel_1_3 is called, and
+ // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
+ // If a driver has any doubt that it can prepare an operation, it must
+ // return false. So here, if a driver isn't sure if it can support an
+ // operation, but reports that it successfully prepared the model, the test
+ // can continue.
+ if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
+ ASSERT_EQ(nullptr, preparedModel.get());
+ return;
+ }
+
+ // verify return status
+ if (!deadlineBound.has_value()) {
+ EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+ } else {
+ switch (deadlineBound.value()) {
+ case DeadlineBoundType::NOW:
+ // If the execution was launched with a deadline of NOW, the
+ // deadline has already passed when the driver would launch the
+ // execution. In this case, the driver must return
+ // MISSED_DEADLINE_*.
+ EXPECT_TRUE(prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
+ prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT);
+ break;
+ case DeadlineBoundType::UNLIMITED:
+ // If an unlimited deadline is supplied, we expect the execution to
+ // proceed normally. In this case, check it normally by breaking out
+ // of the switch statement.
+ EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+ break;
+ }
+ }
+ ASSERT_EQ(prepareReturnStatus == ErrorStatus::NONE, preparedModel.get() != nullptr);
+}
+
+void runPrepareModelTests(const sp<IDevice>& device, const Model& model,
+ bool supportsPrepareModelDeadline) {
+ // test priority
+ for (auto priority : hidl_enum_range<Priority>{}) {
+ SCOPED_TRACE("priority: " + toString(priority));
+ if (priority == kDefaultPriority) continue;
+ runPrepareModelTest(device, model, priority, {});
+ }
+
+ // test deadline
+ if (supportsPrepareModelDeadline) {
+ for (auto deadlineBound : deadlineBounds) {
+ SCOPED_TRACE("deadlineBound: " + toString(deadlineBound));
+ runPrepareModelTest(device, model, kDefaultPriority, deadlineBound);
+ }
+ }
+}
+
+static MaybeResults executeAsynchronously(const sp<IPreparedModel>& preparedModel,
+ const Request& request, DeadlineBoundType deadlineBound) {
+ SCOPED_TRACE("asynchronous");
+ const MeasureTiming measure = MeasureTiming::NO;
+ const OptionalTimePoint deadline = makeOptionalTimePoint(deadlineBound);
+
+ // launch execution
+ const sp<ExecutionCallback> callback = new ExecutionCallback();
+ Return<ErrorStatus> ret = preparedModel->execute_1_3(request, measure, deadline, callback);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(ErrorStatus::NONE, ret.withDefault(ErrorStatus::GENERAL_FAILURE));
+ if (!ret.isOk() || ret != ErrorStatus::NONE) return std::nullopt;
+
+ // retrieve execution results
+ callback->wait();
+ const ErrorStatus status = callback->getStatus();
+ hidl_vec<OutputShape> outputShapes = callback->getOutputShapes();
+ const Timing timing = callback->getTiming();
+
+ // return results
+ return Results{status, std::move(outputShapes), timing};
+}
+
+static MaybeResults executeSynchronously(const sp<IPreparedModel>& preparedModel,
+ const Request& request, DeadlineBoundType deadlineBound) {
+ SCOPED_TRACE("synchronous");
+ const MeasureTiming measure = MeasureTiming::NO;
+ const OptionalTimePoint deadline = makeOptionalTimePoint(deadlineBound);
+
+ // configure results callback
+ MaybeResults results;
+ const auto cb = [&results](const auto&... args) { *results = {args...}; };
+
+ // run execution
+ const Return<void> ret =
+ preparedModel->executeSynchronously_1_3(request, measure, deadline, cb);
+ EXPECT_TRUE(ret.isOk());
+ if (!ret.isOk()) return std::nullopt;
+
+ // return results
+ return results;
+}
+
+void runExecutionTest(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
+ const Request& request, bool synchronous, DeadlineBoundType deadlineBound) {
+ const ExecutionFunction execute = synchronous ? executeSynchronously : executeAsynchronously;
+
+ // Perform execution and unpack results.
+ const auto results = execute(preparedModel, request, deadlineBound);
+ if (!results.has_value()) return;
+ const auto& [status, outputShapes, timing] = results.value();
+
+ // Verify no timing information was returned
+ EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
+ EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
+
+ // Validate deadline information if applicable.
+ switch (deadlineBound) {
+ case DeadlineBoundType::NOW:
+ // If the execution was launched with a deadline of NOW, the
+ // deadline has already passed when the driver would launch the
+ // execution. In this case, the driver must return
+ // MISSED_DEADLINE_*.
+ ASSERT_TRUE(status == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
+ status == ErrorStatus::MISSED_DEADLINE_PERSISTENT);
+ return;
+ case DeadlineBoundType::UNLIMITED:
+ // If an unlimited deadline is supplied, we expect the execution to
+ // proceed normally. In this case, check it normally by breaking out
+ // of the switch statement.
+ ASSERT_EQ(ErrorStatus::NONE, status);
+ break;
+ }
+
+ // If the model output operands are fully specified, outputShapes must be either
+ // either empty, or have the same number of elements as the number of outputs.
+ ASSERT_TRUE(outputShapes.size() == 0 || outputShapes.size() == testModel.outputIndexes.size());
+
+ // Go through all outputs, check returned output shapes.
+ for (uint32_t i = 0; i < outputShapes.size(); i++) {
+ EXPECT_TRUE(outputShapes[i].isSufficient);
+ const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions;
+ const std::vector<uint32_t> actual = outputShapes[i].dimensions;
+ EXPECT_EQ(expect, actual);
+ }
+
+ // Retrieve execution results.
+ ASSERT_TRUE(nn::compliantWithV1_0(request));
+ const V1_0::Request request10 = nn::convertToV1_0(request);
+ const std::vector<TestBuffer> outputs = getOutputBuffers(request10);
+
+ // We want "close-enough" results.
+ checkResults(testModel, outputs);
+}
+
+void runExecutionTests(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
+ const Request& request) {
+ for (bool synchronous : {false, true}) {
+ for (auto deadlineBound : deadlineBounds) {
+ runExecutionTest(preparedModel, testModel, request, synchronous, deadlineBound);
+ }
+ }
+}
+
+void runTests(const sp<IDevice>& device, const TestModel& testModel,
+ std::pair<bool, bool> supportsDeadlines) {
+ // setup
+ const auto [supportsPrepareModelDeadline, supportsExecutionDeadline] = supportsDeadlines;
+ if (!supportsPrepareModelDeadline && !supportsExecutionDeadline) return;
+ const Model model = createModel(testModel);
+
+ // run prepare model tests
+ runPrepareModelTests(device, model, supportsPrepareModelDeadline);
+
+ if (supportsExecutionDeadline) {
+ // prepare model
+ sp<IPreparedModel> preparedModel;
+ createPreparedModel(device, model, &preparedModel);
+ if (preparedModel == nullptr) return;
+
+ // run execution tests
+ const Request request = nn::convertToV1_3(createRequest(testModel));
+ runExecutionTests(preparedModel, testModel, request);
+ }
+}
+
+class DeadlineTest : public GeneratedTestBase {};
+
+TEST_P(DeadlineTest, Test) {
+ runTests(kDevice, kTestModel, mSupportsDeadlines);
+}
+
+INSTANTIATE_GENERATED_TEST(DeadlineTest,
+ [](const TestModel& testModel) { return !testModel.expectFailure; });
+
+} // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/Utils.cpp b/neuralnetworks/1.3/vts/functional/Utils.cpp
new file mode 100644
index 0000000..23e2af8
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/Utils.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "1.3/Utils.h"
+
+#include <iostream>
+
+namespace android::hardware::neuralnetworks::V1_3 {
+
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) {
+ return os << toString(errorStatus);
+}
+
+} // namespace android::hardware::neuralnetworks::V1_3
diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
index 7df8046..6ff9dfd 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
@@ -34,7 +34,6 @@
using nn::ExecutionBurstController;
using nn::RequestChannelSender;
using nn::ResultChannelReceiver;
-using V1_0::ErrorStatus;
using V1_0::Request;
using V1_2::FmqRequestDatum;
using V1_2::FmqResultDatum;
@@ -80,16 +79,17 @@
ASSERT_NE(nullptr, fmqResultDescriptor);
// configure burst
- ErrorStatus errorStatus;
+ V1_0::ErrorStatus errorStatus;
sp<IBurstContext> burstContext;
const Return<void> ret = preparedModel->configureExecutionBurst(
callback, *fmqRequestDescriptor, *fmqResultDescriptor,
- [&errorStatus, &burstContext](ErrorStatus status, const sp<IBurstContext>& context) {
+ [&errorStatus, &burstContext](V1_0::ErrorStatus status,
+ const sp<IBurstContext>& context) {
errorStatus = status;
burstContext = context;
});
ASSERT_TRUE(ret.isOk());
- ASSERT_EQ(ErrorStatus::NONE, errorStatus);
+ ASSERT_EQ(V1_0::ErrorStatus::NONE, errorStatus);
ASSERT_NE(nullptr, burstContext.get());
// return values
@@ -144,7 +144,7 @@
auto results = receiver->getBlocking();
ASSERT_TRUE(results.has_value());
const auto [status, outputShapes, timing] = std::move(*results);
- EXPECT_NE(ErrorStatus::NONE, status);
+ EXPECT_NE(V1_0::ErrorStatus::NONE, status);
EXPECT_EQ(0u, outputShapes.size());
EXPECT_TRUE(badTiming(timing));
}
@@ -302,14 +302,15 @@
// collect serialized result by running regular burst
const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] =
controllerRegular->compute(request, MeasureTiming::NO, keys);
- const ErrorStatus statusRegular = nn::convertResultCodeToErrorStatus(nRegular);
+ const V1_0::ErrorStatus statusRegular =
+ nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nRegular));
EXPECT_FALSE(fallbackRegular);
// skip test if regular burst output isn't useful for testing a failure
// caused by having too small of a length for the result FMQ
const std::vector<FmqResultDatum> serialized =
android::nn::serialize(statusRegular, outputShapesRegular, timingRegular);
- if (statusRegular != ErrorStatus::NONE ||
+ if (statusRegular != V1_0::ErrorStatus::NONE ||
serialized.size() <= kExecutionBurstChannelSmallLength) {
return;
}
@@ -318,8 +319,9 @@
// large enough to return the serialized result
const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] =
controllerSmall->compute(request, MeasureTiming::NO, keys);
- const ErrorStatus statusSmall = nn::convertResultCodeToErrorStatus(nSmall);
- EXPECT_NE(ErrorStatus::NONE, statusSmall);
+ const V1_0::ErrorStatus statusSmall =
+ nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nSmall));
+ EXPECT_NE(V1_0::ErrorStatus::NONE, statusSmall);
EXPECT_EQ(0u, outputShapesSmall.size());
EXPECT_TRUE(badTiming(timingSmall));
EXPECT_FALSE(fallbackSmall);
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 8395111..1245432 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -18,14 +18,13 @@
#include "1.0/Utils.h"
#include "1.3/Callbacks.h"
+#include "1.3/Utils.h"
#include "GeneratedTestHarness.h"
#include "VtsHalNeuralnetworks.h"
namespace android::hardware::neuralnetworks::V1_3::vts::functional {
using implementation::PreparedModelCallback;
-using V1_0::ErrorStatus;
-using V1_0::OperandLifeTime;
using V1_1::ExecutionPreference;
using V1_2::SymmPerChannelQuantParams;
using HidlToken =
@@ -45,13 +44,19 @@
}
static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
- const Model& model, ExecutionPreference preference) {
+ const Model& model, ExecutionPreference preference,
+ bool testDeadline) {
SCOPED_TRACE(message + " [prepareModel_1_3]");
+ OptionalTimePoint deadline;
+ if (testDeadline) {
+ deadline.nanoseconds(std::numeric_limits<uint64_t>::max());
+ }
+
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- Return<ErrorStatus> prepareLaunchStatus =
- device->prepareModel_1_3(model, preference, hidl_vec<hidl_handle>(),
- hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
+ Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_3(
+ model, preference, kDefaultPriority, deadline, hidl_vec<hidl_handle>(),
+ hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
@@ -74,31 +79,32 @@
// to the model does not leave this function.
static void validate(const sp<IDevice>& device, const std::string& message, Model model,
const std::function<void(Model*)>& mutation,
- ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
+ ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER,
+ bool testDeadline = false) {
mutation(&model);
- if (validExecutionPreference(preference)) {
+ if (validExecutionPreference(preference) && !testDeadline) {
validateGetSupportedOperations(device, message, model);
}
- validatePrepareModel(device, message, model, preference);
+ validatePrepareModel(device, message, model, preference, testDeadline);
}
static uint32_t addOperand(Model* model) {
- return hidl_vec_push_back(&model->operands,
+ return hidl_vec_push_back(&model->main.operands,
{
.type = OperandType::INT32,
.dimensions = {},
.numberOfConsumers = 0,
.scale = 0.0f,
.zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_INPUT,
+ .lifetime = OperandLifeTime::SUBGRAPH_INPUT,
.location = {.poolIndex = 0, .offset = 0, .length = 0},
});
}
static uint32_t addOperand(Model* model, OperandLifeTime lifetime) {
uint32_t index = addOperand(model);
- model->operands[index].numberOfConsumers = 1;
- model->operands[index].lifetime = lifetime;
+ model->main.operands[index].numberOfConsumers = 1;
+ model->main.operands[index].lifetime = lifetime;
return index;
}
@@ -112,13 +118,13 @@
};
static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
for (uint32_t invalidOperandType : invalidOperandTypes) {
const std::string message = "mutateOperandTypeTest: operand " +
std::to_string(operand) + " set to value " +
std::to_string(invalidOperandType);
validate(device, message, model, [operand, invalidOperandType](Model* model) {
- model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
+ model->main.operands[operand].type = static_cast<OperandType>(invalidOperandType);
});
}
}
@@ -150,15 +156,15 @@
}
static void mutateOperandRankTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
- const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
+ const uint32_t invalidRank = getInvalidRank(model.main.operands[operand].type);
if (invalidRank == 0) {
continue;
}
const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
" has rank of " + std::to_string(invalidRank);
validate(device, message, model, [operand, invalidRank](Model* model) {
- model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+ model->main.operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
});
}
}
@@ -190,12 +196,12 @@
}
static void mutateOperandScaleTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
- const float invalidScale = getInvalidScale(model.operands[operand].type);
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
+ const float invalidScale = getInvalidScale(model.main.operands[operand].type);
const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
" has scale of " + std::to_string(invalidScale);
validate(device, message, model, [operand, invalidScale](Model* model) {
- model->operands[operand].scale = invalidScale;
+ model->main.operands[operand].scale = invalidScale;
});
}
}
@@ -229,15 +235,15 @@
}
static void mutateOperandZeroPointTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
const std::vector<int32_t> invalidZeroPoints =
- getInvalidZeroPoints(model.operands[operand].type);
+ getInvalidZeroPoints(model.main.operands[operand].type);
for (int32_t invalidZeroPoint : invalidZeroPoints) {
const std::string message = "mutateOperandZeroPointTest: operand " +
std::to_string(operand) + " has zero point of " +
std::to_string(invalidZeroPoint);
validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
- model->operands[operand].zeroPoint = invalidZeroPoint;
+ model->main.operands[operand].zeroPoint = invalidZeroPoint;
});
}
}
@@ -310,11 +316,11 @@
static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, const Model& model) {
// Do not test OEM types
- if (type == model.operands[operand].type || type == OperandType::OEM ||
+ if (type == model.main.operands[operand].type || type == OperandType::OEM ||
type == OperandType::TENSOR_OEM_BYTE) {
return true;
}
- for (const Operation& operation : model.operations) {
+ for (const Operation& operation : model.main.operations) {
// Skip mutateOperationOperandTypeTest for the following operations.
// - LSH_PROJECTION's second argument is allowed to have any type.
// - ARGMIN and ARGMAX's first argument can be any of
@@ -331,6 +337,7 @@
// - TRANSPOSE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
// - AXIS_ALIGNED_BBOX_TRANSFORM bounding boxes (arg 1) can be of
// TENSOR_QUANT8_ASYMM or TENSOR_QUANT8_ASYMM_SIGNED.
+ // - RANK's input can have any TENSOR_* type.
switch (operation.type) {
case OperationType::LSH_PROJECTION: {
if (operand == operation.inputs[1]) {
@@ -393,6 +400,20 @@
return true;
}
} break;
+ case OperationType::RANK: {
+ if (operand == operation.inputs[0] &&
+ (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32 ||
+ type == OperandType::TENSOR_INT32 ||
+ type == OperandType::TENSOR_QUANT8_ASYMM ||
+ type == OperandType::TENSOR_QUANT16_SYMM ||
+ type == OperandType::TENSOR_BOOL8 ||
+ type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL ||
+ type == OperandType::TENSOR_QUANT16_ASYMM ||
+ type == OperandType::TENSOR_QUANT8_SYMM ||
+ type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED)) {
+ return true;
+ }
+ } break;
default:
break;
}
@@ -401,7 +422,7 @@
}
static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
for (OperandType invalidOperandType : hidl_enum_range<OperandType>{}) {
if (mutateOperationOperandTypeSkip(operand, invalidOperandType, model)) {
continue;
@@ -410,7 +431,7 @@
std::to_string(operand) + " set to type " +
toString(invalidOperandType);
validate(device, message, model, [operand, invalidOperandType](Model* model) {
- mutateOperand(&model->operands[operand], invalidOperandType);
+ mutateOperand(&model->main.operands[operand], invalidOperandType);
});
}
}
@@ -425,13 +446,13 @@
};
static void mutateOperationTypeTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
for (uint32_t invalidOperationType : invalidOperationTypes) {
const std::string message = "mutateOperationTypeTest: operation " +
std::to_string(operation) + " set to value " +
std::to_string(invalidOperationType);
validate(device, message, model, [operation, invalidOperationType](Model* model) {
- model->operations[operation].type =
+ model->main.operations[operation].type =
static_cast<OperationType>(invalidOperationType);
});
}
@@ -441,14 +462,14 @@
///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX /////////////////////////
static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- const uint32_t invalidOperand = model.operands.size();
- for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ const uint32_t invalidOperand = model.main.operands.size();
+ for (size_t input = 0; input < model.main.operations[operation].inputs.size(); ++input) {
const std::string message = "mutateOperationInputOperandIndexTest: operation " +
std::to_string(operation) + " input " +
std::to_string(input);
validate(device, message, model, [operation, input, invalidOperand](Model* model) {
- model->operations[operation].inputs[input] = invalidOperand;
+ model->main.operations[operation].inputs[input] = invalidOperand;
});
}
}
@@ -457,14 +478,15 @@
///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX /////////////////////////
static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- const uint32_t invalidOperand = model.operands.size();
- for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ const uint32_t invalidOperand = model.main.operands.size();
+ for (size_t output = 0; output < model.main.operations[operation].outputs.size();
+ ++output) {
const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
std::to_string(operation) + " output " +
std::to_string(output);
validate(device, message, model, [operation, output, invalidOperand](Model* model) {
- model->operations[operation].outputs[output] = invalidOperand;
+ model->main.operations[operation].outputs[output] = invalidOperand;
});
}
}
@@ -485,17 +507,17 @@
}
static void removeOperand(Model* model, uint32_t index) {
- hidl_vec_removeAt(&model->operands, index);
- for (Operation& operation : model->operations) {
+ hidl_vec_removeAt(&model->main.operands, index);
+ for (Operation& operation : model->main.operations) {
removeValueAndDecrementGreaterValues(&operation.inputs, index);
removeValueAndDecrementGreaterValues(&operation.outputs, index);
}
- removeValueAndDecrementGreaterValues(&model->inputIndexes, index);
- removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
+ removeValueAndDecrementGreaterValues(&model->main.inputIndexes, index);
+ removeValueAndDecrementGreaterValues(&model->main.outputIndexes, index);
}
static bool removeOperandSkip(size_t operand, const Model& model) {
- for (const Operation& operation : model.operations) {
+ for (const Operation& operation : model.main.operations) {
// Skip removeOperandTest for the following operations.
// - SPLIT's outputs are not checked during prepareModel.
if (operation.type == OperationType::SPLIT) {
@@ -520,7 +542,7 @@
}
static void removeOperandTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
if (removeOperandSkip(operand, model)) {
continue;
}
@@ -533,14 +555,14 @@
///////////////////////// REMOVE OPERATION /////////////////////////
static void removeOperation(Model* model, uint32_t index) {
- for (uint32_t operand : model->operations[index].inputs) {
- model->operands[operand].numberOfConsumers--;
+ for (uint32_t operand : model->main.operations[index].inputs) {
+ model->main.operands[operand].numberOfConsumers--;
}
- hidl_vec_removeAt(&model->operations, index);
+ hidl_vec_removeAt(&model->main.operations, index);
}
static void removeOperationTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
const std::string message = "removeOperationTest: operation " + std::to_string(operation);
validate(device, message, model,
[operation](Model* model) { removeOperation(model, operation); });
@@ -615,9 +637,9 @@
}
static void removeOperationInputTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
- const Operation& op = model.operations[operation];
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ for (size_t input = 0; input < model.main.operations[operation].inputs.size(); ++input) {
+ const Operation& op = model.main.operations[operation];
if (removeOperationInputSkip(op, input)) {
continue;
}
@@ -625,9 +647,9 @@
std::to_string(operation) + ", input " +
std::to_string(input);
validate(device, message, model, [operation, input](Model* model) {
- uint32_t operand = model->operations[operation].inputs[input];
- model->operands[operand].numberOfConsumers--;
- hidl_vec_removeAt(&model->operations[operation].inputs, input);
+ uint32_t operand = model->main.operations[operation].inputs[input];
+ model->main.operands[operand].numberOfConsumers--;
+ hidl_vec_removeAt(&model->main.operations[operation].inputs, input);
});
}
}
@@ -636,13 +658,14 @@
///////////////////////// REMOVE OPERATION OUTPUT /////////////////////////
static void removeOperationOutputTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ for (size_t output = 0; output < model.main.operations[operation].outputs.size();
+ ++output) {
const std::string message = "removeOperationOutputTest: operation " +
std::to_string(operation) + ", output " +
std::to_string(output);
validate(device, message, model, [operation, output](Model* model) {
- hidl_vec_removeAt(&model->operations[operation].outputs, output);
+ hidl_vec_removeAt(&model->main.operations[operation].outputs, output);
});
}
}
@@ -669,15 +692,15 @@
}
static void addOperationInputTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- if (addOperationInputSkip(model.operations[operation])) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ if (addOperationInputSkip(model.main.operations[operation])) {
continue;
}
const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
validate(device, message, model, [operation](Model* model) {
- uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
- hidl_vec_push_back(&model->operations[operation].inputs, index);
- hidl_vec_push_back(&model->inputIndexes, index);
+ uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_INPUT);
+ hidl_vec_push_back(&model->main.operations[operation].inputs, index);
+ hidl_vec_push_back(&model->main.inputIndexes, index);
});
}
}
@@ -685,13 +708,13 @@
///////////////////////// ADD OPERATION OUTPUT /////////////////////////
static void addOperationOutputTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
const std::string message =
"addOperationOutputTest: operation " + std::to_string(operation);
validate(device, message, model, [operation](Model* model) {
- uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
- hidl_vec_push_back(&model->operations[operation].outputs, index);
- hidl_vec_push_back(&model->outputIndexes, index);
+ uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_OUTPUT);
+ hidl_vec_push_back(&model->main.operations[operation].outputs, index);
+ hidl_vec_push_back(&model->main.outputIndexes, index);
});
}
}
@@ -713,9 +736,19 @@
}
}
+///////////////////////// DEADLINE /////////////////////////
+
+static void deadlineTest(const sp<IDevice>& device, const Model& model) {
+ const std::string message = "deadlineTest: deadline not supported";
+ const auto noop = [](Model*) {};
+ validate(device, message, model, noop, ExecutionPreference::FAST_SINGLE_ANSWER,
+ /*testDeadline=*/true);
+}
+
////////////////////////// ENTRY POINT //////////////////////////////
-void validateModel(const sp<IDevice>& device, const Model& model) {
+void validateModel(const sp<IDevice>& device, const Model& model,
+ bool prepareModelDeadlineSupported) {
mutateOperandTypeTest(device, model);
mutateOperandRankTest(device, model);
mutateOperandScaleTest(device, model);
@@ -731,6 +764,9 @@
addOperationInputTest(device, model);
addOperationOutputTest(device, model);
mutateExecutionPreferenceTest(device, model);
+ if (!prepareModelDeadlineSupported) {
+ deadlineTest(device, model);
+ }
}
} // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index 8092d04..1ddd09c 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -16,9 +16,11 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
+#include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
#include <chrono>
+
#include "1.0/Utils.h"
-#include "1.2/Callbacks.h"
+#include "1.3/Callbacks.h"
#include "ExecutionBurstController.h"
#include "GeneratedTestHarness.h"
#include "TestHarness.h"
@@ -27,12 +29,10 @@
namespace android::hardware::neuralnetworks::V1_3::vts::functional {
-using V1_0::ErrorStatus;
-using V1_0::Request;
+using implementation::ExecutionCallback;
using V1_2::MeasureTiming;
using V1_2::OutputShape;
using V1_2::Timing;
-using V1_2::implementation::ExecutionCallback;
///////////////////////// UTILITY FUNCTIONS /////////////////////////
@@ -45,7 +45,8 @@
// that use the request. Note that the request here is passed by value, and any
// mutation to the request does not leave this function.
static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
- Request request, const std::function<void(Request*)>& mutation) {
+ Request request, const std::function<void(Request*)>& mutation,
+ bool testDeadline = false) {
mutation(&request);
// We'd like to test both with timing requested and without timing
@@ -58,13 +59,18 @@
};
MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO;
+ OptionalTimePoint deadline;
+ if (testDeadline) {
+ deadline.nanoseconds(std::numeric_limits<uint64_t>::max());
+ }
+
// asynchronous
{
SCOPED_TRACE(message + " [execute_1_3]");
sp<ExecutionCallback> executionCallback = new ExecutionCallback();
Return<ErrorStatus> executeLaunchStatus =
- preparedModel->execute_1_3(request, measure, executionCallback);
+ preparedModel->execute_1_3(request, measure, deadline, executionCallback);
ASSERT_TRUE(executeLaunchStatus.isOk());
ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
@@ -82,7 +88,7 @@
SCOPED_TRACE(message + " [executeSynchronously_1_3]");
Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
- request, measure,
+ request, measure, deadline,
[](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes,
const Timing& timing) {
ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
@@ -93,9 +99,13 @@
}
// burst
- {
+ // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2.
+ if (!testDeadline) {
SCOPED_TRACE(message + " [burst]");
+ ASSERT_TRUE(nn::compliantWithV1_0(request));
+ V1_0::Request request10 = nn::convertToV1_0(request);
+
// create burst
std::shared_ptr<::android::nn::ExecutionBurstController> burst =
android::nn::ExecutionBurstController::create(preparedModel,
@@ -103,13 +113,13 @@
ASSERT_NE(nullptr, burst.get());
// create memory keys
- std::vector<intptr_t> keys(request.pools.size());
+ std::vector<intptr_t> keys(request10.pools.size());
for (size_t i = 0; i < keys.size(); ++i) {
- keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
+ keys[i] = reinterpret_cast<intptr_t>(&request10.pools[i]);
}
// execute and verify
- const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys);
+ const auto [n, outputShapes, timing, fallback] = burst->compute(request10, measure, keys);
const ErrorStatus status = nn::convertResultCodeToErrorStatus(n);
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
EXPECT_EQ(outputShapes.size(), 0);
@@ -117,7 +127,7 @@
EXPECT_FALSE(fallback);
// additional burst testing
- if (request.pools.size() > 0) {
+ if (request10.pools.size() > 0) {
// valid free
burst->freeMemory(keys.front());
@@ -128,6 +138,22 @@
burst->freeMemory(keys.front());
}
}
+
+ // dispatch
+ {
+ SCOPED_TRACE(message + " [executeFenced]");
+ Return<void> ret = preparedModel->executeFenced(
+ request, {}, MeasureTiming::NO,
+ [](ErrorStatus error, const hidl_handle& handle,
+ const sp<IFencedExecutionCallback>& callback) {
+ if (error != ErrorStatus::DEVICE_UNAVAILABLE) {
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+ }
+ ASSERT_EQ(handle.getNativeHandle(), nullptr);
+ ASSERT_EQ(callback, nullptr);
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
}
///////////////////////// REMOVE INPUT ////////////////////////////////////
@@ -150,17 +176,29 @@
}
}
+///////////////////////// DEADLINE ////////////////////////////////////
+
+static void deadlineTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+ const std::string message = "deadlineTest: deadline not supported";
+ const auto noop = [](Request*) {};
+ validate(preparedModel, message, request, noop, /*testDeadline=*/true);
+}
+
///////////////////////////// ENTRY POINT //////////////////////////////////
-void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request,
+ bool executionDeadlineSupported) {
removeInputTest(preparedModel, request);
removeOutputTest(preparedModel, request);
+ if (!executionDeadlineSupported) {
+ deadlineTest(preparedModel, request);
+ }
}
void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request) {
SCOPED_TRACE("Expecting request to fail [executeSynchronously_1_3]");
Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
- request, MeasureTiming::NO,
+ request, MeasureTiming::NO, {},
[](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
ASSERT_NE(ErrorStatus::NONE, error);
EXPECT_EQ(outputShapes.size(), 0);
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
index 92d8fa7..c84f5b7 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
@@ -23,16 +23,16 @@
#include <utility>
#include "1.0/Utils.h"
#include "1.3/Callbacks.h"
+#include "1.3/Utils.h"
#include "GeneratedTestHarness.h"
#include "TestHarness.h"
+#include "Utils.h"
namespace android::hardware::neuralnetworks::V1_3::vts::functional {
using HidlToken =
hidl_array<uint8_t, static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
using implementation::PreparedModelCallback;
-using V1_0::ErrorStatus;
-using V1_0::Request;
using V1_1::ExecutionPreference;
// internal helper function
@@ -55,8 +55,8 @@
// launch prepare model
const sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
const Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_3(
- model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec<hidl_handle>(),
- hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
+ model, ExecutionPreference::FAST_SINGLE_ANSWER, kDefaultPriority, {},
+ hidl_vec<hidl_handle>(), hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
@@ -84,6 +84,7 @@
<< std::endl;
GTEST_SKIP();
}
+
ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
ASSERT_NE(nullptr, preparedModel->get());
}
@@ -122,30 +123,58 @@
INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest);
// Forward declaration from ValidateModel.cpp
-void validateModel(const sp<IDevice>& device, const Model& model);
+void validateModel(const sp<IDevice>& device, const Model& model,
+ bool prepareModelDeadlineSupported);
// Forward declaration from ValidateRequest.cpp
-void validateRequest(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
+void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request,
+ bool executionDeadlineSupported);
// Forward declaration from ValidateRequest.cpp
-void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
+void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request);
// Forward declaration from ValidateBurst.cpp
void validateBurst(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
-void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request) {
- validateModel(device, model);
+// Validate sync_fence handles for dispatch with valid input
+void validateExecuteFenced(const sp<IPreparedModel>& preparedModel, const Request& request) {
+ SCOPED_TRACE("Expecting request to fail [executeFenced]");
+ Return<void> ret_null =
+ preparedModel->executeFenced(request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO,
+ [](ErrorStatus error, const hidl_handle& handle,
+ const sp<IFencedExecutionCallback>& callback) {
+ // TODO: fix this once sample driver impl is merged.
+ if (error != ErrorStatus::DEVICE_UNAVAILABLE) {
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+ }
+ ASSERT_EQ(handle.getNativeHandle(), nullptr);
+ ASSERT_EQ(callback, nullptr);
+ });
+ ASSERT_TRUE(ret_null.isOk());
+}
+
+void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request,
+ std::pair<bool, bool> supportsDeadlines) {
+ const auto [prepareModelDeadlineSupported, executionDeadlineSupported] = supportsDeadlines;
+ validateModel(device, model, prepareModelDeadlineSupported);
// Create IPreparedModel.
sp<IPreparedModel> preparedModel;
createPreparedModel(device, model, &preparedModel);
if (preparedModel == nullptr) return;
- validateRequest(preparedModel, request);
- validateBurst(preparedModel, request);
+ validateRequest(preparedModel, request, executionDeadlineSupported);
+ validateExecuteFenced(preparedModel, request);
+
+ // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2.
+ ASSERT_TRUE(nn::compliantWithV1_0(request));
+ V1_0::Request request10 = nn::convertToV1_0(request);
+ validateBurst(preparedModel, request10);
}
-void validateFailure(const sp<IDevice>& device, const Model& model, const Request& request) {
+void validateFailure(const sp<IDevice>& device, const Model& model, const Request& request,
+ std::pair<bool, bool> supportsDeadlines) {
+ const bool prepareModelDeadlineSupported = supportsDeadlines.first;
// TODO: Should this always succeed?
// What if the invalid input is part of the model (i.e., a parameter).
- validateModel(device, model);
+ validateModel(device, model, prepareModelDeadlineSupported);
// Create IPreparedModel.
sp<IPreparedModel> preparedModel;
@@ -157,11 +186,11 @@
TEST_P(ValidationTest, Test) {
const Model model = createModel(kTestModel);
- const Request request = createRequest(kTestModel);
+ const Request request = nn::convertToV1_3(createRequest(kTestModel));
if (kTestModel.expectFailure) {
- validateFailure(kDevice, model, request);
+ validateFailure(kDevice, model, request, mSupportsDeadlines);
} else {
- validateEverything(kDevice, model, request);
+ validateEverything(kDevice, model, request, mSupportsDeadlines);
}
}
diff --git a/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h b/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h
index fb19a84..e9dec2d 100644
--- a/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h
+++ b/neuralnetworks/1.3/vts/functional/include/1.3/Callbacks.h
@@ -18,8 +18,11 @@
#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_CALLBACKS_H
#include <android-base/thread_annotations.h>
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.3/IExecutionCallback.h>
#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
#include <hidl/Status.h>
#include <condition_variable>
@@ -136,7 +139,7 @@
* @param preparedModel Returned model that has been prepared for execution,
* nullptr if the model was unable to be prepared.
*/
- Return<void> notify_1_3(V1_0::ErrorStatus status,
+ Return<void> notify_1_3(V1_3::ErrorStatus status,
const sp<V1_3::IPreparedModel>& preparedModel) override;
/**
@@ -158,7 +161,7 @@
* - GENERAL_FAILURE if there is an unspecified error
* - INVALID_ARGUMENT if the input model is invalid
*/
- V1_0::ErrorStatus getStatus() const;
+ ErrorStatus getStatus() const;
/**
* Retrieves the model that has been prepared for execution from the
@@ -173,13 +176,216 @@
sp<V1_0::IPreparedModel> getPreparedModel() const;
private:
+ Return<void> notifyInternal(ErrorStatus status, const sp<V1_0::IPreparedModel>& preparedModel);
+
mutable std::mutex mMutex;
mutable std::condition_variable mCondition;
bool mNotified GUARDED_BY(mMutex) = false;
- V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE;
+ ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
sp<V1_0::IPreparedModel> mPreparedModel;
};
+/**
+ * The ExecutionCallback class is used to receive the results of the execution
+ * from a task executing asynchronously with respect to the runtime. If a
+ * calling thread calls wait or get* on a ExecutionCallback object and the
+ * corresponding asynchronous task has not finished the execution, the calling
+ * thread will block until the asynchronous task has either called one of the
+ * notify* methods.
+ *
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify* are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IPreparedModel::execute*.
+ */
+class ExecutionCallback : public IExecutionCallback {
+ public:
+ /**
+ * IExecutionCallback::notify marks the callback object with the return
+ * status of the asynchronous execution that held this callback and enables
+ * all prior and future wait calls on the ExecutionCallback object to
+ * proceed.
+ *
+ * One of the IExecutionCallback::notify* methods must be called on a given
+ * ExecutionCallback object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify* are used, and the results from subsequent calls
+ * are discarded.
+ *
+ * @param status Error status returned from launching the asynchronous task
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). Must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large
+ * enough to store the resultant values
+ * - INVALID_ARGUMENT if the input request is invalid
+ */
+ Return<void> notify(V1_0::ErrorStatus status) override;
+
+ /**
+ * IExecutionCallback::notify_1_2 marks the callback object with the results
+ * (error status, dynamic output shapes, and timing information) of the
+ * asynchronous execution that held this callback and enables all prior and
+ * future wait calls on the ExecutionCallback object to proceed.
+ *
+ * One of the IExecutionCallback::notify* methods must be called on a given
+ * ExecutionCallback object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify* are used, and the results from subsequent calls
+ * are discarded.
+ *
+ * @param status Error status returned from launching the asynchronous task
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). Must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified
+ * error
+ * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is
+ * not large enough to store the corresponding output
+ * - INVALID_ARGUMENT if one of the input arguments to prepareModel is
+ * invalid
+ * @param outputShapes A list of shape information of model output operands.
+ * The index into "outputShapes" corresponds to the index of the output
+ * operand in the Request outputs vector. outputShapes must be empty
+ * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE.
+ * @param Timing Duration of execution. Unless MeasureTiming::YES was passed
+ * when launching the execution and status is NONE, all times must be
+ * reported as UINT64_MAX. A driver may choose to report any time as
+ * UINT64_MAX, indicating that particular measurement is not available.
+ */
+ Return<void> notify_1_2(V1_0::ErrorStatus status,
+ const hidl_vec<V1_2::OutputShape>& outputShapes,
+ const V1_2::Timing& timing) override;
+
+ /**
+ * IExecutionCallback::notify_1_3 marks the callback object with the results
+ * (error status, dynamic output shapes, and timing information) of the
+ * asynchronous execution that held this callback and enables all prior and
+ * future wait calls on the ExecutionCallback object to proceed.
+ *
+ * One of the IExecutionCallback::notify* methods must be called on a given
+ * ExecutionCallback object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify* are used, and the results from subsequent calls
+ * are discarded.
+ *
+ * @param status Error status returned from launching the asynchronous task
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). Must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified
+ * error
+ * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is
+ * not large enough to store the corresponding output
+ * - INVALID_ARGUMENT if one of the input arguments to prepareModel is
+ * invalid
+ * - MISSED_DEADLINE_* if the deadline was not met
+ * @param outputShapes A list of shape information of model output operands.
+ * The index into "outputShapes" corresponds to the index of the output
+ * operand in the Request outputs vector. outputShapes must be empty
+ * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE.
+ * @param Timing Duration of execution. Unless MeasureTiming::YES was passed
+ * when launching the execution and status is NONE, all times must be
+ * reported as UINT64_MAX. A driver may choose to report any time as
+ * UINT64_MAX, indicating that particular measurement is not available.
+ */
+ Return<void> notify_1_3(V1_3::ErrorStatus status,
+ const hidl_vec<V1_2::OutputShape>& outputShapes,
+ const V1_2::Timing& timing) override;
+
+ /**
+ * ExecutionCallback::wait blocks until notify* has been called on the
+ * callback object.
+ */
+ void wait() const;
+
+ /**
+ * Retrieves the error status returned from the asynchronous task launched
+ * by one of the IPreparedModel::execute* methods. If
+ * IPreparedModel::execute* (but not IPreparedModel::executeSynchronously*)
+ * has not finished asynchronously executing, this call will block until the
+ * asynchronous task notifies the object.
+ *
+ * @return status Error status returned from launching the asynchronous task
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). Must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified
+ * error
+ * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is
+ * not large enough to store the corresponding output
+ * - INVALID_ARGUMENT if one of the input arguments to prepareModel is
+ * invalid
+ * - MISSED_DEADLINE_* if the deadline could not be met
+ */
+ V1_3::ErrorStatus getStatus() const;
+
+ /**
+ * Retrieves the error status returned from the asynchronous task launched
+ * by one of the IPreparedModel::execute* methods. If
+ * IPreparedModel::execute* (but not IPreparedModel::executeSynchronously*)
+ * has not finished asynchronously executing, this call will block until the
+ * asynchronous task notifies the object.
+ *
+ * If the asynchronous task was launched by IPreparedModel::execute, an
+ * empty vector will be returned.
+ *
+ * @return outputShapes A list of shape information of model output
+ * operands. The index into "outputShapes" corresponds to the index of
+ * the output operand in the Request outputs vector. outputShapes must
+ * be empty unless the status is either NONE or
+ * OUTPUT_INSUFFICIENT_SIZE. outputShaps may be empty if the status is
+ * NONE and all model output operands are fully-specified at execution
+ * time. outputShapes must have the same number of elements as the
+ * number of model output operands if the status is
+ * OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has
+ * at least one output operand that is not fully-specified.
+ */
+ const std::vector<V1_2::OutputShape>& getOutputShapes() const;
+
+ /**
+ * Retrieves the error status returned from the asynchronous task launched
+ * by one of the IPreparedModel::execute* methods. If
+ * IPreparedModel::execute* (but not IPreparedModel::executeSynchronously*)
+ * has not finished asynchronously executing, this call will block until the
+ * asynchronous task notifies the object.
+ *
+ * If the asynchronous task was launched by IPreparedModel::execute, every
+ * time must be UINT64_MAX.
+ *
+ * @return timing Duration of the execution. Every time must be UINT64_MAX
+ * unless the status is NONE.
+ */
+ V1_2::Timing getTiming() const;
+
+ private:
+ /*
+ * ExecutionCallback::notifyInternal stores the results of the execution
+ * (status, output shapes, and timing information) in the ExecutionCallback
+ * object before any call to wait or get* return. It then enables all prior
+ * and future wait calls on the ExecutionCallback object to proceed.
+ */
+ Return<void> notifyInternal(V1_3::ErrorStatus errorStatus,
+ hidl_vec<V1_2::OutputShape> outputShapes, V1_2::Timing timing);
+
+ // members
+ mutable std::mutex mMutex;
+ mutable std::condition_variable mCondition;
+ bool mNotified GUARDED_BY(mMutex) = false;
+ V1_3::ErrorStatus mErrorStatus = V1_3::ErrorStatus::GENERAL_FAILURE;
+ std::vector<V1_2::OutputShape> mOutputShapes = {};
+ V1_2::Timing mTiming = {};
+};
+
} // namespace android::hardware::neuralnetworks::V1_3::implementation
#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_CALLBACKS_H
diff --git a/neuralnetworks/1.3/vts/functional/include/1.3/Utils.h b/neuralnetworks/1.3/vts/functional/include/1.3/Utils.h
new file mode 100644
index 0000000..3661b66
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/include/1.3/Utils.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.
+ */
+
+#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_UTILS_H
+#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_UTILS_H
+
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <iosfwd>
+
+namespace android::hardware::neuralnetworks {
+
+inline constexpr V1_3::Priority kDefaultPriority = V1_3::Priority::MEDIUM;
+
+} // namespace android::hardware::neuralnetworks
+
+namespace android::hardware::neuralnetworks::V1_3 {
+
+// pretty-print values for error messages
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus);
+
+} // namespace android::hardware::neuralnetworks::V1_3
+
+#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_UTILS_H
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
index 22cc4e1..bc40500 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -16,10 +16,10 @@
package android.hardware.radio@1.5;
-import @1.2::DataRequestReason;
import @1.0::CdmaSmsMessage;
-import @1.4::IRadio;
+import @1.2::DataRequestReason;
import @1.4::DataProfileInfo;
+import @1.4::IRadio;
import @1.5::AccessNetwork;
import @1.5::BarringInfo;
import @1.5::DataProfileInfo;
@@ -27,6 +27,7 @@
import @1.5::LinkAddress;
import @1.5::NetworkScanRequest;
import @1.5::PersoSubstate;
+import @1.5::RadioAccessNetworks;
import @1.5::RadioAccessSpecifier;
import @1.5::SignalThresholdInfo;
@@ -249,15 +250,40 @@
oneway getBarringInfo(int32_t serial);
/**
- * Requests that deactivates one category of the device personalization.
+ * Request current voice registration state
*
* @param serial Serial number of request.
- * @param persoType SIM personalization type.
- * @param controlKey depersonalization code corresponding to persoType
*
- * Response function is IRadioResponse.supplySimDepersonalizationResponse()
+ * Response function is IRadioResponse.getVoiceRegistrationStateResponse_1_5()
*/
- oneway supplySimDepersonalization(int32_t serial, PersoSubstate persoType, string controlKey);
+ oneway getVoiceRegistrationState_1_5(int32_t serial);
+
+ /**
+ * Request current data registration state
+ *
+ * @param serial Serial number of request.
+ *
+ * Response function is IRadioResponse.getDataRegistrationStateResponse_1_5()
+ */
+ oneway getDataRegistrationState_1_5(int32_t serial);
+
+ /*
+ * Manually select a specified network.
+ * This request must not respond until the new operator is selected and registered.
+ * Per TS 23.122, the RAN is just the initial suggested value.
+ * If registration fails, the RAN is not available afterwards, or the RAN is not within
+ * the network types specified by IRadio::setPreferredNetworkTypeBitmap, then the modem
+ * will need to select the next best RAN for network registration.
+ *
+ * @param serial Serial number of request.
+ * @param operatorNumeric String specifying MCCMNC of network to select (eg "310170").
+ * @param ran Initial suggested radio access network type. If value is UNKNOWN, the modem
+ * will select the next best RAN for network registration.
+ *
+ * Response function is IRadioResponse.setNetworkSelectionModeManualResponse_1_5()
+ */
+ oneway setNetworkSelectionModeManual_1_5(int32_t serial, string operatorNumeric,
+ RadioAccessNetworks ran);
/**
* Send an SMS message. Identical to sendCdmaSms,
@@ -269,4 +295,15 @@
* Response callback is IRadioResponse.sendCdmaSMSExpectMoreResponse()
*/
oneway sendCdmaSmsExpectMore(int32_t serial, CdmaSmsMessage sms);
+
+ /**
+ * Requests that deactivates one category of the device personalization.
+ *
+ * @param serial Serial number of request.
+ * @param persoType SIM personalization type.
+ * @param controlKey depersonalization code corresponding to persoType
+ *
+ * Response function is IRadioResponse.supplySimDepersonalizationResponse()
+ */
+ oneway supplySimDepersonalization(int32_t serial, PersoSubstate persoType, string controlKey);
};
diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal
index cafecbc..c40b473 100644
--- a/radio/1.5/IRadioIndication.hal
+++ b/radio/1.5/IRadioIndication.hal
@@ -76,4 +76,23 @@
*/
oneway barringInfoChanged(
RadioIndicationType type, CellIdentity cellIdentity, vec<BarringInfo> barringInfos);
+
+ /**
+ * Report all of the current cell information known to the radio.
+ *
+ * This indication is updated from IRadioIndication@1.4 to report the @1.5 version of
+ * CellInfo.
+ *
+ * @param type Type of radio indication
+ * @param records Current cell information
+ */
+ oneway cellInfoList_1_5(RadioIndicationType type, vec<CellInfo> records);
+
+ /**
+ * Incremental network scan results.
+ *
+ * This indication is updated from IRadioIndication@1.4 to report the @1.5 version of
+ * CellInfo.
+ */
+ oneway networkScanResult_1_5(RadioIndicationType type, NetworkScanResult result);
};
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index 88f3134..6a2187f 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -20,6 +20,8 @@
import @1.0::SendSmsResult;
import @1.4::IRadioResponse;
import @1.5::BarringInfo;
+import @1.5::CellInfo;
+import @1.5::RegStateResult;
import @1.5::SetupDataCallResult;
import @1.4::SetupDataCallResult;
import @1.5::PersoSubstate;
@@ -175,26 +177,67 @@
oneway getBarringInfoResponse(RadioResponseInfo info, vec<BarringInfo> barringInfos);
/**
- * @param info Response info struct containing response type, serial no. and error
- * @param persoType SIM Personalisation type
- * @param remainingRetries Positive values indicates number of retries remaining,
- * must be equal to -1 if number of retries are infinite.
+ * @param voiceRegResponse Current Voice registration response as defined by RegStateResult
+ * in types.hal
*
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:PASSWORD_INCORRECT (code is invalid)
+ * RadioError:INTERNAL_ERR
+ */
+ oneway getVoiceRegistrationStateResponse_1_5(RadioResponseInfo info,
+ RegStateResult voiceRegResponse);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param dataRegResponse Current Data registration response as defined by RegStateResult in
+ * types.hal
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ * RadioError:NOT_PROVISIONED
+ */
+ oneway getDataRegistrationStateResponse_1_5(RadioResponseInfo info,
+ RegStateResult dataRegResponse);
+
+ /**
+ * This is identitcal to getCellInfoListResponse_1_4 but uses an updated version of CellInfo.
+ *
+ * @param info Response info struct containing response type, serial no. and error
+ * @param cellInfo List of current cell information known to radio
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ */
+ oneway getCellInfoListResponse_1_5(RadioResponseInfo info, vec<CellInfo> cellInfo);
+
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:ILLEGAL_SIM_OR_ME
+ * RadioError:OPERATION_NOT_ALLOWED
+ * RadioError:INVALID_STATE
* RadioError:NO_MEMORY
- * RadioError:INVALID_SIM_STATE
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
- * RadioError:MODEM_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:NO_RESOURCES
+ * RadioError:MODEM_ERR
* RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:NO_RESOURCES
+ * RadioError:CANCELLED
+ *
+ * Returns RadioError:ILLEGAL_SIM_OR_ME when the failure is permanent and
+ * no retries needed, such as illegal SIM or ME.
*/
- oneway supplySimDepersonalizationResponse(RadioResponseInfo info,
- PersoSubstate persoType, int32_t remainingRetries);
+ oneway setNetworkSelectionModeManualResponse_1_5(RadioResponseInfo info);
/**
* @param info Response info struct containing response type, serial no. and error
@@ -226,4 +269,26 @@
* RadioError:SIM_ABSENT
*/
oneway sendCdmaSmsExpectMoreResponse(RadioResponseInfo info, SendSmsResult sms);
+
+ /**
+ * @param info Response info struct contatining response type, serial no. and error
+ * @param persoType SIM Personalisation type
+ * @param remainingRetries postiive values indicates number of retries remaining,
+ * must be equal to -1 if number of retries is infinite.
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:PASSWORD_INCORRECT (code is invalid)
+ * RadioError:NO_MEMORY
+ * RadioError:INVALID_SIM_STATE
+ * RadioError:INTERNAL_ERR
+ * RadioError:SYSTEM_ERR
+ * RadioError:MODEM_ERR
+ * RadioError:INVALID_ARGUMENTS
+ * RadioError:NO_RESOURCES
+ * RadioError:REQUEST_NOT_SUPPORTED
+ */
+ oneway supplySimDepersonalizationResponse(RadioResponseInfo info,
+ PersoSubstate persoType, int32_t remainingRetries);
};
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index b056408..cf195cc 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -16,27 +16,47 @@
package android.hardware.radio@1.5;
+import @1.0::ApnAuthType;
+import @1.0::DataProfileId;
+import @1.0::DataProfileInfoType;
+import @1.0::CdmaSignalStrength;
+import @1.0::EvdoSignalStrength;
+import @1.0::GsmSignalStrength;
+import @1.0::LteSignalStrength;
import @1.0::PersoSubstate;
+import @1.0::RadioAccessFamily;
+import @1.0::RadioError;
+import @1.0::RegState;
+import @1.0::TimeStampType;
import @1.1::EutranBands;
import @1.1::GeranBands;
import @1.1::RadioAccessNetworks;
import @1.1::RadioAccessSpecifier;
+import @1.1::ScanStatus;
import @1.1::ScanType;
import @1.1::UtranBands;
+import @1.2::CellConnectionStatus;
import @1.2::CellIdentityCdma;
import @1.2::CellIdentityGsm;
import @1.2::CellIdentityWcdma;
import @1.2::CellIdentityTdscdma;
import @1.2::CellIdentityLte;
+import @1.2::CellInfoCdma;
import @1.2::IndicationFilter;
import @1.2::NetworkScanRequest;
+import @1.2::TdscdmaSignalStrength;
+import @1.2::WcdmaSignalStrength;
import @1.4::AccessNetwork;
import @1.4::ApnTypes;
import @1.4::CellIdentityNr;
import @1.4::DataCallFailCause;
import @1.4::DataConnActiveStatus;
import @1.4::DataProfileInfo;
+import @1.4::LteVopsInfo;
+import @1.4::NrIndicators;
+import @1.4::NrSignalStrength;
import @1.4::PdpProtocolType;
+import @1.4::RadioTechnology;
import android.hidl.safe_union@1.0::Monostate;
@@ -147,7 +167,11 @@
};
enum RadioAccessNetworks : @1.1::RadioAccessNetworks {
+ UNKNOWN = 0,
+ /** Next Generation Radio Access Network */
NGRAN = 4,
+ /** CDMA 2000 Network */
+ CDMA2000 = 5,
};
/**
@@ -229,6 +253,16 @@
BAND_261 = 261,
};
+enum UtranBands : @1.1::UtranBands {
+ /** TD-SCDMA bands. 3GPP TS 25.102, Table 5.2: Frequency bands */
+ BAND_A = 101,
+ BAND_B = 102,
+ BAND_C = 103,
+ BAND_D = 104,
+ BAND_E = 105,
+ BAND_F = 106,
+};
+
/**
* Overwritten from @1.2::NetworkScanRequest to update
* RadioAccessSpecifier to 1.5 version
@@ -294,13 +328,74 @@
};
/**
- * Extended from @1.4::DataProfileInfo to update ApnTypes to 1.5 version
+ * Extended from @1.4::DataProfileInfo to update ApnTypes to 1.5 version and replace mtu with
+ * mtuV4 and mtuV6. In the future, this must be extended instead of overwritten.
*/
struct DataProfileInfo {
- @1.4::DataProfileInfo base;
+
+ /** ID of the data profile. */
+ DataProfileId profileId;
+
+ /** The APN name. */
+ string apn;
+
+ /** PDP_type values. */
+ PdpProtocolType protocol;
+
+ /** PDP_type values used on roaming network. */
+ PdpProtocolType roamingProtocol;
+
+ /** APN authentication type. */
+ ApnAuthType authType;
+
+ /** The username for APN, or empty string. */
+ string user;
+
+ /** The password for APN, or empty string. */
+ string password;
+
+ /** Data profile technology type. */
+ DataProfileInfoType type;
+
+ /** The period in seconds to limit the maximum connections. */
+ int32_t maxConnsTime;
+
+ /** The maximum connections during maxConnsTime. */
+ int32_t maxConns;
+
+ /**
+ * The required wait time in seconds after a successful UE initiated disconnect of a given PDN
+ * connection before the device can send a new PDN connection request for that given PDN.
+ */
+ int32_t waitTime;
+
+ /** True to enable the profile, false to disable. */
+ bool enabled;
/** Supported APN types bitmap. See ApnTypes for the value of each bit. */
bitfield<ApnTypes> supportedApnTypesBitmap;
+
+ /** The bearer bitmap. See RadioAccessFamily for the value of each bit. */
+ bitfield<RadioAccessFamily> bearerBitmap;
+
+ /** Maximum transmission unit (MTU) size in bytes for IPv4. */
+ int32_t mtuV4;
+
+ /** Maximum transmission unit (MTU) size in bytes for IPv6. */
+ int32_t mtuV6;
+
+ /**
+ * True if this data profile was used to bring up the last default (i.e internet) data
+ * connection successfully.
+ */
+ bool preferred;
+
+ /**
+ * If true, modem must persist this data profile and profileId must not be
+ * set to DataProfileId.INVALID. If the same data profile exists, this data profile must
+ * overwrite it.
+ */
+ bool persistent;
};
/**
@@ -333,21 +428,26 @@
bitfield<AddressProperty> properties;
/**
- * The UTC time that this link address will be deprecated. 0 indicates this information is not
- * available.
+ * The time, as reported by SystemClock.elapsedRealtime(), when this link address will be or
+ * was deprecated. -1 indicates this information is not available. At the time existing
+ * connections can still use this address until it expires, but new connections should use the
+ * new address. LONG_MAX(0x7FFFFFFFFFFFFFFF) indicates this link address will never be
+ * deprecated.
*/
- uint64_t deprecatedTime;
+ uint64_t deprecationTime;
/**
- * The UTC time that this link address will expire and no longer valid. 0 indicates this
- * information is not available.
+ * The time, as reported by SystemClock.elapsedRealtime(), when this link address will expire
+ * and be removed from the interface. -1 indicates this information is not available.
+ * LONG_MAX(0x7FFFFFFFFFFFFFFF) indicates this link address will never expire.
*/
- uint64_t expiredTime;
+ uint64_t expirationTime;
};
/**
* Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5
- * version. In 1.5 the type of addresses changes to vector of LinkAddress.
+ * version. In 1.5 the type of addresses changes to vector of LinkAddress, and mtu is replaced by
+ * mtuV4 and mtuV6.
*/
struct SetupDataCallResult {
/** Data call fail cause. DataCallFailCause.NONE if no error. */
@@ -401,10 +501,16 @@
vec<string> pcscf;
/**
- * MTU received from network. Value <= 0 means network has either not sent a value or sent an
- * invalid value.
+ * MTU received from network for IPv4.
+ * Value <= 0 means network has either not sent a value or sent an invalid value.
*/
- int32_t mtu;
+ int32_t mtuV4;
+
+ /**
+ * MTU received from network for IPv6.
+ * Value <= 0 means network has either not sent a value or sent an invalid value.
+ */
+ int32_t mtuV6;
};
enum Domain : int32_t {
@@ -415,6 +521,172 @@
PS = 1 << 1,
};
+struct ClosedSubscriberGroupInfo {
+ /**
+ * Indicates whether the cell is restricted to only CSG members. A cell not broadcasting the
+ * CSG Indication but reporting CSG information is considered a Hybrid Cell.
+ * Refer to the "csg-Indication" field in 3GPP TS 36.331 section 6.2.2
+ * SystemInformationBlockType1.
+ * Also refer to "CSG Indicator" in 3GPP TS 25.331 section 10.2.48.8.1 and TS 25.304.
+ */
+ bool csgIndication;
+
+ /**
+ * The human-readable name of the closed subscriber group operating this cell.
+ * Refer to "hnb-Name" in TS 36.331 section 6.2.2 SystemInformationBlockType9.
+ * Also refer to "HNB Name" in 3GPP TS25.331 section 10.2.48.8.23 and TS 23.003 section 4.8.
+ */
+ string homeNodebName;
+
+ /**
+ * The identity of the closed subscriber group that the cell belongs to.
+ * Refer to "CSG-Identity" in TS 36.336 section 6.3.4.
+ * Also refer to "CSG Identity" in 3GPP TS 25.331 section 10.3.2.8 and TS 23.003 section 4.7.
+ */
+ int32_t csgIdentity;
+};
+
+safe_union OptionalCsgInfo {
+ /**
+ * If no CSG info is provided by the cell, then this structure shall be present.
+ */
+ Monostate noinit;
+
+ /**
+ * If CSG info is provided by the cell, this structure shall be present.
+ */
+ ClosedSubscriberGroupInfo csgInfo;
+};
+
+struct CellIdentityGsm {
+ /**
+ * The fields "mcc" and "mnc" must contain the PLMN-ID of the primary PLMN of this cell.
+ */
+ @1.2::CellIdentityGsm base;
+
+ /** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */
+ vec<string> additionalPlmns;
+};
+
+struct CellIdentityWcdma {
+ /**
+ * The fields "mcc" and "mnc" must contain the PLMN-ID of the primary PLMN of this cell.
+ */
+ @1.2::CellIdentityWcdma base;
+
+ /** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */
+ vec<string> additionalPlmns;
+
+ /** Information about any closed subscriber group ID for this cell */
+ OptionalCsgInfo optionalCsgInfo;
+};
+
+struct CellIdentityTdscdma {
+ /**
+ * The fields "mcc" and "mnc" must contain the PLMN-ID of the primary PLMN of this cell.
+ */
+ @1.2::CellIdentityTdscdma base;
+
+ /** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */
+ vec<string> additionalPlmns;
+
+ /** Information about any closed subscriber group ID for this cell */
+ OptionalCsgInfo optionalCsgInfo;
+};
+
+struct CellIdentityLte {
+ /**
+ * The fields "mcc" and "mnc" must contain the PLMN-ID of the primary PLMN of this cell.
+ */
+ @1.2::CellIdentityLte base;
+
+ /** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */
+ vec<string> additionalPlmns;
+
+ /** Information about any closed subscriber group ID for this cell */
+ OptionalCsgInfo optionalCsgInfo;
+
+ /** Bands used by the cell. */
+ vec<EutranBands> bands;
+};
+
+/**
+ * The CellIdentity structure should be reported once for each element of the PLMN-IdentityInfoList
+ * broadcast in SIB1 CellAccessRelatedInfo as per 3GPP TS 38.331 Section 6.3.2.
+ */
+struct CellIdentityNr {
+ /**
+ * The fields "mcc" and "mnc" must contain the PLMN-ID of the primary PLMN of this cell.
+ */
+ @1.4::CellIdentityNr base;
+
+ /** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */
+ vec<string> additionalPlmns;
+
+ /** Bands used by the cell. */
+ vec<NgranBands> bands;
+};
+
+struct CellInfoGsm {
+ CellIdentityGsm cellIdentityGsm;
+ GsmSignalStrength signalStrengthGsm;
+};
+
+struct CellInfoWcdma {
+ CellIdentityWcdma cellIdentityWcdma;
+ WcdmaSignalStrength signalStrengthWcdma;
+};
+
+struct CellInfoTdscdma {
+ CellIdentityTdscdma cellIdentityTdscdma;
+ TdscdmaSignalStrength signalStrengthTdscdma;
+};
+
+struct CellInfoLte {
+ CellIdentityLte cellIdentityLte;
+ LteSignalStrength signalStrengthLte;
+};
+
+struct CellInfoNr {
+ CellIdentityNr cellIdentityNr;
+ NrSignalStrength signalStrengthNr;
+};
+
+struct CellInfo {
+ /**
+ * True if this cell is registered false if not registered.
+ */
+ bool registered;
+ /**
+ * Type of time stamp represented by timeStamp.
+ */
+ TimeStampType timeStampType;
+ /**
+ * Time in nanos as returned by ril_nano_time.
+ */
+ uint64_t timeStamp;
+ /**
+ * Connection status for the cell.
+ */
+ CellConnectionStatus connectionStatus;
+
+ safe_union CellInfoRatSpecificInfo {
+ /**
+ * 3gpp CellInfo types.
+ */
+ CellInfoGsm gsm;
+ CellInfoWcdma wcdma;
+ CellInfoTdscdma tdscdma;
+ CellInfoLte lte;
+ CellInfoNr nr;
+
+ /**
+ * 3gpp2 CellInfo types;
+ */
+ CellInfoCdma cdma;
+ } ratSpecificInfo;
+};
+
/** A union representing the CellIdentity of a single cell */
safe_union CellIdentity {
Monostate noinit;
@@ -556,6 +828,210 @@
};
/**
+ * Call fail causes for Circuit-switched service enumerated in 3GPP TS 24.008, 10.5.3.6 and
+ * 10.5.147. Additional detail is available in 3GPP TS 24.008 Annex G.
+ */
+enum RegistrationFailCause : int32_t {
+ /** 0 - None */
+ NONE = 0,
+ /** 2 - IMSI unknown in HLR */
+ IMSI_UNKNOWN_IN_HLR = 2,
+ /** 3 - Illegal MS */
+ ILLEGAL_MS = 3,
+ /** 4 - Illegal ME */
+ IMSI_UNKNOWN_IN_VLR = 4,
+ /** 5 - PLMN not allowed */
+ IMEI_NOT_ACCEPTED = 5,
+ /** 6 - Location area not allowed */
+ ILLEGAL_ME = 6,
+ /** 7 - Roaming not allowed */
+ GPRS_SERVICES_NOT_ALLOWED = 7,
+ /** 8 - No Suitable Cells in this Location Area */
+ GPRS_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 8,
+ /** 9 - Network failure */
+ MS_IDENTITY_CANNOT_BE_DERIVED_BY_NETWORK = 9,
+ /** 10 - Persistent location update reject */
+ IMPLICITLY_DETACHED = 10,
+ /** 11 - PLMN not allowed */
+ PLMN_NOT_ALLOWED = 11,
+ /** 12 - Location area not allowed */
+ LOCATION_AREA_NOT_ALLOWED = 12,
+ /** 13 - Roaming not allowed in this Location Area */
+ ROAMING_NOT_ALLOWED = 13,
+ /** 14 - GPRS Services not allowed in this PLMN */
+ GPRS_SERVICES_NOT_ALLOWED_IN_PLMN = 14,
+ /** 15 - No Suitable Cells in this Location Area */
+ NO_SUITABLE_CELLS = 15,
+ /** 16 - MSC temporarily not reachable */
+ MSC_TEMPORARILY_NOT_REACHABLE = 15,
+ /** 17 - Network Failure */
+ NETWORK_FAILURE = 17,
+ /** 20 - MAC Failure */
+ MAC_FAILURE = 20,
+ /** 21 - Sync Failure */
+ SYNC_FAILURE = 21,
+ /** 22 - Congestion */
+ CONGESTION = 22,
+ /** 23 - GSM Authentication unacceptable */
+ GSM_AUTHENTICATION_UNACCEPTABLE = 23,
+ /** 25 - Not Authorized for this CSG */
+ NOT_AUTHORIZED_FOR_THIS_CSG = 25,
+ /** 28 SMS provided via GPRS in this routing area */
+ SMS_PROVIDED_BY_GPRS_IN_ROUTING_AREA,
+ /** 32 - Service option not supported */
+ SERVICE_OPTION_NOT_SUPPORTED = 32,
+ /** 33 - Requested service option not subscribed */
+ SERVICE_OPTION_NOT_SUBSCRIBED = 33,
+ /** 34 - Service option temporarily out of order */
+ SERVICE_OPTION_TEMPORARILY_OUT_OF_ORDER = 34,
+ /** 38 - Call cannot be identified */
+ CALL_CANNOT_BE_IDENTIFIED = 38,
+ /** 40 No PDP context activated */
+ NO_PDP_CONTEXT_ACTIVATED = 40,
+ /** 48-63 - Retry upon entry into a new cell */
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_1 = 48,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_2 = 49,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_3 = 50,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_4 = 51,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_5 = 52,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_6 = 53,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_7 = 54,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_8 = 55,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_9 = 56,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_10 = 57,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_11 = 58,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_12 = 59,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_13 = 60,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_14 = 61,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_15 = 62,
+ RETRY_UPON_ENTRY_INTO_NEW_CELL_16 = 63,
+ /** 95 - Semantically incorrect message */
+ SEMANTICALLY_INCORRECT_MESSAGE = 95,
+ /** 96 - Invalid mandatory information */
+ INVALID_MANDATORY_INFORMATION = 96,
+ /** 97 - Message type non-existent or not implemented */
+ MESSAGE_TYPE_NON_EXISTENT_OR_NOT_IMPLEMENTED = 97,
+ /** 98 - Message type not compatible with protocol state */
+ MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
+ /** 99 - Information element non-existent or not implemented */
+ INFORMATION_ELEMENT_NON_EXISTENT_OR_NOT_IMPLEMENTED = 99,
+ /** 100 - Conditional IE error */
+ CONDITIONAL_IE_ERROR = 100,
+ /** 101 - Message not compatible with protocol state */
+ MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
+ /** 111 - Protocol error, unspecified */
+ PROTOCOL_ERROR_UNSPECIFIED = 111,
+};
+
+enum PrlIndicator : int32_t {
+ NOT_REGISTERED = -1,
+ NOT_IN_PRL = 0,
+ IN_PRL = 1,
+};
+
+struct RegStateResult {
+ /**
+ * Registration state
+ *
+ * If the RAT is indicated as a GERAN, UTRAN, or CDMA2000 technology, this value reports
+ * registration in the Circuit-switched domain.
+ * If the RAT is indicated as an EUTRAN, NGRAN, or another technology that does not support
+ * circuit-switched services, this value reports registration in the Packet-switched domain.
+ */
+ RegState regState;
+
+ /**
+ * Indicates the available voice radio technology, valid values as
+ * defined by RadioTechnology.
+ */
+ RadioTechnology rat;
+
+ /**
+ * Cause code reported by the network in case registration fails. This will be a mobility
+ * management cause code defined for MM, GMM, MME or equivalent as appropriate for the RAT.
+ */
+ RegistrationFailCause reasonForDenial;
+
+ /** CellIdentity */
+ CellIdentity cellIdentity;
+
+ /**
+ * The most-recent PLMN-ID upon which the UE registered (or attempted to register if a failure
+ * is reported in the reasonForDenial field). This PLMN shall be in standard format consisting
+ * of a 3 digit MCC concatenated with a 2 or 3 digit MNC.
+ */
+ string registeredPlmn;
+
+ /**
+ * Access-technology-specific registration information, such as for Cdma2000.
+ */
+ safe_union AccessTechnologySpecificInfo {
+ Monostate noinit;
+
+ struct Cdma2000RegistrationInfo {
+ /**
+ * concurrent services support indicator. if registered on a CDMA system.
+ * false - Concurrent services not supported,
+ * true - Concurrent services supported
+ */
+ bool cssSupported;
+
+ /**
+ * TSB-58 Roaming Indicator if registered on a CDMA or EVDO system or -1 if not.
+ * Valid values are 0-255.
+ */
+ int32_t roamingIndicator;
+
+ /**
+ * Indicates whether the current system is in the PRL if registered on a CDMA or EVDO
+ * system or -1 if not. 0=not in the PRL, 1=in the PRL.
+ */
+ PrlIndicator systemIsInPrl;
+
+ /**
+ * Default Roaming Indicator from the PRL if registered on a CDMA or EVDO system or -1
+ * if not.
+ * Valid values are 0-255.
+ */
+ int32_t defaultRoamingIndicator;
+ } cdmaInfo;
+
+ struct EutranRegistrationInfo {
+ /**
+ * Network capabilities for voice over PS services. This info is valid only on LTE
+ * network and must be present when device is camped on LTE. vopsInfo must be empty when
+ * device is camped only on 2G/3G.
+ */
+ LteVopsInfo lteVopsInfo; // LTE network capability
+
+ /**
+ * The parameters of NR 5G Non-Standalone. This value is only valid on E-UTRAN,
+ * otherwise must be empty.
+ */
+ NrIndicators nrIndicators;
+ } eutranInfo;
+ } accessTechnologySpecificInfo;
+};
+
+/** Overwritten from @1.4::NetworkScanResult in order to update the CellInfo to 1.5 version. */
+struct NetworkScanResult {
+ /**
+ * The status of the scan.
+ */
+ ScanStatus status;
+
+ /**
+ * The error code of the incremental result.
+ */
+ RadioError error;
+
+ /**
+ * List of network information as CellInfo.
+ */
+ vec<CellInfo> networkInfos;
+};
+
+/**
* Additional personalization categories in addition to those specified in 3GPP TS 22.022 and 3GPP2 C.S0068-0.
*/
enum PersoSubstate : @1.0::PersoSubstate {
diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp
index 85c4f99..182985e 100644
--- a/radio/1.5/vts/functional/Android.bp
+++ b/radio/1.5/vts/functional/Android.bp
@@ -34,6 +34,7 @@
"android.hardware.radio@1.0",
"android.hardware.radio.config@1.0",
"android.hardware.radio.config@1.1",
+ "android.hardware.radio.config@1.3",
],
header_libs: ["radio.util.header@1.0"],
test_suites: ["general-tests"]
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 600f801..09305de 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -833,23 +833,24 @@
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.profileId = DataProfileId::DEFAULT;
+ dataProfileInfo.apn = hidl_string("internet");
+ dataProfileInfo.protocol = PdpProtocolType::IP;
+ dataProfileInfo.roamingProtocol = PdpProtocolType::IP;
+ dataProfileInfo.authType = ApnAuthType::NO_PAP_NO_CHAP;
+ dataProfileInfo.user = hidl_string("username");
+ dataProfileInfo.password = hidl_string("password");
+ dataProfileInfo.type = DataProfileInfoType::THREE_GPP;
+ dataProfileInfo.maxConnsTime = 300;
+ dataProfileInfo.maxConns = 20;
+ dataProfileInfo.waitTime = 0;
+ dataProfileInfo.enabled = true;
dataProfileInfo.supportedApnTypesBitmap = 320;
- dataProfileInfo.base.bearerBitmap = 161543;
- dataProfileInfo.base.mtu = 0;
- dataProfileInfo.base.preferred = true;
- dataProfileInfo.base.persistent = false;
+ dataProfileInfo.bearerBitmap = 161543;
+ dataProfileInfo.mtuV4 = 0;
+ dataProfileInfo.mtuV6 = 0;
+ dataProfileInfo.preferred = true;
+ dataProfileInfo.persistent = false;
bool roamingAllowed = false;
@@ -878,29 +879,33 @@
}
}
+/*
+ * Test IRadio.setInitialAttachApn_1_5() for the response returned.
+ */
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.profileId = DataProfileId::DEFAULT;
+ dataProfileInfo.apn = hidl_string("internet");
+ dataProfileInfo.protocol = PdpProtocolType::IPV4V6;
+ dataProfileInfo.roamingProtocol = PdpProtocolType::IPV4V6;
+ dataProfileInfo.authType = ApnAuthType::NO_PAP_NO_CHAP;
+ dataProfileInfo.user = hidl_string("username");
+ dataProfileInfo.password = hidl_string("password");
+ dataProfileInfo.type = DataProfileInfoType::THREE_GPP;
+ dataProfileInfo.maxConnsTime = 300;
+ dataProfileInfo.maxConns = 20;
+ dataProfileInfo.waitTime = 0;
+ dataProfileInfo.enabled = true;
dataProfileInfo.supportedApnTypesBitmap = 320;
- dataProfileInfo.base.bearerBitmap = 161543;
- dataProfileInfo.base.mtu = 0;
- dataProfileInfo.base.preferred = true;
- dataProfileInfo.base.persistent = false;
+ dataProfileInfo.bearerBitmap = 161543;
+ dataProfileInfo.mtuV4 = 0;
+ dataProfileInfo.mtuV6 = 0;
+ dataProfileInfo.preferred = true;
+ dataProfileInfo.persistent = false;
radio_v1_5->setInitialAttachApn_1_5(serial, dataProfileInfo);
@@ -917,29 +922,33 @@
}
}
+/*
+ * Test IRadio.setDataProfile_1_5() for the response returned.
+ */
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.profileId = DataProfileId::DEFAULT;
+ dataProfileInfo.apn = hidl_string("internet");
+ dataProfileInfo.protocol = PdpProtocolType::IPV4V6;
+ dataProfileInfo.roamingProtocol = PdpProtocolType::IPV4V6;
+ dataProfileInfo.authType = ApnAuthType::NO_PAP_NO_CHAP;
+ dataProfileInfo.user = hidl_string("username");
+ dataProfileInfo.password = hidl_string("password");
+ dataProfileInfo.type = DataProfileInfoType::THREE_GPP;
+ dataProfileInfo.maxConnsTime = 300;
+ dataProfileInfo.maxConns = 20;
+ dataProfileInfo.waitTime = 0;
+ dataProfileInfo.enabled = true;
dataProfileInfo.supportedApnTypesBitmap = 320;
- dataProfileInfo.base.bearerBitmap = 161543;
- dataProfileInfo.base.mtu = 0;
- dataProfileInfo.base.preferred = true;
- dataProfileInfo.base.persistent = true;
+ dataProfileInfo.bearerBitmap = 161543;
+ dataProfileInfo.mtuV4 = 0;
+ dataProfileInfo.mtuV6 = 0;
+ dataProfileInfo.preferred = true;
+ dataProfileInfo.persistent = true;
// Create a dataProfileInfoList
android::hardware::hidl_vec<android::hardware::radio::V1_5::DataProfileInfo>
@@ -989,6 +998,32 @@
}
/*
+ * Test IRadio.setNetworkSelectionModeManual_1_5() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_5, setNetworkSelectionModeManual_1_5) {
+ serial = GetRandomSerialNumber();
+
+ // can't camp on nonexistent MCCMNC, so we expect this to fail.
+ Return<void> res = radio_v1_5->setNetworkSelectionModeManual_1_5(
+ serial, "123456", android::hardware::radio::V1_5::RadioAccessNetworks::GERAN);
+ 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::NONE, RadioError::ILLEGAL_SIM_OR_ME,
+ RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE},
+ CHECK_GENERAL_ERROR));
+ } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE},
+ CHECK_GENERAL_ERROR));
+ }
+}
+
+/*
* Test IRadio.sendCdmaSmsExpectMore() for the response returned.
*/
TEST_F(RadioHidlTest_v1_5, sendCdmaSmsExpectMore) {
@@ -1016,7 +1051,7 @@
cdmaSmsMessage.address = cdmaSmsAddress;
cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
cdmaSmsMessage.bearerData =
- (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
+ (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
radio_v1_5->sendCdmaSmsExpectMore(serial, cdmaSmsMessage);
@@ -1026,8 +1061,8 @@
if (cardStatus.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_v1_5->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
- CHECK_GENERAL_ERROR));
+ radioRsp_v1_5->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
+ CHECK_GENERAL_ERROR));
}
-}
\ No newline at end of file
+}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
index a5d236d..c29ebf9 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
@@ -47,9 +47,9 @@
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
- sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig =
+ sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig =
::testing::VtsHalHidlTargetTestBase::getService<
- ::android::hardware::radio::config::V1_1::IRadioConfig>();
+ ::android::hardware::radio::config::V1_3::IRadioConfig>();
/* Enforce Vts tesing with RadioConfig is existed. */
ASSERT_NE(nullptr, radioConfig.get());
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 1c4ec9f..d1c17e6 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
@@ -22,7 +22,7 @@
#include <condition_variable>
#include <mutex>
-#include <android/hardware/radio/config/1.1/IRadioConfig.h>
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
#include <android/hardware/radio/1.5/IRadio.h>
#include <android/hardware/radio/1.5/IRadioIndication.h>
@@ -293,8 +293,6 @@
Return<void> sendCdmaSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
- Return<void> sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
-
Return<void> acknowledgeLastIncomingCdmaSmsResponse(const RadioResponseInfo& info);
Return<void> getGsmBroadcastConfigResponse(
@@ -563,6 +561,24 @@
const RadioResponseInfo& info,
const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>&
barringInfos);
+
+ Return<void> getVoiceRegistrationStateResponse_1_5(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_5::RegStateResult& regResponse);
+
+ Return<void> getDataRegistrationStateResponse_1_5(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_5::RegStateResult& regResponse);
+
+ Return<void> getCellInfoListResponse_1_5(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::CellInfo>&
+ cellInfo);
+
+ Return<void> setNetworkSelectionModeManualResponse_1_5(const RadioResponseInfo& info);
+
+ Return<void> sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& info,
+ const SendSmsResult& sms);
};
/* Callback class for radio indication */
@@ -577,6 +593,15 @@
/* 1.5 Api */
Return<void> uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled);
+ Return<void> networkScanResult_1_5(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_5::NetworkScanResult& result);
+
+ Return<void> cellInfoList_1_5(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::CellInfo>&
+ records);
+
/* 1.4 Api */
Return<void> currentEmergencyNumberList(
RadioIndicationType type,
diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp
index 1483907..d448a22 100644
--- a/radio/1.5/vts/functional/radio_indication.cpp
+++ b/radio/1.5/vts/functional/radio_indication.cpp
@@ -350,3 +350,16 @@
/*barringInfos*/) {
return Void();
}
+
+Return<void> RadioIndication_v1_5::networkScanResult_1_5(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_5::NetworkScanResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList_1_5(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_5::CellInfo>& /*records*/) {
+ return Void();
+}
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index c56087c..a62d086 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -421,11 +421,6 @@
return Void();
}
-Return<void> RadioResponse_v1_5::sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& /*info*/,
- const SendSmsResult& /*sms*/) {
- return Void();
-}
-
Return<void> RadioResponse_v1_5::acknowledgeLastIncomingCdmaSmsResponse(
const RadioResponseInfo& /*info*/) {
return Void();
@@ -981,3 +976,38 @@
parent_v1_5.notify(info.serial);
return Void();
}
+
+Return<void> RadioResponse_v1_5::getVoiceRegistrationStateResponse_1_5(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_5::RegStateResult& /*regResponse*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse_1_5(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_5::RegStateResult& /*regResponse*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse_1_5(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_5::CellInfo>& /*cellInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setNetworkSelectionModeManualResponse_1_5(
+ const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& /*info*/,
+ const SendSmsResult& /*sms*/) {
+ return Void();
+}
diff --git a/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp
index 88de666..7360270 100644
--- a/radio/config/1.3/Android.bp
+++ b/radio/config/1.3/Android.bp
@@ -17,6 +17,9 @@
"android.hardware.radio.config@1.1",
"android.hardware.radio.config@1.2",
"android.hardware.radio@1.0",
+ "android.hardware.radio@1.1",
+ "android.hardware.radio@1.4",
+ "android.hardware.radio@1.5",
"android.hidl.base@1.0",
],
gen_java: true,
diff --git a/radio/config/1.3/IRadioConfig.hal b/radio/config/1.3/IRadioConfig.hal
index a0ce6e0..d01f54b 100644
--- a/radio/config/1.3/IRadioConfig.hal
+++ b/radio/config/1.3/IRadioConfig.hal
@@ -27,5 +27,13 @@
* serial to different methods), multiple responses (one for each method call) must still be served.
*/
interface IRadioConfig extends @1.1::IRadioConfig {
-
+ /**
+ * Request current phone capability.
+ *
+ * @param serial Serial number of request.
+ *
+ * Response callback is IRadioResponse.getPhoneCapabilityResponse_1_3() which
+ * will return <@1.3::PhoneCapability>.
+ */
+ oneway getPhoneCapability_1_3(int32_t serial);
};
diff --git a/radio/config/1.3/IRadioConfigResponse.hal b/radio/config/1.3/IRadioConfigResponse.hal
index 9c4c971..e13aa1e 100644
--- a/radio/config/1.3/IRadioConfigResponse.hal
+++ b/radio/config/1.3/IRadioConfigResponse.hal
@@ -16,11 +16,22 @@
package android.hardware.radio.config@1.3;
+import android.hardware.radio@1.0::RadioResponseInfo;
import @1.2::IRadioConfigResponse;
+import @1.3::PhoneCapability;
/**
* Interface declaring response functions to solicited radio config requests.
*/
interface IRadioConfigResponse extends @1.2::IRadioConfigResponse {
-
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param phoneCapability <@1.3::PhoneCapability> it defines modem's capability for example
+ * how many logical modems it has, how many data connections it supports.
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ */
+ oneway getPhoneCapabilityResponse_1_3(RadioResponseInfo info, PhoneCapability phoneCapability);
};
diff --git a/radio/config/1.3/default/RadioConfig.cpp b/radio/config/1.3/default/RadioConfig.cpp
index c28119c..01e98f1 100644
--- a/radio/config/1.3/default/RadioConfig.cpp
+++ b/radio/config/1.3/default/RadioConfig.cpp
@@ -24,7 +24,6 @@
namespace implementation {
using namespace ::android::hardware::radio::V1_0;
-using namespace ::android::hardware::radio::config;
// Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow.
Return<void> RadioConfig::setResponseFunctions(
@@ -105,6 +104,14 @@
return Void();
}
+// Methods from ::android::hardware::radio::config::V1_3::IRadioConfig follow.
+Return<void> RadioConfig::getPhoneCapability_1_3(int32_t /* serial */) {
+ V1_3::PhoneCapability phoneCapability;
+ RadioResponseInfo info;
+ mRadioConfigResponseV1_3->getPhoneCapabilityResponse_1_3(info, phoneCapability);
+ return Void();
+}
+
} // namespace implementation
} // namespace V1_3
} // namespace config
diff --git a/radio/config/1.3/default/RadioConfig.h b/radio/config/1.3/default/RadioConfig.h
index 00585e6..57ff368 100644
--- a/radio/config/1.3/default/RadioConfig.h
+++ b/radio/config/1.3/default/RadioConfig.h
@@ -62,6 +62,9 @@
Return<void> setPreferredDataModem(int32_t serial, uint8_t modemId);
Return<void> setModemsConfig(int32_t serial, const V1_1::ModemsConfig& modemsConfig);
Return<void> getModemsConfig(int32_t serial);
+
+ // Methods from ::android::hardware::radio::config::V1_3::IRadioConfig follow.
+ Return<void> getPhoneCapability_1_3(int32_t serial);
};
} // namespace implementation
diff --git a/radio/config/1.3/default/RadioConfigIndication.cpp b/radio/config/1.3/default/RadioConfigIndication.cpp
index eb77a48..608fa1c 100644
--- a/radio/config/1.3/default/RadioConfigIndication.cpp
+++ b/radio/config/1.3/default/RadioConfigIndication.cpp
@@ -23,10 +23,6 @@
namespace V1_3 {
namespace implementation {
-using namespace ::android::hardware::radio::V1_0;
-using namespace ::android::hardware::radio::config::V1_0;
-using namespace ::android::hardware::radio::config::V1_2;
-
// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow.
Return<void> RadioConfigIndication::simSlotsStatusChanged(
RadioIndicationType /* type */, const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
diff --git a/radio/config/1.3/default/RadioConfigIndication.h b/radio/config/1.3/default/RadioConfigIndication.h
index 3697492..c92446c 100644
--- a/radio/config/1.3/default/RadioConfigIndication.h
+++ b/radio/config/1.3/default/RadioConfigIndication.h
@@ -31,10 +31,6 @@
using namespace ::android::hardware::radio::V1_0;
using namespace ::android::hardware::radio::config;
-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;
diff --git a/radio/config/1.3/default/RadioConfigResponse.cpp b/radio/config/1.3/default/RadioConfigResponse.cpp
index 48e81da..1d48a13 100644
--- a/radio/config/1.3/default/RadioConfigResponse.cpp
+++ b/radio/config/1.3/default/RadioConfigResponse.cpp
@@ -23,11 +23,6 @@
namespace V1_3 {
namespace implementation {
-using namespace ::android::hardware::radio::V1_0;
-using namespace ::android::hardware::radio::config::V1_0;
-using namespace ::android::hardware::radio::config::V1_1;
-using namespace ::android::hardware::radio::config::V1_2;
-
// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow.
Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
const RadioResponseInfo& /* info */,
@@ -73,6 +68,13 @@
return Void();
}
+// Methods from ::android::hardware::radio::config::V1_3::IRadioConfigResponse follow.
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse_1_3(
+ const RadioResponseInfo& /* info */, const V1_3::PhoneCapability& /* phoneCapability */) {
+ // TODO implement
+ return Void();
+}
+
} // namespace implementation
} // namespace V1_3
} // namespace config
diff --git a/radio/config/1.3/default/RadioConfigResponse.h b/radio/config/1.3/default/RadioConfigResponse.h
index 0f0033f..dc169bb 100644
--- a/radio/config/1.3/default/RadioConfigResponse.h
+++ b/radio/config/1.3/default/RadioConfigResponse.h
@@ -28,43 +28,36 @@
namespace V1_3 {
namespace implementation {
-using ::android::sp;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
+using namespace ::android::hardware::radio::config;
+
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
-using ::android::hardware::Void;
+
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
struct RadioConfigResponse : public IRadioConfigResponse {
// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow.
Return<void> getSimSlotsStatusResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
- const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus)
- override;
- Return<void> setSimSlotsMappingResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
+ const RadioResponseInfo& info,
+ const hidl_vec<V1_0::SimSlotStatus>& slotStatus) override;
+ Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info) override;
// Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow.
- Return<void> getPhoneCapabilityResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
- const ::android::hardware::radio::config::V1_1::PhoneCapability& phoneCapability)
- override;
- Return<void> setPreferredDataModemResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
- Return<void> setModemsConfigResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
- Return<void> getModemsConfigResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
- const ::android::hardware::radio::config::V1_1::ModemsConfig& modemsConfig) override;
+ Return<void> getPhoneCapabilityResponse(const RadioResponseInfo& info,
+ const V1_1::PhoneCapability& phoneCapability) override;
+ Return<void> setPreferredDataModemResponse(const RadioResponseInfo& info) override;
+ Return<void> setModemsConfigResponse(const RadioResponseInfo& info) override;
+ Return<void> getModemsConfigResponse(const RadioResponseInfo& info,
+ const V1_1::ModemsConfig& modemsConfig) override;
// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow.
Return<void> getSimSlotsStatusResponse_1_2(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
- const hidl_vec<::android::hardware::radio::config::V1_2::SimSlotStatus>& slotStatus)
- override;
+ const RadioResponseInfo& info,
+ const hidl_vec<V1_2::SimSlotStatus>& slotStatus) override;
- // Methods from ::android::hidl::base::V1_0::IBase follow.
+ // Methods from ::android::hardware::radio::config::V1_3::IRadioConfigResponse follow.
+ Return<void> getPhoneCapabilityResponse_1_3(
+ const RadioResponseInfo& info, const V1_3::PhoneCapability& phoneCapability) override;
};
} // namespace implementation
diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal
index 866002a..7860006 100644
--- a/radio/config/1.3/types.hal
+++ b/radio/config/1.3/types.hal
@@ -15,3 +15,181 @@
*/
package android.hardware.radio.config@1.3;
+
+import android.hardware.radio@1.1::GeranBands;
+import android.hardware.radio@1.1::EutranBands;
+import android.hardware.radio@1.4::RadioAccessFamily;
+import android.hardware.radio@1.5::NgranBands;
+import android.hardware.radio@1.5::UtranBands;
+
+/** Type for the SIM slot. */
+enum SlotType : int32_t {
+ /** Slot type for UICC/pSIM (physical SIM). */
+ UICC = 1,
+ /** Slot type for iUICC/iSIM (integrated SIM). */
+ IUICC = 2,
+ /** Slot type for eUICC/eSIM (embedded SIM). */
+ EUICC = 3,
+ /** Slot type for soft SIM (no physical SIM). */
+ SOFT_SIM = 4,
+};
+
+/** A field in PhoneCapability that holds information about the SIM slot. */
+struct SimSlotCapability {
+ /** Corresponds to physicalSlotId in Radio@1.2::CardStatus. */
+ uint32_t physicalSlotId;
+
+ /** Type of slot. */
+ SlotType slotType;
+};
+
+/** Bitmask of features that can be supported by a single modem. */
+enum ModemFeatures : int32_t {
+ /** 3GPP2 capability. */
+ THREE_GPP2_REG = 1 << 0,
+ /** 3GPP capability. */
+ THREE_GPP_REG = 1 << 1,
+ /** CDMA 2000 with EHRPD capability. */
+ CDMA2000_EHRPD_REG = 1 << 2,
+ /** GSM capability. */
+ GERAN_REG = 1 << 3,
+ /** UMTS capability. */
+ UTRAN_REG = 1 << 4,
+ /** LTE capability. */
+ EUTRAN_REG = 1 << 5,
+ /** 5G capability. */
+ NGRAN_REG = 1 << 6,
+ /** Dual Connectivity capability. */
+ EN_DC_REG = 1 << 7,
+ /** VoLTE capability (IMS registered). */
+ PS_VOICE_REG = 1 << 8,
+ /** CS voice call capability. */
+ CS_VOICE_SESSION = 1 << 9,
+ /** Internet connection capability. */
+ INTERACTIVE_DATA_SESSION = 1 << 10,
+ /** Dedicated bearer capability. */
+ DEDICATED_BEARER = 1 << 11,
+ /** Network scanning capability. */
+ NETWORK_SCAN = 1 << 12,
+ /** CDMA capability for SIM associated with modem. */
+ CSIM = 1 << 13,
+};
+
+struct ConcurrentModemFeatures {
+ /**
+ * A vector of concurrently supportable modem features across all modems.
+ * Each entry in the vector is a bitfield of ModemFeatures that can be used
+ * concurrently with the other ModemFeatures in that list.
+ * Each bitfield must be the full set of features for a single modem.
+ *
+ * On a Dual-SIM device, each entry will be a vector of length 2.
+ * The examples below depict the modemFeatures for four Dual-SIM setups:
+ * 1. Only one modem can PS attach (IMS registered).
+ * {
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER),
+ * (GERAN_REG | UTRAN_REG)
+ * }
+ * or
+ * {
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * INTERACTIVE_DATA_SESSION),
+ * (GERAN_REG | UTRAN_REG | CS_VOICE_SESSION)
+ * }
+ * 2. Both modems can PS attach (dual VoLTE).
+ * {
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER),
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG)
+ * }
+ * 3. Both modems can maintain an Internet connection, but they share
+ * one RF hardware.
+ * {
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER),
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * INTERACTIVE_DATA_SESSION)
+ * }
+ * 4. Both modems can maintain an Internet connection, and they have
+ * their own RF hardware.
+ * {
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER),
+ * (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
+ * INTERACTIVE_DATA_SESSION | DEDICATED_BEARER)
+ * }
+ */
+ vec<bitfield<ModemFeatures>> modemFeatures;
+};
+
+/**
+ * Overwritten from @1.1::PhoneCapability to add new capabilities and deprecate
+ * maxActiveData, maxActiveInternetData, isInternetLingeringSupported, logicalModemList.
+ * Replaces RadioConfig@1.1::ModemInfo and should replace Radio@1.4::RadioCapabilities
+ * in the next major version upgrade. In the future, this should be extended instead of overwritten.
+ */
+struct PhoneCapability {
+ /**
+ * 3GPP UE category for UTRAN downlink direction.
+ * 25.306 Table 5.1a
+ */
+ uint8_t utranUeCategoryDl;
+ /**
+ * 3GPP UE category for UTRAN uplink direction.
+ * 25.306 Table 5.1g
+ */
+ uint8_t utranUeCategoryUl;
+ /**
+ * 3GPP UE category for EUTRAN downlink direction.
+ * 25.306 Table 4.1a
+ */
+ uint8_t eutranUeCategoryDl;
+ /**
+ * 3GPP UE category for EUTRAN uplink direction.
+ * 25.306 Table 4.1a-2
+ */
+ uint8_t eutranUeCategoryUl;
+
+ /**
+ * Length of grace period for switching between logical modems, in milliseconds.
+ * Used only when the number of logical modems is greater than the number of
+ * Internet connections the device can support, otherwise must be 0.
+ */
+ uint64_t psDataConnectionLingerTimeMillis;
+
+ vec<GeranBands> geranBands;
+ vec<UtranBands> utranBands;
+ vec<EutranBands> eutranBands;
+ vec<NgranBands> ngranBands;
+
+ /**
+ * 32-bit bitmap of supported Radio@1.4::RadioAccessFamily types.
+ * Note that RadioAccessFamily is actually the radio access technologies, so it should be
+ * renamed in the next major version upgrade.
+ */
+ bitfield<RadioAccessFamily> supportedRats;
+
+ /**
+ * List of unique logical modem UUIDs from Radio@1.4::RadioCapabilities.
+ * A UUID is typically "com.xxxx.lmX" where X is the logical modem ID.
+ * Must be equal to the number of logical modems in the device.
+ * Radio@1.2::RadioConst::MAX_UUID_LENGTH is the max length of each UUID.
+ */
+ vec<string> logicalModemUuids;
+
+ /**
+ * List of SIM slot capabilities. The order of physical slot IDs must correspond to
+ * the order of modems in logicalModemUuids.
+ */
+ vec<SimSlotCapability> simSlotCapabilities;
+
+ /**
+ * A vector of all sets of concurrently supportable modem feature sets. The order of modems
+ * in modemFeatures must correspond to the order of modems in logicalModemUuids.
+ * Each entry in concurrentFeatureSupport is independent of others in the list
+ * and represents a set of concurrently supportable features across all modems.
+ * Each entry in ConcurrentModemFeatures::modemFeatures is a bitfield of
+ * concurrently supported ModemFeatures for one modem.
+ */
+ vec<ConcurrentModemFeatures> concurrentFeatureSupport;
+};
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
index 07e9ede..7f90023 100644
--- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
@@ -17,3 +17,34 @@
#include <radio_config_hidl_hal_utils.h>
#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+/*
+ * Test IRadioConfig.getPhoneCapability_1_3()
+ */
+TEST_P(RadioConfigHidlTest, getPhoneCapability_1_3) {
+ serial = GetRandomSerialNumber();
+ Return<void> res = radioConfig->getPhoneCapability_1_3(serial);
+ ASSERT_OK(res);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type);
+ EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial);
+ ALOGI("getPhoneCapability_1_3, rspInfo.error = %s\n",
+ toString(radioConfigRsp->rspInfo.error).c_str());
+
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioConfigRsp->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR}));
+
+ if (radioConfigRsp->rspInfo.error == RadioError ::NONE) {
+ int numModems = radioConfigRsp->phoneCap_1_3.logicalModemUuids.size();
+ EXPECT_GE(numModems, 0);
+ // length of simSlotCapabilities should be equal to length of logicalModemUuids.
+ EXPECT_EQ(numModems, radioConfigRsp->phoneCap_1_3.simSlotCapabilities.size());
+ // length of modemFeatures in each ConcurrentModemFeatures should be
+ // equal to length of logicalModemUuids.
+ for (V1_3::ConcurrentModemFeatures cmf :
+ radioConfigRsp->phoneCap_1_3.concurrentFeatureSupport) {
+ EXPECT_EQ(numModems, cmf.modemFeatures.size());
+ }
+ }
+}
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
index dbb4bf4..cd48b25 100644
--- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
@@ -17,7 +17,7 @@
#include <radio_config_hidl_hal_utils.h>
void RadioConfigHidlTest::SetUp() {
- radioConfig = ::android::hardware::radio::config::V1_3::IRadioConfig::getService(GetParam());
+ radioConfig = V1_3::IRadioConfig::getService(GetParam());
ASSERT_NE(nullptr, radioConfig.get());
radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this);
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
index 9b78c04..b21c7c0 100644
--- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
@@ -28,19 +28,18 @@
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
+#include <log/log.h>
#include "vts_test_util.h"
-using namespace ::android::hardware::radio::config::V1_1;
-using namespace ::android::hardware::radio::config::V1_2;
-using namespace ::android::hardware::radio::config::V1_3;
+using namespace ::android::hardware::radio::config;
using ::android::sp;
-using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
+using ::android::hardware::radio::V1_0::RadioIndicationType;
using ::android::hardware::radio::V1_0::RadioResponseInfo;
using ::android::hardware::radio::V1_0::RadioResponseType;
@@ -49,43 +48,46 @@
class RadioConfigHidlTest;
/* Callback class for radio config response */
-class RadioConfigResponse : public ::android::hardware::radio::config::V1_3::IRadioConfigResponse {
+class RadioConfigResponse : public V1_3::IRadioConfigResponse {
protected:
RadioConfigHidlTest& parent;
public:
RadioResponseInfo rspInfo;
- PhoneCapability phoneCap;
+ V1_1::PhoneCapability phoneCap_1_1;
+ V1_3::PhoneCapability phoneCap_1_3;
RadioConfigResponse(RadioConfigHidlTest& parent);
virtual ~RadioConfigResponse() = default;
/* 1.0 Api */
- Return<void> getSimSlotsStatusResponse(
- const RadioResponseInfo& info,
- const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus);
+ Return<void> getSimSlotsStatusResponse(const RadioResponseInfo& info,
+ const hidl_vec<V1_0::SimSlotStatus>& slotStatus);
Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info);
/* 1.1 Api */
Return<void> getPhoneCapabilityResponse(const RadioResponseInfo& info,
- const PhoneCapability& phoneCapability);
+ const V1_1::PhoneCapability& phoneCapability);
Return<void> setPreferredDataModemResponse(const RadioResponseInfo& info);
Return<void> getModemsConfigResponse(const RadioResponseInfo& info,
- const ModemsConfig& mConfig);
+ const V1_1::ModemsConfig& mConfig);
Return<void> setModemsConfigResponse(const RadioResponseInfo& info);
/* 1.2 Api */
Return<void> getSimSlotsStatusResponse_1_2(const RadioResponseInfo& info,
- const hidl_vec<SimSlotStatus>& slotStatus);
+ const hidl_vec<V1_2::SimSlotStatus>& slotStatus);
+
+ /* 1.3 Api */
+ Return<void> getPhoneCapabilityResponse_1_3(const RadioResponseInfo& info,
+ const V1_3::PhoneCapability& phoneCapability);
};
/* Callback class for radio config indication */
-class RadioConfigIndication
- : public ::android::hardware::radio::config::V1_3::IRadioConfigIndication {
+class RadioConfigIndication : public V1_3::IRadioConfigIndication {
protected:
RadioConfigHidlTest& parent;
@@ -94,9 +96,8 @@
virtual ~RadioConfigIndication() = default;
/* 1.2 Api */
- Return<void> simSlotsStatusChanged_1_2(
- ::android::hardware::radio::V1_0::RadioIndicationType type,
- const hidl_vec<SimSlotStatus>& slotStatus);
+ Return<void> simSlotsStatusChanged_1_2(RadioIndicationType type,
+ const hidl_vec<V1_2::SimSlotStatus>& slotStatus);
};
// The main test class for Radio config HIDL.
@@ -121,7 +122,7 @@
int serial;
/* radio config service handle */
- sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig;
+ sp<V1_3::IRadioConfig> radioConfig;
/* radio config response handle */
sp<RadioConfigResponse> radioConfigRsp;
diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp
index 1ca960e..22098d3 100644
--- a/radio/config/1.3/vts/functional/radio_config_response.cpp
+++ b/radio/config/1.3/vts/functional/radio_config_response.cpp
@@ -16,17 +16,18 @@
#include <radio_config_hidl_hal_utils.h>
-using ::android::hardware::radio::V1_0::RadioResponseInfo;
+using namespace ::android::hardware::radio::config;
-// SimSlotStatus slotStatus;
+using ::android::hardware::hidl_vec;
+
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {}
/* 1.0 Apis */
Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
const RadioResponseInfo& /* info */,
- const ::android::hardware::hidl_vec<
- ::android::hardware::radio::config::V1_0::SimSlotStatus>& /* slotStatus */) {
+ const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
return Void();
}
@@ -36,9 +37,9 @@
/* 1.1 Apis */
Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
- const RadioResponseInfo& info, const PhoneCapability& phoneCapability) {
+ const RadioResponseInfo& info, const V1_1::PhoneCapability& phoneCapability) {
rspInfo = info;
- phoneCap = phoneCapability;
+ phoneCap_1_1 = phoneCapability;
parent.notify(info.serial);
return Void();
}
@@ -49,7 +50,7 @@
}
Return<void> RadioConfigResponse::getModemsConfigResponse(const RadioResponseInfo& /* info */,
- const ModemsConfig& /* mConfig */) {
+ const V1_1::ModemsConfig& /* mConfig */) {
return Void();
}
@@ -60,6 +61,15 @@
/* 1.2 Apis */
Return<void> RadioConfigResponse::getSimSlotsStatusResponse_1_2(
const RadioResponseInfo& /* info */,
- const ::android::hardware::hidl_vec<SimSlotStatus>& /* slotStatus */) {
+ const hidl_vec<V1_2::SimSlotStatus>& /* slotStatus */) {
return Void();
-}
\ No newline at end of file
+}
+
+/* 1.3 Apis */
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse_1_3(
+ const RadioResponseInfo& info, const V1_3::PhoneCapability& phoneCapability) {
+ rspInfo = info;
+ phoneCap_1_3 = phoneCapability;
+ parent.notify(info.serial);
+ return Void();
+}
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..ad90465
--- /dev/null
+++ b/rebootescrow/aidl/default/rebootescrow-default.rc
@@ -0,0 +1,5 @@
+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
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..cd8cc3e
--- /dev/null
+++ b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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;
+
+#define SKIP_UNSUPPORTED \
+ if (rebootescrow == nullptr) GTEST_SKIP() << "Not supported on this device"
+
+/**
+ * This tests that the key can be written, read, and removed. It does not test
+ * that the key survives a reboot. That needs a host-based test.
+ *
+ * atest VtsHalRebootEscrowV1_0TargetTest
+ */
+class RebootEscrowAidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ rebootescrow = android::waitForDeclaredService<IRebootEscrow>(String16(GetParam().c_str()));
+ }
+
+ 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) {
+ SKIP_UNSUPPORTED;
+
+ 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) {
+ SKIP_UNSUPPORTED;
+
+ 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) {
+ SKIP_UNSUPPORTED;
+
+ 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) {
+ SKIP_UNSUPPORTED;
+
+ 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/sensors/1.0/default/OWNERS b/sensors/1.0/default/OWNERS
index 2031d84..90c2330 100644
--- a/sensors/1.0/default/OWNERS
+++ b/sensors/1.0/default/OWNERS
@@ -1,2 +1,3 @@
+arthuri@google.com
bduddie@google.com
-bstack@google.com
+stange@google.com
diff --git a/sensors/1.0/vts/functional/OWNERS b/sensors/1.0/vts/functional/OWNERS
index 759d87b..892da15 100644
--- a/sensors/1.0/vts/functional/OWNERS
+++ b/sensors/1.0/vts/functional/OWNERS
@@ -1,6 +1,7 @@
# Sensors team
+arthuri@google.com
bduddie@google.com
-bstack@google.com
+stange@google.com
# VTS team
trong@google.com
diff --git a/sensors/2.0/default/OWNERS b/sensors/2.0/default/OWNERS
index 2031d84..90c2330 100644
--- a/sensors/2.0/default/OWNERS
+++ b/sensors/2.0/default/OWNERS
@@ -1,2 +1,3 @@
+arthuri@google.com
bduddie@google.com
-bstack@google.com
+stange@google.com
diff --git a/sensors/2.0/vts/functional/OWNERS b/sensors/2.0/vts/functional/OWNERS
index 759d87b..892da15 100644
--- a/sensors/2.0/vts/functional/OWNERS
+++ b/sensors/2.0/vts/functional/OWNERS
@@ -1,6 +1,7 @@
# Sensors team
+arthuri@google.com
bduddie@google.com
-bstack@google.com
+stange@google.com
# VTS team
trong@google.com
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
index 2071c5a..81db5a0 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
@@ -129,8 +129,8 @@
void SensorsHidlEnvironmentV2_0::startPollingThread() {
mStopThread = false;
- mPollThread = std::thread(pollingThread, this);
mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT);
+ mPollThread = std::thread(pollingThread, this);
}
void SensorsHidlEnvironmentV2_0::readEvents() {
diff --git a/sensors/common/vts/OWNERS b/sensors/common/vts/OWNERS
index 759d87b..892da15 100644
--- a/sensors/common/vts/OWNERS
+++ b/sensors/common/vts/OWNERS
@@ -1,6 +1,7 @@
# Sensors team
+arthuri@google.com
bduddie@google.com
-bstack@google.com
+stange@google.com
# VTS team
trong@google.com
diff --git a/sensors/common/vts/utils/OWNERS b/sensors/common/vts/utils/OWNERS
index 759d87b..892da15 100644
--- a/sensors/common/vts/utils/OWNERS
+++ b/sensors/common/vts/utils/OWNERS
@@ -1,6 +1,7 @@
# Sensors team
+arthuri@google.com
bduddie@google.com
-bstack@google.com
+stange@google.com
# VTS team
trong@google.com
diff --git a/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..270b00e
--- /dev/null
+++ b/soundtrigger/2.3/ISoundTriggerHw.hal
@@ -0,0 +1,122 @@
+/*
+ * 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.0::ISoundTriggerHwCallback.CallbackCookie;
+import @2.2::ISoundTriggerHw;
+import @2.1::ISoundTriggerHwCallback;
+
+/**
+ * SoundTrigger HAL interface. Used for hardware recognition of hotwords
+ * and other sounds.
+ */
+interface ISoundTriggerHw extends @2.2::ISoundTriggerHw {
+
+ /**
+ * Retrieve extended implementation properties.
+ * The returned properties includes what is returned from the
+ * getProperties along with expanded implementation details.
+ *
+ * @return retval Operation completion status: 0 in case of success,
+ * -ENODEV in case of initialization error.
+ * @return properties A Properties structure containing implementation
+ * description and capabilities.
+ */
+ getProperties_2_3() generates (int32_t retval, Properties properties);
+
+ /**
+ * Start recognition on a given model. Only one recognition active
+ * at a time per model. Once recognition succeeds or fails, the callback
+ * associated with the model handle is called.
+ *
+ * Must have the exact same semantics as startRecognition from
+ * ISoundTriggerHw@2.1 except that the RecognitionConfig includes audio
+ * capabilities applied when the recognition is active.
+ *
+ * @param modelHandle the handle of the sound model to use for recognition
+ * @param config A RecognitionConfig structure containing attributes of the
+ * recognition to perform
+ * @return retval Operation completion status: 0 in case of success,
+ * -EINVAL in case of invalid recognition attributes,
+ * -ENOSYS in case of invalid model handle,
+ * -ENOMEM in case of memory allocation failure,
+ * -ENODEV in case of initialization error.
+ */
+ startRecognition_2_3(SoundModelHandle modelHandle, RecognitionConfig config)
+ generates (int32_t retval);
+
+ /**
+ * 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..d3136b9
--- /dev/null
+++ b/soundtrigger/2.3/default/SoundTriggerHw.cpp
@@ -0,0 +1,920 @@
+/*
+ * 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;
+ V2_0::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(
+ V2_0::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::convertPropertiesFromHal(
+ V2_3::Properties* properties, const struct sound_trigger_properties_header* header) {
+ if (header->version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_3) {
+ const struct sound_trigger_properties_extended_1_3* halProperties =
+ (const struct sound_trigger_properties_extended_1_3*)header;
+ convertPropertiesFromHal(&properties->base, &halProperties->base);
+ properties->supportedModelArch = halProperties->supported_model_arch;
+ properties->audioCapabilities = halProperties->audio_capabilities;
+ }
+}
+
+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;
+}
+
+struct sound_trigger_recognition_config_header* SoundTriggerHw::convertRecognitionConfigToHalHeader(
+ const V2_3::RecognitionConfig* config) {
+ sp<IMemory> memory;
+ const V2_1::ISoundTriggerHw::RecognitionConfig* config_2_1 = &config->base;
+ const V2_0::ISoundTriggerHw::RecognitionConfig* config_2_0 = &config_2_1->header;
+
+ size_t allocSize =
+ sizeof(struct sound_trigger_recognition_config_extended_1_3) + config_2_1->data.size();
+ struct sound_trigger_recognition_config_extended_1_3* halConfigExtended =
+ static_cast<struct sound_trigger_recognition_config_extended_1_3*>(malloc(allocSize));
+ LOG_ALWAYS_FATAL_IF(halConfigExtended == nullptr,
+ "malloc failed for size %zu in convertRecognitionConfigToHalHeader",
+ allocSize);
+ halConfigExtended->header.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_3;
+ halConfigExtended->header.size = allocSize;
+
+ struct sound_trigger_recognition_config* halConfigBase = &halConfigExtended->base;
+
+ halConfigBase->capture_handle = (audio_io_handle_t)config_2_0->captureHandle;
+ halConfigBase->capture_device = (audio_devices_t)config_2_0->captureDevice;
+ halConfigBase->capture_requested = config_2_0->captureRequested;
+
+ unsigned int i;
+ for (i = 0; i < config_2_0->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
+ convertPhraseRecognitionExtraToHal(&halConfigBase->phrases[i], &config_2_0->phrases[i]);
+ }
+ halConfigBase->num_phrases = i;
+
+ halConfigBase->data_offset = sizeof(struct sound_trigger_recognition_config_extended_1_3);
+ halConfigBase->data_size = config_2_1->data.size();
+ if (config_2_1->data.size() != 0) {
+ memory = mapMemory(config_2_1->data);
+ LOG_ALWAYS_FATAL_IF(memory == nullptr,
+ "failed to map config memory in convertRecognitionConfigToHalHeader");
+ memory->read();
+
+ uint8_t* dst = reinterpret_cast<uint8_t*>(halConfigExtended) + halConfigBase->data_offset;
+ const uint8_t* src = static_cast<const uint8_t*>(static_cast<void*>(memory->getPointer()));
+ memcpy(dst, src, config_2_1->data.size());
+
+ memory->commit();
+ }
+
+ halConfigExtended->audio_capabilities = config->audioCapabilities;
+
+ return &halConfigExtended->header;
+}
+
+// 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<void> SoundTriggerHw::getProperties_2_3(ISoundTriggerHw::getProperties_2_3_cb _hidl_cb) {
+ ALOGV("getProperties_2_3() mHwDevice %p", mHwDevice);
+ int ret = 0;
+ V2_3::Properties properties;
+ const struct sound_trigger_properties_header* header;
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ header = mHwDevice->get_properties_extended(mHwDevice);
+
+ convertPropertiesFromHal(&properties, header);
+
+ ALOGV("getProperties_2_3 implementor %s supportedModelArch %s",
+ properties.base.implementor.c_str(), properties.supportedModelArch.c_str());
+
+exit:
+ _hidl_cb(ret, properties);
+ return Void();
+}
+
+Return<int32_t> SoundTriggerHw::startRecognition_2_3(int32_t modelHandle,
+ const V2_3::RecognitionConfig& config) {
+ int32_t ret;
+ sp<SoundTriggerHw::SoundModelClient> client;
+ struct sound_trigger_recognition_config_header* header;
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ ret = -ENOSYS;
+ goto exit;
+ }
+ }
+
+ header = convertRecognitionConfigToHalHeader(&config);
+
+ if (header == nullptr) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ ret = mHwDevice->start_recognition_extended(mHwDevice, client->getHalHandle(), header,
+ recognitionCallback_, client.get());
+
+ free(header);
+
+exit:
+ return ret;
+}
+
+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..ccd468c
--- /dev/null
+++ b/soundtrigger/2.3/default/SoundTriggerHw.h
@@ -0,0 +1,214 @@
+/*
+ * 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<void> getProperties_2_3(getProperties_2_3_cb _hidl_cb) override;
+ Return<int32_t> startRecognition_2_3(int32_t modelHandle,
+ const V2_3::RecognitionConfig& config) override;
+ 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);
+ void convertPropertiesFromHal(V2_3::Properties* properties,
+ const struct sound_trigger_properties_header* header);
+ 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);
+ struct sound_trigger_recognition_config_header* convertRecognitionConfigToHalHeader(
+ const V2_3::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..730f969
--- /dev/null
+++ b/soundtrigger/2.3/types.hal
@@ -0,0 +1,112 @@
+/*
+ * 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;
+import @2.0::ISoundTriggerHw.Properties;
+import @2.1::ISoundTriggerHw.RecognitionConfig;
+
+/**
+ * AudioCapabilities supported by the implemented HAL
+ * driver.
+ */
+enum AudioCapabilities : uint32_t {
+ /**
+ * If set the underlying module supports AEC.
+ */
+ ECHO_CANCELLATION = 1 << 0,
+ /**
+ * If set, the underlying module supports noise suppression.
+ */
+ NOISE_SUPPRESSION = 1 << 1,
+};
+
+/**
+ * Extended implementation properties providing verbose implementation
+ * details.
+ */
+struct Properties {
+ @2.0::ISoundTriggerHw.Properties base;
+
+ /**
+ * String naming the architecture used for running the supported models.
+ * (eg. DSP architecture)
+ */
+ string supportedModelArch;
+
+ /**
+ * Bit field encoding of the AudioCapabilities
+ * supported by the firmware.
+ */
+ bitfield<AudioCapabilities> audioCapabilities;
+};
+
+/**
+ * Configuration for sound trigger capture session passed to
+ * startRecognition_2_1() method.
+ */
+struct RecognitionConfig {
+ @2.1::ISoundTriggerHw.RecognitionConfig base;
+
+ /**
+ * Bit field encoding of the AudioCapabilities
+ * supported by the firmware.
+ */
+ uint32_t audioCapabilities;
+};
+
+/**
+ * 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..2d147e4
--- /dev/null
+++ b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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_0::RecognitionMode;
+using ::android::hardware::soundtrigger::V2_3::AudioCapabilities;
+using ::android::hardware::soundtrigger::V2_3::ISoundTriggerHw;
+using ::android::hardware::soundtrigger::V2_3::Properties;
+
+/**
+ * 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) {}
+
+/**
+ * Test ISoundTriggerHw::getProperties_2_3 method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the method returns no error
+ * - the implementation supports at least one sound model and one key phrase
+ * - the implementation supports at least VOICE_TRIGGER recognition mode
+ */
+TEST_P(SoundTriggerHidlTest, GetProperties_2_3) {
+ Properties halProperties;
+ Return<void> hidlReturn;
+ int ret = -ENODEV;
+
+ hidlReturn = soundtrigger->getProperties_2_3([&](int rc, auto res) {
+ ret = rc;
+ halProperties = res;
+ });
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(0, ret);
+ EXPECT_GT(halProperties.base.maxSoundModels, 0u);
+ EXPECT_GT(halProperties.base.maxKeyPhrases, 0u);
+ EXPECT_NE(0u, (halProperties.base.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER));
+ EXPECT_TRUE(halProperties.audioCapabilities <=
+ (AudioCapabilities::ECHO_CANCELLATION | AudioCapabilities::NOISE_SUPPRESSION));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, SoundTriggerHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/tv/cec/1.0/config/sadConfig.xsd b/tv/cec/1.0/config/sadConfig.xsd
new file mode 100644
index 0000000..7f99311
--- /dev/null
+++ b/tv/cec/1.0/config/sadConfig.xsd
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<xs:schema version="1.0"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:include schemaLocation="../../../../audio/4.0/config/audio_policy_configuration.xsd"/>
+ <xs:complexType name="config">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ List the config versions supported by Short Audio Descriptor(SAD) config.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="device" type="device" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="version" type="version"/>
+ </xs:complexType>
+ <xs:complexType name="device">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Device section:
+ There is a list of configurations in this SAD config for all the input audio
+ devices that the current Android device supports.
+ Each device has the following attributes:
+ "type": type of the audio device.
+ And the following element
+ <supportedFormat/>: the supported format info of the device. There can be
+ multiple formats supported by one audio device.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="supportedFormat" type="supportedFormat" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="type" type="extendableAudioDevice" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="supportedFormat">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ SupportedFormat section:
+ The details of the short audio descriptor of a specific audio format
+ supported by the audio device. Attributes as follows:
+ "format": format enum of the current supported format.
+ "descriptor": three-byte short audio descriptor for the given format in hex.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="format" type="hdmiAudioFormat" use="required"/>
+ <xs:attribute name="descriptor" type="descriptor" use="required"/>
+ </xs:complexType>
+ <xs:simpleType name="descriptor">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[a-fA-F0-9]{6}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="hdmiAudioFormat">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_FORMAT_NONE"/>
+ <xs:enumeration value="AUDIO_FORMAT_LPCM"/>
+ <xs:enumeration value="AUDIO_FORMAT_DD"/>
+ <xs:enumeration value="AUDIO_FORMAT_MPEG1"/>
+ <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+ <xs:enumeration value="AUDIO_FORMAT_MPEG2"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+ <xs:enumeration value="AUDIO_FORMAT_ATRAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_ONEBITAUDIO"/>
+ <xs:enumeration value="AUDIO_FORMAT_DDP"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTSHD"/>
+ <xs:enumeration value="AUDIO_FORMAT_TRUEHD"/>
+ <xs:enumeration value="AUDIO_FORMAT_DST"/>
+ <xs:enumeration value="AUDIO_FORMAT_WMAPRO"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:element name="config" type="config"/>
+</xs:schema>
diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal
index 94e3c0c..567971f 100644
--- a/tv/tuner/1.0/IFilter.hal
+++ b/tv/tuner/1.0/IFilter.hal
@@ -120,12 +120,13 @@
* presented by file descripor in the handle as released.
*
* @param avMemory A handle associated to the memory for audio or video.
+ * @param avDataId An Id provides additional information for AV data.
* @return result Result status of the operation.
* SUCCESS if successful,
* INVALID_ARGUMENT if failed for wrong parameter.
* UNKNOWN_ERROR if failed for other reasons.
*/
- releaseAvHandle(handle avMemory) generates (Result result);
+ releaseAvHandle(handle avMemory, uint64_t avDataId) generates (Result result);
/**
* Set the filter's data source.
diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal
index ceda2b3..756ab46 100644
--- a/tv/tuner/1.0/IFrontend.hal
+++ b/tv/tuner/1.0/IFrontend.hal
@@ -20,15 +20,16 @@
import ILnb;
/**
- * A Tuner Frontend is used to tune to a frequency and lock signal. It provide
- * live data feed to Tuner Demux interface.
+ * A Tuner Frontend is used to tune to a frequency and lock signal.
+ *
+ * IFrontend provides a bit stream to the Tuner Demux interface.
*/
interface IFrontend {
/**
- * Set the callback
+ * Set the frontend callback.
*
- * It is used by the client to receive events from the Frontend.
- * Only one callback for one Frontend instance is supported. The callback
+ * IFrontendCallback is used by the client to receive events from the Frontend.
+ * Only one callback per IFrontend instance is supported. The callback
* will be replaced if it's set again.
*
* @param callback Callback object to pass Frontend events to the system.
@@ -42,14 +43,14 @@
setCallback(IFrontendCallback callback) generates (Result result);
/**
- * Tuning Frontend
+ * Tunes the frontend to using the settings given.
*
- * It is used by the client to lock a frequency by providing signal
- * delivery information. If previous tuning isn't completed, this call must
- * stop previous tuning, and start a new tuning. Tune is a async call.
- * LOCKED or NO_SIGNAL eventi is sent back to caller through callback.
+ * This locks the frontend to a frequency by providing signal
+ * delivery information. If previous tuning isn't completed, this call MUST
+ * stop previous tuning, and start a new tuning.
+ * Tune is an async call, with LOCKED or NO_SIGNAL events sent via callback.
*
- * @param settings Signal delivery information which frontend can use to
+ * @param settings Signal delivery information the frontend uses to
* search and lock the signal.
*
* @return result Result status of the operation.
@@ -60,9 +61,10 @@
tune(FrontendSettings settings) generates (Result result);
/**
- * Stop the tuning
+ * Stops a previous tuning.
*
- * It is used by the client to stop a previous tuning.
+ * If the method completes successfully the frontend is no longer tuned and no data
+ * will be sent to attached demuxes.
*
* @return result Result status of the operation.
* SUCCESS if successfully stop tuning.
@@ -71,10 +73,10 @@
stopTune() generates (Result result);
/**
- * Release the Frontend instance
+ * Releases the Frontend instance
*
- * It is used by the client to release the frontend instance. HAL clear
- * underneath resource. client mustn't access the instance any more.
+ * Associated resources are released. close may be called more than once.
+ * Calls to any other method after this will return an error
*
* @return result Result status of the operation.
* SUCCESS if successful,
@@ -148,7 +150,7 @@
setLnb(LnbId lnbId) generates (Result result);
/**
- * Enble or Disable Low Noise Amplifier (LNA).
+ * Enable or Disable Low Noise Amplifier (LNA).
*
* @param bEnable true if activate LNA module; false if deactivate LNA
*
diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal
index 2712c13..ba183f1 100644
--- a/tv/tuner/1.0/ITuner.hal
+++ b/tv/tuner/1.0/ITuner.hal
@@ -123,4 +123,21 @@
* @return lnb the newly created Lnb interface.
*/
openLnbById(LnbId lnbId) generates (Result result, ILnb lnb);
+
+ /**
+ * Create a new instance of Lnb given a LNB name.
+ *
+ * It is used by the client to create a LNB instance for external device.
+ *
+ * @param lnbName the name for an external LNB to be opened. The app
+ * provides the name. Frammework doesn't depend on the name, instead
+ * use lnbId return from this call.
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNAVAILABLE if no resource.
+ * UNKNOWN_ERROR if creation failed for other reasons.
+ * @return lnbId the id of the LNB to be opened.
+ * @return lnb the newly created Lnb interface.
+ */
+ openLnbByName(string lnbName) generates (Result result, LnbId lnbId, ILnb lnb);
};
diff --git a/tv/tuner/1.0/TEST_MAPPING b/tv/tuner/1.0/TEST_MAPPING
new file mode 100644
index 0000000..1979887
--- /dev/null
+++ b/tv/tuner/1.0/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "VtsHalTvTunerV1_0TargetTest"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
index b3160fc..54d0952 100644
--- a/tv/tuner/1.0/default/Filter.cpp
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -120,7 +120,7 @@
return Result::SUCCESS;
}
-Return<Result> Filter::releaseAvHandle(const hidl_handle& /*avMemory*/) {
+Return<Result> Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t /*avDataId*/) {
ALOGV("%s", __FUNCTION__);
return Result::SUCCESS;
diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
index d397f73..0dc992a 100644
--- a/tv/tuner/1.0/default/Filter.h
+++ b/tv/tuner/1.0/default/Filter.h
@@ -70,7 +70,7 @@
virtual Return<Result> flush() override;
- virtual Return<Result> releaseAvHandle(const hidl_handle& avMemory) override;
+ virtual Return<Result> releaseAvHandle(const hidl_handle& avMemory, uint64_t avDataId) override;
virtual Return<Result> close() override;
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index c143d61..c6017f0 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -139,6 +139,15 @@
return mFrontends[frontendId];
}
+Return<void> Tuner::openLnbByName(const hidl_string& /*lnbName*/, openLnbByName_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ sp<ILnb> lnb = new Lnb();
+
+ _hidl_cb(Result::SUCCESS, 1234, lnb);
+ return Void();
+}
+
void Tuner::setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId) {
mFrontendToDemux[frontendId] = demuxId;
}
diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h
index 96da257..7a8a919 100644
--- a/tv/tuner/1.0/default/Tuner.h
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -55,6 +55,9 @@
virtual Return<void> openLnbById(LnbId lnbId, openLnbById_cb _hidl_cb) override;
+ virtual Return<void> openLnbByName(const hidl_string& lnbName,
+ openLnbByName_cb _hidl_cb) override;
+
sp<Frontend> getFrontendById(uint32_t frontendId);
void setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId);
diff --git a/tv/tuner/1.0/default/service.cpp b/tv/tuner/1.0/default/service.cpp
index 581d269..7bbc09e 100644
--- a/tv/tuner/1.0/default/service.cpp
+++ b/tv/tuner/1.0/default/service.cpp
@@ -21,7 +21,6 @@
#define LOG_TAG "android.hardware.tv.tuner@1.0-service"
#endif
-#include <binder/ProcessState.h>
#include <hidl/HidlTransportSupport.h>
#include <hidl/LegacySupport.h>
@@ -46,8 +45,8 @@
android::sp<ITuner> service = new Tuner();
android::status_t status;
if (kLazyService) {
- auto serviceRegistrar = std::make_shared<LazyServiceRegistrar>();
- status = serviceRegistrar->registerService(service);
+ auto serviceRegistrar = LazyServiceRegistrar::getInstance();
+ status = serviceRegistrar.registerService(service);
} else {
status = service->registerAsService();
}
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 944da5a..2eaab36 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -63,7 +63,7 @@
DVBS,
/**
* Digital Video Broadcasting - Terrestrial
- * DVB Terresttrial Frontend Standard ETSI EN 300 468 V1.15.1 and
+ * DVB Terrestrial Frontend Standard ETSI EN 300 468 V1.15.1 and
* ETSI EN 302 755 V1.4.1.
*/
DVBT,
@@ -255,7 +255,7 @@
};
/**
- * Signal Setting for ATSC Frontend.
+ * Signal Settings for an ATSC Frontend.
*/
struct FrontendAtscSettings {
/**
@@ -537,6 +537,16 @@
};
/**
+ * VCM mode in DVBS.
+ */
+@export
+enum FrontendDvbsVcmMode : uint32_t {
+ UNDEFINED,
+ AUTO,
+ MANUAL,
+};
+
+/**
* Signal Settings for an DVBS Frontend.
*/
struct FrontendDvbsSettings {
@@ -561,6 +571,8 @@
uint32_t inputStreamId;
FrontendDvbsStandard standard;
+
+ FrontendDvbsVcmMode vcmMode;
};
/**
@@ -773,6 +785,7 @@
/**
* Physical Layer Pipe (PLP) Mode for DVBT.
*/
+@export
enum FrontendDvbtPlpMode : uint32_t {
UNDEFINED,
AUTO,
@@ -868,7 +881,7 @@
};
/**
- * Modulaltion Type for ISDBS.
+ * Modulation Type for ISDBS.
*/
@export
enum FrontendIsdbsModulation : uint32_t {
@@ -960,7 +973,7 @@
/**
* hardware is able to detect and set Modulation automatically
*/
- AUTO = 1 << 5,
+ AUTO = 1 << 0,
MOD_BPSK = 1 << 1,
MOD_QPSK = 1 << 2,
MOD_8PSK = 1 << 3,
@@ -1105,7 +1118,7 @@
bitfield<FrontendIsdbtBandwidth> bandwidthCap;
- bitfield<FrontendIsdbtModulation> constellationCap;
+ bitfield<FrontendIsdbtModulation> modulationCap;
bitfield<FrontendIsdbtCoderate> coderateCap;
@@ -1118,9 +1131,14 @@
@export
enum FrontendAnalogType : uint32_t {
UNDEFINED = 0,
- PAL = 1 << 0,
- SECAM = 1 << 1,
- NTSC = 1 << 2,
+ AUTO = 1 << 0,
+ PAL = 1 << 1,
+ PAL_M = 1 << 2,
+ PAL_N = 1 << 3,
+ PAL_60 = 1 << 4,
+ NTSC = 1 << 5,
+ NTSC_443 = 1 << 6,
+ SECAM = 1 << 7,
};
/**
@@ -1129,23 +1147,24 @@
@export
enum FrontendAnalogSifStandard : uint32_t {
UNDEFINED = 0,
- BG = 1 << 0,
- BG_A2 = 1 << 1,
- BG_NICAM = 1 << 2,
- I = 1 << 3,
- DK = 1 << 4,
- DK1 = 1 << 5,
- DK2 = 1 << 6,
- DK3 = 1 << 7,
- DK_NICAM = 1 << 8,
- L = 1 << 9,
- M = 1 << 10,
- M_BTSC = 1 << 11,
- M_A2 = 1 << 12,
- M_EIA_J = 1 << 13,
- I_NICAM = 1 << 14,
- L_NICAM = 1 << 15,
- L_PRIME = 1 << 16,
+ AUTO = 1 << 0,
+ BG = 1 << 1,
+ BG_A2 = 1 << 2,
+ BG_NICAM = 1 << 3,
+ I = 1 << 4,
+ DK = 1 << 5,
+ DK1_A2 = 1 << 6,
+ DK2_A2 = 1 << 7,
+ DK3_A2 = 1 << 8,
+ DK_NICAM = 1 << 9,
+ L = 1 << 10,
+ M = 1 << 11,
+ M_BTSC = 1 << 12,
+ M_A2 = 1 << 13,
+ M_EIAJ = 1 << 14,
+ I_NICAM = 1 << 15,
+ L_NICAM = 1 << 16,
+ L_PRIME = 1 << 17,
};
/**
@@ -1197,6 +1216,7 @@
/**
* Scan type for Frontend.
*/
+@export
enum FrontendScanType : uint32_t {
SCAN_UNDEFINED = 0,
SCAN_AUTO = 1 << 0,
@@ -1206,6 +1226,7 @@
/**
* Scan Message Type for Frontend.
*/
+@export
enum FrontendScanMessageType : uint32_t {
/**
* Scan locked the signal.
@@ -1228,6 +1249,11 @@
*/
SYMBOL_RATE,
/**
+ * Locked HIERARCHY for DVBT2 frontend.
+ */
+ HIERARCHY,
+ ANALOG_TYPE,
+ /**
* Locked Plp Ids for DVBT2 frontend.
*/
PLP_IDS,
@@ -1272,14 +1298,18 @@
uint8_t progressPercent;
/**
- * Signal frequency in Hertz
+ * Signal frequencies in Hertz
*/
- uint32_t frequency;
+ vec<uint32_t> frequencies;
/**
* Symbols per second
*/
- uint32_t symbolRate;
+ vec<uint32_t> symbolRates;
+
+ FrontendDvbtHierarchy hierarchy;
+
+ FrontendAnalogType analogType;
vec<uint8_t> plpIds;
@@ -1287,10 +1317,12 @@
vec<uint16_t> inputStreamIds;
- safe_union standard {
+ safe_union Standard {
FrontendDvbsStandard sStd;
FrontendDvbtStandard tStd;
+
+ FrontendAnalogSifStandard sifStd;
} std;
/**
@@ -1305,18 +1337,15 @@
@export
enum FrontendEventType : uint32_t {
/**
- * If frontend locked the signal which is specified by tune method, HAL sends
- * Locked event.
+ * The frontend has locked to the signal specified by the tune method.
*/
LOCKED,
/**
- * If frontend can't locked the signal which is specified by tune method,
- * HAL sends NO_SIGNAL event.
+ * The frontend is unable to lock to the signal specified by the tune method.
*/
NO_SIGNAL,
/**
- * If frontend detect that the locked signal get lost, HAL sends LOST_LOCK
- * event.
+ * The frontend has lost the lock to the signal specified by the tune method.
*/
LOST_LOCK,
};
@@ -2020,19 +2049,15 @@
};
/**
- * Index type to be used in the filter for record
+ * Start Code Index type to be used in the filter for record
*/
@export
-enum DemuxRecordIndexType : uint32_t {
+enum DemuxRecordScIndexType : uint32_t {
/**
- * Don't use index
+ * Don't use SC index
*/
NONE,
/**
- * Use TS index
- */
- TS,
- /**
* Use Start Code index
*/
SC,
@@ -2046,15 +2071,16 @@
* Filter Settings for Record data.
*/
struct DemuxFilterRecordSettings {
- DemuxRecordIndexType indexType;
+ bitfield<DemuxTsIndex> tsIndexMask;
- safe_union IndexMask {
- bitfield<DemuxTsIndex> tsIndexMask;
+ DemuxRecordScIndexType scIndexType;
- bitfield<DemuxScIndex> scIndexMask;
+ safe_union ScIndexMask {
- bitfield<DemuxScHevcIndex> scHevcIndexMask;
- } indexMask;
+ bitfield<DemuxScIndex> sc;
+
+ bitfield<DemuxScHevcIndex> scHevc;
+ } scIndexMask;
};
/**
@@ -2399,6 +2425,12 @@
uint32_t dataLength;
/**
+ * The offset in the memory block which is shared among multiple
+ * MediaEvents.
+ */
+ uint32_t offset;
+
+ /**
* A handle associated to the memory where audio or video data stays.
*/
handle avMemory;
@@ -2409,6 +2441,12 @@
bool isSecureMemory;
/**
+ * An Id is used by HAL to provide additional information for AV data.
+ * For secure audio, it's the audio handle used by Audio Track.
+ */
+ uint64_t avDataId;
+
+ /**
* MPU sequence number of filtered data (only for MMTP)
*/
uint32_t mpuSequenceNumber;
@@ -2448,16 +2486,17 @@
struct DemuxFilterTsRecordEvent {
DemuxPid pid;
+ bitfield<DemuxTsIndex> tsIndexMask;
+
/**
* Indexes of record output
*/
- safe_union IndexMask {
- bitfield<DemuxTsIndex> tsIndexMask;
+ safe_union ScIndexMask {
- bitfield<DemuxScIndex> scIndexMask;
+ bitfield<DemuxScIndex> sc;
- bitfield<DemuxScHevcIndex> scHevcIndexMask;
- } indexMask;
+ bitfield<DemuxScHevcIndex> scHevc;
+ } scIndexMask;
/**
* Byte number from beginning of the filter's output
diff --git a/tv/tuner/README.md b/tv/tuner/README.md
new file mode 100644
index 0000000..aa1f62d
--- /dev/null
+++ b/tv/tuner/README.md
@@ -0,0 +1,12 @@
+# Tuner HALs
+
+## Overview
+
+TV specific tuners.
+
+See 1.0/ITuner.hal for an overview.
+
+*** note
+**Warning:** The HALs are not (yet) frozen, as the HAL definition is
+expected to evolve between Android releases.
+***
diff --git a/usb/gadget/1.1/Android.bp b/usb/gadget/1.1/Android.bp
new file mode 100644
index 0000000..b41eb9c
--- /dev/null
+++ b/usb/gadget/1.1/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.usb.gadget@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "IUsbGadget.hal",
+ ],
+ interfaces: [
+ "android.hardware.usb.gadget@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/usb/gadget/1.1/IUsbGadget.hal b/usb/gadget/1.1/IUsbGadget.hal
new file mode 100644
index 0000000..af88ef0
--- /dev/null
+++ b/usb/gadget/1.1/IUsbGadget.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb.gadget@1.1;
+
+import @1.0::IUsbGadget;
+import @1.0::Status;
+
+interface IUsbGadget extends @1.0::IUsbGadget {
+ /**
+ * This function is used to reset USB gadget driver.
+ * Performs USB data connection reset. The connection will disconnect and
+ * reconnect.
+ *
+ * return status indicate success or not.
+ */
+ reset() generates(Status status);
+};
diff --git a/usb/gadget/1.1/default/Android.bp b/usb/gadget/1.1/default/Android.bp
new file mode 100644
index 0000000..68e2a29
--- /dev/null
+++ b/usb/gadget/1.1/default/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_binary {
+ name: "android.hardware.usb.gadget@1.1-service",
+ defaults: ["hidl_defaults"],
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.usb.gadget@1.1-service.rc"],
+ vintf_fragments: ["android.hardware.usb.gadget@1.1-service.xml"],
+ vendor: true,
+ srcs: [
+ "service.cpp",
+ "UsbGadget.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.usb.gadget@1.0",
+ "android.hardware.usb.gadget@1.1",
+ "libbase",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: ["libusbconfigfs"],
+}
diff --git a/usb/gadget/1.1/default/UsbGadget.cpp b/usb/gadget/1.1/default/UsbGadget.cpp
new file mode 100644
index 0000000..36d865d
--- /dev/null
+++ b/usb/gadget/1.1/default/UsbGadget.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.usb.gadget@1.1-service"
+
+#include "UsbGadget.h"
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+namespace V1_1 {
+namespace implementation {
+
+UsbGadget::UsbGadget() {
+ if (access(OS_DESC_PATH, R_OK) != 0) {
+ ALOGE("configfs setup not done yet");
+ abort();
+ }
+}
+
+void currentFunctionsAppliedCallback(bool functionsApplied, void* payload) {
+ UsbGadget* gadget = (UsbGadget*)payload;
+ gadget->mCurrentUsbFunctionsApplied = functionsApplied;
+}
+
+Return<void> UsbGadget::getCurrentUsbFunctions(const sp<V1_0::IUsbGadgetCallback>& callback) {
+ Return<void> ret = callback->getCurrentUsbFunctionsCb(
+ mCurrentUsbFunctions, mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED
+ : Status::FUNCTIONS_NOT_APPLIED);
+ if (!ret.isOk()) ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.description().c_str());
+
+ return Void();
+}
+
+V1_0::Status UsbGadget::tearDownGadget() {
+ if (resetGadget() != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;
+
+ if (monitorFfs.isMonitorRunning()) {
+ monitorFfs.reset();
+ } else {
+ ALOGI("mMonitor not running");
+ }
+ return V1_0::Status::SUCCESS;
+}
+
+Return<Status> UsbGadget::reset() {
+ if (!WriteStringToFile("none", PULLUP_PATH)) {
+ ALOGI("Gadget cannot be pulled down");
+ return Status::ERROR;
+ }
+
+ return Status::SUCCESS;
+}
+
+static V1_0::Status validateAndSetVidPid(uint64_t functions) {
+ V1_0::Status ret = V1_0::Status::SUCCESS;
+
+ switch (functions) {
+ case static_cast<uint64_t>(V1_0::GadgetFunction::MTP):
+ ret = setVidPid("0x18d1", "0x4ee1");
+ break;
+ case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::MTP:
+ ret = setVidPid("0x18d1", "0x4ee2");
+ break;
+ case static_cast<uint64_t>(V1_0::GadgetFunction::RNDIS):
+ ret = setVidPid("0x18d1", "0x4ee3");
+ break;
+ case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::RNDIS:
+ ret = setVidPid("0x18d1", "0x4ee4");
+ break;
+ case static_cast<uint64_t>(V1_0::GadgetFunction::PTP):
+ ret = setVidPid("0x18d1", "0x4ee5");
+ break;
+ case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::PTP:
+ ret = setVidPid("0x18d1", "0x4ee6");
+ break;
+ case static_cast<uint64_t>(V1_0::GadgetFunction::ADB):
+ ret = setVidPid("0x18d1", "0x4ee7");
+ break;
+ case static_cast<uint64_t>(V1_0::GadgetFunction::MIDI):
+ ret = setVidPid("0x18d1", "0x4ee8");
+ break;
+ case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::MIDI:
+ ret = setVidPid("0x18d1", "0x4ee9");
+ break;
+ case static_cast<uint64_t>(V1_0::GadgetFunction::ACCESSORY):
+ ret = setVidPid("0x18d1", "0x2d00");
+ break;
+ case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::ACCESSORY:
+ ret = setVidPid("0x18d1", "0x2d01");
+ break;
+ case static_cast<uint64_t>(V1_0::GadgetFunction::AUDIO_SOURCE):
+ ret = setVidPid("0x18d1", "0x2d02");
+ break;
+ case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::AUDIO_SOURCE:
+ ret = setVidPid("0x18d1", "0x2d03");
+ break;
+ case V1_0::GadgetFunction::ACCESSORY | V1_0::GadgetFunction::AUDIO_SOURCE:
+ ret = setVidPid("0x18d1", "0x2d04");
+ break;
+ case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::ACCESSORY |
+ V1_0::GadgetFunction::AUDIO_SOURCE:
+ ret = setVidPid("0x18d1", "0x2d05");
+ break;
+ default:
+ ALOGE("Combination not supported");
+ ret = V1_0::Status::CONFIGURATION_NOT_SUPPORTED;
+ }
+ return ret;
+}
+
+V1_0::Status UsbGadget::setupFunctions(uint64_t functions,
+ const sp<V1_0::IUsbGadgetCallback>& callback,
+ uint64_t timeout) {
+ bool ffsEnabled = false;
+ int i = 0;
+
+ if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) !=
+ V1_0::Status::SUCCESS)
+ return V1_0::Status::ERROR;
+
+ if ((functions & V1_0::GadgetFunction::ADB) != 0) {
+ ffsEnabled = true;
+ if (addAdb(&monitorFfs, &i) != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;
+ }
+
+ // Pull up the gadget right away when there are no ffs functions.
+ if (!ffsEnabled) {
+ if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) return V1_0::Status::ERROR;
+ mCurrentUsbFunctionsApplied = true;
+ if (callback) callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
+ return V1_0::Status::SUCCESS;
+ }
+
+ monitorFfs.registerFunctionsAppliedCallback(¤tFunctionsAppliedCallback, this);
+ // Monitors the ffs paths to pull up the gadget when descriptors are written.
+ // Also takes of the pulling up the gadget again if the userspace process
+ // dies and restarts.
+ monitorFfs.startMonitor();
+
+ if (kDebug) ALOGI("Mainthread in Cv");
+
+ if (callback) {
+ bool pullup = monitorFfs.waitForPullUp(timeout);
+ Return<void> ret = callback->setCurrentUsbFunctionsCb(
+ functions, pullup ? V1_0::Status::SUCCESS : V1_0::Status::ERROR);
+ if (!ret.isOk()) ALOGE("setCurrentUsbFunctionsCb error %s", ret.description().c_str());
+ }
+
+ return V1_0::Status::SUCCESS;
+}
+
+Return<void> UsbGadget::setCurrentUsbFunctions(uint64_t functions,
+ const sp<V1_0::IUsbGadgetCallback>& callback,
+ uint64_t timeout) {
+ std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
+
+ mCurrentUsbFunctions = functions;
+ mCurrentUsbFunctionsApplied = false;
+
+ // Unlink the gadget and stop the monitor if running.
+ V1_0::Status status = tearDownGadget();
+ if (status != V1_0::Status::SUCCESS) {
+ goto error;
+ }
+
+ ALOGI("Returned from tearDown gadget");
+
+ // Leave the gadget pulled down to give time for the host to sense disconnect.
+ usleep(kDisconnectWaitUs);
+
+ if (functions == static_cast<uint64_t>(V1_0::GadgetFunction::NONE)) {
+ if (callback == NULL) return Void();
+ Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
+ if (!ret.isOk())
+ ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
+ return Void();
+ }
+
+ status = validateAndSetVidPid(functions);
+
+ if (status != V1_0::Status::SUCCESS) {
+ goto error;
+ }
+
+ status = setupFunctions(functions, callback, timeout);
+ if (status != V1_0::Status::SUCCESS) {
+ goto error;
+ }
+
+ ALOGI("Usb Gadget setcurrent functions called successfully");
+ return Void();
+
+error:
+ ALOGI("Usb Gadget setcurrent functions failed");
+ if (callback == NULL) return Void();
+ Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, status);
+ if (!ret.isOk())
+ ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
+ return Void();
+}
+} // namespace implementation
+} // namespace V1_1
+} // namespace gadget
+} // namespace usb
+} // namespace hardware
+} // namespace android
diff --git a/usb/gadget/1.1/default/UsbGadget.h b/usb/gadget/1.1/default/UsbGadget.h
new file mode 100644
index 0000000..b278071
--- /dev/null
+++ b/usb/gadget/1.1/default/UsbGadget.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_USB_GADGET_V1_1_USBGADGET_H
+#define ANDROID_HARDWARE_USB_GADGET_V1_1_USBGADGET_H
+
+#include <UsbGadgetCommon.h>
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/usb/gadget/1.1/IUsbGadget.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <utils/Log.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::base::GetProperty;
+using ::android::base::SetProperty;
+using ::android::base::unique_fd;
+using ::android::base::WriteStringToFile;
+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::usb::gadget::addAdb;
+using ::android::hardware::usb::gadget::addEpollFd;
+using ::android::hardware::usb::gadget::getVendorFunctions;
+using ::android::hardware::usb::gadget::kDebug;
+using ::android::hardware::usb::gadget::kDisconnectWaitUs;
+using ::android::hardware::usb::gadget::linkFunction;
+using ::android::hardware::usb::gadget::MonitorFfs;
+using ::android::hardware::usb::gadget::resetGadget;
+using ::android::hardware::usb::gadget::setVidPid;
+using ::android::hardware::usb::gadget::unlinkFunctions;
+using ::std::string;
+
+constexpr char kGadgetName[] = "a600000.dwc3";
+static MonitorFfs monitorFfs(kGadgetName);
+
+struct UsbGadget : public IUsbGadget {
+ UsbGadget();
+
+ // Makes sure that only one request is processed at a time.
+ std::mutex mLockSetCurrentFunction;
+ uint64_t mCurrentUsbFunctions;
+ bool mCurrentUsbFunctionsApplied;
+
+ Return<void> setCurrentUsbFunctions(uint64_t functions,
+ const sp<V1_0::IUsbGadgetCallback>& callback,
+ uint64_t timeout) override;
+
+ Return<void> getCurrentUsbFunctions(const sp<V1_0::IUsbGadgetCallback>& callback) override;
+
+ Return<Status> reset() override;
+
+ private:
+ V1_0::Status tearDownGadget();
+ V1_0::Status setupFunctions(uint64_t functions, const sp<V1_0::IUsbGadgetCallback>& callback,
+ uint64_t timeout);
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gadget
+} // namespace usb
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_USB_V1_1_USBGADGET_H
diff --git a/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.rc b/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.rc
new file mode 100644
index 0000000..34ea7da
--- /dev/null
+++ b/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.rc
@@ -0,0 +1,6 @@
+service vendor.usb-gadget-hal-1-1 /vendor/bin/hw/android.hardware.usb.gadget@1.1-service
+ interface android.hardware.usb.gadget@1.0::IUsbGadget default
+ interface android.hardware.usb.gadget@1.1::IUsbGadget default
+ class hal
+ user root
+ group root shell mtp
diff --git a/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.xml b/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.xml
new file mode 100644
index 0000000..b40fa77
--- /dev/null
+++ b/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.xml
@@ -0,0 +1,12 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.usb.gadget</name>
+ <transport>hwbinder</transport>
+ <version>1.1</version>
+ <interface>
+ <name>IUsbGadget</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
+
diff --git a/usb/gadget/1.1/default/lib/Android.bp b/usb/gadget/1.1/default/lib/Android.bp
new file mode 100644
index 0000000..bba8340
--- /dev/null
+++ b/usb/gadget/1.1/default/lib/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_library_static {
+ name: "libusbconfigfs",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+
+ srcs: [
+ "UsbGadgetUtils.cpp",
+ "MonitorFfs.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "android.hardware.usb.gadget@1.0",
+ "android.hardware.usb.gadget@1.1",
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "libutils",
+ ],
+}
diff --git a/usb/gadget/1.1/default/lib/MonitorFfs.cpp b/usb/gadget/1.1/default/lib/MonitorFfs.cpp
new file mode 100644
index 0000000..0cdf038
--- /dev/null
+++ b/usb/gadget/1.1/default/lib/MonitorFfs.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libusbconfigfs"
+
+#include "include/UsbGadgetCommon.h"
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+
+static volatile bool gadgetPullup;
+
+MonitorFfs::MonitorFfs(const char* const gadget)
+ : mWatchFd(),
+ mEndpointList(),
+ mLock(),
+ mCv(),
+ mLockFd(),
+ mCurrentUsbFunctionsApplied(false),
+ mMonitor(),
+ mCallback(NULL),
+ mPayload(NULL),
+ mGadgetName(gadget),
+ mMonitorRunning(false) {
+ unique_fd eventFd(eventfd(0, 0));
+ if (eventFd == -1) {
+ ALOGE("mEventFd failed to create %d", errno);
+ abort();
+ }
+
+ unique_fd epollFd(epoll_create(2));
+ if (epollFd == -1) {
+ ALOGE("mEpollFd failed to create %d", errno);
+ abort();
+ }
+
+ unique_fd inotifyFd(inotify_init());
+ if (inotifyFd < 0) {
+ ALOGE("inotify init failed");
+ abort();
+ }
+
+ if (addEpollFd(epollFd, inotifyFd) == -1) abort();
+
+ if (addEpollFd(epollFd, eventFd) == -1) abort();
+
+ mEpollFd = move(epollFd);
+ mInotifyFd = move(inotifyFd);
+ mEventFd = move(eventFd);
+ gadgetPullup = false;
+}
+
+static void displayInotifyEvent(struct inotify_event* i) {
+ ALOGE(" wd =%2d; ", i->wd);
+ if (i->cookie > 0) ALOGE("cookie =%4d; ", i->cookie);
+
+ ALOGE("mask = ");
+ if (i->mask & IN_ACCESS) ALOGE("IN_ACCESS ");
+ if (i->mask & IN_ATTRIB) ALOGE("IN_ATTRIB ");
+ if (i->mask & IN_CLOSE_NOWRITE) ALOGE("IN_CLOSE_NOWRITE ");
+ if (i->mask & IN_CLOSE_WRITE) ALOGE("IN_CLOSE_WRITE ");
+ if (i->mask & IN_CREATE) ALOGE("IN_CREATE ");
+ if (i->mask & IN_DELETE) ALOGE("IN_DELETE ");
+ if (i->mask & IN_DELETE_SELF) ALOGE("IN_DELETE_SELF ");
+ if (i->mask & IN_IGNORED) ALOGE("IN_IGNORED ");
+ if (i->mask & IN_ISDIR) ALOGE("IN_ISDIR ");
+ if (i->mask & IN_MODIFY) ALOGE("IN_MODIFY ");
+ if (i->mask & IN_MOVE_SELF) ALOGE("IN_MOVE_SELF ");
+ if (i->mask & IN_MOVED_FROM) ALOGE("IN_MOVED_FROM ");
+ if (i->mask & IN_MOVED_TO) ALOGE("IN_MOVED_TO ");
+ if (i->mask & IN_OPEN) ALOGE("IN_OPEN ");
+ if (i->mask & IN_Q_OVERFLOW) ALOGE("IN_Q_OVERFLOW ");
+ if (i->mask & IN_UNMOUNT) ALOGE("IN_UNMOUNT ");
+ ALOGE("\n");
+
+ if (i->len > 0) ALOGE(" name = %s\n", i->name);
+}
+
+void* MonitorFfs::startMonitorFd(void* param) {
+ MonitorFfs* monitorFfs = (MonitorFfs*)param;
+ char buf[kBufferSize];
+ bool writeUdc = true, stopMonitor = false;
+ struct epoll_event events[kEpollEvents];
+ steady_clock::time_point disconnect;
+
+ bool descriptorWritten = true;
+ for (int i = 0; i < static_cast<int>(monitorFfs->mEndpointList.size()); i++) {
+ if (access(monitorFfs->mEndpointList.at(i).c_str(), R_OK)) {
+ descriptorWritten = false;
+ break;
+ }
+ }
+
+ // notify here if the endpoints are already present.
+ if (descriptorWritten) {
+ usleep(kPullUpDelay);
+ if (!!WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) {
+ lock_guard<mutex> lock(monitorFfs->mLock);
+ monitorFfs->mCurrentUsbFunctionsApplied = true;
+ monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied, monitorFfs->mPayload);
+ gadgetPullup = true;
+ writeUdc = false;
+ ALOGI("GADGET pulled up");
+ monitorFfs->mCv.notify_all();
+ }
+ }
+
+ while (!stopMonitor) {
+ int nrEvents = epoll_wait(monitorFfs->mEpollFd, events, kEpollEvents, -1);
+
+ if (nrEvents <= 0) {
+ ALOGE("epoll wait did not return descriptor number");
+ continue;
+ }
+
+ for (int i = 0; i < nrEvents; i++) {
+ ALOGI("event=%u on fd=%d\n", events[i].events, events[i].data.fd);
+
+ if (events[i].data.fd == monitorFfs->mInotifyFd) {
+ // Process all of the events in buffer returned by read().
+ int numRead = read(monitorFfs->mInotifyFd, buf, kBufferSize);
+ for (char* p = buf; p < buf + numRead;) {
+ struct inotify_event* event = (struct inotify_event*)p;
+ if (kDebug) displayInotifyEvent(event);
+
+ p += sizeof(struct inotify_event) + event->len;
+
+ bool descriptorPresent = true;
+ for (int j = 0; j < static_cast<int>(monitorFfs->mEndpointList.size()); j++) {
+ if (access(monitorFfs->mEndpointList.at(j).c_str(), R_OK)) {
+ if (kDebug) ALOGI("%s absent", monitorFfs->mEndpointList.at(j).c_str());
+ descriptorPresent = false;
+ break;
+ }
+ }
+
+ if (!descriptorPresent && !writeUdc) {
+ if (kDebug) ALOGI("endpoints not up");
+ writeUdc = true;
+ disconnect = std::chrono::steady_clock::now();
+ } else if (descriptorPresent && writeUdc) {
+ steady_clock::time_point temp = steady_clock::now();
+
+ if (std::chrono::duration_cast<microseconds>(temp - disconnect).count() <
+ kPullUpDelay)
+ usleep(kPullUpDelay);
+
+ if (!!WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) {
+ lock_guard<mutex> lock(monitorFfs->mLock);
+ monitorFfs->mCurrentUsbFunctionsApplied = true;
+ monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied,
+ monitorFfs->mPayload);
+ ALOGI("GADGET pulled up");
+ writeUdc = false;
+ gadgetPullup = true;
+ // notify the main thread to signal userspace.
+ monitorFfs->mCv.notify_all();
+ }
+ }
+ }
+ } else {
+ uint64_t flag;
+ read(monitorFfs->mEventFd, &flag, sizeof(flag));
+ if (flag == 100) {
+ stopMonitor = true;
+ break;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+void MonitorFfs::reset() {
+ lock_guard<mutex> lock(mLockFd);
+ uint64_t flag = 100;
+ unsigned long ret;
+
+ if (mMonitorRunning) {
+ // Stop the monitor thread by writing into signal fd.
+ ret = TEMP_FAILURE_RETRY(write(mEventFd, &flag, sizeof(flag)));
+ if (ret < 0) ALOGE("Error writing eventfd errno=%d", errno);
+
+ ALOGI("mMonitor signalled to exit");
+ mMonitor->join();
+ ALOGI("mMonitor destroyed");
+ mMonitorRunning = false;
+ }
+
+ for (std::vector<int>::size_type i = 0; i != mWatchFd.size(); i++)
+ inotify_rm_watch(mInotifyFd, mWatchFd[i]);
+
+ mEndpointList.clear();
+ gadgetPullup = false;
+ mCallback = NULL;
+ mPayload = NULL;
+}
+
+bool MonitorFfs::startMonitor() {
+ mMonitor = unique_ptr<thread>(new thread(this->startMonitorFd, this));
+ mMonitorRunning = true;
+ return true;
+}
+
+bool MonitorFfs::isMonitorRunning() {
+ return mMonitorRunning;
+}
+
+bool MonitorFfs::waitForPullUp(int timeout_ms) {
+ std::unique_lock<std::mutex> lk(mLock);
+
+ if (gadgetPullup) return true;
+
+ if (mCv.wait_for(lk, timeout_ms * 1ms, [] { return gadgetPullup; })) {
+ ALOGI("monitorFfs signalled true");
+ return true;
+ } else {
+ ALOGI("monitorFfs signalled error");
+ // continue monitoring as the descriptors might be written at a later
+ // point.
+ return false;
+ }
+}
+
+bool MonitorFfs::addInotifyFd(string fd) {
+ lock_guard<mutex> lock(mLockFd);
+ int wfd;
+
+ wfd = inotify_add_watch(mInotifyFd, fd.c_str(), IN_ALL_EVENTS);
+ if (wfd == -1)
+ return false;
+ else
+ mWatchFd.push_back(wfd);
+
+ return true;
+}
+
+void MonitorFfs::addEndPoint(string ep) {
+ lock_guard<mutex> lock(mLockFd);
+
+ mEndpointList.push_back(ep);
+}
+
+void MonitorFfs::registerFunctionsAppliedCallback(void (*callback)(bool functionsApplied,
+ void* payload),
+ void* payload) {
+ mCallback = callback;
+ mPayload = payload;
+}
+
+} // namespace gadget
+} // namespace usb
+} // namespace hardware
+} // namespace android
diff --git a/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp b/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp
new file mode 100644
index 0000000..8402853
--- /dev/null
+++ b/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libusbconfigfs"
+
+#include "include/UsbGadgetCommon.h"
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+
+int unlinkFunctions(const char* path) {
+ DIR* config = opendir(path);
+ struct dirent* function;
+ char filepath[kMaxFilePathLength];
+ int ret = 0;
+
+ if (config == NULL) return -1;
+
+ // d_type does not seems to be supported in /config
+ // so filtering by name.
+ while (((function = readdir(config)) != NULL)) {
+ if ((strstr(function->d_name, FUNCTION_NAME) == NULL)) continue;
+ // build the path for each file in the folder.
+ sprintf(filepath, "%s/%s", path, function->d_name);
+ ret = remove(filepath);
+ if (ret) {
+ ALOGE("Unable remove file %s errno:%d", filepath, errno);
+ break;
+ }
+ }
+
+ closedir(config);
+ return ret;
+}
+
+int addEpollFd(const unique_fd& epfd, const unique_fd& fd) {
+ struct epoll_event event;
+ int ret;
+
+ event.data.fd = fd;
+ event.events = EPOLLIN;
+
+ ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
+ if (ret) ALOGE("epoll_ctl error %d", errno);
+
+ return ret;
+}
+
+int linkFunction(const char* function, int index) {
+ char functionPath[kMaxFilePathLength];
+ char link[kMaxFilePathLength];
+
+ sprintf(functionPath, "%s%s", FUNCTIONS_PATH, function);
+ sprintf(link, "%s%d", FUNCTION_PATH, index);
+ if (symlink(functionPath, link)) {
+ ALOGE("Cannot create symlink %s -> %s errno:%d", link, functionPath, errno);
+ return -1;
+ }
+ return 0;
+}
+
+Status setVidPid(const char* vid, const char* pid) {
+ if (!WriteStringToFile(vid, VENDOR_ID_PATH)) return Status::ERROR;
+
+ if (!WriteStringToFile(pid, PRODUCT_ID_PATH)) return Status::ERROR;
+
+ return Status::SUCCESS;
+}
+
+std::string getVendorFunctions() {
+ if (GetProperty(kBuildType, "") == "user") return "user";
+
+ std::string bootMode = GetProperty(PERSISTENT_BOOT_MODE, "");
+ std::string persistVendorFunctions = GetProperty(kPersistentVendorConfig, "");
+ std::string vendorFunctions = GetProperty(kVendorConfig, "");
+ std::string ret = "";
+
+ if (vendorFunctions != "") {
+ ret = vendorFunctions;
+ } else if (bootMode == "usbradio" || bootMode == "factory" || bootMode == "ffbm-00" ||
+ bootMode == "ffbm-01") {
+ if (persistVendorFunctions != "")
+ ret = persistVendorFunctions;
+ else
+ ret = "diag";
+ // vendor.usb.config will reflect the current configured functions
+ SetProperty(kVendorConfig, ret);
+ }
+
+ return ret;
+}
+
+Status resetGadget() {
+ ALOGI("setCurrentUsbFunctions None");
+
+ if (!WriteStringToFile("none", PULLUP_PATH)) ALOGI("Gadget cannot be pulled down");
+
+ if (!WriteStringToFile("0", DEVICE_CLASS_PATH)) return Status::ERROR;
+
+ if (!WriteStringToFile("0", DEVICE_SUB_CLASS_PATH)) return Status::ERROR;
+
+ if (!WriteStringToFile("0", DEVICE_PROTOCOL_PATH)) return Status::ERROR;
+
+ if (!WriteStringToFile("0", DESC_USE_PATH)) return Status::ERROR;
+
+ if (unlinkFunctions(CONFIG_PATH)) return Status::ERROR;
+
+ return Status::SUCCESS;
+}
+
+Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,
+ int* functionCount) {
+ if (((functions & GadgetFunction::MTP) != 0)) {
+ *ffsEnabled = true;
+ ALOGI("setCurrentUsbFunctions mtp");
+ if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;
+
+ if (!monitorFfs->addInotifyFd("/dev/usb-ffs/mtp/")) return Status::ERROR;
+
+ if (linkFunction("ffs.mtp", (*functionCount)++)) return Status::ERROR;
+
+ // Add endpoints to be monitored.
+ monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep1");
+ monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep2");
+ monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep3");
+ } else if (((functions & GadgetFunction::PTP) != 0)) {
+ *ffsEnabled = true;
+ ALOGI("setCurrentUsbFunctions ptp");
+ if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;
+
+ if (!monitorFfs->addInotifyFd("/dev/usb-ffs/ptp/")) return Status::ERROR;
+
+ if (linkFunction("ffs.ptp", (*functionCount)++)) return Status::ERROR;
+
+ // Add endpoints to be monitored.
+ monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep1");
+ monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep2");
+ monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep3");
+ }
+
+ if ((functions & GadgetFunction::MIDI) != 0) {
+ ALOGI("setCurrentUsbFunctions MIDI");
+ if (linkFunction("midi.gs5", (*functionCount)++)) return Status::ERROR;
+ }
+
+ if ((functions & GadgetFunction::ACCESSORY) != 0) {
+ ALOGI("setCurrentUsbFunctions Accessory");
+ if (linkFunction("accessory.gs2", (*functionCount)++)) return Status::ERROR;
+ }
+
+ if ((functions & GadgetFunction::AUDIO_SOURCE) != 0) {
+ ALOGI("setCurrentUsbFunctions Audio Source");
+ if (linkFunction("audio_source.gs3", (*functionCount)++)) return Status::ERROR;
+ }
+
+ if ((functions & GadgetFunction::RNDIS) != 0) {
+ ALOGI("setCurrentUsbFunctions rndis");
+ if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
+ }
+
+ return Status::SUCCESS;
+}
+
+Status addAdb(MonitorFfs* monitorFfs, int* functionCount) {
+ ALOGI("setCurrentUsbFunctions Adb");
+ if (!monitorFfs->addInotifyFd("/dev/usb-ffs/adb/")) return Status::ERROR;
+
+ if (linkFunction("ffs.adb", (*functionCount)++)) return Status::ERROR;
+ monitorFfs->addEndPoint("/dev/usb-ffs/adb/ep1");
+ monitorFfs->addEndPoint("/dev/usb-ffs/adb/ep2");
+ ALOGI("Service started");
+ return Status::SUCCESS;
+}
+
+} // namespace gadget
+} // namespace usb
+} // namespace hardware
+} // namespace android
diff --git a/usb/gadget/1.1/default/lib/include/UsbGadgetCommon.h b/usb/gadget/1.1/default/lib/include/UsbGadgetCommon.h
new file mode 100644
index 0000000..b30f18e
--- /dev/null
+++ b/usb/gadget/1.1/default/lib/include/UsbGadgetCommon.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_USB_USBGADGETCOMMON_H
+#define HARDWARE_USB_USBGADGETCOMMON_H
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+
+#include <android/hardware/usb/gadget/1.1/IUsbGadget.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+
+constexpr int kBufferSize = 512;
+constexpr int kMaxFilePathLength = 256;
+constexpr int kEpollEvents = 10;
+constexpr bool kDebug = false;
+constexpr int kDisconnectWaitUs = 100000;
+constexpr int kPullUpDelay = 500000;
+constexpr int kShutdownMonitor = 100;
+
+constexpr char kBuildType[] = "ro.build.type";
+constexpr char kPersistentVendorConfig[] = "persist.vendor.usb.usbradio.config";
+constexpr char kVendorConfig[] = "vendor.usb.config";
+
+#define GADGET_PATH "/config/usb_gadget/g1/"
+#define PULLUP_PATH GADGET_PATH "UDC"
+#define PERSISTENT_BOOT_MODE "ro.bootmode"
+#define VENDOR_ID_PATH GADGET_PATH "idVendor"
+#define PRODUCT_ID_PATH GADGET_PATH "idProduct"
+#define DEVICE_CLASS_PATH GADGET_PATH "bDeviceClass"
+#define DEVICE_SUB_CLASS_PATH GADGET_PATH "bDeviceSubClass"
+#define DEVICE_PROTOCOL_PATH GADGET_PATH "bDeviceProtocol"
+#define DESC_USE_PATH GADGET_PATH "os_desc/use"
+#define OS_DESC_PATH GADGET_PATH "os_desc/b.1"
+#define CONFIG_PATH GADGET_PATH "configs/b.1/"
+#define FUNCTIONS_PATH GADGET_PATH "functions/"
+#define FUNCTION_NAME "function"
+#define FUNCTION_PATH CONFIG_PATH FUNCTION_NAME
+#define RNDIS_PATH FUNCTIONS_PATH "gsi.rndis"
+
+using ::android::base::GetProperty;
+using ::android::base::SetProperty;
+using ::android::base::unique_fd;
+using ::android::base::WriteStringToFile;
+using ::android::hardware::usb::gadget::V1_0::GadgetFunction;
+using ::android::hardware::usb::gadget::V1_0::Status;
+
+using ::std::lock_guard;
+using ::std::move;
+using ::std::mutex;
+using ::std::string;
+using ::std::thread;
+using ::std::unique_ptr;
+using ::std::vector;
+using ::std::chrono::microseconds;
+using ::std::chrono::steady_clock;
+using ::std::literals::chrono_literals::operator""ms;
+
+// MonitorFfs automously manages gadget pullup by monitoring
+// the ep file status. Restarts the usb gadget when the ep
+// owner restarts.
+class MonitorFfs {
+ private:
+ // Monitors the endpoints Inotify events.
+ unique_fd mInotifyFd;
+ // Control pipe for shutting down the mMonitor thread.
+ // mMonitor exits when SHUTDOWN_MONITOR is written into
+ // mEventFd/
+ unique_fd mEventFd;
+ // Pools on mInotifyFd and mEventFd.
+ unique_fd mEpollFd;
+ vector<int> mWatchFd;
+
+ // Maintains the list of Endpoints.
+ vector<string> mEndpointList;
+ // protects the CV.
+ std::mutex mLock;
+ std::condition_variable mCv;
+ // protects mInotifyFd, mEpollFd.
+ std::mutex mLockFd;
+
+ // Flag to maintain the current status of gadget pullup.
+ bool mCurrentUsbFunctionsApplied;
+
+ // Thread object that executes the ep monitoring logic.
+ unique_ptr<thread> mMonitor;
+ // Callback to be invoked when gadget is pulled up.
+ void (*mCallback)(bool functionsApplied, void* payload);
+ void* mPayload;
+ // Name of the USB gadget. Used for pullup.
+ const char* const mGadgetName;
+ // Monitor State
+ bool mMonitorRunning;
+
+ public:
+ MonitorFfs(const char* const gadget);
+ // Inits all the UniqueFds.
+ void reset();
+ // Starts monitoring endpoints and pullup the gadget when
+ // the descriptors are written.
+ bool startMonitor();
+ // Waits for timeout_ms for gadget pull up to happen.
+ // Returns immediately if the gadget is already pulled up.
+ bool waitForPullUp(int timeout_ms);
+ // Adds the given fd to the watch list.
+ bool addInotifyFd(string fd);
+ // Adds the given endpoint to the watch list.
+ void addEndPoint(string ep);
+ // Registers the async callback from the caller to notify the caller
+ // when the gadget pull up happens.
+ void registerFunctionsAppliedCallback(void (*callback)(bool functionsApplied, void*(payload)),
+ void* payload);
+ bool isMonitorRunning();
+ // Ep monitoring and the gadget pull up logic.
+ static void* startMonitorFd(void* param);
+};
+
+//**************** Helper functions ************************//
+
+// Adds the given fd to the epollfd(epfd).
+int addEpollFd(const unique_fd& epfd, const unique_fd& fd);
+// Removes all the usb functions link in the specified path.
+int unlinkFunctions(const char* path);
+// Craetes a configfs link for the function.
+int linkFunction(const char* function, int index);
+// Sets the USB VID and PID.
+Status setVidPid(const char* vid, const char* pid);
+// Extracts vendor functions from the vendor init properties.
+std::string getVendorFunctions();
+// Adds Adb to the usb configuration.
+Status addAdb(MonitorFfs* monitorFfs, int* functionCount);
+// Adds all applicable generic android usb functions other than ADB.
+Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,
+ int* functionCount);
+// Pulls down USB gadget.
+Status resetGadget();
+
+} // namespace gadget
+} // namespace usb
+} // namespace hardware
+} // namespace android
+#endif
diff --git a/usb/gadget/1.1/default/service.cpp b/usb/gadget/1.1/default/service.cpp
new file mode 100644
index 0000000..7414e89
--- /dev/null
+++ b/usb/gadget/1.1/default/service.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.usb.gadget@1.1-service"
+
+#include <hidl/HidlTransportSupport.h>
+#include "UsbGadget.h"
+
+using android::sp;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::usb::gadget::V1_1::IUsbGadget;
+using android::hardware::usb::gadget::V1_1::implementation::UsbGadget;
+
+using android::OK;
+using android::status_t;
+
+int main() {
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+ android::sp<IUsbGadget> service2 = new UsbGadget();
+
+ status_t status = service2->registerAsService();
+
+ if (status != OK) {
+ ALOGE("Cannot register USB Gadget HAL service");
+ return 1;
+ }
+
+ ALOGI("USB Gadget HAL Ready.");
+ joinRpcThreadpool();
+ // Under noraml cases, execution will not reach this line.
+ ALOGI("USB Gadget HAL failed to join thread pool.");
+ return 1;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
index b9a80ec..0fdfa5d 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
@@ -49,4 +49,9 @@
* A haptic effect that simulates quick downwards movement with gravity.
*/
QUICK_FALL,
+ /**
+ * This very short effect should produce a light crisp sensation intended
+ * to be used repetitively for dynamic feedback.
+ */
+ LIGHT_TICK,
}
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index f553664..06a8bf5 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -158,12 +158,31 @@
int getCompositionSizeMax();
/**
+ * List of supported effect primitive.
+ *
+ * Return the effect primitives which are supported by the compose API.
+ * Implementations are expected to support all primitives of the interface
+ * version that they implement.
+ */
+ CompositePrimitive[] getSupportedPrimitives();
+
+ /**
+ * Retrieve effect primitive's duration in milliseconds.
+ *
+ * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS).
+ *
+ * @return Best effort estimation of effect primitive's duration.
+ * @param primitive Effect primitive being queried.
+ */
+ int getPrimitiveDuration(CompositePrimitive primitive);
+
+ /**
* Fire off a string of effect primitives, combined to perform richer effects.
*
* Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS).
*
* Doing this operation while the vibrator is already on is undefined behavior. Clients should
- * explicitly call off.
+ * explicitly call off. IVibratorCallback.onComplete() support is required for this API.
*
* @param composite Array of composition parameters.
*/
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index cedd9cb..0d7131a 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -113,6 +113,26 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* supported) {
+ *supported = {
+ CompositePrimitive::NOOP, CompositePrimitive::CLICK,
+ CompositePrimitive::THUD, CompositePrimitive::SPIN,
+ CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
+ CompositePrimitive::QUICK_FALL, CompositePrimitive::LIGHT_TICK,
+ };
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
+ int32_t* durationMs) {
+ if (primitive != CompositePrimitive::NOOP) {
+ *durationMs = 100;
+ } else {
+ *durationMs = 0;
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite,
const std::shared_ptr<IVibratorCallback>& callback) {
if (composite.size() > kComposeSizeMax) {
@@ -127,7 +147,7 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
if (e.primitive < CompositePrimitive::NOOP ||
- e.primitive > CompositePrimitive::QUICK_FALL) {
+ e.primitive > CompositePrimitive::LIGHT_TICK) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
}
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index 0eb957d..c3f3616 100644
--- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
+++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
@@ -36,6 +36,9 @@
ndk::ScopedAStatus setExternalControl(bool enabled) override;
ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs);
ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize);
+ ndk::ScopedAStatus getSupportedPrimitives(std::vector<CompositePrimitive>* supported) override;
+ ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive,
+ int32_t* durationMs) override;
ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite,
const std::shared_ptr<IVibratorCallback>& callback) override;
ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) override;
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index f197763..411fe7a 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -261,6 +261,29 @@
}
}
+TEST_P(VibratorAidl, GetSupportedPrimitives) {
+ if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+ std::vector<CompositePrimitive> supported;
+
+ EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode());
+
+ std::sort(supported.begin(), supported.end());
+
+ EXPECT_EQ(kCompositePrimitives, supported);
+ }
+}
+
+TEST_P(VibratorAidl, GetPrimitiveDuration) {
+ if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+ int32_t duration;
+
+ for (auto primitive : kCompositePrimitives) {
+ EXPECT_EQ(Status::EX_NONE,
+ vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode());
+ }
+ }
+}
+
TEST_P(VibratorAidl, ComposeValidPrimitives) {
if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
int32_t maxDelay, maxSize;
@@ -357,6 +380,30 @@
}
}
+TEST_P(VibratorAidl, ComposeCallback) {
+ if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+ std::promise<void> completionPromise;
+ std::future<void> completionFuture{completionPromise.get_future()};
+ sp<CompletionCallback> callback =
+ new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ CompositePrimitive primitive = CompositePrimitive::CLICK;
+ CompositeEffect effect;
+ std::vector<CompositeEffect> composite;
+ int32_t duration;
+
+ effect.delayMs = 0;
+ effect.primitive = primitive;
+ effect.scale = 1.0f;
+ composite.emplace_back(effect);
+
+ EXPECT_EQ(Status::EX_NONE,
+ vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode());
+ EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode());
+ EXPECT_EQ(completionFuture.wait_for(std::chrono::milliseconds(duration * 2)),
+ std::future_status::ready);
+ }
+}
+
TEST_P(VibratorAidl, AlwaysOn) {
if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) {
std::vector<Effect> supported;
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index 95bb59c..bf77503 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -39,7 +39,6 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"VtsHalWifiV1_0TargetTest.cpp",
- "wifi_ap_iface_hidl_test.cpp",
"wifi_chip_hidl_test.cpp",
"wifi_p2p_iface_hidl_test.cpp",
"wifi_rtt_controller_hidl_test.cpp",
@@ -53,14 +52,17 @@
"android.hardware.wifi@1.3",
"libwifi-system-iface"
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
+// These tests are split out so that they can be conditioned on presence of the
+// "android.hardware.wifi.aware" feature.
cc_test {
name: "VtsHalWifiNanV1_0TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"VtsHalWifiV1_0TargetTest.cpp",
+ "wifi_chip_hidl_nan_test.cpp",
"wifi_nan_iface_hidl_test.cpp",
],
static_libs: [
@@ -68,5 +70,23 @@
"android.hardware.wifi@1.0",
"libwifi-system-iface"
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
+}
+
+// These tests are split out so that they can be conditioned on presence of
+// the hostapd HAL, which indicates SoftAP support.
+cc_test {
+ name: "VtsHalWifiApV1_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "VtsHalWifiV1_0TargetTest.cpp",
+ "wifi_ap_iface_hidl_test.cpp",
+ "wifi_chip_hidl_ap_test.cpp",
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "android.hardware.wifi@1.0",
+ "libwifi-system-iface"
+ ],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
index e7b8593..128dae5 100644
--- a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
+++ b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
@@ -14,37 +14,8 @@
* limitations under the License.
*/
-#include <android-base/logging.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
-#include "wifi_hidl_test_utils.h"
-
-class WifiVtsHidlEnvironment_1_0 : public WifiHidlEnvironment {
- public:
- // get the test environment singleton
- static WifiVtsHidlEnvironment_1_0* Instance() {
- static WifiVtsHidlEnvironment_1_0* instance =
- new WifiVtsHidlEnvironment_1_0;
- return instance;
- }
-
- virtual void registerTestServices() override {
- registerTestService<android::hardware::wifi::V1_0::IWifi>();
- }
-
- private:
- WifiVtsHidlEnvironment_1_0() {}
-};
-
-WifiHidlEnvironment* gEnv = WifiVtsHidlEnvironment_1_0::Instance();
-
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(gEnv);
- ::testing::InitGoogleTest(&argc, argv);
- gEnv->init(&argc, argv);
- int status = gEnv->initFromOptions(argc, argv);
- if (status == 0) {
- status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- }
- return status;
-}
+// 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/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
index e5762f2..3599b94 100644
--- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -16,39 +16,40 @@
#include <android-base/logging.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/1.0/IWifiApIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#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::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
using ::android::hardware::wifi::V1_0::IWifiApIface;
using ::android::hardware::wifi::V1_0::WifiBand;
using ::android::hardware::wifi::V1_0::WifiStatusCode;
-using ::android::sp;
-
-extern WifiHidlEnvironment* gEnv;
/**
* Fixture to use for all AP Iface HIDL interface tests.
*/
-class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiApIfaceHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- if (!gEnv->isSoftApOn) return;
- wifi_ap_iface_ = getWifiApIface();
+ // Make sure test starts with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_ap_iface_ = getWifiApIface(GetInstanceName());
ASSERT_NE(nullptr, wifi_ap_iface_.get());
}
- virtual void TearDown() override {
- if (!gEnv->isSoftApOn) return;
- stopWifi();
- }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
protected:
sp<IWifiApIface> wifi_ap_iface_;
+ std::string GetInstanceName() { return GetParam(); }
};
/*
@@ -56,18 +57,15 @@
* Ensures that an instance of the IWifiApIface proxy object is
* successfully created.
*/
-TEST(WifiApIfaceHidlTestNoFixture, Create) {
- if (!gEnv->isSoftApOn) return;
- EXPECT_NE(nullptr, getWifiApIface().get());
- stopWifi();
+TEST_P(WifiApIfaceHidlTest, Create) {
+ // The creation of a proxy object is tested as part of SetUp method.
}
/*
* GetType:
* Ensures that the correct interface type is returned for AP interface.
*/
-TEST_F(WifiApIfaceHidlTest, GetType) {
- if (!gEnv->isSoftApOn) return;
+TEST_P(WifiApIfaceHidlTest, GetType) {
const auto& status_and_type = HIDL_INVOKE(wifi_ap_iface_, getType);
EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_type.first.code);
EXPECT_EQ(IfaceType::AP, status_and_type.second);
@@ -78,8 +76,7 @@
* Ensures that a call to set the country code will return with a success
* status code.
*/
-TEST_F(WifiApIfaceHidlTest, SetCountryCode) {
- if (!gEnv->isSoftApOn) return;
+TEST_P(WifiApIfaceHidlTest, SetCountryCode) {
const android::hardware::hidl_array<int8_t, 2> kCountryCode{
std::array<int8_t, 2>{{0x55, 0x53}}};
EXPECT_EQ(WifiStatusCode::SUCCESS,
@@ -90,10 +87,15 @@
* GetValidFrequenciesForBand:
* Ensures that we can retrieve valid frequencies for 2.4 GHz band.
*/
-TEST_F(WifiApIfaceHidlTest, GetValidFrequenciesForBand) {
- if (!gEnv->isSoftApOn) return;
+TEST_P(WifiApIfaceHidlTest, GetValidFrequenciesForBand) {
const auto& status_and_freqs = HIDL_INVOKE(
wifi_ap_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ);
EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code);
EXPECT_GT(status_and_freqs.second.size(), 0u);
}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiApIfaceHidlTest,
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
new file mode 100644
index 0000000..5a2c6a7
--- /dev/null
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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 <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.0/IWifiChip.h>
+#include <gtest/gtest.h>
+#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::ChipModeId;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiApIface;
+using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::V1_0::IWifiIface;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+
+/**
+ * Fixture for IWifiChip tests that are conditioned on SoftAP support.
+ */
+class WifiChipHidlApTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ // Make sure test starts with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_chip_ = getWifiChip(GetInstanceName());
+ ASSERT_NE(nullptr, wifi_chip_.get());
+ }
+
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+ protected:
+ // Helper function to configure the Chip in one of the supported modes.
+ // Most of the non-mode-configuration-related methods require chip
+ // to be first configured.
+ ChipModeId configureChipForIfaceType(IfaceType type, bool expectSuccess) {
+ ChipModeId mode_id;
+ EXPECT_EQ(expectSuccess,
+ configureChipToSupportIfaceType(wifi_chip_, type, &mode_id));
+ return mode_id;
+ }
+
+ std::string getIfaceName(const sp<IWifiIface>& iface) {
+ const auto& status_and_name = HIDL_INVOKE(iface, getName);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_name.first.code);
+ return status_and_name.second;
+ }
+
+ WifiStatusCode createApIface(sp<IWifiApIface>* ap_iface) {
+ const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createApIface);
+ *ap_iface = status_and_iface.second;
+ return status_and_iface.first.code;
+ }
+
+ WifiStatusCode removeApIface(const std::string& name) {
+ return HIDL_INVOKE(wifi_chip_, removeApIface, name).code;
+ }
+
+ sp<IWifiChip> wifi_chip_;
+
+ private:
+ std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * CreateApIface
+ * Configures the chip in AP mode and ensures that at least 1 iface creation
+ * succeeds.
+ */
+TEST_P(WifiChipHidlApTest, CreateApIface) {
+ configureChipForIfaceType(IfaceType::AP, true);
+
+ sp<IWifiApIface> iface;
+ EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
+ EXPECT_NE(nullptr, iface.get());
+}
+
+/*
+ * GetApIfaceNames
+ * Configures the chip in AP mode and ensures that the iface list is empty
+ * before creating the iface. Then, create the iface and ensure that
+ * iface name is returned via the list.
+ */
+TEST_P(WifiChipHidlApTest, GetApIfaceNames) {
+ configureChipForIfaceType(IfaceType::AP, true);
+
+ const auto& status_and_iface_names1 =
+ HIDL_INVOKE(wifi_chip_, getApIfaceNames);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code);
+ EXPECT_EQ(0u, status_and_iface_names1.second.size());
+
+ sp<IWifiApIface> iface;
+ EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
+ EXPECT_NE(nullptr, iface.get());
+
+ std::string iface_name = getIfaceName(iface);
+ const auto& status_and_iface_names2 =
+ HIDL_INVOKE(wifi_chip_, getApIfaceNames);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code);
+ EXPECT_EQ(1u, status_and_iface_names2.second.size());
+ EXPECT_EQ(iface_name, status_and_iface_names2.second[0]);
+
+ EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name));
+ const auto& status_and_iface_names3 =
+ HIDL_INVOKE(wifi_chip_, getApIfaceNames);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code);
+ EXPECT_EQ(0u, status_and_iface_names3.second.size());
+}
+
+/*
+ * GetApIface
+ * Configures the chip in AP mode and create an iface. Then, retrieve
+ * the iface object using the correct name and ensure any other name
+ * doesn't retrieve an iface object.
+ */
+TEST_P(WifiChipHidlApTest, GetApIface) {
+ configureChipForIfaceType(IfaceType::AP, true);
+
+ sp<IWifiApIface> ap_iface;
+ EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface));
+ EXPECT_NE(nullptr, ap_iface.get());
+
+ std::string iface_name = getIfaceName(ap_iface);
+ const auto& status_and_iface1 =
+ HIDL_INVOKE(wifi_chip_, getApIface, iface_name);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code);
+ EXPECT_NE(nullptr, status_and_iface1.second.get());
+
+ std::string invalid_name = iface_name + "0";
+ const auto& status_and_iface2 =
+ HIDL_INVOKE(wifi_chip_, getApIface, invalid_name);
+ EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code);
+ EXPECT_EQ(nullptr, status_and_iface2.second.get());
+}
+
+/*
+ * RemoveApIface
+ * Configures the chip in AP mode and create an iface. Then, remove
+ * the iface object using the correct name and ensure any other name
+ * doesn't remove the iface.
+ */
+TEST_P(WifiChipHidlApTest, RemoveApIface) {
+ configureChipForIfaceType(IfaceType::AP, true);
+
+ sp<IWifiApIface> ap_iface;
+ EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface));
+ EXPECT_NE(nullptr, ap_iface.get());
+
+ std::string iface_name = getIfaceName(ap_iface);
+ std::string invalid_name = iface_name + "0";
+ EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(invalid_name));
+ EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name));
+
+ // No such iface exists now. So, this should return failure.
+ EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(iface_name));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiChipHidlApTest,
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
new file mode 100644
index 0000000..c95f4d2
--- /dev/null
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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 <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.0/IWifiChip.h>
+#include <gtest/gtest.h>
+#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::ChipModeId;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::V1_0::IWifiIface;
+using ::android::hardware::wifi::V1_0::IWifiNanIface;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+
+/**
+ * Fixture for IWifiChip tests that are conditioned on NAN support.
+ */
+class WifiChipHidlNanTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ // Make sure test starts with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_chip_ = getWifiChip(GetInstanceName());
+ ASSERT_NE(nullptr, wifi_chip_.get());
+ }
+
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+ protected:
+ // Helper function to configure the Chip in one of the supported modes.
+ // Most of the non-mode-configuration-related methods require chip
+ // to be first configured.
+ ChipModeId configureChipForIfaceType(IfaceType type, bool expectSuccess) {
+ ChipModeId mode_id;
+ EXPECT_EQ(expectSuccess,
+ configureChipToSupportIfaceType(wifi_chip_, type, &mode_id));
+ return mode_id;
+ }
+
+ std::string getIfaceName(const sp<IWifiIface>& iface) {
+ const auto& status_and_name = HIDL_INVOKE(iface, getName);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_name.first.code);
+ return status_and_name.second;
+ }
+
+ WifiStatusCode createNanIface(sp<IWifiNanIface>* nan_iface) {
+ const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createNanIface);
+ *nan_iface = status_and_iface.second;
+ return status_and_iface.first.code;
+ }
+
+ WifiStatusCode removeNanIface(const std::string& name) {
+ return HIDL_INVOKE(wifi_chip_, removeNanIface, name).code;
+ }
+
+ sp<IWifiChip> wifi_chip_;
+
+ private:
+ std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * CreateNanIface
+ * Configures the chip in NAN mode and ensures that at least 1 iface creation
+ * succeeds.
+ */
+TEST_P(WifiChipHidlNanTest, CreateNanIface) {
+ configureChipForIfaceType(IfaceType::NAN, true);
+
+ sp<IWifiNanIface> iface;
+ ASSERT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
+ EXPECT_NE(nullptr, iface.get());
+}
+
+/*
+ * GetNanIfaceNames
+ * Configures the chip in NAN mode and ensures that the iface list is empty
+ * before creating the iface. Then, create the iface and ensure that
+ * iface name is returned via the list.
+ */
+TEST_P(WifiChipHidlNanTest, GetNanIfaceNames) {
+ configureChipForIfaceType(IfaceType::NAN, true);
+
+ const auto& status_and_iface_names1 =
+ HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code);
+ EXPECT_EQ(0u, status_and_iface_names1.second.size());
+
+ sp<IWifiNanIface> iface;
+ EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
+ EXPECT_NE(nullptr, iface.get());
+
+ std::string iface_name = getIfaceName(iface);
+ const auto& status_and_iface_names2 =
+ HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code);
+ EXPECT_EQ(1u, status_and_iface_names2.second.size());
+ EXPECT_EQ(iface_name, status_and_iface_names2.second[0]);
+
+ EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name));
+ const auto& status_and_iface_names3 =
+ HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code);
+ EXPECT_EQ(0u, status_and_iface_names3.second.size());
+}
+
+/*
+ * GetNanIface
+ * Configures the chip in NAN mode and create an iface. Then, retrieve
+ * the iface object using the correct name and ensure any other name
+ * doesn't retrieve an iface object.
+ */
+TEST_P(WifiChipHidlNanTest, GetNanIface) {
+ configureChipForIfaceType(IfaceType::NAN, true);
+
+ sp<IWifiNanIface> nan_iface;
+ EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface));
+ EXPECT_NE(nullptr, nan_iface.get());
+
+ std::string iface_name = getIfaceName(nan_iface);
+ const auto& status_and_iface1 =
+ HIDL_INVOKE(wifi_chip_, getNanIface, iface_name);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code);
+ EXPECT_NE(nullptr, status_and_iface1.second.get());
+
+ std::string invalid_name = iface_name + "0";
+ const auto& status_and_iface2 =
+ HIDL_INVOKE(wifi_chip_, getNanIface, invalid_name);
+ EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code);
+ EXPECT_EQ(nullptr, status_and_iface2.second.get());
+}
+
+/*
+ * RemoveNanIface
+ * Configures the chip in NAN mode and create an iface. Then, remove
+ * the iface object using the correct name and ensure any other name
+ * doesn't remove the iface.
+ */
+TEST_P(WifiChipHidlNanTest, RemoveNanIface) {
+ configureChipForIfaceType(IfaceType::NAN, true);
+
+ sp<IWifiNanIface> nan_iface;
+ EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface));
+ EXPECT_NE(nullptr, nan_iface.get());
+
+ std::string iface_name = getIfaceName(nan_iface);
+ std::string invalid_name = iface_name + "0";
+ EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(invalid_name));
+
+ EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name));
+
+ // No such iface exists now. So, this should return failure.
+ EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(iface_name));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiChipHidlNanTest,
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+ android::hardware::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 1b7e821..f332001 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
@@ -16,10 +16,12 @@
#include <android-base/logging.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/1.0/IWifiChip.h>
#include <android/hardware/wifi/1.3/IWifiChip.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "wifi_hidl_call_util.h"
#include "wifi_hidl_test_utils.h"
@@ -27,21 +29,20 @@
using ::android::sp;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
-using ::android::hardware::wifi::V1_0::IfaceType;
using ::android::hardware::wifi::V1_0::ChipId;
using ::android::hardware::wifi::V1_0::ChipModeId;
-using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus;
-using ::android::hardware::wifi::V1_0::WifiDebugRingBufferVerboseLevel;
-using ::android::hardware::wifi::V1_0::WifiDebugHostWakeReasonStats;
-using ::android::hardware::wifi::V1_0::WifiStatus;
-using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
using ::android::hardware::wifi::V1_0::IWifiChip;
-using ::android::hardware::wifi::V1_0::IWifiApIface;
using ::android::hardware::wifi::V1_0::IWifiIface;
-using ::android::hardware::wifi::V1_0::IWifiNanIface;
using ::android::hardware::wifi::V1_0::IWifiP2pIface;
using ::android::hardware::wifi::V1_0::IWifiRttController;
using ::android::hardware::wifi::V1_0::IWifiStaIface;
+using ::android::hardware::wifi::V1_0::WifiDebugHostWakeReasonStats;
+using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus;
+using ::android::hardware::wifi::V1_0::WifiDebugRingBufferVerboseLevel;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
extern WifiHidlEnvironment* gEnv;
@@ -64,16 +65,22 @@
} // namespace
/**
- * Fixture to use for all Wifi chip HIDL interface tests.
+ * Fixture for IWifiChip tests.
+ *
+ * Tests that require SoftAP or NAN support should go into WifiChipHidlApTest or
+ * WifiChipHidlNanTest respectively.
*/
-class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- wifi_chip_ = getWifiChip();
+ // Make sure test starts with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_chip_ = getWifiChip(GetInstanceName());
ASSERT_NE(nullptr, wifi_chip_.get());
}
- virtual void TearDown() override { stopWifi(); }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
protected:
// Helper function to configure the Chip in one of the supported modes.
@@ -114,26 +121,6 @@
return status_and_name.second;
}
- WifiStatusCode createApIface(sp<IWifiApIface>* ap_iface) {
- const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createApIface);
- *ap_iface = status_and_iface.second;
- return status_and_iface.first.code;
- }
-
- WifiStatusCode removeApIface(const std::string& name) {
- return HIDL_INVOKE(wifi_chip_, removeApIface, name).code;
- }
-
- WifiStatusCode createNanIface(sp<IWifiNanIface>* nan_iface) {
- const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createNanIface);
- *nan_iface = status_and_iface.second;
- return status_and_iface.first.code;
- }
-
- WifiStatusCode removeNanIface(const std::string& name) {
- return HIDL_INVOKE(wifi_chip_, removeNanIface, name).code;
- }
-
WifiStatusCode createP2pIface(sp<IWifiP2pIface>* p2p_iface) {
const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createP2pIface);
*p2p_iface = status_and_iface.second;
@@ -155,6 +142,9 @@
}
sp<IWifiChip> wifi_chip_;
+
+ protected:
+ std::string GetInstanceName() { return GetParam(); }
};
/*
@@ -162,15 +152,14 @@
* Ensures that an instance of the IWifiChip proxy object is
* successfully created.
*/
-TEST(WifiChipHidlTestNoFixture, Create) {
- EXPECT_NE(nullptr, getWifiChip().get());
- stopWifi();
+TEST_P(WifiChipHidlTest, Create) {
+ // The creation of a proxy object is tested as part of SetUp method.
}
/*
* GetId:
*/
-TEST_F(WifiChipHidlTest, GetId) {
+TEST_P(WifiChipHidlTest, GetId) {
EXPECT_EQ(WifiStatusCode::SUCCESS,
HIDL_INVOKE(wifi_chip_, getId).first.code);
}
@@ -178,7 +167,7 @@
/*
* GetAvailableMode:
*/
-TEST_F(WifiChipHidlTest, GetAvailableModes) {
+TEST_P(WifiChipHidlTest, GetAvailableModes) {
const auto& status_and_modes = HIDL_INVOKE(wifi_chip_, getAvailableModes);
EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_modes.first.code);
EXPECT_LT(0u, status_and_modes.second.size());
@@ -187,17 +176,17 @@
/*
* ConfigureChip:
*/
-TEST_F(WifiChipHidlTest, ConfigureChip) {
+TEST_P(WifiChipHidlTest, ConfigureChip) {
const auto& status_and_modes = HIDL_INVOKE(wifi_chip_, getAvailableModes);
EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_modes.first.code);
EXPECT_LT(0u, status_and_modes.second.size());
for (const auto& mode : status_and_modes.second) {
// configureChip() requires to be called with a fresh IWifiChip object.
- wifi_chip_ = getWifiChip();
+ wifi_chip_ = getWifiChip(GetInstanceName());
ASSERT_NE(nullptr, wifi_chip_.get());
EXPECT_EQ(WifiStatusCode::SUCCESS,
HIDL_INVOKE(wifi_chip_, configureChip, mode.id).code);
- stopWifi();
+ stopWifi(GetInstanceName());
// Sleep for 5 milliseconds between each wifi state toggle.
usleep(5000);
}
@@ -206,7 +195,7 @@
/*
* GetCapabilities:
*/
-TEST_F(WifiChipHidlTest, GetCapabilities) {
+TEST_P(WifiChipHidlTest, GetCapabilities) {
configureChipForIfaceType(IfaceType::STA, true);
const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities);
if (status_and_caps.first.code != WifiStatusCode::SUCCESS) {
@@ -219,7 +208,7 @@
/*
* GetMode:
*/
-TEST_F(WifiChipHidlTest, GetMode) {
+TEST_P(WifiChipHidlTest, GetMode) {
ChipModeId chip_mode_id = configureChipForIfaceType(IfaceType::STA, true);
const auto& status_and_mode = HIDL_INVOKE(wifi_chip_, getMode);
EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mode.first.code);
@@ -229,7 +218,7 @@
/*
* RequestChipDebugInfo:
*/
-TEST_F(WifiChipHidlTest, RequestChipDebugInfo) {
+TEST_P(WifiChipHidlTest, RequestChipDebugInfo) {
configureChipForIfaceType(IfaceType::STA, true);
const auto& status_and_chip_info =
HIDL_INVOKE(wifi_chip_, requestChipDebugInfo);
@@ -241,7 +230,7 @@
/*
* RequestFirmwareDebugDump
*/
-TEST_F(WifiChipHidlTest, RequestFirmwareDebugDump) {
+TEST_P(WifiChipHidlTest, RequestFirmwareDebugDump) {
uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
const auto& status_and_firmware_dump =
HIDL_INVOKE(wifi_chip_, requestFirmwareDebugDump);
@@ -256,7 +245,7 @@
/*
* RequestDriverDebugDump
*/
-TEST_F(WifiChipHidlTest, RequestDriverDebugDump) {
+TEST_P(WifiChipHidlTest, RequestDriverDebugDump) {
uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
const auto& status_and_driver_dump =
HIDL_INVOKE(wifi_chip_, requestDriverDebugDump);
@@ -273,7 +262,7 @@
/*
* GetDebugRingBuffersStatus
*/
-TEST_F(WifiChipHidlTest, GetDebugRingBuffersStatus) {
+TEST_P(WifiChipHidlTest, GetDebugRingBuffersStatus) {
uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
const auto& status_and_ring_buffer_status =
HIDL_INVOKE(wifi_chip_, getDebugRingBuffersStatus);
@@ -292,7 +281,7 @@
/*
* StartLoggingToDebugRingBuffer
*/
-TEST_F(WifiChipHidlTest, StartLoggingToDebugRingBuffer) {
+TEST_P(WifiChipHidlTest, StartLoggingToDebugRingBuffer) {
uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
std::string ring_name;
const auto& status_and_ring_buffer_status =
@@ -320,7 +309,7 @@
/*
* ForceDumpToDebugRingBuffer
*/
-TEST_F(WifiChipHidlTest, ForceDumpToDebugRingBuffer) {
+TEST_P(WifiChipHidlTest, ForceDumpToDebugRingBuffer) {
uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
std::string ring_name;
const auto& status_and_ring_buffer_status =
@@ -346,7 +335,7 @@
/*
* GetDebugHostWakeReasonStats
*/
-TEST_F(WifiChipHidlTest, GetDebugHostWakeReasonStats) {
+TEST_P(WifiChipHidlTest, GetDebugHostWakeReasonStats) {
uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
const auto& status_and_debug_wake_reason =
HIDL_INVOKE(wifi_chip_, getDebugHostWakeReasonStats);
@@ -360,206 +349,11 @@
}
/*
- * CreateApIface
- * Configures the chip in AP mode and ensures that at least 1 iface creation
- * succeeds.
- */
-TEST_F(WifiChipHidlTest, CreateApIface) {
- if (!gEnv->isSoftApOn) return;
- configureChipForIfaceType(IfaceType::AP, true);
-
- sp<IWifiApIface> iface;
- EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
- EXPECT_NE(nullptr, iface.get());
-}
-
-/*
- * GetApIfaceNames
- * Configures the chip in AP mode and ensures that the iface list is empty
- * before creating the iface. Then, create the iface and ensure that
- * iface name is returned via the list.
- */
-TEST_F(WifiChipHidlTest, GetApIfaceNames) {
- if (!gEnv->isSoftApOn) return;
- configureChipForIfaceType(IfaceType::AP, true);
-
- const auto& status_and_iface_names1 =
- HIDL_INVOKE(wifi_chip_, getApIfaceNames);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code);
- EXPECT_EQ(0u, status_and_iface_names1.second.size());
-
- sp<IWifiApIface> iface;
- EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
- EXPECT_NE(nullptr, iface.get());
-
- std::string iface_name = getIfaceName(iface);
- const auto& status_and_iface_names2 =
- HIDL_INVOKE(wifi_chip_, getApIfaceNames);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code);
- EXPECT_EQ(1u, status_and_iface_names2.second.size());
- EXPECT_EQ(iface_name, status_and_iface_names2.second[0]);
-
- EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name));
- const auto& status_and_iface_names3 =
- HIDL_INVOKE(wifi_chip_, getApIfaceNames);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code);
- EXPECT_EQ(0u, status_and_iface_names3.second.size());
-}
-
-/*
- * GetApIface
- * Configures the chip in AP mode and create an iface. Then, retrieve
- * the iface object using the correct name and ensure any other name
- * doesn't retrieve an iface object.
- */
-TEST_F(WifiChipHidlTest, GetApIface) {
- if (!gEnv->isSoftApOn) return;
- configureChipForIfaceType(IfaceType::AP, true);
-
- sp<IWifiApIface> ap_iface;
- EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface));
- EXPECT_NE(nullptr, ap_iface.get());
-
- std::string iface_name = getIfaceName(ap_iface);
- const auto& status_and_iface1 =
- HIDL_INVOKE(wifi_chip_, getApIface, iface_name);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code);
- EXPECT_NE(nullptr, status_and_iface1.second.get());
-
- std::string invalid_name = iface_name + "0";
- const auto& status_and_iface2 =
- HIDL_INVOKE(wifi_chip_, getApIface, invalid_name);
- EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code);
- EXPECT_EQ(nullptr, status_and_iface2.second.get());
-}
-
-/*
- * RemoveApIface
- * Configures the chip in AP mode and create an iface. Then, remove
- * the iface object using the correct name and ensure any other name
- * doesn't remove the iface.
- */
-TEST_F(WifiChipHidlTest, RemoveApIface) {
- if (!gEnv->isSoftApOn) return;
- configureChipForIfaceType(IfaceType::AP, true);
-
- sp<IWifiApIface> ap_iface;
- EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface));
- EXPECT_NE(nullptr, ap_iface.get());
-
- std::string iface_name = getIfaceName(ap_iface);
- std::string invalid_name = iface_name + "0";
- EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(invalid_name));
- EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name));
-
- // No such iface exists now. So, this should return failure.
- EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(iface_name));
-}
-
-/*
- * CreateNanIface
- * Configures the chip in NAN mode and ensures that at least 1 iface creation
- * succeeds.
- */
-TEST_F(WifiChipHidlTest, CreateNanIface) {
- if (!gEnv->isNanOn) return;
- configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn);
-
- sp<IWifiNanIface> iface;
- ASSERT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
- EXPECT_NE(nullptr, iface.get());
-}
-
-/*
- * GetNanIfaceNames
- * Configures the chip in NAN mode and ensures that the iface list is empty
- * before creating the iface. Then, create the iface and ensure that
- * iface name is returned via the list.
- */
-TEST_F(WifiChipHidlTest, GetNanIfaceNames) {
- if (!gEnv->isNanOn) return;
- configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn);
-
- const auto& status_and_iface_names1 =
- HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
- ASSERT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code);
- EXPECT_EQ(0u, status_and_iface_names1.second.size());
-
- sp<IWifiNanIface> iface;
- EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
- EXPECT_NE(nullptr, iface.get());
-
- std::string iface_name = getIfaceName(iface);
- const auto& status_and_iface_names2 =
- HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code);
- EXPECT_EQ(1u, status_and_iface_names2.second.size());
- EXPECT_EQ(iface_name, status_and_iface_names2.second[0]);
-
- EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name));
- const auto& status_and_iface_names3 =
- HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code);
- EXPECT_EQ(0u, status_and_iface_names3.second.size());
-}
-
-/*
- * GetNanIface
- * Configures the chip in NAN mode and create an iface. Then, retrieve
- * the iface object using the correct name and ensure any other name
- * doesn't retrieve an iface object.
- */
-TEST_F(WifiChipHidlTest, GetNanIface) {
- if (!gEnv->isNanOn) return;
- configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn);
-
- sp<IWifiNanIface> nan_iface;
- EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface));
- EXPECT_NE(nullptr, nan_iface.get());
-
- std::string iface_name = getIfaceName(nan_iface);
- const auto& status_and_iface1 =
- HIDL_INVOKE(wifi_chip_, getNanIface, iface_name);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code);
- EXPECT_NE(nullptr, status_and_iface1.second.get());
-
- std::string invalid_name = iface_name + "0";
- const auto& status_and_iface2 =
- HIDL_INVOKE(wifi_chip_, getNanIface, invalid_name);
- EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code);
- EXPECT_EQ(nullptr, status_and_iface2.second.get());
-}
-
-/*
- * RemoveNanIface
- * Configures the chip in NAN mode and create an iface. Then, remove
- * the iface object using the correct name and ensure any other name
- * doesn't remove the iface.
- */
-TEST_F(WifiChipHidlTest, RemoveNanIface) {
- if (!gEnv->isNanOn) return;
- configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn);
-
- sp<IWifiNanIface> nan_iface;
- EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface));
- EXPECT_NE(nullptr, nan_iface.get());
-
- std::string iface_name = getIfaceName(nan_iface);
- std::string invalid_name = iface_name + "0";
- EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(invalid_name));
-
- EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name));
-
- // No such iface exists now. So, this should return failure.
- EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(iface_name));
-}
-
-/*
* CreateP2pIface
* Configures the chip in P2P mode and ensures that at least 1 iface creation
* succeeds.
*/
-TEST_F(WifiChipHidlTest, CreateP2pIface) {
+TEST_P(WifiChipHidlTest, CreateP2pIface) {
configureChipForIfaceType(IfaceType::P2P, true);
sp<IWifiP2pIface> iface;
@@ -573,7 +367,7 @@
* before creating the iface. Then, create the iface and ensure that
* iface name is returned via the list.
*/
-TEST_F(WifiChipHidlTest, GetP2pIfaceNames) {
+TEST_P(WifiChipHidlTest, GetP2pIfaceNames) {
configureChipForIfaceType(IfaceType::P2P, true);
const auto& status_and_iface_names1 =
@@ -605,7 +399,7 @@
* the iface object using the correct name and ensure any other name
* doesn't retrieve an iface object.
*/
-TEST_F(WifiChipHidlTest, GetP2pIface) {
+TEST_P(WifiChipHidlTest, GetP2pIface) {
configureChipForIfaceType(IfaceType::P2P, true);
sp<IWifiP2pIface> p2p_iface;
@@ -631,7 +425,7 @@
* the iface object using the correct name and ensure any other name
* doesn't remove the iface.
*/
-TEST_F(WifiChipHidlTest, RemoveP2pIface) {
+TEST_P(WifiChipHidlTest, RemoveP2pIface) {
configureChipForIfaceType(IfaceType::P2P, true);
sp<IWifiP2pIface> p2p_iface;
@@ -652,7 +446,7 @@
* Configures the chip in STA mode and ensures that at least 1 iface creation
* succeeds.
*/
-TEST_F(WifiChipHidlTest, CreateStaIface) {
+TEST_P(WifiChipHidlTest, CreateStaIface) {
configureChipForIfaceType(IfaceType::STA, true);
sp<IWifiStaIface> iface;
@@ -666,7 +460,7 @@
* before creating the iface. Then, create the iface and ensure that
* iface name is returned via the list.
*/
-TEST_F(WifiChipHidlTest, GetStaIfaceNames) {
+TEST_P(WifiChipHidlTest, GetStaIfaceNames) {
configureChipForIfaceType(IfaceType::STA, true);
const auto& status_and_iface_names1 =
@@ -698,7 +492,7 @@
* the iface object using the correct name and ensure any other name
* doesn't retrieve an iface object.
*/
-TEST_F(WifiChipHidlTest, GetStaIface) {
+TEST_P(WifiChipHidlTest, GetStaIface) {
configureChipForIfaceType(IfaceType::STA, true);
sp<IWifiStaIface> sta_iface;
@@ -724,7 +518,7 @@
* the iface object using the correct name and ensure any other name
* doesn't remove the iface.
*/
-TEST_F(WifiChipHidlTest, RemoveStaIface) {
+TEST_P(WifiChipHidlTest, RemoveStaIface) {
configureChipForIfaceType(IfaceType::STA, true);
sp<IWifiStaIface> sta_iface;
@@ -743,7 +537,7 @@
/*
* CreateRttController
*/
-TEST_F(WifiChipHidlTest, CreateRttController) {
+TEST_P(WifiChipHidlTest, CreateRttController) {
configureChipForIfaceType(IfaceType::STA, true);
sp<IWifiStaIface> iface;
@@ -752,6 +546,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);
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
index b8e501c..f3c82da 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
@@ -18,7 +18,9 @@
#include <android/hardware/wifi/1.0/IWifi.h>
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "wifi_hidl_test_utils.h"
@@ -28,13 +30,17 @@
/**
* Fixture to use for all root Wifi HIDL interface tests.
*/
-class WifiHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiHidlTest : public ::testing::TestWithParam<std::string> {
public:
- virtual void SetUp() override {}
+ virtual void SetUp() override {
+ // Make sure test starts with a clean state
+ stopWifi(GetInstanceName());
+ }
- virtual void TearDown() override { stopWifi(); }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
protected:
+ std::string GetInstanceName() { return GetParam(); }
};
/*
@@ -42,7 +48,12 @@
* Ensures that an instance of the IWifi proxy object is
* successfully created.
*/
-TEST(WifiHidlTestNoFixture, Create) {
- EXPECT_NE(nullptr, getWifi().get());
- stopWifi();
+TEST_P(WifiHidlTest, Create) {
+ // The creation of a proxy object is tested as part of SetUp method.
}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiHidlTest,
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+ 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 529b142..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(
@@ -61,48 +59,4 @@
stopWifi();
sleep(5);
}
-
- public:
- // Whether NaN feature is supported on the device.
- bool isNanOn = false;
- // Whether SoftAp feature is supported on the device.
- bool isSoftApOn = false;
-
- void usage(char* me, char* arg) {
- fprintf(stderr,
- "unrecognized option: %s\n\n"
- "usage: %s <gtest options> <test options>\n\n"
- "test options are:\n\n"
- "-N, --nan_on: Whether NAN feature is supported\n"
- "-S, --softap_on: Whether SOFTAP feature is supported\n",
- arg, me);
- }
-
- int initFromOptions(int argc, char** argv) {
- static struct option options[] = {{"nan_on", no_argument, 0, 'N'},
- {"softap_on", no_argument, 0, 'S'},
- {0, 0, 0, 0}};
-
- int c;
- while ((c = getopt_long(argc, argv, "NS", options, NULL)) >= 0) {
- switch (c) {
- case 'N':
- isNanOn = true;
- break;
- case 'S':
- isSoftApOn = true;
- break;
- default:
- usage(argv[0], argv[optind]);
- return 2;
- }
- }
-
- if (optind < argc) {
- usage(argv[0], argv[optind]);
- return 2;
- }
-
- return 0;
- }
};
diff --git a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
index 64b4fb6..47a1938 100644
--- a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -16,10 +16,12 @@
#include <android-base/logging.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/1.0/IWifiNanIface.h>
#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <chrono>
#include <condition_variable>
#include <mutex>
@@ -29,27 +31,31 @@
using namespace ::android::hardware::wifi::V1_0;
+using ::android::sp;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using ::android::sp;
+using ::android::hardware::wifi::V1_0::IWifi;
#define TIMEOUT_PERIOD 10
/**
* Fixture to use for all NAN Iface HIDL interface tests.
*/
-class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
+class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
virtual void SetUp() override {
- iwifiNanIface = getWifiNanIface();
- ASSERT_NE(nullptr, iwifiNanIface.get());
- ASSERT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(iwifiNanIface, registerEventCallback,
- new WifiNanIfaceEventCallback(*this)).code);
+ // Make sure test starts with a clean state
+ stopWifi(GetInstanceName());
+
+ iwifiNanIface = getWifiNanIface(GetInstanceName());
+ ASSERT_NE(nullptr, iwifiNanIface.get());
+ ASSERT_EQ(WifiStatusCode::SUCCESS,
+ HIDL_INVOKE(iwifiNanIface, registerEventCallback,
+ new WifiNanIfaceEventCallback(*this))
+ .code);
}
- virtual void TearDown() override {
- stopWifi();
- }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
/* Used as a mechanism to inform the test about data/event callback */
inline void notify() {
@@ -438,6 +444,8 @@
NanFollowupReceivedInd nanFollowupReceivedInd;
NanDataPathRequestInd nanDataPathRequestInd;
NanDataPathConfirmInd nanDataPathConfirmInd;
+
+ std::string GetInstanceName() { return GetParam(); }
};
/*
@@ -445,9 +453,8 @@
* Ensures that an instance of the IWifiNanIface proxy object is
* successfully created.
*/
-TEST(WifiNanIfaceHidlTestNoFixture, Create) {
- ASSERT_NE(nullptr, getWifiNanIface().get());
- stopWifi();
+TEST_P(WifiNanIfaceHidlTest, Create) {
+ // The creation of a proxy object is tested as part of SetUp method.
}
/*
@@ -455,41 +462,51 @@
* Ensure that API calls fail with ERROR_WIFI_IFACE_INVALID when using an interface once wifi
* is disabled.
*/
-TEST(WifiNanIfaceHidlTestNoFixture, FailOnIfaceInvalid) {
- android::sp<IWifiNanIface> iwifiNanIface = getWifiNanIface();
- ASSERT_NE(nullptr, iwifiNanIface.get());
- stopWifi();
- sleep(5); // make sure that all chips/interfaces are invalidated
- ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, 0).code);
+TEST_P(WifiNanIfaceHidlTest, FailOnIfaceInvalid) {
+ stopWifi(GetInstanceName());
+ android::sp<IWifiNanIface> iwifiNanIface =
+ getWifiNanIface(GetInstanceName());
+ ASSERT_NE(nullptr, iwifiNanIface.get());
+ stopWifi(GetInstanceName());
+ sleep(5); // make sure that all chips/interfaces are invalidated
+ ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, 0).code);
}
/*
* getCapabilitiesRequest: validate that returns capabilities.
*/
-TEST_F(WifiNanIfaceHidlTest, getCapabilitiesRequest) {
- uint16_t inputCmdId = 10;
- callbackType = INVALID;
- ASSERT_EQ(WifiStatusCode::SUCCESS,
+TEST_P(WifiNanIfaceHidlTest, getCapabilitiesRequest) {
+ uint16_t inputCmdId = 10;
+ callbackType = INVALID;
+ ASSERT_EQ(
+ WifiStatusCode::SUCCESS,
HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, inputCmdId).code);
- // wait for a callback
- ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
- ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callbackType);
- ASSERT_EQ(id, inputCmdId);
+ // wait for a callback
+ ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
+ ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callbackType);
+ ASSERT_EQ(id, inputCmdId);
- // check for reasonable capability values
- EXPECT_GT(capabilities.maxConcurrentClusters, (unsigned int) 0);
- EXPECT_GT(capabilities.maxPublishes, (unsigned int) 0);
- EXPECT_GT(capabilities.maxSubscribes, (unsigned int) 0);
- EXPECT_EQ(capabilities.maxServiceNameLen, (unsigned int) 255);
- EXPECT_EQ(capabilities.maxMatchFilterLen, (unsigned int) 255);
- EXPECT_GT(capabilities.maxTotalMatchFilterLen, (unsigned int) 255);
- EXPECT_EQ(capabilities.maxServiceSpecificInfoLen, (unsigned int) 255);
- EXPECT_GE(capabilities.maxExtendedServiceSpecificInfoLen, (unsigned int) 255);
- EXPECT_GT(capabilities.maxNdiInterfaces, (unsigned int) 0);
- EXPECT_GT(capabilities.maxNdpSessions, (unsigned int) 0);
- EXPECT_GT(capabilities.maxAppInfoLen, (unsigned int) 0);
- EXPECT_GT(capabilities.maxQueuedTransmitFollowupMsgs, (unsigned int) 0);
- EXPECT_GT(capabilities.maxSubscribeInterfaceAddresses, (unsigned int) 0);
- EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int) 0);
+ // check for reasonable capability values
+ EXPECT_GT(capabilities.maxConcurrentClusters, (unsigned int)0);
+ EXPECT_GT(capabilities.maxPublishes, (unsigned int)0);
+ EXPECT_GT(capabilities.maxSubscribes, (unsigned int)0);
+ EXPECT_EQ(capabilities.maxServiceNameLen, (unsigned int)255);
+ EXPECT_EQ(capabilities.maxMatchFilterLen, (unsigned int)255);
+ EXPECT_GT(capabilities.maxTotalMatchFilterLen, (unsigned int)255);
+ EXPECT_EQ(capabilities.maxServiceSpecificInfoLen, (unsigned int)255);
+ EXPECT_GE(capabilities.maxExtendedServiceSpecificInfoLen,
+ (unsigned int)255);
+ EXPECT_GT(capabilities.maxNdiInterfaces, (unsigned int)0);
+ EXPECT_GT(capabilities.maxNdpSessions, (unsigned int)0);
+ EXPECT_GT(capabilities.maxAppInfoLen, (unsigned int)0);
+ EXPECT_GT(capabilities.maxQueuedTransmitFollowupMsgs, (unsigned int)0);
+ EXPECT_GT(capabilities.maxSubscribeInterfaceAddresses, (unsigned int)0);
+ EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int)0);
}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiNanIfaceHidlTest,
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
index 269eb6c..fd175f5 100644
--- a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
@@ -16,25 +16,32 @@
#include <android-base/logging.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/1.0/IWifiP2pIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "wifi_hidl_test_utils.h"
-using ::android::hardware::wifi::V1_0::IWifiP2pIface;
using ::android::sp;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiP2pIface;
/**
* Fixture to use for all P2P Iface HIDL interface tests.
*/
-class WifiP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiP2pIfaceHidlTest : public ::testing::TestWithParam<std::string> {
public:
- virtual void SetUp() override {}
+ virtual void SetUp() override {
+ // Make sure test starts with a clean state
+ stopWifi(GetInstanceName());
+ }
- virtual void TearDown() override { stopWifi(); }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
protected:
+ std::string GetInstanceName() { return GetParam(); }
};
/*
@@ -42,7 +49,13 @@
* Ensures that an instance of the IWifiP2pIface proxy object is
* successfully created.
*/
-TEST(WifiP2pIfaceHidlTestNoFixture, Create) {
- EXPECT_NE(nullptr, getWifiP2pIface().get());
- stopWifi();
+TEST_P(WifiP2pIfaceHidlTest, Create) {
+ stopWifi(GetInstanceName());
+ EXPECT_NE(nullptr, getWifiP2pIface(GetInstanceName()).get());
}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiP2pIfaceHidlTest,
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
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 e13086d..1eb9c99 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
@@ -16,25 +16,36 @@
#include <android-base/logging.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/1.0/IWifiRttController.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
-#include <VtsHalHidlTargetTestBase.h>
-
+#include "wifi_hidl_call_util.h"
#include "wifi_hidl_test_utils.h"
-using ::android::hardware::wifi::V1_0::IWifiRttController;
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.
*/
-class WifiRttControllerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiRttControllerHidlTest : public ::testing::TestWithParam<std::string> {
public:
- virtual void SetUp() override {}
+ virtual void SetUp() override {
+ // Make sure test starts with a clean state
+ stopWifi(GetInstanceName());
+ }
- virtual void TearDown() override { stopWifi(); }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
protected:
+ std::string GetInstanceName() { return GetParam(); }
};
/*
@@ -42,7 +53,28 @@
* Ensures that an instance of the IWifiRttController proxy object is
* successfully created.
*/
-TEST(WifiRttControllerHidlTestNoFixture, Create) {
- EXPECT_NE(nullptr, getWifiRttController().get());
- stopWifi();
+TEST_P(WifiRttControllerHidlTest, Create) {
+ stopWifi(GetInstanceName());
+
+ 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);
diff --git a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
index a413863..7db0526 100644
--- a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -16,10 +16,12 @@
#include <android-base/logging.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/1.0/IWifiStaIface.h>
#include <android/hardware/wifi/1.3/IWifiStaIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "wifi_hidl_call_util.h"
#include "wifi_hidl_test_utils.h"
@@ -28,6 +30,7 @@
using ::android::hardware::wifi::V1_0::Bssid;
using ::android::hardware::wifi::V1_0::CommandId;
using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
using ::android::hardware::wifi::V1_0::IWifiStaIface;
using ::android::hardware::wifi::V1_0::Rssi;
using ::android::hardware::wifi::V1_0::Ssid;
@@ -41,14 +44,17 @@
/**
* Fixture to use for all STA Iface HIDL interface tests.
*/
-class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- wifi_sta_iface_ = getWifiStaIface();
+ // Make sure test starts with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_sta_iface_ = getWifiStaIface(GetInstanceName());
ASSERT_NE(nullptr, wifi_sta_iface_.get());
}
- virtual void TearDown() override { stopWifi(); }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
protected:
bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) {
@@ -59,6 +65,7 @@
}
sp<IWifiStaIface> wifi_sta_iface_;
+ std::string GetInstanceName() { return GetParam(); }
};
/*
@@ -66,15 +73,14 @@
* Ensures that an instance of the IWifiStaIface proxy object is
* successfully created.
*/
-TEST(WifiStaIfaceHidlTestNoFixture, Create) {
- EXPECT_NE(nullptr, getWifiStaIface().get());
- stopWifi();
+TEST_P(WifiStaIfaceHidlTest, Create) {
+ // The creation of a proxy object is tested as part of SetUp method.
}
/*
* GetCapabilities:
*/
-TEST_F(WifiStaIfaceHidlTest, GetCapabilities) {
+TEST_P(WifiStaIfaceHidlTest, GetCapabilities) {
const auto& status_and_caps = HIDL_INVOKE(wifi_sta_iface_, getCapabilities);
EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
EXPECT_GT(status_and_caps.second, 0u);
@@ -84,7 +90,7 @@
* GetType:
* Ensures that the correct interface type is returned for station interface.
*/
-TEST_F(WifiStaIfaceHidlTest, GetType) {
+TEST_P(WifiStaIfaceHidlTest, GetType) {
const auto& status_and_type = HIDL_INVOKE(wifi_sta_iface_, getType);
EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_type.first.code);
EXPECT_EQ(IfaceType::STA, status_and_type.second);
@@ -94,7 +100,7 @@
* GetApfPacketFilterCapabilities:
* Ensures that we can retrieve APF packet filter capabilites.
*/
-TEST_F(WifiStaIfaceHidlTest, GetApfPacketFilterCapabilities) {
+TEST_P(WifiStaIfaceHidlTest, GetApfPacketFilterCapabilities) {
if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::APF)) {
// No-op if APF packet filer is not supported.
return;
@@ -109,7 +115,7 @@
* GetBackgroundScanCapabilities:
* Ensures that we can retrieve background scan capabilities.
*/
-TEST_F(WifiStaIfaceHidlTest, GetBackgroundScanCapabilities) {
+TEST_P(WifiStaIfaceHidlTest, GetBackgroundScanCapabilities) {
if (!isCapabilitySupported(
IWifiStaIface::StaIfaceCapabilityMask::BACKGROUND_SCAN)) {
// No-op if background scan is not supported.
@@ -125,7 +131,7 @@
* GetValidFrequenciesForBand:
* Ensures that we can retrieve valid frequencies for 2.4 GHz band.
*/
-TEST_F(WifiStaIfaceHidlTest, GetValidFrequenciesForBand) {
+TEST_P(WifiStaIfaceHidlTest, GetValidFrequenciesForBand) {
const auto& status_and_freqs = HIDL_INVOKE(
wifi_sta_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ);
EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code);
@@ -137,7 +143,7 @@
* Ensures that calls to enable, disable, and retrieve link layer stats
* will return a success status code.
*/
-TEST_F(WifiStaIfaceHidlTest, LinkLayerStatsCollection) {
+TEST_P(WifiStaIfaceHidlTest, LinkLayerStatsCollection) {
if (!isCapabilitySupported(
IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) {
// No-op if link layer stats is not supported.
@@ -172,7 +178,7 @@
* Ensures that calls to disable RSSI monitoring will return an error status
* code if RSSI monitoring is not enabled.
*/
-TEST_F(WifiStaIfaceHidlTest, RSSIMonitoring) {
+TEST_P(WifiStaIfaceHidlTest, RSSIMonitoring) {
if (!isCapabilitySupported(
IWifiStaIface::StaIfaceCapabilityMask::RSSI_MONITOR)) {
// No-op if RSSI monitor is not supported.
@@ -197,7 +203,7 @@
* Ensures that calls to configure and enable roaming will return a success
* status code.
*/
-TEST_F(WifiStaIfaceHidlTest, RoamingControl) {
+TEST_P(WifiStaIfaceHidlTest, RoamingControl) {
if (!isCapabilitySupported(
IWifiStaIface::StaIfaceCapabilityMask::CONTROL_ROAMING)) {
// No-op if roaming control is not supported.
@@ -242,9 +248,9 @@
* Ensures that calls to enable neighbor discovery offload will return a success
* status code.
*/
-TEST_F(WifiStaIfaceHidlTest, EnableNDOffload) {
- if (!isCapabilitySupported(
- IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD)) {
+TEST_P(WifiStaIfaceHidlTest, EnableNDOffload) {
+ if (!isCapabilitySupported(
+ IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD)) {
// No-op if nd offload is not supported.
return;
}
@@ -257,7 +263,7 @@
* Ensures that calls to set scanning MAC OUI will return a success status
* code.
*/
-TEST_F(WifiStaIfaceHidlTest, SetScanningMacOui) {
+TEST_P(WifiStaIfaceHidlTest, SetScanningMacOui) {
if (!isCapabilitySupported(
IWifiStaIface::StaIfaceCapabilityMask::SCAN_RAND)) {
// No-op if SetScanningMacOui is not supported.
@@ -274,9 +280,9 @@
* Ensures that calls to start packet fate monitoring and retrieve TX/RX
* packets will return a success status code.
*/
-TEST_F(WifiStaIfaceHidlTest, PacketFateMonitoring) {
- if (!isCapabilitySupported(
- IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE)) {
+TEST_P(WifiStaIfaceHidlTest, PacketFateMonitoring) {
+ if (!isCapabilitySupported(
+ IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE)) {
// No-op if packet fate monitor is not supported.
return;
}
@@ -291,3 +297,9 @@
EXPECT_EQ(WifiStatusCode::SUCCESS,
HIDL_INVOKE(wifi_sta_iface_, getDebugRxPacketFates).first.code);
}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiStaIfaceHidlTest,
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp
index 6d7635d..775031e 100644
--- a/wifi/1.1/vts/functional/Android.bp
+++ b/wifi/1.1/vts/functional/Android.bp
@@ -28,5 +28,5 @@
"android.hardware.wifi@1.3",
"libwifi-system-iface"
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
index a0f97f8..4b62b15 100644
--- a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
+++ b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
@@ -14,37 +14,8 @@
* limitations under the License.
*/
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.1/IWifi.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
-#include "wifi_hidl_test_utils.h"
-
-class WifiHidlEnvironment_1_1 : public WifiHidlEnvironment {
- public:
- // get the test environment singleton
- static WifiHidlEnvironment_1_1* Instance() {
- static WifiHidlEnvironment_1_1* instance = new WifiHidlEnvironment_1_1;
- return instance;
- }
-
- virtual void registerTestServices() override {
- registerTestService<android::hardware::wifi::V1_1::IWifi>();
- }
-
- private:
- WifiHidlEnvironment_1_1() {}
-};
-
-WifiHidlEnvironment* gEnv = WifiHidlEnvironment_1_1::Instance();
-
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(gEnv);
- ::testing::InitGoogleTest(&argc, argv);
- gEnv->init(&argc, argv);
- int status = gEnv->initFromOptions(argc, argv);
- if (status == 0) {
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- }
- return status;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr;
diff --git a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
index 6323547..4b94acb 100644
--- a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
@@ -19,8 +19,9 @@
#include <android/hardware/wifi/1.1/IWifi.h>
#include <android/hardware/wifi/1.1/IWifiChip.h>
#include <android/hardware/wifi/1.3/IWifiChip.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "wifi_hidl_call_util.h"
#include "wifi_hidl_test_utils.h"
@@ -45,14 +46,17 @@
/**
* Fixture to use for all Wifi chip HIDL interface tests.
*/
-class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- wifi_chip_ = IWifiChip::castFrom(getWifiChip());
+ // Make sure to start with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
ASSERT_NE(nullptr, wifi_chip_.get());
}
- virtual void TearDown() override { stopWifi(); }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
protected:
uint32_t configureChipForStaIfaceAndGetCapabilities() {
@@ -77,12 +81,15 @@
}
sp<IWifiChip> wifi_chip_;
+
+ private:
+ std::string GetInstanceName() { return GetParam(); }
};
/*
* SelectTxPowerScenario
*/
-TEST_F(WifiChipHidlTest, SelectTxPowerScenario) {
+TEST_P(WifiChipHidlTest, SelectTxPowerScenario) {
uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
const auto& status =
HIDL_INVOKE(wifi_chip_, selectTxPowerScenario, kFakePowerScenario);
@@ -96,7 +103,7 @@
/*
* ResetTxPowerScenario
*/
-TEST_F(WifiChipHidlTest, ResetTxPowerScenario) {
+TEST_P(WifiChipHidlTest, ResetTxPowerScenario) {
uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
const auto& status =
HIDL_INVOKE(wifi_chip_, resetTxPowerScenario);
@@ -106,3 +113,9 @@
EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code);
}
}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiChipHidlTest,
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp
index 97853d0..f43e49e 100644
--- a/wifi/1.2/vts/functional/Android.bp
+++ b/wifi/1.2/vts/functional/Android.bp
@@ -30,7 +30,8 @@
"android.hardware.wifi@1.3",
"libwifi-system-iface"
],
- test_suites: ["general-tests"],
+ disable_framework: true,
+ test_suites: ["general-tests", "vts-core"],
}
cc_test {
@@ -47,5 +48,6 @@
"android.hardware.wifi@1.2",
"libwifi-system-iface"
],
- test_suites: ["general-tests"],
+ disable_framework: true,
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp b/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp
index c765cdc..52c7a4a 100644
--- a/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp
+++ b/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp
@@ -14,35 +14,8 @@
* limitations under the License.
*/
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.2/IWifi.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
-#include "wifi_hidl_test_utils.h"
-
-using ::android::hardware::wifi::V1_2::IWifi;
-
-// Test environment for Wifi HIDL HAL.
-class WifiHidlEnvironment_1_2 : public WifiHidlEnvironment {
- public:
- // get the test environment singleton
- static WifiHidlEnvironment_1_2* Instance() {
- static WifiHidlEnvironment_1_2* instance = new WifiHidlEnvironment_1_2;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IWifi>(); }
-
- private:
- WifiHidlEnvironment_1_2() {}
-};
-
-WifiHidlEnvironment_1_2* gEnv = WifiHidlEnvironment_1_2::Instance();
-
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(gEnv);
- ::testing::InitGoogleTest(&argc, argv);
- gEnv->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+// 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/1.2/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
index 9d567fe..b04acad 100644
--- a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
@@ -16,12 +16,14 @@
#include <android-base/logging.h>
+#include <android/hardware/wifi/1.2/IWifi.h>
#include <android/hardware/wifi/1.2/IWifiChip.h>
#include <android/hardware/wifi/1.2/IWifiChipEventCallback.h>
#include <android/hardware/wifi/1.3/IWifiChip.h>
-
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
#include "wifi_hidl_call_util.h"
#include "wifi_hidl_test_utils.h"
@@ -50,14 +52,17 @@
/**
* Fixture to use for all Wifi chip HIDL interface tests.
*/
-class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- wifi_chip_ = IWifiChip::castFrom(getWifiChip());
- ASSERT_NE(nullptr, wifi_chip_.get());
+ // Make sure test starts with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
+ ASSERT_NE(nullptr, wifi_chip_.get());
}
- virtual void TearDown() override { stopWifi(); }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
// A simple test implementation of WifiChipEventCallback.
class WifiChipEventCallback
@@ -123,6 +128,9 @@
}
sp<IWifiChip> wifi_chip_;
+
+ private:
+ std::string GetInstanceName() { return GetParam(); }
};
/*
@@ -130,7 +138,7 @@
* This test case tests the selectTxPowerScenario_1_2() API with SAR scenarios
* newly defined in 1.2
*/
-TEST_F(WifiChipHidlTest, SelectTxPowerScenario_1_2_body) {
+TEST_P(WifiChipHidlTest, SelectTxPowerScenario_1_2_body) {
uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
const auto& status =
HIDL_INVOKE(wifi_chip_, selectTxPowerScenario_1_2, kPowerScenarioBody);
@@ -147,7 +155,7 @@
* This test case tests the selectTxPowerScenario_1_2() API with previously
* defined SAR scenarios
*/
-TEST_F(WifiChipHidlTest, SelectTxPowerScenario_1_2_voiceCall) {
+TEST_P(WifiChipHidlTest, SelectTxPowerScenario_1_2_voiceCall) {
uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
const auto& status =
HIDL_INVOKE(wifi_chip_, selectTxPowerScenario_1_2, kPowerScenarioVoiceCall);
@@ -167,9 +175,19 @@
* since event is triggered internally in the HAL implementation, and can not be
* triggered from the test case
*/
-TEST_F(WifiChipHidlTest, registerEventCallback_1_2) {
+TEST_P(WifiChipHidlTest, registerEventCallback_1_2) {
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);
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 4dbc82b..6e55664 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
@@ -16,10 +16,12 @@
#include <android-base/logging.h>
+#include <android/hardware/wifi/1.2/IWifi.h>
#include <android/hardware/wifi/1.2/IWifiNanIface.h>
#include <android/hardware/wifi/1.2/IWifiNanIfaceEventCallback.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <chrono>
#include <condition_variable>
#include <mutex>
@@ -36,19 +38,22 @@
#define TIMEOUT_PERIOD 10
-android::sp<android::hardware::wifi::V1_2::IWifiNanIface>
-getWifiNanIface_1_2() {
+android::sp<android::hardware::wifi::V1_2::IWifiNanIface> getWifiNanIface_1_2(
+ const std::string& instance_name) {
return android::hardware::wifi::V1_2::IWifiNanIface::castFrom(
- getWifiNanIface());
+ getWifiNanIface(instance_name));
}
/**
* Fixture to use for all NAN Iface HIDL interface tests.
*/
-class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- iwifiNanIface = getWifiNanIface_1_2();
+ // Make sure to start with a clean state
+ stopWifi(GetInstanceName());
+
+ iwifiNanIface = getWifiNanIface_1_2(GetInstanceName());
ASSERT_NE(nullptr, iwifiNanIface.get());
ASSERT_EQ(WifiStatusCode::SUCCESS,
HIDL_INVOKE(iwifiNanIface, registerEventCallback_1_2,
@@ -56,7 +61,7 @@
.code);
}
- virtual void TearDown() override { stopWifi(); }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
/* Used as a mechanism to inform the test about data/event callback */
inline void notify() {
@@ -458,6 +463,8 @@
::android::hardware::wifi::V1_2::NanDataPathConfirmInd
nanDataPathConfirmInd_1_2;
NanDataPathScheduleUpdateInd nanDataPathScheduleUpdateInd;
+
+ std::string GetInstanceName() { return GetParam(); }
};
/*
@@ -465,76 +472,92 @@
* Ensures that an instance of the IWifiNanIface proxy object is
* successfully created.
*/
-TEST(WifiNanIfaceHidlTestNoFixture, Create) {
- ASSERT_NE(nullptr, getWifiNanIface_1_2().get());
- stopWifi();
+TEST_P(WifiNanIfaceHidlTest, Create) {
+ // The creation of a proxy object is tested as part of SetUp method.
}
/*
* enableRequest_1_2InvalidArgs: validate that fails with invalid arguments
*/
-TEST_F(WifiNanIfaceHidlTest, enableRequest_1_2InvalidArgs) {
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_2InvalidArgs) {
uint16_t inputCmdId = 10;
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);
+ }
}
/*
* enableRequest_1_2ShimInvalidArgs: validate that fails with invalid arguments
* to the shim
*/
-TEST_F(WifiNanIfaceHidlTest, enableRequest_1_2ShimInvalidArgs) {
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_2ShimInvalidArgs) {
uint16_t inputCmdId = 10;
NanEnableRequest nanEnableRequest = {};
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);
+ }
}
/*
* configRequest_1_2InvalidArgs: validate that fails with invalid arguments
*/
-TEST_F(WifiNanIfaceHidlTest, configRequest_1_2InvalidArgs) {
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_2InvalidArgs) {
uint16_t inputCmdId = 10;
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);
+ }
}
/*
* configRequest_1_2ShimInvalidArgs: validate that fails with invalid arguments
* to the shim
*/
-TEST_F(WifiNanIfaceHidlTest, configRequest_1_2ShimInvalidArgs) {
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_2ShimInvalidArgs) {
uint16_t inputCmdId = 10;
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);
diff --git a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
index 92f5d14..066dcaa 100644
--- a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -19,9 +19,11 @@
#include <android-base/logging.h>
+#include <android/hardware/wifi/1.2/IWifi.h>
#include <android/hardware/wifi/1.2/IWifiStaIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "wifi_hidl_call_util.h"
#include "wifi_hidl_test_utils.h"
@@ -34,14 +36,18 @@
/**
* Fixture to use for all STA Iface HIDL interface tests.
*/
-class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface());
+ // Make sure to start with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_sta_iface_ =
+ IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName()));
ASSERT_NE(nullptr, wifi_sta_iface_.get());
}
- virtual void TearDown() override { stopWifi(); }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
protected:
bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) {
@@ -52,6 +58,9 @@
}
sp<IWifiStaIface> wifi_sta_iface_;
+
+ private:
+ std::string GetInstanceName() { return GetParam(); }
};
/*
@@ -59,7 +68,7 @@
* Ensures that calls to set MAC address will return a success status
* code.
*/
-TEST_F(WifiStaIfaceHidlTest, SetMacAddress) {
+TEST_P(WifiStaIfaceHidlTest, SetMacAddress) {
const android::hardware::hidl_array<uint8_t, 6> kMac{
std::array<uint8_t, 6>{{0x12, 0x22, 0x33, 0x52, 0x10, 0x41}}};
EXPECT_EQ(WifiStatusCode::SUCCESS,
@@ -76,7 +85,7 @@
* TODO: We can't execute APF opcodes from this test because there's no way
* to loop test packets through the wifi firmware (b/73804303#comment29).
*/
-TEST_F(WifiStaIfaceHidlTest, DISABLED_ReadApfPacketFilterData) {
+TEST_P(WifiStaIfaceHidlTest, DISABLED_ReadApfPacketFilterData) {
if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::APF)) {
// Disable test if APF packet filer is not supported.
LOG(WARNING) << "TEST SKIPPED: APF packet filtering not supported";
@@ -107,3 +116,9 @@
EXPECT_EQ(status_and_data.second, data);
}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiStaIfaceHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ ::android::hardware::wifi::V1_2::IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.3/default/Android.mk b/wifi/1.3/default/Android.mk
deleted file mode 100644
index 29f1c42..0000000
--- a/wifi/1.3/default/Android.mk
+++ /dev/null
@@ -1,169 +0,0 @@
-# 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.
-LOCAL_PATH := $(call my-dir)
-
-###
-### android.hardware.wifi static library
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service-lib
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-ifdef WIFI_HAL_INTERFACE_COMBINATIONS
-LOCAL_CPPFLAGS += -DWIFI_HAL_INTERFACE_COMBINATIONS="$(WIFI_HAL_INTERFACE_COMBINATIONS)"
-endif
-ifdef WIFI_HIDL_FEATURE_AWARE
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_AWARE
-endif
-ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DUAL_INTERFACE
-endif
-ifdef WIFI_HIDL_FEATURE_DISABLE_AP
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP
-endif
-ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-endif
-# Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
-LOCAL_CFLAGS += -Wno-error=implicit-fallthrough
-LOCAL_SRC_FILES := \
- hidl_struct_util.cpp \
- hidl_sync_util.cpp \
- ringbuffer.cpp \
- wifi.cpp \
- wifi_ap_iface.cpp \
- wifi_chip.cpp \
- wifi_feature_flags.cpp \
- wifi_iface_util.cpp \
- wifi_legacy_hal.cpp \
- wifi_legacy_hal_stubs.cpp \
- wifi_mode_controller.cpp \
- wifi_nan_iface.cpp \
- wifi_p2p_iface.cpp \
- wifi_rtt_controller.cpp \
- wifi_sta_iface.cpp \
- wifi_status_util.cpp
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- libcutils \
- libhidlbase \
- liblog \
- libnl \
- libutils \
- libwifi-hal \
- libwifi-system-iface \
- android.hardware.wifi@1.0 \
- android.hardware.wifi@1.1 \
- android.hardware.wifi@1.2 \
- android.hardware.wifi@1.3
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-include $(BUILD_STATIC_LIBRARY)
-
-###
-### android.hardware.wifi daemon
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-LOCAL_SRC_FILES := \
- service.cpp
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- libcutils \
- libhidlbase \
- liblog \
- libnl \
- libutils \
- libwifi-hal \
- libwifi-system-iface \
- android.hardware.wifi@1.0 \
- android.hardware.wifi@1.1 \
- android.hardware.wifi@1.2 \
- android.hardware.wifi@1.3
-LOCAL_STATIC_LIBRARIES := \
- android.hardware.wifi@1.0-service-lib
-LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
-include $(BUILD_EXECUTABLE)
-
-###
-### android.hardware.wifi daemon
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service-lazy
-LOCAL_OVERRIDES_MODULES := android.hardware.wifi@1.0-service
-LOCAL_CFLAGS := -DLAZY_SERVICE
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-LOCAL_SRC_FILES := \
- service.cpp
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- libcutils \
- libhidlbase \
- liblog \
- libnl \
- libutils \
- libwifi-hal \
- libwifi-system-iface \
- android.hardware.wifi@1.0 \
- android.hardware.wifi@1.1 \
- android.hardware.wifi@1.2 \
- android.hardware.wifi@1.3
-LOCAL_STATIC_LIBRARIES := \
- android.hardware.wifi@1.0-service-lib
-LOCAL_INIT_RC := android.hardware.wifi@1.0-service-lazy.rc
-include $(BUILD_EXECUTABLE)
-
-###
-### android.hardware.wifi unit tests.
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service-tests
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-LOCAL_SRC_FILES := \
- tests/hidl_struct_util_unit_tests.cpp \
- tests/main.cpp \
- tests/mock_interface_tool.cpp \
- tests/mock_wifi_feature_flags.cpp \
- tests/mock_wifi_iface_util.cpp \
- tests/mock_wifi_legacy_hal.cpp \
- tests/mock_wifi_mode_controller.cpp \
- tests/ringbuffer_unit_tests.cpp \
- tests/wifi_ap_iface_unit_tests.cpp \
- tests/wifi_nan_iface_unit_tests.cpp \
- tests/wifi_chip_unit_tests.cpp \
- tests/wifi_iface_util_unit_tests.cpp
-LOCAL_STATIC_LIBRARIES := \
- libgmock \
- libgtest \
- android.hardware.wifi@1.0-service-lib
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- libcutils \
- libhidlbase \
- liblog \
- libnl \
- libutils \
- libwifi-hal \
- libwifi-system-iface \
- android.hardware.wifi@1.0 \
- android.hardware.wifi@1.1 \
- android.hardware.wifi@1.2 \
- android.hardware.wifi@1.3
-include $(BUILD_NATIVE_TEST)
diff --git a/wifi/1.3/default/hidl_callback_util.h b/wifi/1.3/default/hidl_callback_util.h
deleted file mode 100644
index a44af79..0000000
--- a/wifi/1.3/default/hidl_callback_util.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HIDL_CALLBACK_UTIL_H_
-#define HIDL_CALLBACK_UTIL_H_
-
-#include <set>
-
-#include <hidl/HidlSupport.h>
-
-namespace {
-// Type of callback invoked by the death handler.
-using on_death_cb_function = std::function<void(uint64_t)>;
-
-// Private class used to keep track of death of individual
-// callbacks stored in HidlCallbackHandler.
-template <typename CallbackType>
-class HidlDeathHandler : public android::hardware::hidl_death_recipient {
- public:
- HidlDeathHandler(const on_death_cb_function& user_cb_function)
- : cb_function_(user_cb_function) {}
- ~HidlDeathHandler() = default;
-
- // Death notification for callbacks.
- void serviceDied(
- uint64_t cookie,
- const android::wp<android::hidl::base::V1_0::IBase>& /* who */)
- override {
- cb_function_(cookie);
- }
-
- private:
- on_death_cb_function cb_function_;
-
- DISALLOW_COPY_AND_ASSIGN(HidlDeathHandler);
-};
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace hidl_callback_util {
-template <typename CallbackType>
-// Provides a class to manage callbacks for the various HIDL interfaces and
-// handle the death of the process hosting each callback.
-class HidlCallbackHandler {
- public:
- HidlCallbackHandler()
- : death_handler_(new HidlDeathHandler<CallbackType>(
- std::bind(&HidlCallbackHandler::onObjectDeath, this,
- std::placeholders::_1))) {}
- ~HidlCallbackHandler() = default;
-
- bool addCallback(const sp<CallbackType>& cb) {
- // TODO(b/33818800): Can't compare proxies yet. So, use the cookie
- // (callback proxy's raw pointer) to track the death of individual
- // clients.
- uint64_t cookie = reinterpret_cast<uint64_t>(cb.get());
- if (cb_set_.find(cb) != cb_set_.end()) {
- LOG(WARNING) << "Duplicate death notification registration";
- return true;
- }
- if (!cb->linkToDeath(death_handler_, cookie)) {
- LOG(ERROR) << "Failed to register death notification";
- return false;
- }
- cb_set_.insert(cb);
- return true;
- }
-
- const std::set<android::sp<CallbackType>>& getCallbacks() {
- return cb_set_;
- }
-
- // Death notification for callbacks.
- void onObjectDeath(uint64_t cookie) {
- CallbackType* cb = reinterpret_cast<CallbackType*>(cookie);
- const auto& iter = cb_set_.find(cb);
- if (iter == cb_set_.end()) {
- LOG(ERROR) << "Unknown callback death notification received";
- return;
- }
- cb_set_.erase(iter);
- LOG(DEBUG) << "Dead callback removed from list";
- }
-
- void invalidate() {
- for (const sp<CallbackType>& cb : cb_set_) {
- if (!cb->unlinkToDeath(death_handler_)) {
- LOG(ERROR) << "Failed to deregister death notification";
- }
- }
- cb_set_.clear();
- }
-
- private:
- std::set<sp<CallbackType>> cb_set_;
- sp<HidlDeathHandler<CallbackType>> death_handler_;
-
- DISALLOW_COPY_AND_ASSIGN(HidlCallbackHandler);
-};
-
-} // namespace hidl_callback_util
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-#endif // HIDL_CALLBACK_UTIL_H_
diff --git a/wifi/1.3/default/hidl_return_util.h b/wifi/1.3/default/hidl_return_util.h
deleted file mode 100644
index 9707444..0000000
--- a/wifi/1.3/default/hidl_return_util.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HIDL_RETURN_UTIL_H_
-#define HIDL_RETURN_UTIL_H_
-
-#include "hidl_sync_util.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace hidl_return_util {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * These utility functions are used to invoke a method on the provided
- * HIDL interface object.
- * These functions checks if the provided HIDL interface object is valid.
- * a) if valid, Invokes the corresponding internal implementation function of
- * the HIDL method. It then invokes the HIDL continuation callback with
- * the status and any returned values.
- * b) if invalid, invokes the HIDL continuation callback with the
- * provided error status and default values.
- */
-// Use for HIDL methods which return only an instance of WifiStatus.
-template <typename ObjT, typename WorkFuncT, typename... Args>
-Return<void> validateAndCall(
- ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
- const std::function<void(const WifiStatus&)>& hidl_cb, Args&&... args) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (obj->isValid()) {
- hidl_cb((obj->*work)(std::forward<Args>(args)...));
- } else {
- hidl_cb(createWifiStatus(status_code_if_invalid));
- }
- return Void();
-}
-
-// Use for HIDL methods which return only an instance of WifiStatus.
-// This version passes the global lock acquired to the body of the method.
-// Note: Only used by IWifi::stop() currently.
-template <typename ObjT, typename WorkFuncT, typename... Args>
-Return<void> validateAndCallWithLock(
- ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
- const std::function<void(const WifiStatus&)>& hidl_cb, Args&&... args) {
- auto lock = hidl_sync_util::acquireGlobalLock();
- if (obj->isValid()) {
- hidl_cb((obj->*work)(&lock, std::forward<Args>(args)...));
- } else {
- hidl_cb(createWifiStatus(status_code_if_invalid));
- }
- return Void();
-}
-
-// Use for HIDL methods which return instance of WifiStatus and a single return
-// value.
-template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
-Return<void> validateAndCall(
- ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
- const std::function<void(const WifiStatus&, ReturnT)>& hidl_cb,
- Args&&... args) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (obj->isValid()) {
- const auto& ret_pair = (obj->*work)(std::forward<Args>(args)...);
- const WifiStatus& status = std::get<0>(ret_pair);
- const auto& ret_value = std::get<1>(ret_pair);
- hidl_cb(status, ret_value);
- } else {
- hidl_cb(createWifiStatus(status_code_if_invalid),
- typename std::remove_reference<ReturnT>::type());
- }
- return Void();
-}
-
-// Use for HIDL methods which return instance of WifiStatus and 2 return
-// values.
-template <typename ObjT, typename WorkFuncT, typename ReturnT1,
- typename ReturnT2, typename... Args>
-Return<void> validateAndCall(
- ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
- const std::function<void(const WifiStatus&, ReturnT1, ReturnT2)>& hidl_cb,
- Args&&... args) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (obj->isValid()) {
- const auto& ret_tuple = (obj->*work)(std::forward<Args>(args)...);
- const WifiStatus& status = std::get<0>(ret_tuple);
- const auto& ret_value1 = std::get<1>(ret_tuple);
- const auto& ret_value2 = std::get<2>(ret_tuple);
- hidl_cb(status, ret_value1, ret_value2);
- } else {
- hidl_cb(createWifiStatus(status_code_if_invalid),
- typename std::remove_reference<ReturnT1>::type(),
- typename std::remove_reference<ReturnT2>::type());
- }
- return Void();
-}
-
-} // namespace hidl_return_util
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-#endif // HIDL_RETURN_UTIL_H_
diff --git a/wifi/1.3/default/hidl_struct_util.cpp b/wifi/1.3/default/hidl_struct_util.cpp
deleted file mode 100644
index d305c09..0000000
--- a/wifi/1.3/default/hidl_struct_util.cpp
+++ /dev/null
@@ -1,2701 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-#include <utils/SystemClock.h>
-
-#include "hidl_struct_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace hidl_struct_util {
-
-WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
- legacy_hal::wifi_channel_width type);
-
-hidl_string safeConvertChar(const char* str, size_t max_len) {
- const char* c = str;
- size_t size = 0;
- while (*c && (unsigned char)*c < 128 && size < max_len) {
- ++size;
- ++c;
- }
- return hidl_string(str, size);
-}
-
-IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToHidlChipCapability(
- uint32_t feature) {
- using HidlChipCaps = IWifiChip::ChipCapabilityMask;
- switch (feature) {
- case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED:
- return HidlChipCaps::DEBUG_MEMORY_FIRMWARE_DUMP;
- case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED:
- return HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP;
- case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED:
- return HidlChipCaps::DEBUG_RING_BUFFER_CONNECT_EVENT;
- case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED:
- return HidlChipCaps::DEBUG_RING_BUFFER_POWER_EVENT;
- case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED:
- return HidlChipCaps::DEBUG_RING_BUFFER_WAKELOCK_EVENT;
- };
- CHECK(false) << "Unknown legacy feature: " << feature;
- return {};
-}
-
-IWifiStaIface::StaIfaceCapabilityMask
-convertLegacyLoggerFeatureToHidlStaIfaceCapability(uint32_t feature) {
- using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
- switch (feature) {
- case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED:
- return HidlStaIfaceCaps::DEBUG_PACKET_FATE;
- };
- CHECK(false) << "Unknown legacy feature: " << feature;
- return {};
-}
-
-V1_3::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
- uint32_t feature) {
- using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
- switch (feature) {
- case WIFI_FEATURE_SET_TX_POWER_LIMIT:
- return HidlChipCaps::SET_TX_POWER_LIMIT;
- case WIFI_FEATURE_USE_BODY_HEAD_SAR:
- return HidlChipCaps::USE_BODY_HEAD_SAR;
- case WIFI_FEATURE_D2D_RTT:
- return HidlChipCaps::D2D_RTT;
- case WIFI_FEATURE_D2AP_RTT:
- return HidlChipCaps::D2AP_RTT;
- case WIFI_FEATURE_SET_LATENCY_MODE:
- return HidlChipCaps::SET_LATENCY_MODE;
- case WIFI_FEATURE_P2P_RAND_MAC:
- return HidlChipCaps::P2P_RAND_MAC;
- };
- CHECK(false) << "Unknown legacy feature: " << feature;
- return {};
-}
-
-IWifiStaIface::StaIfaceCapabilityMask
-convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) {
- using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
- switch (feature) {
- case WIFI_FEATURE_GSCAN:
- return HidlStaIfaceCaps::BACKGROUND_SCAN;
- case WIFI_FEATURE_LINK_LAYER_STATS:
- return HidlStaIfaceCaps::LINK_LAYER_STATS;
- case WIFI_FEATURE_RSSI_MONITOR:
- return HidlStaIfaceCaps::RSSI_MONITOR;
- case WIFI_FEATURE_CONTROL_ROAMING:
- return HidlStaIfaceCaps::CONTROL_ROAMING;
- case WIFI_FEATURE_IE_WHITELIST:
- return HidlStaIfaceCaps::PROBE_IE_WHITELIST;
- case WIFI_FEATURE_SCAN_RAND:
- return HidlStaIfaceCaps::SCAN_RAND;
- case WIFI_FEATURE_INFRA_5G:
- return HidlStaIfaceCaps::STA_5G;
- case WIFI_FEATURE_HOTSPOT:
- return HidlStaIfaceCaps::HOTSPOT;
- case WIFI_FEATURE_PNO:
- return HidlStaIfaceCaps::PNO;
- case WIFI_FEATURE_TDLS:
- return HidlStaIfaceCaps::TDLS;
- case WIFI_FEATURE_TDLS_OFFCHANNEL:
- return HidlStaIfaceCaps::TDLS_OFFCHANNEL;
- case WIFI_FEATURE_CONFIG_NDO:
- return HidlStaIfaceCaps::ND_OFFLOAD;
- case WIFI_FEATURE_MKEEP_ALIVE:
- return HidlStaIfaceCaps::KEEP_ALIVE;
- };
- CHECK(false) << "Unknown legacy feature: " << feature;
- return {};
-}
-
-bool convertLegacyFeaturesToHidlChipCapabilities(
- uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
- uint32_t* hidl_caps) {
- if (!hidl_caps) {
- return false;
- }
- *hidl_caps = {};
- using HidlChipCaps = IWifiChip::ChipCapabilityMask;
- for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
- legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
- legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED,
- legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED,
- legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED}) {
- if (feature & legacy_logger_feature_set) {
- *hidl_caps |=
- convertLegacyLoggerFeatureToHidlChipCapability(feature);
- }
- }
- std::vector<uint32_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT,
- WIFI_FEATURE_USE_BODY_HEAD_SAR,
- WIFI_FEATURE_D2D_RTT,
- WIFI_FEATURE_D2AP_RTT,
- WIFI_FEATURE_SET_LATENCY_MODE,
- WIFI_FEATURE_P2P_RAND_MAC};
- for (const auto feature : features) {
- if (feature & legacy_feature_set) {
- *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
- }
- }
-
- // There are no flags for these 3 in the legacy feature set. Adding them to
- // the set because all the current devices support it.
- *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA;
- *hidl_caps |= HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS;
- *hidl_caps |= HidlChipCaps::DEBUG_ERROR_ALERTS;
- return true;
-}
-
-WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToHidl(
- uint32_t flag) {
- switch (flag) {
- case WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES:
- return WifiDebugRingBufferFlags::HAS_BINARY_ENTRIES;
- case WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES:
- return WifiDebugRingBufferFlags::HAS_ASCII_ENTRIES;
- };
- CHECK(false) << "Unknown legacy flag: " << flag;
- return {};
-}
-
-bool convertLegacyDebugRingBufferStatusToHidl(
- const legacy_hal::wifi_ring_buffer_status& legacy_status,
- WifiDebugRingBufferStatus* hidl_status) {
- if (!hidl_status) {
- return false;
- }
- *hidl_status = {};
- hidl_status->ringName =
- safeConvertChar(reinterpret_cast<const char*>(legacy_status.name),
- sizeof(legacy_status.name));
- hidl_status->flags = 0;
- for (const auto flag : {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES,
- WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES}) {
- if (flag & legacy_status.flags) {
- hidl_status->flags |= static_cast<
- std::underlying_type<WifiDebugRingBufferFlags>::type>(
- convertLegacyDebugRingBufferFlagsToHidl(flag));
- }
- }
- hidl_status->ringId = legacy_status.ring_id;
- hidl_status->sizeInBytes = legacy_status.ring_buffer_byte_size;
- // Calculate free size of the ring the buffer. We don't need to send the
- // exact read/write pointers that were there in the legacy HAL interface.
- if (legacy_status.written_bytes >= legacy_status.read_bytes) {
- hidl_status->freeSizeInBytes =
- legacy_status.ring_buffer_byte_size -
- (legacy_status.written_bytes - legacy_status.read_bytes);
- } else {
- hidl_status->freeSizeInBytes =
- legacy_status.read_bytes - legacy_status.written_bytes;
- }
- hidl_status->verboseLevel = legacy_status.verbose_level;
- return true;
-}
-
-bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
- const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
- std::vector<WifiDebugRingBufferStatus>* hidl_status_vec) {
- if (!hidl_status_vec) {
- return false;
- }
- *hidl_status_vec = {};
- for (const auto& legacy_status : legacy_status_vec) {
- WifiDebugRingBufferStatus hidl_status;
- if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status,
- &hidl_status)) {
- return false;
- }
- hidl_status_vec->push_back(hidl_status);
- }
- return true;
-}
-
-bool convertLegacyWakeReasonStatsToHidl(
- const legacy_hal::WakeReasonStats& legacy_stats,
- WifiDebugHostWakeReasonStats* hidl_stats) {
- if (!hidl_stats) {
- return false;
- }
- *hidl_stats = {};
- hidl_stats->totalCmdEventWakeCnt =
- legacy_stats.wake_reason_cnt.total_cmd_event_wake;
- hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
- hidl_stats->totalDriverFwLocalWakeCnt =
- legacy_stats.wake_reason_cnt.total_driver_fw_local_wake;
- hidl_stats->driverFwLocalWakeCntPerType =
- legacy_stats.driver_fw_local_wake_cnt;
- hidl_stats->totalRxPacketWakeCnt =
- legacy_stats.wake_reason_cnt.total_rx_data_wake;
- hidl_stats->rxPktWakeDetails.rxUnicastCnt =
- legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt;
- hidl_stats->rxPktWakeDetails.rxMulticastCnt =
- legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt;
- hidl_stats->rxPktWakeDetails.rxBroadcastCnt =
- legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt;
- hidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt =
- legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
- .ipv4_rx_multicast_addr_cnt;
- hidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt =
- legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
- .ipv6_rx_multicast_addr_cnt;
- hidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt =
- legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
- .other_rx_multicast_addr_cnt;
- hidl_stats->rxIcmpPkWakeDetails.icmpPkt =
- legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt;
- hidl_stats->rxIcmpPkWakeDetails.icmp6Pkt =
- legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt;
- hidl_stats->rxIcmpPkWakeDetails.icmp6Ra =
- legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra;
- hidl_stats->rxIcmpPkWakeDetails.icmp6Na =
- legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na;
- hidl_stats->rxIcmpPkWakeDetails.icmp6Ns =
- legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns;
- return true;
-}
-
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
- V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
- switch (hidl_scenario) {
- // This is the only supported scenario for V1_1
- case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
- return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
- };
- CHECK(false);
-}
-
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
- V1_2::IWifiChip::TxPowerScenario hidl_scenario) {
- switch (hidl_scenario) {
- // This is the only supported scenario for V1_1
- case V1_2::IWifiChip::TxPowerScenario::VOICE_CALL:
- return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
- // Those are the supported scenarios for V1_2
- case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
- return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
- case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
- return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
- case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
- return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
- case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
- return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
- };
- CHECK(false);
-}
-
-legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
- IWifiChip::LatencyMode hidl_latency_mode) {
- switch (hidl_latency_mode) {
- case IWifiChip::LatencyMode::NORMAL:
- return legacy_hal::WIFI_LATENCY_MODE_NORMAL;
- case IWifiChip::LatencyMode::LOW:
- return legacy_hal::WIFI_LATENCY_MODE_LOW;
- }
- CHECK(false);
-}
-
-bool convertLegacyWifiMacInfoToHidl(
- const legacy_hal::WifiMacInfo& legacy_mac_info,
- V1_2::IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
- if (!hidl_radio_mode_info) {
- return false;
- }
- *hidl_radio_mode_info = {};
-
- hidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id;
- // Convert from bitmask of bands in the legacy HAL to enum value in
- // the HIDL interface.
- if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
- legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
- hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ;
- } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
- hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ;
- } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
- hidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ;
- } else {
- hidl_radio_mode_info->bandInfo = WifiBand::BAND_UNSPECIFIED;
- }
- std::vector<V1_2::IWifiChipEventCallback::IfaceInfo> iface_info_vec;
- for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
- V1_2::IWifiChipEventCallback::IfaceInfo iface_info;
- iface_info.name = legacy_iface_info.name;
- iface_info.channel = legacy_iface_info.channel;
- iface_info_vec.push_back(iface_info);
- }
- hidl_radio_mode_info->ifaceInfos = iface_info_vec;
- return true;
-}
-
-bool convertLegacyWifiMacInfosToHidl(
- const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
- std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>*
- hidl_radio_mode_infos) {
- if (!hidl_radio_mode_infos) {
- return false;
- }
- *hidl_radio_mode_infos = {};
-
- for (const auto& legacy_mac_info : legacy_mac_infos) {
- V1_2::IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
- if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info,
- &hidl_radio_mode_info)) {
- return false;
- }
- hidl_radio_mode_infos->push_back(hidl_radio_mode_info);
- }
- return true;
-}
-
-bool convertLegacyFeaturesToHidlStaCapabilities(
- uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
- uint32_t* hidl_caps) {
- if (!hidl_caps) {
- return false;
- }
- *hidl_caps = {};
- using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
- for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
- if (feature & legacy_logger_feature_set) {
- *hidl_caps |=
- convertLegacyLoggerFeatureToHidlStaIfaceCapability(feature);
- }
- }
- for (const auto feature :
- {WIFI_FEATURE_GSCAN, WIFI_FEATURE_LINK_LAYER_STATS,
- WIFI_FEATURE_RSSI_MONITOR, WIFI_FEATURE_CONTROL_ROAMING,
- 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}) {
- if (feature & legacy_feature_set) {
- *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
- }
- }
- // There is no flag for this one in the legacy feature set. Adding it to the
- // set because all the current devices support it.
- *hidl_caps |= HidlStaIfaceCaps::APF;
- return true;
-}
-
-bool convertLegacyApfCapabilitiesToHidl(
- const legacy_hal::PacketFilterCapabilities& legacy_caps,
- StaApfPacketFilterCapabilities* hidl_caps) {
- if (!hidl_caps) {
- return false;
- }
- *hidl_caps = {};
- hidl_caps->version = legacy_caps.version;
- hidl_caps->maxLength = legacy_caps.max_len;
- return true;
-}
-
-uint8_t convertHidlGscanReportEventFlagToLegacy(
- StaBackgroundScanBucketEventReportSchemeMask hidl_flag) {
- using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
- switch (hidl_flag) {
- case HidlFlag::EACH_SCAN:
- return REPORT_EVENTS_EACH_SCAN;
- case HidlFlag::FULL_RESULTS:
- return REPORT_EVENTS_FULL_RESULTS;
- case HidlFlag::NO_BATCH:
- return REPORT_EVENTS_NO_BATCH;
- };
- CHECK(false);
-}
-
-StaScanDataFlagMask convertLegacyGscanDataFlagToHidl(uint8_t legacy_flag) {
- switch (legacy_flag) {
- case legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED:
- return StaScanDataFlagMask::INTERRUPTED;
- };
- CHECK(false) << "Unknown legacy flag: " << legacy_flag;
- // To silence the compiler warning about reaching the end of non-void
- // function.
- return {};
-}
-
-bool convertLegacyGscanCapabilitiesToHidl(
- const legacy_hal::wifi_gscan_capabilities& legacy_caps,
- StaBackgroundScanCapabilities* hidl_caps) {
- if (!hidl_caps) {
- return false;
- }
- *hidl_caps = {};
- hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
- hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
- hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
- hidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold;
- return true;
-}
-
-legacy_hal::wifi_band convertHidlWifiBandToLegacy(WifiBand band) {
- switch (band) {
- case WifiBand::BAND_UNSPECIFIED:
- return legacy_hal::WIFI_BAND_UNSPECIFIED;
- case WifiBand::BAND_24GHZ:
- return legacy_hal::WIFI_BAND_BG;
- case WifiBand::BAND_5GHZ:
- return legacy_hal::WIFI_BAND_A;
- case WifiBand::BAND_5GHZ_DFS:
- return legacy_hal::WIFI_BAND_A_DFS;
- case WifiBand::BAND_5GHZ_WITH_DFS:
- return legacy_hal::WIFI_BAND_A_WITH_DFS;
- case WifiBand::BAND_24GHZ_5GHZ:
- return legacy_hal::WIFI_BAND_ABG;
- case WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
- return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
- };
- CHECK(false);
-}
-
-bool convertHidlGscanParamsToLegacy(
- const StaBackgroundScanParameters& hidl_scan_params,
- legacy_hal::wifi_scan_cmd_params* legacy_scan_params) {
- if (!legacy_scan_params) {
- return false;
- }
- *legacy_scan_params = {};
- legacy_scan_params->base_period = hidl_scan_params.basePeriodInMs;
- legacy_scan_params->max_ap_per_scan = hidl_scan_params.maxApPerScan;
- legacy_scan_params->report_threshold_percent =
- hidl_scan_params.reportThresholdPercent;
- legacy_scan_params->report_threshold_num_scans =
- hidl_scan_params.reportThresholdNumScans;
- if (hidl_scan_params.buckets.size() > MAX_BUCKETS) {
- return false;
- }
- legacy_scan_params->num_buckets = hidl_scan_params.buckets.size();
- for (uint32_t bucket_idx = 0; bucket_idx < hidl_scan_params.buckets.size();
- bucket_idx++) {
- const StaBackgroundScanBucketParameters& hidl_bucket_spec =
- hidl_scan_params.buckets[bucket_idx];
- legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
- legacy_scan_params->buckets[bucket_idx];
- if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
- return false;
- }
- legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
- legacy_bucket_spec.band =
- convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
- legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
- legacy_bucket_spec.max_period =
- hidl_bucket_spec.exponentialMaxPeriodInMs;
- legacy_bucket_spec.base = hidl_bucket_spec.exponentialBase;
- legacy_bucket_spec.step_count = hidl_bucket_spec.exponentialStepCount;
- legacy_bucket_spec.report_events = 0;
- using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
- for (const auto flag : {HidlFlag::EACH_SCAN, HidlFlag::FULL_RESULTS,
- HidlFlag::NO_BATCH}) {
- if (hidl_bucket_spec.eventReportScheme &
- static_cast<std::underlying_type<HidlFlag>::type>(flag)) {
- legacy_bucket_spec.report_events |=
- convertHidlGscanReportEventFlagToLegacy(flag);
- }
- }
- if (hidl_bucket_spec.frequencies.size() > MAX_CHANNELS) {
- return false;
- }
- legacy_bucket_spec.num_channels = hidl_bucket_spec.frequencies.size();
- for (uint32_t freq_idx = 0;
- freq_idx < hidl_bucket_spec.frequencies.size(); freq_idx++) {
- legacy_bucket_spec.channels[freq_idx].channel =
- hidl_bucket_spec.frequencies[freq_idx];
- }
- }
- return true;
-}
-
-bool convertLegacyIeToHidl(
- const legacy_hal::wifi_information_element& legacy_ie,
- WifiInformationElement* hidl_ie) {
- if (!hidl_ie) {
- return false;
- }
- *hidl_ie = {};
- hidl_ie->id = legacy_ie.id;
- hidl_ie->data =
- std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
- return true;
-}
-
-bool convertLegacyIeBlobToHidl(const uint8_t* ie_blob, uint32_t ie_blob_len,
- std::vector<WifiInformationElement>* hidl_ies) {
- if (!ie_blob || !hidl_ies) {
- return false;
- }
- *hidl_ies = {};
- const uint8_t* ies_begin = ie_blob;
- const uint8_t* ies_end = ie_blob + ie_blob_len;
- const uint8_t* next_ie = ies_begin;
- using wifi_ie = legacy_hal::wifi_information_element;
- constexpr size_t kIeHeaderLen = sizeof(wifi_ie);
- // Each IE should atleast have the header (i.e |id| & |len| fields).
- while (next_ie + kIeHeaderLen <= ies_end) {
- const wifi_ie& legacy_ie = (*reinterpret_cast<const wifi_ie*>(next_ie));
- uint32_t curr_ie_len = kIeHeaderLen + legacy_ie.len;
- if (next_ie + curr_ie_len > ies_end) {
- LOG(ERROR) << "Error parsing IE blob. Next IE: " << (void*)next_ie
- << ", Curr IE len: " << curr_ie_len
- << ", IEs End: " << (void*)ies_end;
- break;
- }
- WifiInformationElement hidl_ie;
- if (!convertLegacyIeToHidl(legacy_ie, &hidl_ie)) {
- LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id
- << ", len: " << legacy_ie.len;
- break;
- }
- hidl_ies->push_back(std::move(hidl_ie));
- next_ie += curr_ie_len;
- }
- // Check if the blob has been fully consumed.
- if (next_ie != ies_end) {
- LOG(ERROR) << "Failed to fully parse IE blob. Next IE: "
- << (void*)next_ie << ", IEs End: " << (void*)ies_end;
- }
- return true;
-}
-
-bool convertLegacyGscanResultToHidl(
- const legacy_hal::wifi_scan_result& legacy_scan_result, bool has_ie_data,
- StaScanResult* hidl_scan_result) {
- if (!hidl_scan_result) {
- return false;
- }
- *hidl_scan_result = {};
- hidl_scan_result->timeStampInUs = legacy_scan_result.ts;
- hidl_scan_result->ssid = std::vector<uint8_t>(
- legacy_scan_result.ssid,
- legacy_scan_result.ssid + strnlen(legacy_scan_result.ssid,
- sizeof(legacy_scan_result.ssid) - 1));
- memcpy(hidl_scan_result->bssid.data(), legacy_scan_result.bssid,
- hidl_scan_result->bssid.size());
- hidl_scan_result->frequency = legacy_scan_result.channel;
- hidl_scan_result->rssi = legacy_scan_result.rssi;
- hidl_scan_result->beaconPeriodInMs = legacy_scan_result.beacon_period;
- hidl_scan_result->capability = legacy_scan_result.capability;
- if (has_ie_data) {
- std::vector<WifiInformationElement> ies;
- if (!convertLegacyIeBlobToHidl(
- reinterpret_cast<const uint8_t*>(legacy_scan_result.ie_data),
- legacy_scan_result.ie_length, &ies)) {
- return false;
- }
- hidl_scan_result->informationElements = std::move(ies);
- }
- return true;
-}
-
-bool convertLegacyCachedGscanResultsToHidl(
- const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result,
- StaScanData* hidl_scan_data) {
- if (!hidl_scan_data) {
- return false;
- }
- *hidl_scan_data = {};
- hidl_scan_data->flags = 0;
- for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
- if (legacy_cached_scan_result.flags & flag) {
- hidl_scan_data->flags |=
- static_cast<std::underlying_type<StaScanDataFlagMask>::type>(
- convertLegacyGscanDataFlagToHidl(flag));
- }
- }
- hidl_scan_data->bucketsScanned = legacy_cached_scan_result.buckets_scanned;
-
- CHECK(legacy_cached_scan_result.num_results >= 0 &&
- legacy_cached_scan_result.num_results <= MAX_AP_CACHE_PER_SCAN);
- std::vector<StaScanResult> hidl_scan_results;
- for (int32_t result_idx = 0;
- result_idx < legacy_cached_scan_result.num_results; result_idx++) {
- StaScanResult hidl_scan_result;
- if (!convertLegacyGscanResultToHidl(
- legacy_cached_scan_result.results[result_idx], false,
- &hidl_scan_result)) {
- return false;
- }
- hidl_scan_results.push_back(hidl_scan_result);
- }
- hidl_scan_data->results = std::move(hidl_scan_results);
- return true;
-}
-
-bool convertLegacyVectorOfCachedGscanResultsToHidl(
- const std::vector<legacy_hal::wifi_cached_scan_results>&
- legacy_cached_scan_results,
- std::vector<StaScanData>* hidl_scan_datas) {
- if (!hidl_scan_datas) {
- return false;
- }
- *hidl_scan_datas = {};
- for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
- StaScanData hidl_scan_data;
- if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result,
- &hidl_scan_data)) {
- return false;
- }
- hidl_scan_datas->push_back(hidl_scan_data);
- }
- return true;
-}
-
-WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToHidl(
- legacy_hal::wifi_tx_packet_fate fate) {
- switch (fate) {
- case legacy_hal::TX_PKT_FATE_ACKED:
- return WifiDebugTxPacketFate::ACKED;
- case legacy_hal::TX_PKT_FATE_SENT:
- return WifiDebugTxPacketFate::SENT;
- case legacy_hal::TX_PKT_FATE_FW_QUEUED:
- return WifiDebugTxPacketFate::FW_QUEUED;
- case legacy_hal::TX_PKT_FATE_FW_DROP_INVALID:
- return WifiDebugTxPacketFate::FW_DROP_INVALID;
- case legacy_hal::TX_PKT_FATE_FW_DROP_NOBUFS:
- return WifiDebugTxPacketFate::FW_DROP_NOBUFS;
- case legacy_hal::TX_PKT_FATE_FW_DROP_OTHER:
- return WifiDebugTxPacketFate::FW_DROP_OTHER;
- case legacy_hal::TX_PKT_FATE_DRV_QUEUED:
- return WifiDebugTxPacketFate::DRV_QUEUED;
- case legacy_hal::TX_PKT_FATE_DRV_DROP_INVALID:
- return WifiDebugTxPacketFate::DRV_DROP_INVALID;
- case legacy_hal::TX_PKT_FATE_DRV_DROP_NOBUFS:
- return WifiDebugTxPacketFate::DRV_DROP_NOBUFS;
- case legacy_hal::TX_PKT_FATE_DRV_DROP_OTHER:
- return WifiDebugTxPacketFate::DRV_DROP_OTHER;
- };
- CHECK(false) << "Unknown legacy fate type: " << fate;
-}
-
-WifiDebugRxPacketFate convertLegacyDebugRxPacketFateToHidl(
- legacy_hal::wifi_rx_packet_fate fate) {
- switch (fate) {
- case legacy_hal::RX_PKT_FATE_SUCCESS:
- return WifiDebugRxPacketFate::SUCCESS;
- case legacy_hal::RX_PKT_FATE_FW_QUEUED:
- return WifiDebugRxPacketFate::FW_QUEUED;
- case legacy_hal::RX_PKT_FATE_FW_DROP_FILTER:
- return WifiDebugRxPacketFate::FW_DROP_FILTER;
- case legacy_hal::RX_PKT_FATE_FW_DROP_INVALID:
- return WifiDebugRxPacketFate::FW_DROP_INVALID;
- case legacy_hal::RX_PKT_FATE_FW_DROP_NOBUFS:
- return WifiDebugRxPacketFate::FW_DROP_NOBUFS;
- case legacy_hal::RX_PKT_FATE_FW_DROP_OTHER:
- return WifiDebugRxPacketFate::FW_DROP_OTHER;
- case legacy_hal::RX_PKT_FATE_DRV_QUEUED:
- return WifiDebugRxPacketFate::DRV_QUEUED;
- case legacy_hal::RX_PKT_FATE_DRV_DROP_FILTER:
- return WifiDebugRxPacketFate::DRV_DROP_FILTER;
- case legacy_hal::RX_PKT_FATE_DRV_DROP_INVALID:
- return WifiDebugRxPacketFate::DRV_DROP_INVALID;
- case legacy_hal::RX_PKT_FATE_DRV_DROP_NOBUFS:
- return WifiDebugRxPacketFate::DRV_DROP_NOBUFS;
- case legacy_hal::RX_PKT_FATE_DRV_DROP_OTHER:
- return WifiDebugRxPacketFate::DRV_DROP_OTHER;
- };
- CHECK(false) << "Unknown legacy fate type: " << fate;
-}
-
-WifiDebugPacketFateFrameType convertLegacyDebugPacketFateFrameTypeToHidl(
- legacy_hal::frame_type type) {
- switch (type) {
- case legacy_hal::FRAME_TYPE_UNKNOWN:
- return WifiDebugPacketFateFrameType::UNKNOWN;
- case legacy_hal::FRAME_TYPE_ETHERNET_II:
- return WifiDebugPacketFateFrameType::ETHERNET_II;
- case legacy_hal::FRAME_TYPE_80211_MGMT:
- return WifiDebugPacketFateFrameType::MGMT_80211;
- };
- CHECK(false) << "Unknown legacy frame type: " << type;
-}
-
-bool convertLegacyDebugPacketFateFrameToHidl(
- const legacy_hal::frame_info& legacy_frame,
- WifiDebugPacketFateFrameInfo* hidl_frame) {
- if (!hidl_frame) {
- return false;
- }
- *hidl_frame = {};
- hidl_frame->frameType =
- convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
- hidl_frame->frameLen = legacy_frame.frame_len;
- hidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec;
- hidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec;
- const uint8_t* frame_begin = reinterpret_cast<const uint8_t*>(
- legacy_frame.frame_content.ethernet_ii_bytes);
- hidl_frame->frameContent =
- std::vector<uint8_t>(frame_begin, frame_begin + legacy_frame.frame_len);
- return true;
-}
-
-bool convertLegacyDebugTxPacketFateToHidl(
- const legacy_hal::wifi_tx_report& legacy_fate,
- WifiDebugTxPacketFateReport* hidl_fate) {
- if (!hidl_fate) {
- return false;
- }
- *hidl_fate = {};
- hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
- return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
- &hidl_fate->frameInfo);
-}
-
-bool convertLegacyVectorOfDebugTxPacketFateToHidl(
- const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
- std::vector<WifiDebugTxPacketFateReport>* hidl_fates) {
- if (!hidl_fates) {
- return false;
- }
- *hidl_fates = {};
- for (const auto& legacy_fate : legacy_fates) {
- WifiDebugTxPacketFateReport hidl_fate;
- if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
- return false;
- }
- hidl_fates->push_back(hidl_fate);
- }
- return true;
-}
-
-bool convertLegacyDebugRxPacketFateToHidl(
- const legacy_hal::wifi_rx_report& legacy_fate,
- WifiDebugRxPacketFateReport* hidl_fate) {
- if (!hidl_fate) {
- return false;
- }
- *hidl_fate = {};
- hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
- return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
- &hidl_fate->frameInfo);
-}
-
-bool convertLegacyVectorOfDebugRxPacketFateToHidl(
- const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
- std::vector<WifiDebugRxPacketFateReport>* hidl_fates) {
- if (!hidl_fates) {
- return false;
- }
- *hidl_fates = {};
- for (const auto& legacy_fate : legacy_fates) {
- WifiDebugRxPacketFateReport hidl_fate;
- if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
- return false;
- }
- hidl_fates->push_back(hidl_fate);
- }
- return true;
-}
-
-bool convertLegacyLinkLayerRadioStatsToHidl(
- const legacy_hal::LinkLayerRadioStats& legacy_radio_stat,
- V1_3::StaLinkLayerRadioStats* hidl_radio_stat) {
- if (!hidl_radio_stat) {
- return false;
- }
- *hidl_radio_stat = {};
-
- hidl_radio_stat->V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
- hidl_radio_stat->V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
- hidl_radio_stat->V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
- hidl_radio_stat->V1_0.onTimeInMsForScan =
- legacy_radio_stat.stats.on_time_scan;
- hidl_radio_stat->V1_0.txTimeInMsPerLevel =
- legacy_radio_stat.tx_time_per_levels;
- hidl_radio_stat->onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd;
- hidl_radio_stat->onTimeInMsForBgScan =
- legacy_radio_stat.stats.on_time_gscan;
- hidl_radio_stat->onTimeInMsForRoamScan =
- legacy_radio_stat.stats.on_time_roam_scan;
- hidl_radio_stat->onTimeInMsForPnoScan =
- legacy_radio_stat.stats.on_time_pno_scan;
- hidl_radio_stat->onTimeInMsForHs20Scan =
- legacy_radio_stat.stats.on_time_hs20;
-
- std::vector<V1_3::WifiChannelStats> hidl_channel_stats;
-
- for (const auto& channel_stat : legacy_radio_stat.channel_stats) {
- V1_3::WifiChannelStats hidl_channel_stat;
- hidl_channel_stat.onTimeInMs = channel_stat.on_time;
- hidl_channel_stat.ccaBusyTimeInMs = channel_stat.cca_busy_time;
- /*
- * TODO once b/119142899 is fixed,
- * replace below code with convertLegacyWifiChannelInfoToHidl()
- */
- hidl_channel_stat.channel.width = WifiChannelWidthInMhz::WIDTH_20;
- hidl_channel_stat.channel.centerFreq = channel_stat.channel.center_freq;
- hidl_channel_stat.channel.centerFreq0 =
- channel_stat.channel.center_freq0;
- hidl_channel_stat.channel.centerFreq1 =
- channel_stat.channel.center_freq1;
- hidl_channel_stats.push_back(hidl_channel_stat);
- }
-
- hidl_radio_stat->channelStats = hidl_channel_stats;
-
- return true;
-}
-
-bool convertLegacyLinkLayerStatsToHidl(
- const legacy_hal::LinkLayerStats& legacy_stats,
- V1_3::StaLinkLayerStats* hidl_stats) {
- if (!hidl_stats) {
- return false;
- }
- *hidl_stats = {};
- // iface legacy_stats conversion.
- hidl_stats->iface.beaconRx = legacy_stats.iface.beacon_rx;
- hidl_stats->iface.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
- hidl_stats->iface.wmeBePktStats.rxMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
- hidl_stats->iface.wmeBePktStats.txMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
- hidl_stats->iface.wmeBePktStats.lostMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
- hidl_stats->iface.wmeBePktStats.retries =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
- hidl_stats->iface.wmeBkPktStats.rxMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
- hidl_stats->iface.wmeBkPktStats.txMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
- hidl_stats->iface.wmeBkPktStats.lostMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
- hidl_stats->iface.wmeBkPktStats.retries =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
- hidl_stats->iface.wmeViPktStats.rxMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
- hidl_stats->iface.wmeViPktStats.txMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
- hidl_stats->iface.wmeViPktStats.lostMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
- hidl_stats->iface.wmeViPktStats.retries =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
- hidl_stats->iface.wmeVoPktStats.rxMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
- hidl_stats->iface.wmeVoPktStats.txMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
- hidl_stats->iface.wmeVoPktStats.lostMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
- hidl_stats->iface.wmeVoPktStats.retries =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
- // radio legacy_stats conversion.
- std::vector<V1_3::StaLinkLayerRadioStats> hidl_radios_stats;
- for (const auto& legacy_radio_stats : legacy_stats.radios) {
- V1_3::StaLinkLayerRadioStats hidl_radio_stats;
- if (!convertLegacyLinkLayerRadioStatsToHidl(legacy_radio_stats,
- &hidl_radio_stats)) {
- return false;
- }
- hidl_radios_stats.push_back(hidl_radio_stats);
- }
- hidl_stats->radios = hidl_radios_stats;
- // Timestamp in the HAL wrapper here since it's not provided in the legacy
- // HAL API.
- hidl_stats->timeStampInMs = uptimeMillis();
- return true;
-}
-
-bool convertLegacyRoamingCapabilitiesToHidl(
- const legacy_hal::wifi_roaming_capabilities& legacy_caps,
- StaRoamingCapabilities* hidl_caps) {
- if (!hidl_caps) {
- return false;
- }
- *hidl_caps = {};
- hidl_caps->maxBlacklistSize = legacy_caps.max_blacklist_size;
- hidl_caps->maxWhitelistSize = legacy_caps.max_whitelist_size;
- return true;
-}
-
-bool convertHidlRoamingConfigToLegacy(
- const StaRoamingConfig& hidl_config,
- legacy_hal::wifi_roaming_config* legacy_config) {
- if (!legacy_config) {
- return false;
- }
- *legacy_config = {};
- if (hidl_config.bssidBlacklist.size() > MAX_BLACKLIST_BSSID ||
- hidl_config.ssidWhitelist.size() > MAX_WHITELIST_SSID) {
- return false;
- }
- legacy_config->num_blacklist_bssid = hidl_config.bssidBlacklist.size();
- uint32_t i = 0;
- for (const auto& bssid : hidl_config.bssidBlacklist) {
- CHECK(bssid.size() == sizeof(legacy_hal::mac_addr));
- memcpy(legacy_config->blacklist_bssid[i++], bssid.data(), bssid.size());
- }
- legacy_config->num_whitelist_ssid = hidl_config.ssidWhitelist.size();
- i = 0;
- for (const auto& ssid : hidl_config.ssidWhitelist) {
- CHECK(ssid.size() <= sizeof(legacy_hal::ssid_t::ssid_str));
- legacy_config->whitelist_ssid[i].length = ssid.size();
- memcpy(legacy_config->whitelist_ssid[i].ssid_str, ssid.data(),
- ssid.size());
- i++;
- }
- return true;
-}
-
-legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
- StaRoamingState state) {
- switch (state) {
- case StaRoamingState::ENABLED:
- return legacy_hal::ROAMING_ENABLE;
- case StaRoamingState::DISABLED:
- return legacy_hal::ROAMING_DISABLE;
- };
- CHECK(false);
-}
-
-legacy_hal::NanMatchAlg convertHidlNanMatchAlgToLegacy(NanMatchAlg type) {
- switch (type) {
- case NanMatchAlg::MATCH_ONCE:
- return legacy_hal::NAN_MATCH_ALG_MATCH_ONCE;
- case NanMatchAlg::MATCH_CONTINUOUS:
- return legacy_hal::NAN_MATCH_ALG_MATCH_CONTINUOUS;
- case NanMatchAlg::MATCH_NEVER:
- return legacy_hal::NAN_MATCH_ALG_MATCH_NEVER;
- }
- CHECK(false);
-}
-
-legacy_hal::NanPublishType convertHidlNanPublishTypeToLegacy(
- NanPublishType type) {
- switch (type) {
- case NanPublishType::UNSOLICITED:
- return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED;
- case NanPublishType::SOLICITED:
- return legacy_hal::NAN_PUBLISH_TYPE_SOLICITED;
- case NanPublishType::UNSOLICITED_SOLICITED:
- return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
- }
- CHECK(false);
-}
-
-legacy_hal::NanTxType convertHidlNanTxTypeToLegacy(NanTxType type) {
- switch (type) {
- case NanTxType::BROADCAST:
- return legacy_hal::NAN_TX_TYPE_BROADCAST;
- case NanTxType::UNICAST:
- return legacy_hal::NAN_TX_TYPE_UNICAST;
- }
- CHECK(false);
-}
-
-legacy_hal::NanSubscribeType convertHidlNanSubscribeTypeToLegacy(
- NanSubscribeType type) {
- switch (type) {
- case NanSubscribeType::PASSIVE:
- return legacy_hal::NAN_SUBSCRIBE_TYPE_PASSIVE;
- case NanSubscribeType::ACTIVE:
- return legacy_hal::NAN_SUBSCRIBE_TYPE_ACTIVE;
- }
- CHECK(false);
-}
-
-legacy_hal::NanSRFType convertHidlNanSrfTypeToLegacy(NanSrfType type) {
- switch (type) {
- case NanSrfType::BLOOM_FILTER:
- return legacy_hal::NAN_SRF_ATTR_BLOOM_FILTER;
- case NanSrfType::PARTIAL_MAC_ADDR:
- return legacy_hal::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
- }
- CHECK(false);
-}
-
-legacy_hal::NanDataPathChannelCfg convertHidlNanDataPathChannelCfgToLegacy(
- NanDataPathChannelCfg type) {
- switch (type) {
- case NanDataPathChannelCfg::CHANNEL_NOT_REQUESTED:
- return legacy_hal::NAN_DP_CHANNEL_NOT_REQUESTED;
- case NanDataPathChannelCfg::REQUEST_CHANNEL_SETUP:
- return legacy_hal::NAN_DP_REQUEST_CHANNEL_SETUP;
- case NanDataPathChannelCfg::FORCE_CHANNEL_SETUP:
- return legacy_hal::NAN_DP_FORCE_CHANNEL_SETUP;
- }
- CHECK(false);
-}
-
-NanStatusType convertLegacyNanStatusTypeToHidl(legacy_hal::NanStatusType type) {
- switch (type) {
- case legacy_hal::NAN_STATUS_SUCCESS:
- return NanStatusType::SUCCESS;
- case legacy_hal::NAN_STATUS_INTERNAL_FAILURE:
- return NanStatusType::INTERNAL_FAILURE;
- case legacy_hal::NAN_STATUS_PROTOCOL_FAILURE:
- return NanStatusType::PROTOCOL_FAILURE;
- case legacy_hal::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
- return NanStatusType::INVALID_SESSION_ID;
- case legacy_hal::NAN_STATUS_NO_RESOURCE_AVAILABLE:
- return NanStatusType::NO_RESOURCES_AVAILABLE;
- case legacy_hal::NAN_STATUS_INVALID_PARAM:
- return NanStatusType::INVALID_ARGS;
- case legacy_hal::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
- return NanStatusType::INVALID_PEER_ID;
- case legacy_hal::NAN_STATUS_INVALID_NDP_ID:
- return NanStatusType::INVALID_NDP_ID;
- case legacy_hal::NAN_STATUS_NAN_NOT_ALLOWED:
- return NanStatusType::NAN_NOT_ALLOWED;
- case legacy_hal::NAN_STATUS_NO_OTA_ACK:
- return NanStatusType::NO_OTA_ACK;
- case legacy_hal::NAN_STATUS_ALREADY_ENABLED:
- return NanStatusType::ALREADY_ENABLED;
- case legacy_hal::NAN_STATUS_FOLLOWUP_QUEUE_FULL:
- return NanStatusType::FOLLOWUP_TX_QUEUE_FULL;
- case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
- return NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
- }
- CHECK(false);
-}
-
-void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
- size_t max_len, WifiNanStatus* wifiNanStatus) {
- wifiNanStatus->status = convertLegacyNanStatusTypeToHidl(type);
- wifiNanStatus->description = safeConvertChar(str, max_len);
-}
-
-bool convertHidlNanEnableRequestToLegacy(
- const NanEnableRequest& hidl_request,
- legacy_hal::NanEnableRequest* legacy_request) {
- if (!legacy_request) {
- LOG(ERROR)
- << "convertHidlNanEnableRequestToLegacy: null legacy_request";
- return false;
- }
- *legacy_request = {};
-
- legacy_request->config_2dot4g_support = 1;
- legacy_request->support_2dot4g_val =
- hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_24GHZ];
- legacy_request->config_support_5g = 1;
- legacy_request->support_5g_val =
- hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_5GHZ];
- legacy_request->config_hop_count_limit = 1;
- legacy_request->hop_count_limit_val = hidl_request.hopCountMax;
- legacy_request->master_pref = hidl_request.configParams.masterPref;
- legacy_request->discovery_indication_cfg = 0;
- legacy_request->discovery_indication_cfg |=
- hidl_request.configParams.disableDiscoveryAddressChangeIndication ? 0x1
- : 0x0;
- legacy_request->discovery_indication_cfg |=
- hidl_request.configParams.disableStartedClusterIndication ? 0x2 : 0x0;
- legacy_request->discovery_indication_cfg |=
- hidl_request.configParams.disableJoinedClusterIndication ? 0x4 : 0x0;
- legacy_request->config_sid_beacon = 1;
- if (hidl_request.configParams.numberOfPublishServiceIdsInBeacon > 127) {
- LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
- "numberOfPublishServiceIdsInBeacon > 127";
- return false;
- }
- legacy_request->sid_beacon_val =
- (hidl_request.configParams.includePublishServiceIdsInBeacon ? 0x1
- : 0x0) |
- (hidl_request.configParams.numberOfPublishServiceIdsInBeacon << 1);
- legacy_request->config_subscribe_sid_beacon = 1;
- if (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon > 127) {
- LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
- "numberOfSubscribeServiceIdsInBeacon > 127";
- return false;
- }
- legacy_request->subscribe_sid_beacon_val =
- (hidl_request.configParams.includeSubscribeServiceIdsInBeacon ? 0x1
- : 0x0) |
- (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon << 1);
- legacy_request->config_rssi_window_size = 1;
- legacy_request->rssi_window_size_val =
- hidl_request.configParams.rssiWindowSize;
- legacy_request->config_disc_mac_addr_randomization = 1;
- 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) {
- LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
- "bandSpecificConfig.size() != 2";
- return false;
- }
- legacy_request->rssi_close_2dot4g_val =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
- .rssiClose;
- legacy_request->config_2dot4g_rssi_middle = 1;
- legacy_request->rssi_middle_2dot4g_val =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
- .rssiMiddle;
- legacy_request->config_2dot4g_rssi_proximity = 1;
- legacy_request->rssi_proximity_2dot4g_val =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
- .rssiCloseProximity;
- legacy_request->config_scan_params = 1;
- legacy_request->scan_params_val
- .dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
- .dwellTimeMs;
- legacy_request->scan_params_val
- .scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
- .scanPeriodSec;
- legacy_request->config_dw.config_2dot4g_dw_band =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
- .validDiscoveryWindowIntervalVal;
- legacy_request->config_dw.dw_2dot4g_interval_val =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
- .discoveryWindowIntervalVal;
- legacy_request->config_5g_rssi_close = 1;
- legacy_request->rssi_close_5g_val =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .rssiClose;
- legacy_request->config_5g_rssi_middle = 1;
- legacy_request->rssi_middle_5g_val =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .rssiMiddle;
- legacy_request->config_5g_rssi_close_proximity = 1;
- legacy_request->rssi_close_proximity_5g_val =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .rssiCloseProximity;
- legacy_request->scan_params_val
- .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .dwellTimeMs;
- legacy_request->scan_params_val
- .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .scanPeriodSec;
- legacy_request->scan_params_val
- .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .dwellTimeMs;
- legacy_request->scan_params_val
- .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .scanPeriodSec;
- legacy_request->config_dw.config_5g_dw_band =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .validDiscoveryWindowIntervalVal;
- legacy_request->config_dw.dw_5g_interval_val =
- hidl_request.configParams
- .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .discoveryWindowIntervalVal;
- if (hidl_request.debugConfigs.validClusterIdVals) {
- legacy_request->cluster_low =
- hidl_request.debugConfigs.clusterIdBottomRangeVal;
- legacy_request->cluster_high =
- hidl_request.debugConfigs.clusterIdTopRangeVal;
- } else { // need 'else' since not configurable in legacy HAL
- legacy_request->cluster_low = 0x0000;
- legacy_request->cluster_high = 0xFFFF;
- }
- legacy_request->config_intf_addr =
- hidl_request.debugConfigs.validIntfAddrVal;
- memcpy(legacy_request->intf_addr_val,
- hidl_request.debugConfigs.intfAddrVal.data(), 6);
- legacy_request->config_oui = hidl_request.debugConfigs.validOuiVal;
- legacy_request->oui_val = hidl_request.debugConfigs.ouiVal;
- legacy_request->config_random_factor_force =
- hidl_request.debugConfigs.validRandomFactorForceVal;
- legacy_request->random_factor_force_val =
- hidl_request.debugConfigs.randomFactorForceVal;
- legacy_request->config_hop_count_force =
- hidl_request.debugConfigs.validHopCountForceVal;
- legacy_request->hop_count_force_val =
- hidl_request.debugConfigs.hopCountForceVal;
- legacy_request->config_24g_channel =
- hidl_request.debugConfigs.validDiscoveryChannelVal;
- legacy_request->channel_24g_val =
- hidl_request.debugConfigs
- .discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
- legacy_request->config_5g_channel =
- hidl_request.debugConfigs.validDiscoveryChannelVal;
- legacy_request->channel_5g_val =
- hidl_request.debugConfigs
- .discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
- legacy_request->config_2dot4g_beacons =
- hidl_request.debugConfigs.validUseBeaconsInBandVal;
- legacy_request->beacon_2dot4g_val =
- hidl_request.debugConfigs
- .useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
- legacy_request->config_5g_beacons =
- hidl_request.debugConfigs.validUseBeaconsInBandVal;
- legacy_request->beacon_5g_val =
- hidl_request.debugConfigs
- .useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
- legacy_request->config_2dot4g_sdf =
- hidl_request.debugConfigs.validUseSdfInBandVal;
- legacy_request->sdf_2dot4g_val =
- hidl_request.debugConfigs
- .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
- legacy_request->config_5g_sdf =
- hidl_request.debugConfigs.validUseSdfInBandVal;
- legacy_request->sdf_5g_val =
- hidl_request.debugConfigs
- .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-
- return true;
-}
-
-bool convertHidlNanEnableRequest_1_2ToLegacy(
- 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";
- return false;
- }
-
- *legacy_request = {};
- if (!convertHidlNanEnableRequestToLegacy(hidl_request1, legacy_request)) {
- return false;
- }
-
- legacy_request->config_discovery_beacon_int = 1;
- legacy_request->discovery_beacon_interval =
- hidl_request2.discoveryBeaconIntervalMs;
- legacy_request->config_nss = 1;
- legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
- legacy_request->config_dw_early_termination = 1;
- legacy_request->enable_dw_termination =
- hidl_request2.enableDiscoveryWindowEarlyTermination;
- legacy_request->config_enable_ranging = 1;
- legacy_request->enable_ranging = hidl_request2.enableRanging;
-
- return true;
-}
-
-bool convertHidlNanPublishRequestToLegacy(
- const NanPublishRequest& hidl_request,
- legacy_hal::NanPublishRequest* legacy_request) {
- if (!legacy_request) {
- LOG(ERROR)
- << "convertHidlNanPublishRequestToLegacy: null legacy_request";
- return false;
- }
- *legacy_request = {};
-
- legacy_request->publish_id = hidl_request.baseConfigs.sessionId;
- legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
- legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
- legacy_request->publish_count = hidl_request.baseConfigs.discoveryCount;
- legacy_request->service_name_len =
- hidl_request.baseConfigs.serviceName.size();
- if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
- LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: service_name_len "
- "too large";
- return false;
- }
- memcpy(legacy_request->service_name,
- hidl_request.baseConfigs.serviceName.data(),
- legacy_request->service_name_len);
- legacy_request->publish_match_indicator = convertHidlNanMatchAlgToLegacy(
- hidl_request.baseConfigs.discoveryMatchIndicator);
- legacy_request->service_specific_info_len =
- hidl_request.baseConfigs.serviceSpecificInfo.size();
- if (legacy_request->service_specific_info_len >
- NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
- LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
- "service_specific_info_len too large";
- return false;
- }
- memcpy(legacy_request->service_specific_info,
- hidl_request.baseConfigs.serviceSpecificInfo.data(),
- legacy_request->service_specific_info_len);
- legacy_request->sdea_service_specific_info_len =
- hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
- if (legacy_request->sdea_service_specific_info_len >
- NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
- LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
- "sdea_service_specific_info_len too large";
- return false;
- }
- memcpy(legacy_request->sdea_service_specific_info,
- hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
- legacy_request->sdea_service_specific_info_len);
- legacy_request->rx_match_filter_len =
- hidl_request.baseConfigs.rxMatchFilter.size();
- if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
- LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
- "rx_match_filter_len too large";
- return false;
- }
- memcpy(legacy_request->rx_match_filter,
- hidl_request.baseConfigs.rxMatchFilter.data(),
- legacy_request->rx_match_filter_len);
- legacy_request->tx_match_filter_len =
- hidl_request.baseConfigs.txMatchFilter.size();
- if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
- LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
- "tx_match_filter_len too large";
- return false;
- }
- memcpy(legacy_request->tx_match_filter,
- hidl_request.baseConfigs.txMatchFilter.data(),
- legacy_request->tx_match_filter_len);
- legacy_request->rssi_threshold_flag =
- hidl_request.baseConfigs.useRssiThreshold;
- legacy_request->recv_indication_cfg = 0;
- legacy_request->recv_indication_cfg |=
- hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1
- : 0x0;
- legacy_request->recv_indication_cfg |=
- hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
- legacy_request->recv_indication_cfg |=
- hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
- legacy_request->recv_indication_cfg |= 0x8;
- legacy_request->cipher_type =
- (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
- if (hidl_request.baseConfigs.securityConfig.securityType ==
- NanDataPathSecurityType::PMK) {
- legacy_request->key_info.key_type =
- legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
- legacy_request->key_info.body.pmk_info.pmk_len =
- hidl_request.baseConfigs.securityConfig.pmk.size();
- if (legacy_request->key_info.body.pmk_info.pmk_len !=
- NAN_PMK_INFO_LEN) {
- LOG(ERROR)
- << "convertHidlNanPublishRequestToLegacy: invalid pmk_len";
- return false;
- }
- memcpy(legacy_request->key_info.body.pmk_info.pmk,
- hidl_request.baseConfigs.securityConfig.pmk.data(),
- legacy_request->key_info.body.pmk_info.pmk_len);
- }
- if (hidl_request.baseConfigs.securityConfig.securityType ==
- NanDataPathSecurityType::PASSPHRASE) {
- legacy_request->key_info.key_type =
- legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
- legacy_request->key_info.body.passphrase_info.passphrase_len =
- hidl_request.baseConfigs.securityConfig.passphrase.size();
- if (legacy_request->key_info.body.passphrase_info.passphrase_len <
- NAN_SECURITY_MIN_PASSPHRASE_LEN) {
- LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
- "passphrase_len too small";
- return false;
- }
- if (legacy_request->key_info.body.passphrase_info.passphrase_len >
- NAN_SECURITY_MAX_PASSPHRASE_LEN) {
- LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
- "passphrase_len too large";
- return false;
- }
- memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
- hidl_request.baseConfigs.securityConfig.passphrase.data(),
- legacy_request->key_info.body.passphrase_info.passphrase_len);
- }
- legacy_request->sdea_params.security_cfg =
- (hidl_request.baseConfigs.securityConfig.securityType !=
- NanDataPathSecurityType::OPEN)
- ? legacy_hal::NAN_DP_CONFIG_SECURITY
- : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
- legacy_request->sdea_params.ranging_state =
- hidl_request.baseConfigs.rangingRequired
- ? legacy_hal::NAN_RANGING_ENABLE
- : legacy_hal::NAN_RANGING_DISABLE;
- legacy_request->ranging_cfg.ranging_interval_msec =
- hidl_request.baseConfigs.rangingIntervalMsec;
- legacy_request->ranging_cfg.config_ranging_indications =
- hidl_request.baseConfigs.configRangingIndications;
- legacy_request->ranging_cfg.distance_ingress_mm =
- hidl_request.baseConfigs.distanceIngressCm * 10;
- legacy_request->ranging_cfg.distance_egress_mm =
- hidl_request.baseConfigs.distanceEgressCm * 10;
- legacy_request->ranging_auto_response =
- hidl_request.baseConfigs.rangingRequired
- ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
- : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
- legacy_request->sdea_params.range_report =
- legacy_hal::NAN_DISABLE_RANGE_REPORT;
- legacy_request->publish_type =
- convertHidlNanPublishTypeToLegacy(hidl_request.publishType);
- legacy_request->tx_type = convertHidlNanTxTypeToLegacy(hidl_request.txType);
- legacy_request->service_responder_policy =
- hidl_request.autoAcceptDataPathRequests
- ? legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL
- : legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE;
-
- return true;
-}
-
-bool convertHidlNanSubscribeRequestToLegacy(
- const NanSubscribeRequest& hidl_request,
- legacy_hal::NanSubscribeRequest* legacy_request) {
- if (!legacy_request) {
- LOG(ERROR)
- << "convertHidlNanSubscribeRequestToLegacy: legacy_request is null";
- return false;
- }
- *legacy_request = {};
-
- legacy_request->subscribe_id = hidl_request.baseConfigs.sessionId;
- legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
- legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
- legacy_request->subscribe_count = hidl_request.baseConfigs.discoveryCount;
- legacy_request->service_name_len =
- hidl_request.baseConfigs.serviceName.size();
- if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
- LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
- "service_name_len too large";
- return false;
- }
- memcpy(legacy_request->service_name,
- hidl_request.baseConfigs.serviceName.data(),
- legacy_request->service_name_len);
- legacy_request->subscribe_match_indicator = convertHidlNanMatchAlgToLegacy(
- hidl_request.baseConfigs.discoveryMatchIndicator);
- legacy_request->service_specific_info_len =
- hidl_request.baseConfigs.serviceSpecificInfo.size();
- if (legacy_request->service_specific_info_len >
- NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
- LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
- "service_specific_info_len too large";
- return false;
- }
- memcpy(legacy_request->service_specific_info,
- hidl_request.baseConfigs.serviceSpecificInfo.data(),
- legacy_request->service_specific_info_len);
- legacy_request->sdea_service_specific_info_len =
- hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
- if (legacy_request->sdea_service_specific_info_len >
- NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
- LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
- "sdea_service_specific_info_len too large";
- return false;
- }
- memcpy(legacy_request->sdea_service_specific_info,
- hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
- legacy_request->sdea_service_specific_info_len);
- legacy_request->rx_match_filter_len =
- hidl_request.baseConfigs.rxMatchFilter.size();
- if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
- LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
- "rx_match_filter_len too large";
- return false;
- }
- memcpy(legacy_request->rx_match_filter,
- hidl_request.baseConfigs.rxMatchFilter.data(),
- legacy_request->rx_match_filter_len);
- legacy_request->tx_match_filter_len =
- hidl_request.baseConfigs.txMatchFilter.size();
- if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
- LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
- "tx_match_filter_len too large";
- return false;
- }
- memcpy(legacy_request->tx_match_filter,
- hidl_request.baseConfigs.txMatchFilter.data(),
- legacy_request->tx_match_filter_len);
- legacy_request->rssi_threshold_flag =
- hidl_request.baseConfigs.useRssiThreshold;
- legacy_request->recv_indication_cfg = 0;
- legacy_request->recv_indication_cfg |=
- hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1
- : 0x0;
- legacy_request->recv_indication_cfg |=
- hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
- legacy_request->recv_indication_cfg |=
- hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
- legacy_request->cipher_type =
- (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
- if (hidl_request.baseConfigs.securityConfig.securityType ==
- NanDataPathSecurityType::PMK) {
- legacy_request->key_info.key_type =
- legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
- legacy_request->key_info.body.pmk_info.pmk_len =
- hidl_request.baseConfigs.securityConfig.pmk.size();
- if (legacy_request->key_info.body.pmk_info.pmk_len !=
- NAN_PMK_INFO_LEN) {
- LOG(ERROR)
- << "convertHidlNanSubscribeRequestToLegacy: invalid pmk_len";
- return false;
- }
- memcpy(legacy_request->key_info.body.pmk_info.pmk,
- hidl_request.baseConfigs.securityConfig.pmk.data(),
- legacy_request->key_info.body.pmk_info.pmk_len);
- }
- if (hidl_request.baseConfigs.securityConfig.securityType ==
- NanDataPathSecurityType::PASSPHRASE) {
- legacy_request->key_info.key_type =
- legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
- legacy_request->key_info.body.passphrase_info.passphrase_len =
- hidl_request.baseConfigs.securityConfig.passphrase.size();
- if (legacy_request->key_info.body.passphrase_info.passphrase_len <
- NAN_SECURITY_MIN_PASSPHRASE_LEN) {
- LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
- "passphrase_len too small";
- return false;
- }
- if (legacy_request->key_info.body.passphrase_info.passphrase_len >
- NAN_SECURITY_MAX_PASSPHRASE_LEN) {
- LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
- "passphrase_len too large";
- return false;
- }
- memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
- hidl_request.baseConfigs.securityConfig.passphrase.data(),
- legacy_request->key_info.body.passphrase_info.passphrase_len);
- }
- legacy_request->sdea_params.security_cfg =
- (hidl_request.baseConfigs.securityConfig.securityType !=
- NanDataPathSecurityType::OPEN)
- ? legacy_hal::NAN_DP_CONFIG_SECURITY
- : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
- legacy_request->sdea_params.ranging_state =
- hidl_request.baseConfigs.rangingRequired
- ? legacy_hal::NAN_RANGING_ENABLE
- : legacy_hal::NAN_RANGING_DISABLE;
- legacy_request->ranging_cfg.ranging_interval_msec =
- hidl_request.baseConfigs.rangingIntervalMsec;
- legacy_request->ranging_cfg.config_ranging_indications =
- hidl_request.baseConfigs.configRangingIndications;
- legacy_request->ranging_cfg.distance_ingress_mm =
- hidl_request.baseConfigs.distanceIngressCm * 10;
- legacy_request->ranging_cfg.distance_egress_mm =
- hidl_request.baseConfigs.distanceEgressCm * 10;
- legacy_request->ranging_auto_response =
- hidl_request.baseConfigs.rangingRequired
- ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
- : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
- legacy_request->sdea_params.range_report =
- legacy_hal::NAN_DISABLE_RANGE_REPORT;
- legacy_request->subscribe_type =
- convertHidlNanSubscribeTypeToLegacy(hidl_request.subscribeType);
- legacy_request->serviceResponseFilter =
- convertHidlNanSrfTypeToLegacy(hidl_request.srfType);
- legacy_request->serviceResponseInclude =
- hidl_request.srfRespondIfInAddressSet
- ? legacy_hal::NAN_SRF_INCLUDE_RESPOND
- : legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
- legacy_request->useServiceResponseFilter =
- hidl_request.shouldUseSrf ? legacy_hal::NAN_USE_SRF
- : legacy_hal::NAN_DO_NOT_USE_SRF;
- legacy_request->ssiRequiredForMatchIndication =
- hidl_request.isSsiRequiredForMatch
- ? legacy_hal::NAN_SSI_REQUIRED_IN_MATCH_IND
- : legacy_hal::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
- legacy_request->num_intf_addr_present = hidl_request.intfAddr.size();
- if (legacy_request->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
- LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
- "num_intf_addr_present - too many";
- return false;
- }
- for (int i = 0; i < legacy_request->num_intf_addr_present; i++) {
- memcpy(legacy_request->intf_addr[i], hidl_request.intfAddr[i].data(),
- 6);
- }
-
- return true;
-}
-
-bool convertHidlNanTransmitFollowupRequestToLegacy(
- const NanTransmitFollowupRequest& hidl_request,
- legacy_hal::NanTransmitFollowupRequest* legacy_request) {
- if (!legacy_request) {
- LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
- "legacy_request is null";
- return false;
- }
- *legacy_request = {};
-
- legacy_request->publish_subscribe_id = hidl_request.discoverySessionId;
- legacy_request->requestor_instance_id = hidl_request.peerId;
- memcpy(legacy_request->addr, hidl_request.addr.data(), 6);
- legacy_request->priority = hidl_request.isHighPriority
- ? legacy_hal::NAN_TX_PRIORITY_HIGH
- : legacy_hal::NAN_TX_PRIORITY_NORMAL;
- legacy_request->dw_or_faw = hidl_request.shouldUseDiscoveryWindow
- ? legacy_hal::NAN_TRANSMIT_IN_DW
- : legacy_hal::NAN_TRANSMIT_IN_FAW;
- legacy_request->service_specific_info_len =
- hidl_request.serviceSpecificInfo.size();
- if (legacy_request->service_specific_info_len >
- NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
- LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
- "service_specific_info_len too large";
- return false;
- }
- memcpy(legacy_request->service_specific_info,
- hidl_request.serviceSpecificInfo.data(),
- legacy_request->service_specific_info_len);
- legacy_request->sdea_service_specific_info_len =
- hidl_request.extendedServiceSpecificInfo.size();
- if (legacy_request->sdea_service_specific_info_len >
- NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
- LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
- "sdea_service_specific_info_len too large";
- return false;
- }
- memcpy(legacy_request->sdea_service_specific_info,
- hidl_request.extendedServiceSpecificInfo.data(),
- legacy_request->sdea_service_specific_info_len);
- legacy_request->recv_indication_cfg =
- hidl_request.disableFollowupResultIndication ? 0x1 : 0x0;
-
- return true;
-}
-
-bool convertHidlNanConfigRequestToLegacy(
- const NanConfigRequest& hidl_request,
- legacy_hal::NanConfigRequest* legacy_request) {
- if (!legacy_request) {
- LOG(ERROR)
- << "convertHidlNanConfigRequestToLegacy: legacy_request is null";
- return false;
- }
- *legacy_request = {};
-
- // TODO: b/34059183 tracks missing configurations in legacy HAL or uknown
- // defaults
- legacy_request->master_pref = hidl_request.masterPref;
- legacy_request->discovery_indication_cfg = 0;
- legacy_request->discovery_indication_cfg |=
- hidl_request.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
- legacy_request->discovery_indication_cfg |=
- hidl_request.disableStartedClusterIndication ? 0x2 : 0x0;
- legacy_request->discovery_indication_cfg |=
- hidl_request.disableJoinedClusterIndication ? 0x4 : 0x0;
- legacy_request->config_sid_beacon = 1;
- if (hidl_request.numberOfPublishServiceIdsInBeacon > 127) {
- LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
- "numberOfPublishServiceIdsInBeacon > 127";
- return false;
- }
- legacy_request->sid_beacon =
- (hidl_request.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
- (hidl_request.numberOfPublishServiceIdsInBeacon << 1);
- legacy_request->config_subscribe_sid_beacon = 1;
- if (hidl_request.numberOfSubscribeServiceIdsInBeacon > 127) {
- LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
- "numberOfSubscribeServiceIdsInBeacon > 127";
- return false;
- }
- legacy_request->subscribe_sid_beacon_val =
- (hidl_request.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
- (hidl_request.numberOfSubscribeServiceIdsInBeacon << 1);
- legacy_request->config_rssi_window_size = 1;
- legacy_request->rssi_window_size_val = hidl_request.rssiWindowSize;
- legacy_request->config_disc_mac_addr_randomization = 1;
- legacy_request->disc_mac_addr_rand_interval_sec =
- hidl_request.macAddressRandomizationIntervalSec;
- /* TODO : missing
- legacy_request->config_2dot4g_rssi_close = 1;
- legacy_request->rssi_close_2dot4g_val =
- hidl_request.bandSpecificConfig[
- (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiClose;
- legacy_request->config_2dot4g_rssi_middle = 1;
- legacy_request->rssi_middle_2dot4g_val =
- hidl_request.bandSpecificConfig[
- (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiMiddle;
- legacy_request->config_2dot4g_rssi_proximity = 1;
- legacy_request->rssi_proximity_2dot4g_val =
- hidl_request.bandSpecificConfig[
- (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiCloseProximity;
- */
- legacy_request->config_scan_params = 1;
- legacy_request->scan_params_val
- .dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
- hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
- .dwellTimeMs;
- legacy_request->scan_params_val
- .scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
- hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
- .scanPeriodSec;
- legacy_request->config_dw.config_2dot4g_dw_band =
- hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
- .validDiscoveryWindowIntervalVal;
- legacy_request->config_dw.dw_2dot4g_interval_val =
- hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
- .discoveryWindowIntervalVal;
- /* TODO: missing
- legacy_request->config_5g_rssi_close = 1;
- legacy_request->rssi_close_5g_val =
- hidl_request.bandSpecificConfig[
- (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiClose;
- legacy_request->config_5g_rssi_middle = 1;
- legacy_request->rssi_middle_5g_val =
- hidl_request.bandSpecificConfig[
- (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiMiddle;
- */
- legacy_request->config_5g_rssi_close_proximity = 1;
- legacy_request->rssi_close_proximity_5g_val =
- hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .rssiCloseProximity;
- legacy_request->scan_params_val
- .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
- hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .dwellTimeMs;
- legacy_request->scan_params_val
- .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
- hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .scanPeriodSec;
- legacy_request->scan_params_val
- .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
- hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .dwellTimeMs;
- legacy_request->scan_params_val
- .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
- hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .scanPeriodSec;
- legacy_request->config_dw.config_5g_dw_band =
- hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .validDiscoveryWindowIntervalVal;
- legacy_request->config_dw.dw_5g_interval_val =
- hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
- .discoveryWindowIntervalVal;
-
- return true;
-}
-
-bool convertHidlNanConfigRequest_1_2ToLegacy(
- 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 "
- "is null";
- return false;
- }
-
- *legacy_request = {};
- if (!convertHidlNanConfigRequestToLegacy(hidl_request1, legacy_request)) {
- return false;
- }
-
- legacy_request->config_discovery_beacon_int = 1;
- legacy_request->discovery_beacon_interval =
- hidl_request2.discoveryBeaconIntervalMs;
- legacy_request->config_nss = 1;
- legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
- legacy_request->config_dw_early_termination = 1;
- legacy_request->enable_dw_termination =
- hidl_request2.enableDiscoveryWindowEarlyTermination;
- legacy_request->config_enable_ranging = 1;
- legacy_request->enable_ranging = hidl_request2.enableRanging;
-
- return true;
-}
-
-bool convertHidlNanDataPathInitiatorRequestToLegacy(
- const NanInitiateDataPathRequest& hidl_request,
- legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
- if (!legacy_request) {
- LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
- "legacy_request is null";
- return false;
- }
- *legacy_request = {};
-
- legacy_request->requestor_instance_id = hidl_request.peerId;
- memcpy(legacy_request->peer_disc_mac_addr,
- hidl_request.peerDiscMacAddr.data(), 6);
- legacy_request->channel_request_type =
- convertHidlNanDataPathChannelCfgToLegacy(
- hidl_request.channelRequestType);
- legacy_request->channel = hidl_request.channel;
- if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
- LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
- "ifaceName too long";
- return false;
- }
- strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(),
- IFNAMSIZ + 1);
- legacy_request->ndp_cfg.security_cfg =
- (hidl_request.securityConfig.securityType !=
- NanDataPathSecurityType::OPEN)
- ? legacy_hal::NAN_DP_CONFIG_SECURITY
- : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
- legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
- if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
- LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
- "ndp_app_info_len too large";
- return false;
- }
- memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
- legacy_request->app_info.ndp_app_info_len);
- legacy_request->cipher_type =
- (unsigned int)hidl_request.securityConfig.cipherType;
- if (hidl_request.securityConfig.securityType ==
- NanDataPathSecurityType::PMK) {
- legacy_request->key_info.key_type =
- legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
- legacy_request->key_info.body.pmk_info.pmk_len =
- hidl_request.securityConfig.pmk.size();
- if (legacy_request->key_info.body.pmk_info.pmk_len !=
- NAN_PMK_INFO_LEN) {
- LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
- "invalid pmk_len";
- return false;
- }
- memcpy(legacy_request->key_info.body.pmk_info.pmk,
- hidl_request.securityConfig.pmk.data(),
- legacy_request->key_info.body.pmk_info.pmk_len);
- }
- if (hidl_request.securityConfig.securityType ==
- NanDataPathSecurityType::PASSPHRASE) {
- legacy_request->key_info.key_type =
- legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
- legacy_request->key_info.body.passphrase_info.passphrase_len =
- hidl_request.securityConfig.passphrase.size();
- if (legacy_request->key_info.body.passphrase_info.passphrase_len <
- NAN_SECURITY_MIN_PASSPHRASE_LEN) {
- LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
- "passphrase_len too small";
- return false;
- }
- if (legacy_request->key_info.body.passphrase_info.passphrase_len >
- NAN_SECURITY_MAX_PASSPHRASE_LEN) {
- LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
- "passphrase_len too large";
- return false;
- }
- memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
- hidl_request.securityConfig.passphrase.data(),
- legacy_request->key_info.body.passphrase_info.passphrase_len);
- }
- legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
- if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
- LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
- "service_name_len too large";
- return false;
- }
- memcpy(legacy_request->service_name,
- hidl_request.serviceNameOutOfBand.data(),
- legacy_request->service_name_len);
-
- return true;
-}
-
-bool convertHidlNanDataPathIndicationResponseToLegacy(
- const NanRespondToDataPathIndicationRequest& hidl_request,
- legacy_hal::NanDataPathIndicationResponse* legacy_request) {
- if (!legacy_request) {
- LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
- "legacy_request is null";
- return false;
- }
- *legacy_request = {};
-
- legacy_request->rsp_code = hidl_request.acceptRequest
- ? legacy_hal::NAN_DP_REQUEST_ACCEPT
- : legacy_hal::NAN_DP_REQUEST_REJECT;
- legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
- if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
- LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
- "ifaceName too long";
- return false;
- }
- strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(),
- IFNAMSIZ + 1);
- legacy_request->ndp_cfg.security_cfg =
- (hidl_request.securityConfig.securityType !=
- NanDataPathSecurityType::OPEN)
- ? legacy_hal::NAN_DP_CONFIG_SECURITY
- : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
- legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
- if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
- LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
- "ndp_app_info_len too large";
- return false;
- }
- memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
- legacy_request->app_info.ndp_app_info_len);
- legacy_request->cipher_type =
- (unsigned int)hidl_request.securityConfig.cipherType;
- if (hidl_request.securityConfig.securityType ==
- NanDataPathSecurityType::PMK) {
- legacy_request->key_info.key_type =
- legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
- legacy_request->key_info.body.pmk_info.pmk_len =
- hidl_request.securityConfig.pmk.size();
- if (legacy_request->key_info.body.pmk_info.pmk_len !=
- NAN_PMK_INFO_LEN) {
- LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
- "invalid pmk_len";
- return false;
- }
- memcpy(legacy_request->key_info.body.pmk_info.pmk,
- hidl_request.securityConfig.pmk.data(),
- legacy_request->key_info.body.pmk_info.pmk_len);
- }
- if (hidl_request.securityConfig.securityType ==
- NanDataPathSecurityType::PASSPHRASE) {
- legacy_request->key_info.key_type =
- legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
- legacy_request->key_info.body.passphrase_info.passphrase_len =
- hidl_request.securityConfig.passphrase.size();
- if (legacy_request->key_info.body.passphrase_info.passphrase_len <
- NAN_SECURITY_MIN_PASSPHRASE_LEN) {
- LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
- "passphrase_len too small";
- return false;
- }
- if (legacy_request->key_info.body.passphrase_info.passphrase_len >
- NAN_SECURITY_MAX_PASSPHRASE_LEN) {
- LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
- "passphrase_len too large";
- return false;
- }
- memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
- hidl_request.securityConfig.passphrase.data(),
- legacy_request->key_info.body.passphrase_info.passphrase_len);
- }
- legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
- if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
- LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
- "service_name_len too large";
- return false;
- }
- memcpy(legacy_request->service_name,
- hidl_request.serviceNameOutOfBand.data(),
- legacy_request->service_name_len);
-
- return true;
-}
-
-bool convertLegacyNanResponseHeaderToHidl(
- const legacy_hal::NanResponseMsg& legacy_response,
- WifiNanStatus* wifiNanStatus) {
- if (!wifiNanStatus) {
- LOG(ERROR)
- << "convertLegacyNanResponseHeaderToHidl: wifiNanStatus is null";
- return false;
- }
- *wifiNanStatus = {};
-
- convertToWifiNanStatus(legacy_response.status, legacy_response.nan_error,
- sizeof(legacy_response.nan_error), wifiNanStatus);
- return true;
-}
-
-bool convertLegacyNanCapabilitiesResponseToHidl(
- const legacy_hal::NanCapabilities& legacy_response,
- NanCapabilities* hidl_response) {
- if (!hidl_response) {
- LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToHidl: "
- "hidl_response is null";
- return false;
- }
- *hidl_response = {};
-
- hidl_response->maxConcurrentClusters =
- legacy_response.max_concurrent_nan_clusters;
- hidl_response->maxPublishes = legacy_response.max_publishes;
- hidl_response->maxSubscribes = legacy_response.max_subscribes;
- hidl_response->maxServiceNameLen = legacy_response.max_service_name_len;
- hidl_response->maxMatchFilterLen = legacy_response.max_match_filter_len;
- hidl_response->maxTotalMatchFilterLen =
- legacy_response.max_total_match_filter_len;
- hidl_response->maxServiceSpecificInfoLen =
- legacy_response.max_service_specific_info_len;
- hidl_response->maxExtendedServiceSpecificInfoLen =
- legacy_response.max_sdea_service_specific_info_len;
- hidl_response->maxNdiInterfaces = legacy_response.max_ndi_interfaces;
- hidl_response->maxNdpSessions = legacy_response.max_ndp_sessions;
- hidl_response->maxAppInfoLen = legacy_response.max_app_info_len;
- hidl_response->maxQueuedTransmitFollowupMsgs =
- legacy_response.max_queued_transmit_followup_msgs;
- hidl_response->maxSubscribeInterfaceAddresses =
- legacy_response.max_subscribe_address;
- hidl_response->supportedCipherSuites =
- legacy_response.cipher_suites_supported;
-
- return true;
-}
-
-bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
- NanMatchInd* hidl_ind) {
- if (!hidl_ind) {
- LOG(ERROR) << "convertLegacyNanMatchIndToHidl: hidl_ind is null";
- return false;
- }
- *hidl_ind = {};
-
- hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
- hidl_ind->peerId = legacy_ind.requestor_instance_id;
- hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
- hidl_ind->serviceSpecificInfo =
- std::vector<uint8_t>(legacy_ind.service_specific_info,
- legacy_ind.service_specific_info +
- legacy_ind.service_specific_info_len);
- hidl_ind->extendedServiceSpecificInfo =
- std::vector<uint8_t>(legacy_ind.sdea_service_specific_info,
- legacy_ind.sdea_service_specific_info +
- legacy_ind.sdea_service_specific_info_len);
- hidl_ind->matchFilter = std::vector<uint8_t>(
- legacy_ind.sdf_match_filter,
- legacy_ind.sdf_match_filter + legacy_ind.sdf_match_filter_len);
- hidl_ind->matchOccuredInBeaconFlag = legacy_ind.match_occured_flag == 1;
- hidl_ind->outOfResourceFlag = legacy_ind.out_of_resource_flag == 1;
- hidl_ind->rssiValue = legacy_ind.rssi_value;
- hidl_ind->peerCipherType = (NanCipherSuiteType)legacy_ind.peer_cipher_type;
- hidl_ind->peerRequiresSecurityEnabledInNdp =
- legacy_ind.peer_sdea_params.security_cfg ==
- legacy_hal::NAN_DP_CONFIG_SECURITY;
- hidl_ind->peerRequiresRanging = legacy_ind.peer_sdea_params.ranging_state ==
- legacy_hal::NAN_RANGING_ENABLE;
- hidl_ind->rangingMeasurementInCm =
- legacy_ind.range_info.range_measurement_mm / 10;
- hidl_ind->rangingIndicationType = legacy_ind.range_info.ranging_event_type;
-
- return true;
-}
-
-bool convertLegacyNanFollowupIndToHidl(
- const legacy_hal::NanFollowupInd& legacy_ind,
- NanFollowupReceivedInd* hidl_ind) {
- if (!hidl_ind) {
- LOG(ERROR) << "convertLegacyNanFollowupIndToHidl: hidl_ind is null";
- return false;
- }
- *hidl_ind = {};
-
- hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
- hidl_ind->peerId = legacy_ind.requestor_instance_id;
- hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
- hidl_ind->receivedInFaw = legacy_ind.dw_or_faw == 1;
- hidl_ind->serviceSpecificInfo =
- std::vector<uint8_t>(legacy_ind.service_specific_info,
- legacy_ind.service_specific_info +
- legacy_ind.service_specific_info_len);
- hidl_ind->extendedServiceSpecificInfo =
- std::vector<uint8_t>(legacy_ind.sdea_service_specific_info,
- legacy_ind.sdea_service_specific_info +
- legacy_ind.sdea_service_specific_info_len);
-
- return true;
-}
-
-bool convertLegacyNanDataPathRequestIndToHidl(
- const legacy_hal::NanDataPathRequestInd& legacy_ind,
- NanDataPathRequestInd* hidl_ind) {
- if (!hidl_ind) {
- LOG(ERROR)
- << "convertLegacyNanDataPathRequestIndToHidl: hidl_ind is null";
- return false;
- }
- *hidl_ind = {};
-
- hidl_ind->discoverySessionId = legacy_ind.service_instance_id;
- hidl_ind->peerDiscMacAddr =
- hidl_array<uint8_t, 6>(legacy_ind.peer_disc_mac_addr);
- hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
- hidl_ind->securityRequired =
- legacy_ind.ndp_cfg.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
- hidl_ind->appInfo =
- std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
- legacy_ind.app_info.ndp_app_info +
- legacy_ind.app_info.ndp_app_info_len);
-
- return true;
-}
-
-bool convertLegacyNdpChannelInfoToHidl(
- const legacy_hal::NanChannelInfo& legacy_struct,
- V1_2::NanDataPathChannelInfo* hidl_struct) {
- if (!hidl_struct) {
- LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
- return false;
- }
- *hidl_struct = {};
-
- hidl_struct->channelFreq = legacy_struct.channel;
- hidl_struct->channelBandwidth = convertLegacyWifiChannelWidthToHidl(
- (legacy_hal::wifi_channel_width)legacy_struct.bandwidth);
- hidl_struct->numSpatialStreams = legacy_struct.nss;
-
- return true;
-}
-
-bool convertLegacyNanDataPathConfirmIndToHidl(
- const legacy_hal::NanDataPathConfirmInd& legacy_ind,
- V1_2::NanDataPathConfirmInd* hidl_ind) {
- if (!hidl_ind) {
- LOG(ERROR)
- << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
- return false;
- }
- *hidl_ind = {};
-
- hidl_ind->V1_0.ndpInstanceId = legacy_ind.ndp_instance_id;
- hidl_ind->V1_0.dataPathSetupSuccess =
- legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
- hidl_ind->V1_0.peerNdiMacAddr =
- hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
- hidl_ind->V1_0.appInfo =
- std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
- legacy_ind.app_info.ndp_app_info +
- legacy_ind.app_info.ndp_app_info_len);
- hidl_ind->V1_0.status.status =
- convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
- hidl_ind->V1_0.status.description = ""; // TODO: b/34059183
-
- std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
- for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
- V1_2::NanDataPathChannelInfo hidl_struct;
- if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
- &hidl_struct)) {
- return false;
- }
- channelInfo.push_back(hidl_struct);
- }
- hidl_ind->channelInfo = channelInfo;
-
- return true;
-}
-
-bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
- const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
- V1_2::NanDataPathScheduleUpdateInd* hidl_ind) {
- if (!hidl_ind) {
- LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
- "hidl_ind is null";
- return false;
- }
- *hidl_ind = {};
-
- hidl_ind->peerDiscoveryAddress =
- hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
- std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
- for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
- V1_2::NanDataPathChannelInfo hidl_struct;
- if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
- &hidl_struct)) {
- return false;
- }
- channelInfo.push_back(hidl_struct);
- }
- hidl_ind->channelInfo = channelInfo;
- std::vector<uint32_t> ndpInstanceIds;
- for (unsigned int i = 0; i < legacy_ind.num_ndp_instances; ++i) {
- ndpInstanceIds.push_back(legacy_ind.ndp_instance_id[i]);
- }
- hidl_ind->ndpInstanceIds = ndpInstanceIds;
-
- return true;
-}
-
-legacy_hal::wifi_rtt_type convertHidlRttTypeToLegacy(RttType type) {
- switch (type) {
- case RttType::ONE_SIDED:
- return legacy_hal::RTT_TYPE_1_SIDED;
- case RttType::TWO_SIDED:
- return legacy_hal::RTT_TYPE_2_SIDED;
- };
- CHECK(false);
-}
-
-RttType convertLegacyRttTypeToHidl(legacy_hal::wifi_rtt_type type) {
- switch (type) {
- case legacy_hal::RTT_TYPE_1_SIDED:
- return RttType::ONE_SIDED;
- case legacy_hal::RTT_TYPE_2_SIDED:
- return RttType::TWO_SIDED;
- };
- CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::rtt_peer_type convertHidlRttPeerTypeToLegacy(RttPeerType type) {
- switch (type) {
- case RttPeerType::AP:
- return legacy_hal::RTT_PEER_AP;
- case RttPeerType::STA:
- return legacy_hal::RTT_PEER_STA;
- case RttPeerType::P2P_GO:
- return legacy_hal::RTT_PEER_P2P_GO;
- case RttPeerType::P2P_CLIENT:
- return legacy_hal::RTT_PEER_P2P_CLIENT;
- case RttPeerType::NAN:
- return legacy_hal::RTT_PEER_NAN;
- };
- CHECK(false);
-}
-
-legacy_hal::wifi_channel_width convertHidlWifiChannelWidthToLegacy(
- WifiChannelWidthInMhz type) {
- switch (type) {
- case WifiChannelWidthInMhz::WIDTH_20:
- return legacy_hal::WIFI_CHAN_WIDTH_20;
- case WifiChannelWidthInMhz::WIDTH_40:
- return legacy_hal::WIFI_CHAN_WIDTH_40;
- case WifiChannelWidthInMhz::WIDTH_80:
- return legacy_hal::WIFI_CHAN_WIDTH_80;
- case WifiChannelWidthInMhz::WIDTH_160:
- return legacy_hal::WIFI_CHAN_WIDTH_160;
- case WifiChannelWidthInMhz::WIDTH_80P80:
- return legacy_hal::WIFI_CHAN_WIDTH_80P80;
- case WifiChannelWidthInMhz::WIDTH_5:
- return legacy_hal::WIFI_CHAN_WIDTH_5;
- case WifiChannelWidthInMhz::WIDTH_10:
- return legacy_hal::WIFI_CHAN_WIDTH_10;
- case WifiChannelWidthInMhz::WIDTH_INVALID:
- return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
- };
- CHECK(false);
-}
-
-WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
- legacy_hal::wifi_channel_width type) {
- switch (type) {
- case legacy_hal::WIFI_CHAN_WIDTH_20:
- return WifiChannelWidthInMhz::WIDTH_20;
- case legacy_hal::WIFI_CHAN_WIDTH_40:
- return WifiChannelWidthInMhz::WIDTH_40;
- case legacy_hal::WIFI_CHAN_WIDTH_80:
- return WifiChannelWidthInMhz::WIDTH_80;
- case legacy_hal::WIFI_CHAN_WIDTH_160:
- return WifiChannelWidthInMhz::WIDTH_160;
- case legacy_hal::WIFI_CHAN_WIDTH_80P80:
- return WifiChannelWidthInMhz::WIDTH_80P80;
- case legacy_hal::WIFI_CHAN_WIDTH_5:
- return WifiChannelWidthInMhz::WIDTH_5;
- case legacy_hal::WIFI_CHAN_WIDTH_10:
- return WifiChannelWidthInMhz::WIDTH_10;
- case legacy_hal::WIFI_CHAN_WIDTH_INVALID:
- return WifiChannelWidthInMhz::WIDTH_INVALID;
- };
- CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(RttPreamble type) {
- switch (type) {
- case RttPreamble::LEGACY:
- return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
- case RttPreamble::HT:
- return legacy_hal::WIFI_RTT_PREAMBLE_HT;
- case RttPreamble::VHT:
- return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
- };
- CHECK(false);
-}
-
-RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
- switch (type) {
- case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
- return RttPreamble::LEGACY;
- case legacy_hal::WIFI_RTT_PREAMBLE_HT:
- return RttPreamble::HT;
- case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
- return RttPreamble::VHT;
- };
- CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_rtt_bw convertHidlRttBwToLegacy(RttBw type) {
- switch (type) {
- case RttBw::BW_5MHZ:
- return legacy_hal::WIFI_RTT_BW_5;
- case RttBw::BW_10MHZ:
- return legacy_hal::WIFI_RTT_BW_10;
- case RttBw::BW_20MHZ:
- return legacy_hal::WIFI_RTT_BW_20;
- case RttBw::BW_40MHZ:
- return legacy_hal::WIFI_RTT_BW_40;
- case RttBw::BW_80MHZ:
- return legacy_hal::WIFI_RTT_BW_80;
- case RttBw::BW_160MHZ:
- return legacy_hal::WIFI_RTT_BW_160;
- };
- CHECK(false);
-}
-
-RttBw convertLegacyRttBwToHidl(legacy_hal::wifi_rtt_bw type) {
- switch (type) {
- case legacy_hal::WIFI_RTT_BW_5:
- return RttBw::BW_5MHZ;
- case legacy_hal::WIFI_RTT_BW_10:
- return RttBw::BW_10MHZ;
- case legacy_hal::WIFI_RTT_BW_20:
- return RttBw::BW_20MHZ;
- case legacy_hal::WIFI_RTT_BW_40:
- return RttBw::BW_40MHZ;
- case legacy_hal::WIFI_RTT_BW_80:
- return RttBw::BW_80MHZ;
- case legacy_hal::WIFI_RTT_BW_160:
- return RttBw::BW_160MHZ;
- };
- CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_motion_pattern convertHidlRttMotionPatternToLegacy(
- RttMotionPattern type) {
- switch (type) {
- case RttMotionPattern::NOT_EXPECTED:
- return legacy_hal::WIFI_MOTION_NOT_EXPECTED;
- case RttMotionPattern::EXPECTED:
- return legacy_hal::WIFI_MOTION_EXPECTED;
- case RttMotionPattern::UNKNOWN:
- return legacy_hal::WIFI_MOTION_UNKNOWN;
- };
- CHECK(false);
-}
-
-WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
- switch (preamble) {
- case 0:
- return WifiRatePreamble::OFDM;
- case 1:
- return WifiRatePreamble::CCK;
- case 2:
- return WifiRatePreamble::HT;
- case 3:
- return WifiRatePreamble::VHT;
- default:
- return WifiRatePreamble::RESERVED;
- };
- CHECK(false) << "Unknown legacy preamble: " << preamble;
-}
-
-WifiRateNss convertLegacyWifiRateNssToHidl(uint8_t nss) {
- switch (nss) {
- case 0:
- return WifiRateNss::NSS_1x1;
- case 1:
- return WifiRateNss::NSS_2x2;
- case 2:
- return WifiRateNss::NSS_3x3;
- case 3:
- return WifiRateNss::NSS_4x4;
- };
- CHECK(false) << "Unknown legacy nss: " << nss;
- return {};
-}
-
-RttStatus convertLegacyRttStatusToHidl(legacy_hal::wifi_rtt_status status) {
- switch (status) {
- case legacy_hal::RTT_STATUS_SUCCESS:
- return RttStatus::SUCCESS;
- case legacy_hal::RTT_STATUS_FAILURE:
- return RttStatus::FAILURE;
- case legacy_hal::RTT_STATUS_FAIL_NO_RSP:
- return RttStatus::FAIL_NO_RSP;
- case legacy_hal::RTT_STATUS_FAIL_REJECTED:
- return RttStatus::FAIL_REJECTED;
- case legacy_hal::RTT_STATUS_FAIL_NOT_SCHEDULED_YET:
- return RttStatus::FAIL_NOT_SCHEDULED_YET;
- case legacy_hal::RTT_STATUS_FAIL_TM_TIMEOUT:
- return RttStatus::FAIL_TM_TIMEOUT;
- case legacy_hal::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL:
- return RttStatus::FAIL_AP_ON_DIFF_CHANNEL;
- case legacy_hal::RTT_STATUS_FAIL_NO_CAPABILITY:
- return RttStatus::FAIL_NO_CAPABILITY;
- case legacy_hal::RTT_STATUS_ABORTED:
- return RttStatus::ABORTED;
- case legacy_hal::RTT_STATUS_FAIL_INVALID_TS:
- return RttStatus::FAIL_INVALID_TS;
- case legacy_hal::RTT_STATUS_FAIL_PROTOCOL:
- return RttStatus::FAIL_PROTOCOL;
- case legacy_hal::RTT_STATUS_FAIL_SCHEDULE:
- return RttStatus::FAIL_SCHEDULE;
- case legacy_hal::RTT_STATUS_FAIL_BUSY_TRY_LATER:
- return RttStatus::FAIL_BUSY_TRY_LATER;
- case legacy_hal::RTT_STATUS_INVALID_REQ:
- return RttStatus::INVALID_REQ;
- case legacy_hal::RTT_STATUS_NO_WIFI:
- return RttStatus::NO_WIFI;
- case legacy_hal::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE:
- return RttStatus::FAIL_FTM_PARAM_OVERRIDE;
- case legacy_hal::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE:
- return RttStatus::FAILURE; // TODO: add HIDL enumeration
- case legacy_hal::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED:
- return RttStatus::FAILURE; // TODO: add HIDL enumeration
- };
- CHECK(false) << "Unknown legacy status: " << status;
-}
-
-bool convertHidlWifiChannelInfoToLegacy(
- const WifiChannelInfo& hidl_info,
- legacy_hal::wifi_channel_info* legacy_info) {
- if (!legacy_info) {
- return false;
- }
- *legacy_info = {};
- legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
- legacy_info->center_freq = hidl_info.centerFreq;
- legacy_info->center_freq0 = hidl_info.centerFreq0;
- legacy_info->center_freq1 = hidl_info.centerFreq1;
- return true;
-}
-
-bool convertLegacyWifiChannelInfoToHidl(
- const legacy_hal::wifi_channel_info& legacy_info,
- WifiChannelInfo* hidl_info) {
- if (!hidl_info) {
- return false;
- }
- *hidl_info = {};
- hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
- hidl_info->centerFreq = legacy_info.center_freq;
- hidl_info->centerFreq0 = legacy_info.center_freq0;
- hidl_info->centerFreq1 = legacy_info.center_freq1;
- return true;
-}
-
-bool convertHidlRttConfigToLegacy(const RttConfig& hidl_config,
- legacy_hal::wifi_rtt_config* legacy_config) {
- if (!legacy_config) {
- return false;
- }
- *legacy_config = {};
- CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
- memcpy(legacy_config->addr, hidl_config.addr.data(),
- hidl_config.addr.size());
- legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
- legacy_config->peer = convertHidlRttPeerTypeToLegacy(hidl_config.peer);
- if (!convertHidlWifiChannelInfoToLegacy(hidl_config.channel,
- &legacy_config->channel)) {
- return false;
- }
- legacy_config->burst_period = hidl_config.burstPeriod;
- legacy_config->num_burst = hidl_config.numBurst;
- legacy_config->num_frames_per_burst = hidl_config.numFramesPerBurst;
- legacy_config->num_retries_per_rtt_frame =
- hidl_config.numRetriesPerRttFrame;
- legacy_config->num_retries_per_ftmr = hidl_config.numRetriesPerFtmr;
- legacy_config->LCI_request = hidl_config.mustRequestLci;
- legacy_config->LCR_request = hidl_config.mustRequestLcr;
- legacy_config->burst_duration = hidl_config.burstDuration;
- legacy_config->preamble =
- convertHidlRttPreambleToLegacy(hidl_config.preamble);
- legacy_config->bw = convertHidlRttBwToLegacy(hidl_config.bw);
- return true;
-}
-
-bool convertHidlVectorOfRttConfigToLegacy(
- const std::vector<RttConfig>& hidl_configs,
- std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
- if (!legacy_configs) {
- return false;
- }
- *legacy_configs = {};
- for (const auto& hidl_config : hidl_configs) {
- legacy_hal::wifi_rtt_config legacy_config;
- if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
- return false;
- }
- legacy_configs->push_back(legacy_config);
- }
- return true;
-}
-
-bool convertHidlRttLciInformationToLegacy(
- const RttLciInformation& hidl_info,
- legacy_hal::wifi_lci_information* legacy_info) {
- if (!legacy_info) {
- return false;
- }
- *legacy_info = {};
- legacy_info->latitude = hidl_info.latitude;
- legacy_info->longitude = hidl_info.longitude;
- legacy_info->altitude = hidl_info.altitude;
- legacy_info->latitude_unc = hidl_info.latitudeUnc;
- legacy_info->longitude_unc = hidl_info.longitudeUnc;
- legacy_info->altitude_unc = hidl_info.altitudeUnc;
- legacy_info->motion_pattern =
- convertHidlRttMotionPatternToLegacy(hidl_info.motionPattern);
- legacy_info->floor = hidl_info.floor;
- legacy_info->height_above_floor = hidl_info.heightAboveFloor;
- legacy_info->height_unc = hidl_info.heightUnc;
- return true;
-}
-
-bool convertHidlRttLcrInformationToLegacy(
- const RttLcrInformation& hidl_info,
- legacy_hal::wifi_lcr_information* legacy_info) {
- if (!legacy_info) {
- return false;
- }
- *legacy_info = {};
- CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
- memcpy(legacy_info->country_code, hidl_info.countryCode.data(),
- hidl_info.countryCode.size());
- if (hidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) {
- return false;
- }
- legacy_info->length = hidl_info.civicInfo.size();
- memcpy(legacy_info->civic_info, hidl_info.civicInfo.c_str(),
- hidl_info.civicInfo.size());
- return true;
-}
-
-bool convertHidlRttResponderToLegacy(
- const RttResponder& hidl_responder,
- legacy_hal::wifi_rtt_responder* legacy_responder) {
- if (!legacy_responder) {
- return false;
- }
- *legacy_responder = {};
- if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel,
- &legacy_responder->channel)) {
- return false;
- }
- legacy_responder->preamble =
- convertHidlRttPreambleToLegacy(hidl_responder.preamble);
- return true;
-}
-
-bool convertLegacyRttResponderToHidl(
- const legacy_hal::wifi_rtt_responder& legacy_responder,
- RttResponder* hidl_responder) {
- if (!hidl_responder) {
- return false;
- }
- *hidl_responder = {};
- if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel,
- &hidl_responder->channel)) {
- return false;
- }
- hidl_responder->preamble =
- convertLegacyRttPreambleToHidl(legacy_responder.preamble);
- return true;
-}
-
-bool convertLegacyRttCapabilitiesToHidl(
- const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
- RttCapabilities* hidl_capabilities) {
- if (!hidl_capabilities) {
- return false;
- }
- *hidl_capabilities = {};
- hidl_capabilities->rttOneSidedSupported =
- legacy_capabilities.rtt_one_sided_supported;
- hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
- hidl_capabilities->lciSupported = legacy_capabilities.lci_support;
- hidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
- hidl_capabilities->responderSupported =
- legacy_capabilities.responder_supported;
- hidl_capabilities->preambleSupport = 0;
- for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY,
- legacy_hal::WIFI_RTT_PREAMBLE_HT,
- legacy_hal::WIFI_RTT_PREAMBLE_VHT}) {
- if (legacy_capabilities.preamble_support & flag) {
- hidl_capabilities->preambleSupport |=
- static_cast<std::underlying_type<RttPreamble>::type>(
- convertLegacyRttPreambleToHidl(flag));
- }
- }
- hidl_capabilities->bwSupport = 0;
- for (const auto flag :
- {legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10,
- legacy_hal::WIFI_RTT_BW_20, legacy_hal::WIFI_RTT_BW_40,
- legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160}) {
- if (legacy_capabilities.bw_support & flag) {
- hidl_capabilities->bwSupport |=
- static_cast<std::underlying_type<RttBw>::type>(
- convertLegacyRttBwToHidl(flag));
- }
- }
- hidl_capabilities->mcVersion = legacy_capabilities.mc_version;
- return true;
-}
-
-bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
- WifiRateInfo* hidl_rate) {
- if (!hidl_rate) {
- return false;
- }
- *hidl_rate = {};
- hidl_rate->preamble =
- convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
- hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
- hidl_rate->bw = convertLegacyWifiChannelWidthToHidl(
- static_cast<legacy_hal::wifi_channel_width>(legacy_rate.bw));
- hidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx;
- hidl_rate->bitRateInKbps = legacy_rate.bitrate;
- return true;
-}
-
-bool convertLegacyRttResultToHidl(
- const legacy_hal::wifi_rtt_result& legacy_result, RttResult* hidl_result) {
- if (!hidl_result) {
- return false;
- }
- *hidl_result = {};
- CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
- memcpy(hidl_result->addr.data(), legacy_result.addr,
- sizeof(legacy_result.addr));
- hidl_result->burstNum = legacy_result.burst_num;
- hidl_result->measurementNumber = legacy_result.measurement_number;
- hidl_result->successNumber = legacy_result.success_number;
- hidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer;
- hidl_result->status = convertLegacyRttStatusToHidl(legacy_result.status);
- hidl_result->retryAfterDuration = legacy_result.retry_after_duration;
- hidl_result->type = convertLegacyRttTypeToHidl(legacy_result.type);
- hidl_result->rssi = legacy_result.rssi;
- hidl_result->rssiSpread = legacy_result.rssi_spread;
- if (!convertLegacyWifiRateInfoToHidl(legacy_result.tx_rate,
- &hidl_result->txRate)) {
- return false;
- }
- if (!convertLegacyWifiRateInfoToHidl(legacy_result.rx_rate,
- &hidl_result->rxRate)) {
- return false;
- }
- hidl_result->rtt = legacy_result.rtt;
- hidl_result->rttSd = legacy_result.rtt_sd;
- hidl_result->rttSpread = legacy_result.rtt_spread;
- hidl_result->distanceInMm = legacy_result.distance_mm;
- hidl_result->distanceSdInMm = legacy_result.distance_sd_mm;
- hidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm;
- hidl_result->timeStampInUs = legacy_result.ts;
- hidl_result->burstDurationInMs = legacy_result.burst_duration;
- hidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num;
- if (legacy_result.LCI &&
- !convertLegacyIeToHidl(*legacy_result.LCI, &hidl_result->lci)) {
- return false;
- }
- if (legacy_result.LCR &&
- !convertLegacyIeToHidl(*legacy_result.LCR, &hidl_result->lcr)) {
- return false;
- }
- return true;
-}
-
-bool convertLegacyVectorOfRttResultToHidl(
- const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
- std::vector<RttResult>* hidl_results) {
- if (!hidl_results) {
- return false;
- }
- *hidl_results = {};
- for (const auto legacy_result : legacy_results) {
- RttResult hidl_result;
- if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
- return false;
- }
- hidl_results->push_back(hidl_result);
- }
- return true;
-}
-} // namespace hidl_struct_util
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/hidl_struct_util.h b/wifi/1.3/default/hidl_struct_util.h
deleted file mode 100644
index 3eefd95..0000000
--- a/wifi/1.3/default/hidl_struct_util.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HIDL_STRUCT_UTIL_H_
-#define HIDL_STRUCT_UTIL_H_
-
-#include <vector>
-
-#include <android/hardware/wifi/1.0/IWifiChip.h>
-#include <android/hardware/wifi/1.0/types.h>
-#include <android/hardware/wifi/1.2/IWifiChipEventCallback.h>
-#include <android/hardware/wifi/1.2/types.h>
-#include <android/hardware/wifi/1.3/IWifiChip.h>
-#include <android/hardware/wifi/1.3/types.h>
-
-#include "wifi_legacy_hal.h"
-
-/**
- * This file contains a bunch of functions to convert structs from the legacy
- * HAL to HIDL and vice versa.
- * TODO(b/32093047): Add unit tests for these conversion methods in the VTS test
- * suite.
- */
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace hidl_struct_util {
-using namespace android::hardware::wifi::V1_0;
-
-// Chip conversion methods.
-bool convertLegacyFeaturesToHidlChipCapabilities(
- uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
- uint32_t* hidl_caps);
-bool convertLegacyDebugRingBufferStatusToHidl(
- const legacy_hal::wifi_ring_buffer_status& legacy_status,
- WifiDebugRingBufferStatus* hidl_status);
-bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
- const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
- std::vector<WifiDebugRingBufferStatus>* hidl_status_vec);
-bool convertLegacyWakeReasonStatsToHidl(
- const legacy_hal::WakeReasonStats& legacy_stats,
- WifiDebugHostWakeReasonStats* hidl_stats);
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
- V1_1::IWifiChip::TxPowerScenario hidl_scenario);
-legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
- V1_3::IWifiChip::LatencyMode hidl_latency_mode);
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
- V1_2::IWifiChip::TxPowerScenario hidl_scenario);
-bool convertLegacyWifiMacInfosToHidl(
- const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
- std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>*
- hidl_radio_mode_infos);
-
-// STA iface conversion methods.
-bool convertLegacyFeaturesToHidlStaCapabilities(
- uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
- uint32_t* hidl_caps);
-bool convertLegacyApfCapabilitiesToHidl(
- const legacy_hal::PacketFilterCapabilities& legacy_caps,
- StaApfPacketFilterCapabilities* hidl_caps);
-bool convertLegacyGscanCapabilitiesToHidl(
- const legacy_hal::wifi_gscan_capabilities& legacy_caps,
- StaBackgroundScanCapabilities* hidl_caps);
-legacy_hal::wifi_band convertHidlWifiBandToLegacy(WifiBand band);
-bool convertHidlGscanParamsToLegacy(
- const StaBackgroundScanParameters& hidl_scan_params,
- legacy_hal::wifi_scan_cmd_params* legacy_scan_params);
-// |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11
-// Information Elements (IEs)
-bool convertLegacyGscanResultToHidl(
- const legacy_hal::wifi_scan_result& legacy_scan_result, bool has_ie_data,
- StaScanResult* hidl_scan_result);
-// |cached_results| is assumed to not include IEs.
-bool convertLegacyVectorOfCachedGscanResultsToHidl(
- const std::vector<legacy_hal::wifi_cached_scan_results>&
- legacy_cached_scan_results,
- std::vector<StaScanData>* hidl_scan_datas);
-bool convertLegacyLinkLayerStatsToHidl(
- const legacy_hal::LinkLayerStats& legacy_stats,
- V1_3::StaLinkLayerStats* hidl_stats);
-bool convertLegacyRoamingCapabilitiesToHidl(
- const legacy_hal::wifi_roaming_capabilities& legacy_caps,
- StaRoamingCapabilities* hidl_caps);
-bool convertHidlRoamingConfigToLegacy(
- const StaRoamingConfig& hidl_config,
- legacy_hal::wifi_roaming_config* legacy_config);
-legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
- StaRoamingState state);
-bool convertLegacyVectorOfDebugTxPacketFateToHidl(
- const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
- std::vector<WifiDebugTxPacketFateReport>* hidl_fates);
-bool convertLegacyVectorOfDebugRxPacketFateToHidl(
- const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
- std::vector<WifiDebugRxPacketFateReport>* hidl_fates);
-
-// NAN iface conversion methods.
-void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
- size_t max_len, WifiNanStatus* wifiNanStatus);
-bool convertHidlNanEnableRequestToLegacy(
- const NanEnableRequest& hidl_request,
- legacy_hal::NanEnableRequest* legacy_request);
-bool convertHidlNanConfigRequestToLegacy(
- const NanConfigRequest& hidl_request,
- legacy_hal::NanConfigRequest* legacy_request);
-bool convertHidlNanEnableRequest_1_2ToLegacy(
- const NanEnableRequest& hidl_request1,
- const V1_2::NanConfigRequestSupplemental& hidl_request2,
- legacy_hal::NanEnableRequest* legacy_request);
-bool convertHidlNanConfigRequest_1_2ToLegacy(
- const NanConfigRequest& hidl_request1,
- const V1_2::NanConfigRequestSupplemental& hidl_request2,
- legacy_hal::NanConfigRequest* legacy_request);
-bool convertHidlNanPublishRequestToLegacy(
- const NanPublishRequest& hidl_request,
- legacy_hal::NanPublishRequest* legacy_request);
-bool convertHidlNanSubscribeRequestToLegacy(
- const NanSubscribeRequest& hidl_request,
- legacy_hal::NanSubscribeRequest* legacy_request);
-bool convertHidlNanTransmitFollowupRequestToLegacy(
- const NanTransmitFollowupRequest& hidl_request,
- legacy_hal::NanTransmitFollowupRequest* legacy_request);
-bool convertHidlNanDataPathInitiatorRequestToLegacy(
- const NanInitiateDataPathRequest& hidl_request,
- legacy_hal::NanDataPathInitiatorRequest* legacy_request);
-bool convertHidlNanDataPathIndicationResponseToLegacy(
- const NanRespondToDataPathIndicationRequest& hidl_response,
- legacy_hal::NanDataPathIndicationResponse* legacy_response);
-bool convertLegacyNanResponseHeaderToHidl(
- const legacy_hal::NanResponseMsg& legacy_response,
- WifiNanStatus* wifiNanStatus);
-bool convertLegacyNanCapabilitiesResponseToHidl(
- const legacy_hal::NanCapabilities& legacy_response,
- NanCapabilities* hidl_response);
-bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
- NanMatchInd* hidl_ind);
-bool convertLegacyNanFollowupIndToHidl(
- const legacy_hal::NanFollowupInd& legacy_ind,
- NanFollowupReceivedInd* hidl_ind);
-bool convertLegacyNanDataPathRequestIndToHidl(
- const legacy_hal::NanDataPathRequestInd& legacy_ind,
- NanDataPathRequestInd* hidl_ind);
-bool convertLegacyNanDataPathConfirmIndToHidl(
- const legacy_hal::NanDataPathConfirmInd& legacy_ind,
- V1_2::NanDataPathConfirmInd* hidl_ind);
-bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
- const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
- V1_2::NanDataPathScheduleUpdateInd* hidl_ind);
-
-// RTT controller conversion methods.
-bool convertHidlVectorOfRttConfigToLegacy(
- const std::vector<RttConfig>& hidl_configs,
- std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
-bool convertHidlRttLciInformationToLegacy(
- const RttLciInformation& hidl_info,
- legacy_hal::wifi_lci_information* legacy_info);
-bool convertHidlRttLcrInformationToLegacy(
- const RttLcrInformation& hidl_info,
- legacy_hal::wifi_lcr_information* legacy_info);
-bool convertHidlRttResponderToLegacy(
- const RttResponder& hidl_responder,
- legacy_hal::wifi_rtt_responder* legacy_responder);
-bool convertHidlWifiChannelInfoToLegacy(
- const WifiChannelInfo& hidl_info,
- legacy_hal::wifi_channel_info* legacy_info);
-bool convertLegacyRttResponderToHidl(
- const legacy_hal::wifi_rtt_responder& legacy_responder,
- RttResponder* hidl_responder);
-bool convertLegacyRttCapabilitiesToHidl(
- const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
- RttCapabilities* hidl_capabilities);
-bool convertLegacyVectorOfRttResultToHidl(
- const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
- std::vector<RttResult>* hidl_results);
-} // namespace hidl_struct_util
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // HIDL_STRUCT_UTIL_H_
diff --git a/wifi/1.3/default/hidl_sync_util.cpp b/wifi/1.3/default/hidl_sync_util.cpp
deleted file mode 100644
index 160727f..0000000
--- a/wifi/1.3/default/hidl_sync_util.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-#include "hidl_sync_util.h"
-
-namespace {
-std::recursive_mutex g_mutex;
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace hidl_sync_util {
-
-std::unique_lock<std::recursive_mutex> acquireGlobalLock() {
- return std::unique_lock<std::recursive_mutex>{g_mutex};
-}
-
-} // namespace hidl_sync_util
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/hidl_sync_util.h b/wifi/1.3/default/hidl_sync_util.h
deleted file mode 100644
index ebfb051..0000000
--- a/wifi/1.3/default/hidl_sync_util.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HIDL_SYNC_UTIL_H_
-#define HIDL_SYNC_UTIL_H_
-
-#include <mutex>
-
-// Utility that provides a global lock to synchronize access between
-// the HIDL thread and the legacy HAL's event loop.
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace hidl_sync_util {
-std::unique_lock<std::recursive_mutex> acquireGlobalLock();
-} // namespace hidl_sync_util
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-#endif // HIDL_SYNC_UTIL_H_
diff --git a/wifi/1.3/default/ringbuffer.cpp b/wifi/1.3/default/ringbuffer.cpp
deleted file mode 100644
index 1294c52..0000000
--- a/wifi/1.3/default/ringbuffer.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-
-#include "ringbuffer.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
-
-void Ringbuffer::append(const std::vector<uint8_t>& input) {
- if (input.size() == 0) {
- return;
- }
- if (input.size() > maxSize_) {
- LOG(INFO) << "Oversized message of " << input.size()
- << " bytes is dropped";
- return;
- }
- data_.push_back(input);
- size_ += input.size() * sizeof(input[0]);
- while (size_ > maxSize_) {
- size_ -= data_.front().size() * sizeof(data_.front()[0]);
- data_.pop_front();
- }
-}
-
-const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
- return data_;
-}
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/ringbuffer.h b/wifi/1.3/default/ringbuffer.h
deleted file mode 100644
index d9f8df6..0000000
--- a/wifi/1.3/default/ringbuffer.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RINGBUFFER_H_
-#define RINGBUFFER_H_
-
-#include <list>
-#include <vector>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-/**
- * Ringbuffer object used to store debug data.
- */
-class Ringbuffer {
- public:
- explicit Ringbuffer(size_t maxSize);
-
- // Appends the data buffer and deletes from the front until buffer is
- // within |maxSize_|.
- void append(const std::vector<uint8_t>& input);
- const std::list<std::vector<uint8_t>>& getData() const;
-
- private:
- std::list<std::vector<uint8_t>> data_;
- size_t size_;
- size_t maxSize_;
-};
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // RINGBUFFER_H_
diff --git a/wifi/1.3/default/service.cpp b/wifi/1.3/default/service.cpp
deleted file mode 100644
index 0b41d28..0000000
--- a/wifi/1.3/default/service.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-#include <hidl/HidlLazyUtils.h>
-#include <hidl/HidlTransportSupport.h>
-#include <utils/Looper.h>
-#include <utils/StrongPointer.h>
-
-#include "wifi.h"
-#include "wifi_feature_flags.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_mode_controller.h"
-
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-using android::hardware::LazyServiceRegistrar;
-using android::hardware::wifi::V1_3::implementation::feature_flags::
- WifiFeatureFlags;
-using android::hardware::wifi::V1_3::implementation::iface_util::WifiIfaceUtil;
-using android::hardware::wifi::V1_3::implementation::legacy_hal::WifiLegacyHal;
-using android::hardware::wifi::V1_3::implementation::mode_controller::
- WifiModeController;
-
-#ifdef LAZY_SERVICE
-const bool kLazyService = true;
-#else
-const bool kLazyService = false;
-#endif
-
-int main(int /*argc*/, char** argv) {
- android::base::InitLogging(
- argv, android::base::LogdLogger(android::base::SYSTEM));
- LOG(INFO) << "Wifi Hal is booting up...";
-
- configureRpcThreadpool(1, true /* callerWillJoin */);
-
- const auto iface_tool =
- std::make_shared<android::wifi_system::InterfaceTool>();
- // Setup hwbinder service
- android::sp<android::hardware::wifi::V1_3::IWifi> service =
- new android::hardware::wifi::V1_3::implementation::Wifi(
- iface_tool, std::make_shared<WifiLegacyHal>(iface_tool),
- std::make_shared<WifiModeController>(),
- std::make_shared<WifiIfaceUtil>(iface_tool),
- std::make_shared<WifiFeatureFlags>());
- if (kLazyService) {
- auto registrar = LazyServiceRegistrar::getInstance();
- CHECK_EQ(registrar.registerService(service), android::NO_ERROR)
- << "Failed to register wifi HAL";
- } else {
- CHECK_EQ(service->registerAsService(), android::NO_ERROR)
- << "Failed to register wifi HAL";
- }
-
- joinRpcThreadpool();
-
- LOG(INFO) << "Wifi Hal is terminating...";
- return 0;
-}
diff --git a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
deleted file mode 100644
index 4e9ebde..0000000
--- a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN
-#include "hidl_struct_util.h"
-
-using testing::Test;
-
-namespace {
-constexpr uint32_t kMacId1 = 1;
-constexpr uint32_t kMacId2 = 2;
-constexpr uint32_t kIfaceChannel1 = 3;
-constexpr uint32_t kIfaceChannel2 = 5;
-constexpr char kIfaceName1[] = "wlan0";
-constexpr char kIfaceName2[] = "wlan1";
-} // namespace
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
-
-class HidlStructUtilTest : public Test {};
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) {
- std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
- legacy_hal::WifiMacInfo legacy_mac_info1 = {
- .wlan_mac_id = kMacId1,
- .mac_band =
- legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
- legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
- .channel = kIfaceChannel1};
- legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
- .channel = kIfaceChannel2};
- legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
- legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
- legacy_mac_infos.push_back(legacy_mac_info1);
-
- std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>
- hidl_radio_mode_infos;
- ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
- legacy_mac_infos, &hidl_radio_mode_infos));
-
- ASSERT_EQ(1u, hidl_radio_mode_infos.size());
- auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
- EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
- EXPECT_EQ(WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
- ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
- auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
- EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
- EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
- hidl_iface_info1.channel);
- auto hidl_iface_info2 = hidl_radio_mode_info1.ifaceInfos[1];
- EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
- EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
- hidl_iface_info2.channel);
-}
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) {
- std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
- legacy_hal::WifiMacInfo legacy_mac_info1 = {
- .wlan_mac_id = kMacId1, .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
- legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
- .channel = kIfaceChannel1};
- legacy_hal::WifiMacInfo legacy_mac_info2 = {
- .wlan_mac_id = kMacId2, .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
- legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
- .channel = kIfaceChannel2};
- legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
- legacy_mac_infos.push_back(legacy_mac_info1);
- legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
- legacy_mac_infos.push_back(legacy_mac_info2);
-
- std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>
- hidl_radio_mode_infos;
- ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
- legacy_mac_infos, &hidl_radio_mode_infos));
-
- ASSERT_EQ(2u, hidl_radio_mode_infos.size());
-
- // Find mac info 1.
- const auto hidl_radio_mode_info1 =
- std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
- [&legacy_mac_info1](
- const V1_2::IWifiChipEventCallback::RadioModeInfo& x) {
- return x.radioId == legacy_mac_info1.wlan_mac_id;
- });
- ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
- EXPECT_EQ(WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
- ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
- auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
- EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
- EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
- hidl_iface_info1.channel);
-
- // Find mac info 2.
- const auto hidl_radio_mode_info2 =
- std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
- [&legacy_mac_info2](
- const V1_2::IWifiChipEventCallback::RadioModeInfo& x) {
- return x.radioId == legacy_mac_info2.wlan_mac_id;
- });
- ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
- EXPECT_EQ(WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
- ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
- auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
- EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
- EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
- hidl_iface_info2.channel);
-}
-
-TEST_F(HidlStructUtilTest, canConvertLegacyLinkLayerStatsToHidl) {
- legacy_hal::LinkLayerStats legacy_stats{};
- legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
- legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
- legacy_stats.iface.beacon_rx = rand();
- legacy_stats.iface.rssi_mgmt = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries = rand();
-
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries = rand();
-
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries = rand();
-
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand();
-
- for (auto& radio : legacy_stats.radios) {
- radio.stats.on_time = rand();
- radio.stats.tx_time = rand();
- radio.stats.rx_time = rand();
- radio.stats.on_time_scan = rand();
- radio.stats.on_time_nbd = rand();
- radio.stats.on_time_gscan = rand();
- radio.stats.on_time_roam_scan = rand();
- radio.stats.on_time_pno_scan = rand();
- radio.stats.on_time_hs20 = rand();
- for (int i = 0; i < 4; i++) {
- radio.tx_time_per_levels.push_back(rand());
- }
-
- legacy_hal::wifi_channel_stat channel_stat1 = {
- .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
- .on_time = 0x1111,
- .cca_busy_time = 0x55,
- };
- legacy_hal::wifi_channel_stat channel_stat2 = {
- .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
- .on_time = 0x2222,
- .cca_busy_time = 0x66,
- };
- radio.channel_stats.push_back(channel_stat1);
- radio.channel_stats.push_back(channel_stat2);
- }
-
- V1_3::StaLinkLayerStats converted{};
- hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
- &converted);
- EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.beaconRx);
- EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.avgRssiMgmt);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
- converted.iface.wmeBePktStats.rxMpdu);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
- converted.iface.wmeBePktStats.txMpdu);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
- converted.iface.wmeBePktStats.lostMpdu);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
- converted.iface.wmeBePktStats.retries);
-
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
- converted.iface.wmeBkPktStats.rxMpdu);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
- converted.iface.wmeBkPktStats.txMpdu);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
- converted.iface.wmeBkPktStats.lostMpdu);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
- converted.iface.wmeBkPktStats.retries);
-
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
- converted.iface.wmeViPktStats.rxMpdu);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
- converted.iface.wmeViPktStats.txMpdu);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
- converted.iface.wmeViPktStats.lostMpdu);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
- converted.iface.wmeViPktStats.retries);
-
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
- converted.iface.wmeVoPktStats.rxMpdu);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
- converted.iface.wmeVoPktStats.txMpdu);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
- converted.iface.wmeVoPktStats.lostMpdu);
- EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
- converted.iface.wmeVoPktStats.retries);
-
- EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
- for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
- EXPECT_EQ(legacy_stats.radios[i].stats.on_time,
- converted.radios[i].V1_0.onTimeInMs);
- EXPECT_EQ(legacy_stats.radios[i].stats.tx_time,
- converted.radios[i].V1_0.txTimeInMs);
- EXPECT_EQ(legacy_stats.radios[i].stats.rx_time,
- converted.radios[i].V1_0.rxTimeInMs);
- EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
- converted.radios[i].V1_0.onTimeInMsForScan);
- EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
- converted.radios[i].V1_0.txTimeInMsPerLevel.size());
- for (size_t j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size();
- j++) {
- EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
- converted.radios[i].V1_0.txTimeInMsPerLevel[j]);
- }
- EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
- converted.radios[i].onTimeInMsForNanScan);
- EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
- converted.radios[i].onTimeInMsForBgScan);
- EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
- converted.radios[i].onTimeInMsForRoamScan);
- EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
- converted.radios[i].onTimeInMsForPnoScan);
- EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
- converted.radios[i].onTimeInMsForHs20Scan);
- EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(),
- converted.radios[i].channelStats.size());
- for (size_t k = 0; k < legacy_stats.radios[i].channel_stats.size();
- k++) {
- auto& legacy_channel_st = legacy_stats.radios[i].channel_stats[k];
- EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
- converted.radios[i].channelStats[k].channel.width);
- EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq),
- converted.radios[i].channelStats[k].channel.centerFreq);
- EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq0),
- converted.radios[i].channelStats[k].channel.centerFreq0);
- EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq1),
- converted.radios[i].channelStats[k].channel.centerFreq1);
- EXPECT_EQ(legacy_channel_st.cca_busy_time,
- converted.radios[i].channelStats[k].ccaBusyTimeInMs);
- EXPECT_EQ(legacy_channel_st.on_time,
- converted.radios[i].channelStats[k].onTimeInMs);
- }
- }
-}
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyFeaturesToHidl) {
- using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
-
- uint32_t hidle_caps;
-
- uint32_t legacy_feature_set =
- WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE;
- uint32_t legacy_logger_feature_set =
- legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
-
- ASSERT_TRUE(hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
- legacy_feature_set, legacy_logger_feature_set, &hidle_caps));
-
- EXPECT_EQ(HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA |
- HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS |
- HidlChipCaps::DEBUG_ERROR_ALERTS | HidlChipCaps::D2D_RTT |
- HidlChipCaps::SET_LATENCY_MODE |
- HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP,
- hidle_caps);
-}
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp
deleted file mode 100644
index a393fdc..0000000
--- a/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gmock/gmock.h>
-
-#include "mock_wifi_feature_flags.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace feature_flags {
-
-MockWifiFeatureFlags::MockWifiFeatureFlags() {}
-
-} // namespace feature_flags
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_feature_flags.h b/wifi/1.3/default/tests/mock_wifi_feature_flags.h
deleted file mode 100644
index ee12b54..0000000
--- a/wifi/1.3/default/tests/mock_wifi_feature_flags.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOCK_WIFI_FEATURE_FLAGS_H_
-#define MOCK_WIFI_FEATURE_FLAGS_H_
-
-#include <gmock/gmock.h>
-#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
-
-#include "wifi_feature_flags.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace feature_flags {
-
-class MockWifiFeatureFlags : public WifiFeatureFlags {
- public:
- MockWifiFeatureFlags();
-
- MOCK_METHOD0(getChipModes, std::vector<V1_0::IWifiChip::ChipMode>());
- MOCK_METHOD0(isApMacRandomizationDisabled, bool());
-};
-
-} // namespace feature_flags
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // MOCK_WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.3/default/tests/mock_wifi_iface_util.cpp b/wifi/1.3/default/tests/mock_wifi_iface_util.cpp
deleted file mode 100644
index 3d877c0..0000000
--- a/wifi/1.3/default/tests/mock_wifi_iface_util.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "mock_wifi_iface_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace iface_util {
-
-MockWifiIfaceUtil::MockWifiIfaceUtil(
- const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
- : WifiIfaceUtil(iface_tool) {}
-} // namespace iface_util
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_iface_util.h b/wifi/1.3/default/tests/mock_wifi_iface_util.h
deleted file mode 100644
index 8ec93eb..0000000
--- a/wifi/1.3/default/tests/mock_wifi_iface_util.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOCK_WIFI_IFACE_UTIL_H_
-#define MOCK_WIFI_IFACE_UTIL_H_
-
-#include <gmock/gmock.h>
-
-#include "wifi_iface_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace iface_util {
-
-class MockWifiIfaceUtil : public WifiIfaceUtil {
- public:
- MockWifiIfaceUtil(
- const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
- MOCK_METHOD1(getFactoryMacAddress,
- std::array<uint8_t, 6>(const std::string&));
- MOCK_METHOD2(setMacAddress,
- bool(const std::string&, const std::array<uint8_t, 6>&));
- MOCK_METHOD0(getOrCreateRandomMacAddress, std::array<uint8_t, 6>());
- MOCK_METHOD2(registerIfaceEventHandlers,
- void(const std::string&, IfaceEventHandlers));
- MOCK_METHOD1(unregisterIfaceEventHandlers, void(const std::string&));
-};
-} // namespace iface_util
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // MOCK_WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp
deleted file mode 100644
index 0a202c4..0000000
--- a/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "mock_wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace legacy_hal {
-
-MockWifiLegacyHal::MockWifiLegacyHal(
- const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
- : WifiLegacyHal(iface_tool) {}
-} // namespace legacy_hal
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_legacy_hal.h b/wifi/1.3/default/tests/mock_wifi_legacy_hal.h
deleted file mode 100644
index 81cb1de..0000000
--- a/wifi/1.3/default/tests/mock_wifi_legacy_hal.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOCK_WIFI_LEGACY_HAL_H_
-#define MOCK_WIFI_LEGACY_HAL_H_
-
-#include <gmock/gmock.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace legacy_hal {
-
-class MockWifiLegacyHal : public WifiLegacyHal {
- public:
- MockWifiLegacyHal(
- const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
- MOCK_METHOD0(initialize, wifi_error());
- MOCK_METHOD0(start, wifi_error());
- MOCK_METHOD2(stop, wifi_error(std::unique_lock<std::recursive_mutex>*,
- const std::function<void()>&));
- MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool));
- MOCK_METHOD2(registerRadioModeChangeCallbackHandler,
- wifi_error(const std::string&,
- const on_radio_mode_change_callback&));
- MOCK_METHOD1(getFirmwareVersion, std::pair<wifi_error, std::string>(
- const std::string& iface_name));
- MOCK_METHOD1(getDriverVersion, std::pair<wifi_error, std::string>(
- const std::string& iface_name));
-
- MOCK_METHOD2(selectTxPowerScenario,
- wifi_error(const std::string& iface_name,
- wifi_power_scenario scenario));
- MOCK_METHOD1(resetTxPowerScenario,
- wifi_error(const std::string& iface_name));
- MOCK_METHOD2(nanRegisterCallbackHandlers,
- wifi_error(const std::string&, const NanCallbackHandlers&));
- MOCK_METHOD2(nanDisableRequest,
- wifi_error(const std::string&, transaction_id));
- MOCK_METHOD3(nanDataInterfaceDelete,
- wifi_error(const std::string&, transaction_id,
- const std::string&));
-};
-} // namespace legacy_hal
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // MOCK_WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp
deleted file mode 100644
index 2b0ea36..0000000
--- a/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "mock_wifi_mode_controller.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace mode_controller {
-
-MockWifiModeController::MockWifiModeController() : WifiModeController() {}
-} // namespace mode_controller
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_mode_controller.h b/wifi/1.3/default/tests/mock_wifi_mode_controller.h
deleted file mode 100644
index c204059..0000000
--- a/wifi/1.3/default/tests/mock_wifi_mode_controller.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOCK_WIFI_MODE_CONTROLLER_H_
-#define MOCK_WIFI_MODE_CONTROLLER_H_
-
-#include <gmock/gmock.h>
-
-#include "wifi_mode_controller.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace mode_controller {
-
-class MockWifiModeController : public WifiModeController {
- public:
- MockWifiModeController();
- MOCK_METHOD0(initialize, bool());
- MOCK_METHOD1(changeFirmwareMode, bool(IfaceType));
- MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType));
- MOCK_METHOD0(deinitialize, bool());
-};
-} // namespace mode_controller
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // MOCK_WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp
deleted file mode 100644
index 0cf1e4f..0000000
--- a/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gmock/gmock.h>
-
-#include "ringbuffer.h"
-
-using testing::Return;
-using testing::Test;
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-class RingbufferTest : public Test {
- public:
- const uint32_t maxBufferSize_ = 10;
- Ringbuffer buffer_{maxBufferSize_};
-};
-
-TEST_F(RingbufferTest, CreateEmptyBuffer) {
- ASSERT_TRUE(buffer_.getData().empty());
-}
-
-TEST_F(RingbufferTest, CanUseFullBufferCapacity) {
- const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
- const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
- buffer_.append(input);
- buffer_.append(input2);
- ASSERT_EQ(2u, buffer_.getData().size());
- EXPECT_EQ(input, buffer_.getData().front());
- EXPECT_EQ(input2, buffer_.getData().back());
-}
-
-TEST_F(RingbufferTest, OldDataIsRemovedOnOverflow) {
- const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
- const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
- const std::vector<uint8_t> input3 = {'G'};
- buffer_.append(input);
- buffer_.append(input2);
- buffer_.append(input3);
- ASSERT_EQ(2u, buffer_.getData().size());
- EXPECT_EQ(input2, buffer_.getData().front());
- EXPECT_EQ(input3, buffer_.getData().back());
-}
-
-TEST_F(RingbufferTest, MultipleOldDataIsRemovedOnOverflow) {
- const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
- const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
- const std::vector<uint8_t> input3(maxBufferSize_, '2');
- buffer_.append(input);
- buffer_.append(input2);
- buffer_.append(input3);
- ASSERT_EQ(1u, buffer_.getData().size());
- EXPECT_EQ(input3, buffer_.getData().front());
-}
-
-TEST_F(RingbufferTest, AppendingEmptyBufferDoesNotAddGarbage) {
- const std::vector<uint8_t> input = {};
- buffer_.append(input);
- ASSERT_TRUE(buffer_.getData().empty());
-}
-
-TEST_F(RingbufferTest, OversizedAppendIsDropped) {
- const std::vector<uint8_t> input(maxBufferSize_ + 1, '0');
- buffer_.append(input);
- ASSERT_TRUE(buffer_.getData().empty());
-}
-
-TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) {
- const std::vector<uint8_t> input(maxBufferSize_, '0');
- const std::vector<uint8_t> input2(maxBufferSize_ + 1, '1');
- buffer_.append(input);
- buffer_.append(input2);
- ASSERT_EQ(1u, buffer_.getData().size());
- EXPECT_EQ(input, buffer_.getData().front());
-}
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/tests/wifi_ap_iface_unit_tests.cpp b/wifi/1.3/default/tests/wifi_ap_iface_unit_tests.cpp
deleted file mode 100644
index 680f534..0000000
--- a/wifi/1.3/default/tests/wifi_ap_iface_unit_tests.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <cutils/properties.h>
-#include <gmock/gmock.h>
-
-#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "wifi_ap_iface.h"
-
-#include "mock_interface_tool.h"
-#include "mock_wifi_feature_flags.h"
-#include "mock_wifi_iface_util.h"
-#include "mock_wifi_legacy_hal.h"
-
-using testing::NiceMock;
-using testing::Return;
-using testing::Test;
-
-namespace {
-constexpr char kIfaceName[] = "mockWlan0";
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-class WifiApIfaceTest : public Test {
- protected:
- std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
- new NiceMock<wifi_system::MockInterfaceTool>};
- std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
- new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
- std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
- new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
- std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
- feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
-};
-
-TEST_F(WifiApIfaceTest, SetRandomMacAddressIfFeatureEnabled) {
- EXPECT_CALL(*feature_flags_, isApMacRandomizationDisabled())
- .WillOnce(testing::Return(false));
- EXPECT_CALL(*iface_util_, getOrCreateRandomMacAddress())
- .WillOnce(testing::Return(std::array<uint8_t, 6>{0, 0, 0, 0, 0, 0}));
- EXPECT_CALL(*iface_util_, setMacAddress(testing::_, testing::_))
- .WillOnce(testing::Return(true));
- sp<WifiApIface> ap_iface =
- new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_);
-}
-
-TEST_F(WifiApIfaceTest, DontSetRandomMacAddressIfFeatureDisabled) {
- EXPECT_CALL(*feature_flags_, isApMacRandomizationDisabled())
- .WillOnce(testing::Return(true));
- EXPECT_CALL(*iface_util_, getOrCreateRandomMacAddress()).Times(0);
- EXPECT_CALL(*iface_util_, setMacAddress(testing::_, testing::_)).Times(0);
- sp<WifiApIface> ap_iface =
- new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_);
-}
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
deleted file mode 100644
index d8ce278..0000000
--- a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
+++ /dev/null
@@ -1,871 +0,0 @@
-/*
- * Copyright (C) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <cutils/properties.h>
-#include <gmock/gmock.h>
-
-#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "wifi_chip.h"
-
-#include "mock_interface_tool.h"
-#include "mock_wifi_feature_flags.h"
-#include "mock_wifi_iface_util.h"
-#include "mock_wifi_legacy_hal.h"
-#include "mock_wifi_mode_controller.h"
-
-using testing::NiceMock;
-using testing::Return;
-using testing::Test;
-
-namespace {
-using android::hardware::wifi::V1_0::ChipId;
-
-constexpr ChipId kFakeChipId = 5;
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-class WifiChipTest : public Test {
- protected:
- void setupV1IfaceCombination() {
- // clang-format off
- const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
- {{{{IfaceType::STA}, 1}, {{IfaceType::P2P}, 1}}}
- };
- const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = {
- {{{{IfaceType::AP}, 1}}}
- };
- const std::vector<V1_0::IWifiChip::ChipMode> modes = {
- {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
- {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
- };
- // clang-format on
- EXPECT_CALL(*feature_flags_, getChipModes())
- .WillRepeatedly(testing::Return(modes));
- }
-
- void setupV1_AwareIfaceCombination() {
- // clang-format off
- const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
- {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
- };
- const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = {
- {{{{IfaceType::AP}, 1}}}
- };
- const std::vector<V1_0::IWifiChip::ChipMode> modes = {
- {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
- {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
- };
- // clang-format on
- EXPECT_CALL(*feature_flags_, getChipModes())
- .WillRepeatedly(testing::Return(modes));
- }
-
- void setupV1_AwareDisabledApIfaceCombination() {
- // clang-format off
- const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
- {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
- };
- const std::vector<V1_0::IWifiChip::ChipMode> modes = {
- {feature_flags::chip_mode_ids::kV1Sta, combinationsSta}
- };
- // clang-format on
- EXPECT_CALL(*feature_flags_, getChipModes())
- .WillRepeatedly(testing::Return(modes));
- }
-
- void setupV2_AwareIfaceCombination() {
- // clang-format off
- const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
- {{{{IfaceType::STA}, 1}, {{IfaceType::AP}, 1}}},
- {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
- };
- const std::vector<V1_0::IWifiChip::ChipMode> modes = {
- {feature_flags::chip_mode_ids::kV3, combinations}
- };
- // clang-format on
- EXPECT_CALL(*feature_flags_, getChipModes())
- .WillRepeatedly(testing::Return(modes));
- }
-
- void setupV2_AwareDisabledApIfaceCombination() {
- // clang-format off
- const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
- {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
- };
- const std::vector<V1_0::IWifiChip::ChipMode> modes = {
- {feature_flags::chip_mode_ids::kV3, combinations}
- };
- // clang-format on
- EXPECT_CALL(*feature_flags_, getChipModes())
- .WillRepeatedly(testing::Return(modes));
- }
-
- void setup_MultiIfaceCombination() {
- // clang-format off
- const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
- {{{{IfaceType::STA}, 3}, {{IfaceType::AP}, 1}}}
- };
- const std::vector<V1_0::IWifiChip::ChipMode> modes = {
- {feature_flags::chip_mode_ids::kV3, combinations}
- };
- // clang-format on
- EXPECT_CALL(*feature_flags_, getChipModes())
- .WillRepeatedly(testing::Return(modes));
- }
-
- void assertNumberOfModes(uint32_t num_modes) {
- chip_->getAvailableModes(
- [num_modes](const WifiStatus& status,
- const std::vector<WifiChip::ChipMode>& modes) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- // V2_Aware has 1 mode of operation.
- ASSERT_EQ(num_modes, modes.size());
- });
- }
-
- void findModeAndConfigureForIfaceType(const IfaceType& type) {
- // This should be aligned with kInvalidModeId in wifi_chip.cpp.
- ChipModeId mode_id = UINT32_MAX;
- chip_->getAvailableModes(
- [&mode_id, &type](const WifiStatus& status,
- const std::vector<WifiChip::ChipMode>& modes) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- for (const auto& mode : modes) {
- for (const auto& combination : mode.availableCombinations) {
- for (const auto& limit : combination.limits) {
- if (limit.types.end() !=
- std::find(limit.types.begin(),
- limit.types.end(), type)) {
- mode_id = mode.id;
- }
- }
- }
- }
- });
- ASSERT_NE(UINT32_MAX, mode_id);
-
- chip_->configureChip(mode_id, [](const WifiStatus& status) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- });
- }
-
- // Returns an empty string on error.
- std::string createIface(const IfaceType& type) {
- std::string iface_name;
- if (type == IfaceType::AP) {
- chip_->createApIface([&iface_name](const WifiStatus& status,
- const sp<IWifiApIface>& iface) {
- if (WifiStatusCode::SUCCESS == status.code) {
- ASSERT_NE(iface.get(), nullptr);
- iface->getName([&iface_name](const WifiStatus& status,
- const hidl_string& name) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- iface_name = name.c_str();
- });
- }
- });
- } else if (type == IfaceType::NAN) {
- chip_->createNanIface(
- [&iface_name](
- const WifiStatus& status,
- const sp<android::hardware::wifi::V1_0::IWifiNanIface>&
- iface) {
- if (WifiStatusCode::SUCCESS == status.code) {
- ASSERT_NE(iface.get(), nullptr);
- iface->getName([&iface_name](const WifiStatus& status,
- const hidl_string& name) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- iface_name = name.c_str();
- });
- }
- });
- } else if (type == IfaceType::P2P) {
- chip_->createP2pIface(
- [&iface_name](const WifiStatus& status,
- const sp<IWifiP2pIface>& iface) {
- if (WifiStatusCode::SUCCESS == status.code) {
- ASSERT_NE(iface.get(), nullptr);
- iface->getName([&iface_name](const WifiStatus& status,
- const hidl_string& name) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- iface_name = name.c_str();
- });
- }
- });
- } else if (type == IfaceType::STA) {
- chip_->createStaIface(
- [&iface_name](const WifiStatus& status,
- const sp<V1_0::IWifiStaIface>& iface) {
- if (WifiStatusCode::SUCCESS == status.code) {
- ASSERT_NE(iface.get(), nullptr);
- iface->getName([&iface_name](const WifiStatus& status,
- const hidl_string& name) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- iface_name = name.c_str();
- });
- }
- });
- }
- return iface_name;
- }
-
- void removeIface(const IfaceType& type, const std::string& iface_name) {
- if (type == IfaceType::AP) {
- chip_->removeApIface(iface_name, [](const WifiStatus& status) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- });
- } else if (type == IfaceType::NAN) {
- chip_->removeNanIface(iface_name, [](const WifiStatus& status) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- });
- } else if (type == IfaceType::P2P) {
- chip_->removeP2pIface(iface_name, [](const WifiStatus& status) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- });
- } else if (type == IfaceType::STA) {
- chip_->removeStaIface(iface_name, [](const WifiStatus& status) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- });
- }
- }
-
- bool createRttController() {
- bool success = false;
- chip_->createRttController(
- NULL, [&success](const WifiStatus& status,
- const sp<IWifiRttController>& rtt) {
- if (WifiStatusCode::SUCCESS == status.code) {
- ASSERT_NE(rtt.get(), nullptr);
- success = true;
- }
- });
- return success;
- }
-
- sp<WifiChip> chip_;
- ChipId chip_id_ = kFakeChipId;
- std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
- new NiceMock<wifi_system::MockInterfaceTool>};
- std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
- new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
- std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>>
- mode_controller_{new NiceMock<mode_controller::MockWifiModeController>};
- std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
- new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
- std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
- feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
-
- public:
- void SetUp() override {
- chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_,
- iface_util_, feature_flags_);
-
- EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
- .WillRepeatedly(testing::Return(true));
- EXPECT_CALL(*legacy_hal_, start())
- .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
- }
-
- void TearDown() override {
- // Restore default system iface names (This should ideally be using a
- // mock).
- property_set("wifi.interface", "wlan0");
- property_set("wifi.concurrent.interface", "wlan1");
- }
-};
-
-////////// V1 Iface Combinations ////////////
-// Mode 1 - STA + P2P
-// Mode 2 - AP
-class WifiChipV1IfaceCombinationTest : public WifiChipTest {
- public:
- void SetUp() override {
- setupV1IfaceCombination();
- WifiChipTest::SetUp();
- // V1 has 2 modes of operation.
- assertNumberOfModes(2u);
- }
-};
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_TRUE(createIface(IfaceType::AP).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-////////// V1 + Aware Iface Combinations ////////////
-// Mode 1 - STA + P2P/NAN
-// Mode 2 - AP
-class WifiChipV1_AwareIfaceCombinationTest : public WifiChipTest {
- public:
- void SetUp() override {
- setupV1_AwareIfaceCombination();
- WifiChipTest::SetUp();
- // V1_Aware has 2 modes of operation.
- assertNumberOfModes(2u);
- }
-};
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_TRUE(createIface(IfaceType::AP).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
- StaMode_CreateStaP2p_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
- StaMode_CreateStaNan_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
- StaMode_CreateStaP2PNan_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_FALSE(createIface(IfaceType::P2P).empty());
- ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
- StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- const auto p2p_iface_name = createIface(IfaceType::P2P);
- ASSERT_FALSE(p2p_iface_name.empty());
- ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-
- // After removing P2P iface, NAN iface creation should succeed.
- removeIface(IfaceType::P2P, p2p_iface_name);
- ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
- StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- const auto nan_iface_name = createIface(IfaceType::NAN);
- ASSERT_FALSE(nan_iface_name.empty());
- ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-
- // After removing NAN iface, P2P iface creation should succeed.
- removeIface(IfaceType::NAN, nan_iface_name);
- ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowApToSta) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- const auto ap_iface_name = createIface(IfaceType::AP);
- ASSERT_FALSE(ap_iface_name.empty());
- ASSERT_FALSE(createRttController());
-
- removeIface(IfaceType::AP, ap_iface_name);
-
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
- EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
- .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
- chip_->selectTxPowerScenario_1_2(
- V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
- [](const WifiStatus& status) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- });
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
- EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
- .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
- chip_->selectTxPowerScenario_1_2(
- V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
- [](const WifiStatus& status) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- });
-}
-
-////////// V2 + Aware Iface Combinations ////////////
-// Mode 1 - STA + STA/AP
-// - STA + P2P/NAN
-class WifiChipV2_AwareIfaceCombinationTest : public WifiChipTest {
- public:
- void SetUp() override {
- setupV2_AwareIfaceCombination();
- WifiChipTest::SetUp();
- // V2_Aware has 1 mode of operation.
- assertNumberOfModes(1u);
- }
-};
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
- ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
- ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApSta_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
- ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
- CreateSta_AfterStaApRemove_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- const auto sta_iface_name = createIface(IfaceType::STA);
- ASSERT_FALSE(sta_iface_name.empty());
- const auto ap_iface_name = createIface(IfaceType::AP);
- ASSERT_FALSE(ap_iface_name.empty());
-
- ASSERT_TRUE(createIface(IfaceType::STA).empty());
-
- // After removing AP & STA iface, STA iface creation should succeed.
- removeIface(IfaceType::STA, sta_iface_name);
- removeIface(IfaceType::AP, ap_iface_name);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_FALSE(createIface(IfaceType::P2P).empty());
- ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
- CreateStaNan_AfterP2pRemove_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- const auto p2p_iface_name = createIface(IfaceType::P2P);
- ASSERT_FALSE(p2p_iface_name.empty());
- ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-
- // After removing P2P iface, NAN iface creation should succeed.
- removeIface(IfaceType::P2P, p2p_iface_name);
- ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
- CreateStaP2p_AfterNanRemove_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- const auto nan_iface_name = createIface(IfaceType::NAN);
- ASSERT_FALSE(nan_iface_name.empty());
- ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-
- // After removing NAN iface, P2P iface creation should succeed.
- removeIface(IfaceType::NAN, nan_iface_name);
- ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_FALSE(createIface(IfaceType::AP).empty());
- ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_FALSE(createIface(IfaceType::AP).empty());
- ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
- StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- const auto p2p_iface_name = createIface(IfaceType::P2P);
- ASSERT_FALSE(p2p_iface_name.empty());
- ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-
- // After removing P2P iface, NAN iface creation should succeed.
- removeIface(IfaceType::P2P, p2p_iface_name);
- ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
- StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- const auto nan_iface_name = createIface(IfaceType::NAN);
- ASSERT_FALSE(nan_iface_name.empty());
- ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-
- // After removing NAN iface, P2P iface creation should succeed.
- removeIface(IfaceType::NAN, nan_iface_name);
- ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
- CreateStaAp_EnsureDifferentIfaceNames) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- const auto sta_iface_name = createIface(IfaceType::STA);
- const auto ap_iface_name = createIface(IfaceType::AP);
- ASSERT_FALSE(sta_iface_name.empty());
- ASSERT_FALSE(ap_iface_name.empty());
- ASSERT_NE(sta_iface_name, ap_iface_name);
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlow) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_FALSE(createIface(IfaceType::AP).empty());
- ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
- EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
- .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
- chip_->selectTxPowerScenario_1_2(
- V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
- [](const WifiStatus& status) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- });
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
- findModeAndConfigureForIfaceType(IfaceType::AP);
- ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
- EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan1", testing::_))
- .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
- chip_->selectTxPowerScenario_1_2(
- V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
- [](const WifiStatus& status) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- });
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
- InvalidateAndRemoveNanOnStaRemove) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-
- // Create NAN iface
- ASSERT_EQ(createIface(IfaceType::NAN), "wlan0");
-
- // We should have 1 nan iface.
- chip_->getNanIfaceNames(
- [](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- ASSERT_EQ(iface_names.size(), 1u);
- 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;
- });
-
- // Remove the STA iface.
- removeIface(IfaceType::STA, "wlan0");
- // We should have 0 nan iface now.
- chip_->getNanIfaceNames(
- [](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- ASSERT_EQ(iface_names.size(), 0u);
- });
- // Any operation on the nan iface object should return error now.
- nan_iface->getName(
- [](const WifiStatus& status, const std::string& /* iface_name */) {
- ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID, status.code);
- });
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
- InvalidateAndRemoveRttControllerOnStaRemove) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-
- // Create RTT controller
- sp<IWifiRttController> rtt_controller;
- chip_->createRttController(
- NULL, [&rtt_controller](const WifiStatus& status,
- const sp<IWifiRttController>& rtt) {
- if (WifiStatusCode::SUCCESS == status.code) {
- ASSERT_NE(rtt.get(), nullptr);
- rtt_controller = rtt;
- }
- });
-
- // Remove the STA iface.
- removeIface(IfaceType::STA, "wlan0");
-
- // Any operation on the rtt controller object should return error now.
- rtt_controller->getBoundIface(
- [](const WifiStatus& status, const sp<IWifiIface>& /* iface */) {
- ASSERT_EQ(WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
- status.code);
- });
-}
-
-////////// V1 Iface Combinations when AP creation is disabled //////////
-class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
- public:
- void SetUp() override {
- setupV1_AwareDisabledApIfaceCombination();
- WifiChipTest::SetUp();
- }
-};
-
-TEST_F(WifiChipV1_AwareDisabledApIfaceCombinationTest,
- StaMode_CreateSta_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_TRUE(createIface(IfaceType::AP).empty());
-}
-
-////////// V2 Iface Combinations when AP creation is disabled //////////
-class WifiChipV2_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
- public:
- void SetUp() override {
- setupV2_AwareDisabledApIfaceCombination();
- WifiChipTest::SetUp();
- }
-};
-
-TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest,
- CreateSta_ShouldSucceed) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_TRUE(createIface(IfaceType::AP).empty());
-}
-
-////////// Hypothetical Iface Combination with multiple ifaces //////////
-class WifiChip_MultiIfaceTest : public WifiChipTest {
- public:
- void SetUp() override {
- setup_MultiIfaceCombination();
- WifiChipTest::SetUp();
- }
-};
-
-TEST_F(WifiChip_MultiIfaceTest, Create3Sta) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_FALSE(createIface(IfaceType::STA).empty());
- ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChip_MultiIfaceTest, CreateStaWithDefaultNames) {
- property_set("wifi.interface.0", "");
- property_set("wifi.interface.1", "");
- property_set("wifi.interface.2", "");
- property_set("wifi.interface", "");
- property_set("wifi.concurrent.interface", "");
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
- ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
- ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
-}
-
-TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomNames) {
- property_set("wifi.interface.0", "test0");
- property_set("wifi.interface.1", "test1");
- property_set("wifi.interface.2", "test2");
- property_set("wifi.interface", "bad0");
- property_set("wifi.concurrent.interface", "bad1");
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_EQ(createIface(IfaceType::STA), "bad0");
- ASSERT_EQ(createIface(IfaceType::STA), "bad1");
- ASSERT_EQ(createIface(IfaceType::STA), "test2");
-}
-
-TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomAltNames) {
- property_set("wifi.interface.0", "");
- property_set("wifi.interface.1", "");
- property_set("wifi.interface.2", "");
- property_set("wifi.interface", "testA0");
- property_set("wifi.concurrent.interface", "testA1");
- findModeAndConfigureForIfaceType(IfaceType::STA);
- ASSERT_EQ(createIface(IfaceType::STA), "testA0");
- ASSERT_EQ(createIface(IfaceType::STA), "testA1");
- ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
-}
-
-TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) {
- findModeAndConfigureForIfaceType(IfaceType::STA);
- // First AP will be slotted to wlan1.
- ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
- // First STA will be slotted to wlan0.
- ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
- // All further STA will be slotted to the remaining free indices.
- ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
- ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
-}
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/1.3/default/tests/wifi_iface_util_unit_tests.cpp
deleted file mode 100644
index 28d23ff..0000000
--- a/wifi/1.3/default/tests/wifi_iface_util_unit_tests.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN
-#include "wifi_iface_util.h"
-
-#include "mock_interface_tool.h"
-
-using testing::NiceMock;
-using testing::Test;
-
-namespace {
-constexpr uint8_t kValidUnicastLocallyAssignedMacAddressMask = 0x02;
-constexpr uint8_t kMacAddress[] = {0x02, 0x12, 0x45, 0x56, 0xab, 0xcc};
-constexpr char kIfaceName[] = "test-wlan0";
-
-bool isValidUnicastLocallyAssignedMacAddress(
- const std::array<uint8_t, 6>& mac_address) {
- uint8_t first_byte = mac_address[0];
- return (first_byte & 0x3) == kValidUnicastLocallyAssignedMacAddressMask;
-}
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace iface_util {
-class WifiIfaceUtilTest : public Test {
- protected:
- std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
- new NiceMock<wifi_system::MockInterfaceTool>};
- WifiIfaceUtil* iface_util_ = new WifiIfaceUtil(iface_tool_);
-};
-
-TEST_F(WifiIfaceUtilTest, GetOrCreateRandomMacAddress) {
- auto mac_address = iface_util_->getOrCreateRandomMacAddress();
- ASSERT_TRUE(isValidUnicastLocallyAssignedMacAddress(mac_address));
-
- // All further calls should return the same MAC address.
- ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
- ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
-}
-
-TEST_F(WifiIfaceUtilTest, IfaceEventHandlers_SetMacAddress) {
- std::array<uint8_t, 6> mac_address = {};
- std::copy(std::begin(kMacAddress), std::end(kMacAddress),
- std::begin(mac_address));
- EXPECT_CALL(*iface_tool_, SetMacAddress(testing::_, testing::_))
- .WillRepeatedly(testing::Return(true));
- EXPECT_CALL(*iface_tool_, SetUpState(testing::_, testing::_))
- .WillRepeatedly(testing::Return(true));
-
- // Register for iface state toggle events.
- bool callback_invoked = false;
- iface_util::IfaceEventHandlers event_handlers = {};
- event_handlers.on_state_toggle_off_on =
- [&callback_invoked](const std::string& /* iface_name */) {
- callback_invoked = true;
- };
- iface_util_->registerIfaceEventHandlers(kIfaceName, event_handlers);
- // Invoke setMacAddress and ensure that the cb is invoked.
- ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
- ASSERT_TRUE(callback_invoked);
-
- // Unregister for iface state toggle events.
- callback_invoked = false;
- iface_util_->unregisterIfaceEventHandlers(kIfaceName);
- // Invoke setMacAddress and ensure that the cb is not invoked.
- ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
- ASSERT_FALSE(callback_invoked);
-}
-} // namespace iface_util
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.3/default/tests/wifi_nan_iface_unit_tests.cpp
deleted file mode 100644
index eb6c610..0000000
--- a/wifi/1.3/default/tests/wifi_nan_iface_unit_tests.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <cutils/properties.h>
-#include <gmock/gmock.h>
-
-#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "wifi_nan_iface.h"
-
-#include "mock_interface_tool.h"
-#include "mock_wifi_feature_flags.h"
-#include "mock_wifi_iface_util.h"
-#include "mock_wifi_legacy_hal.h"
-
-using testing::NiceMock;
-using testing::Return;
-using testing::Test;
-
-namespace {
-constexpr char kIfaceName[] = "mockWlan0";
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-bool CaptureIfaceEventHandlers(
- const std::string& /* iface_name*/,
- iface_util::IfaceEventHandlers in_iface_event_handlers,
- iface_util::IfaceEventHandlers* out_iface_event_handlers) {
- *out_iface_event_handlers = in_iface_event_handlers;
- return true;
-}
-
-class MockNanIfaceEventCallback : public IWifiNanIfaceEventCallback {
- public:
- MockNanIfaceEventCallback() = default;
-
- MOCK_METHOD3(notifyCapabilitiesResponse,
- Return<void>(uint16_t, const WifiNanStatus&,
- const NanCapabilities&));
- MOCK_METHOD2(notifyEnableResponse,
- Return<void>(uint16_t, const WifiNanStatus&));
- MOCK_METHOD2(notifyConfigResponse,
- Return<void>(uint16_t, const WifiNanStatus&));
- MOCK_METHOD2(notifyDisableResponse,
- Return<void>(uint16_t, const WifiNanStatus&));
- MOCK_METHOD3(notifyStartPublishResponse,
- Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
- MOCK_METHOD2(notifyStopPublishResponse,
- Return<void>(uint16_t, const WifiNanStatus&));
- MOCK_METHOD3(notifyStartSubscribeResponse,
- Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
- MOCK_METHOD2(notifyStopSubscribeResponse,
- Return<void>(uint16_t, const WifiNanStatus&));
- MOCK_METHOD2(notifyTransmitFollowupResponse,
- Return<void>(uint16_t, const WifiNanStatus&));
- MOCK_METHOD2(notifyCreateDataInterfaceResponse,
- Return<void>(uint16_t, const WifiNanStatus&));
- MOCK_METHOD2(notifyDeleteDataInterfaceResponse,
- Return<void>(uint16_t, const WifiNanStatus&));
- MOCK_METHOD3(notifyInitiateDataPathResponse,
- Return<void>(uint16_t, const WifiNanStatus&, uint32_t));
- MOCK_METHOD2(notifyRespondToDataPathIndicationResponse,
- Return<void>(uint16_t, const WifiNanStatus&));
- MOCK_METHOD2(notifyTerminateDataPathResponse,
- Return<void>(uint16_t, const WifiNanStatus&));
- MOCK_METHOD1(eventClusterEvent, Return<void>(const NanClusterEventInd&));
- MOCK_METHOD1(eventDisabled, Return<void>(const WifiNanStatus&));
- MOCK_METHOD2(eventPublishTerminated,
- Return<void>(uint8_t, const WifiNanStatus&));
- MOCK_METHOD2(eventSubscribeTerminated,
- Return<void>(uint8_t, const WifiNanStatus&));
- MOCK_METHOD1(eventMatch, Return<void>(const NanMatchInd&));
- MOCK_METHOD2(eventMatchExpired, Return<void>(uint8_t, uint32_t));
- MOCK_METHOD1(eventFollowupReceived,
- Return<void>(const NanFollowupReceivedInd&));
- MOCK_METHOD2(eventTransmitFollowup,
- Return<void>(uint16_t, const WifiNanStatus&));
- MOCK_METHOD1(eventDataPathRequest,
- Return<void>(const NanDataPathRequestInd&));
- MOCK_METHOD1(eventDataPathConfirm,
- Return<void>(const NanDataPathConfirmInd&));
- MOCK_METHOD1(eventDataPathTerminated, Return<void>(uint32_t));
-};
-
-class WifiNanIfaceTest : public Test {
- protected:
- std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
- new NiceMock<wifi_system::MockInterfaceTool>};
- std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
- new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
- std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
- new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
-};
-
-TEST_F(WifiNanIfaceTest, IfacEventHandlers_OnStateToggleOffOn) {
- iface_util::IfaceEventHandlers captured_iface_event_handlers = {};
- EXPECT_CALL(*legacy_hal_,
- nanRegisterCallbackHandlers(testing::_, testing::_))
- .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
- EXPECT_CALL(*iface_util_,
- registerIfaceEventHandlers(testing::_, testing::_))
- .WillOnce(testing::Invoke(
- bind(CaptureIfaceEventHandlers, std::placeholders::_1,
- std::placeholders::_2, &captured_iface_event_handlers)));
- sp<WifiNanIface> nan_iface =
- new WifiNanIface(kIfaceName, legacy_hal_, iface_util_);
-
- // Register a mock nan event callback.
- sp<NiceMock<MockNanIfaceEventCallback>> mock_event_callback{
- new NiceMock<MockNanIfaceEventCallback>};
- nan_iface->registerEventCallback(
- mock_event_callback, [](const WifiStatus& status) {
- ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
- });
- // Ensure that the eventDisabled() function in mock callback will be
- // invoked.
- WifiNanStatus expected_nan_status = {
- NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
- EXPECT_CALL(*mock_event_callback, eventDisabled(expected_nan_status))
- .Times(1);
-
- // Trigger the iface state toggle callback.
- captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName);
-}
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi.cpp b/wifi/1.3/default/wifi.cpp
deleted file mode 100644
index 2f21819..0000000
--- a/wifi/1.3/default/wifi.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "wifi.h"
-#include "wifi_status_util.h"
-
-namespace {
-// Chip ID to use for the only supported chip.
-static constexpr android::hardware::wifi::V1_0::ChipId kChipId = 0;
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-using hidl_return_util::validateAndCallWithLock;
-
-Wifi::Wifi(
- const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
- const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
- const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
- const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
- : iface_tool_(iface_tool),
- legacy_hal_(legacy_hal),
- mode_controller_(mode_controller),
- iface_util_(iface_util),
- feature_flags_(feature_flags),
- run_state_(RunState::STOPPED) {}
-
-bool Wifi::isValid() {
- // This object is always valid.
- return true;
-}
-
-Return<void> Wifi::registerEventCallback(
- const sp<IWifiEventCallback>& event_callback,
- registerEventCallback_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
- &Wifi::registerEventCallbackInternal, hidl_status_cb,
- event_callback);
-}
-
-Return<bool> Wifi::isStarted() { return run_state_ != RunState::STOPPED; }
-
-Return<void> Wifi::start(start_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
- &Wifi::startInternal, hidl_status_cb);
-}
-
-Return<void> Wifi::stop(stop_cb hidl_status_cb) {
- return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN,
- &Wifi::stopInternal, hidl_status_cb);
-}
-
-Return<void> Wifi::getChipIds(getChipIds_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
- &Wifi::getChipIdsInternal, hidl_status_cb);
-}
-
-Return<void> Wifi::getChip(ChipId chip_id, getChip_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
- &Wifi::getChipInternal, hidl_status_cb, chip_id);
-}
-
-Return<void> Wifi::debug(const hidl_handle& handle,
- const hidl_vec<hidl_string>&) {
- LOG(INFO) << "-----------Debug is called----------------";
- if (!chip_.get()) {
- return Void();
- }
- return chip_->debug(handle, {});
-}
-
-WifiStatus Wifi::registerEventCallbackInternal(
- const sp<IWifiEventCallback>& event_callback) {
- if (!event_cb_handler_.addCallback(event_callback)) {
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
- }
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus Wifi::startInternal() {
- if (run_state_ == RunState::STARTED) {
- return createWifiStatus(WifiStatusCode::SUCCESS);
- } else if (run_state_ == RunState::STOPPING) {
- return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
- "HAL is stopping");
- }
- WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
- if (wifi_status.code == WifiStatusCode::SUCCESS) {
- // Create the chip instance once the HAL is started.
- chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_,
- iface_util_, feature_flags_);
- run_state_ = RunState::STARTED;
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onStart().isOk()) {
- LOG(ERROR) << "Failed to invoke onStart callback";
- };
- }
- LOG(INFO) << "Wifi HAL started";
- } else {
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onFailure(wifi_status).isOk()) {
- LOG(ERROR) << "Failed to invoke onFailure callback";
- }
- }
- LOG(ERROR) << "Wifi HAL start failed";
- }
- return wifi_status;
-}
-
-WifiStatus Wifi::stopInternal(
- /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
- if (run_state_ == RunState::STOPPED) {
- return createWifiStatus(WifiStatusCode::SUCCESS);
- } else if (run_state_ == RunState::STOPPING) {
- return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
- "HAL is stopping");
- }
- // Clear the chip object and its child objects since the HAL is now
- // stopped.
- if (chip_.get()) {
- chip_->invalidate();
- chip_.clear();
- }
- WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
- if (wifi_status.code == WifiStatusCode::SUCCESS) {
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onStop().isOk()) {
- LOG(ERROR) << "Failed to invoke onStop callback";
- };
- }
- LOG(INFO) << "Wifi HAL stopped";
- } else {
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onFailure(wifi_status).isOk()) {
- LOG(ERROR) << "Failed to invoke onFailure callback";
- }
- }
- LOG(ERROR) << "Wifi HAL stop failed";
- }
- return wifi_status;
-}
-
-std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
- std::vector<ChipId> chip_ids;
- if (chip_.get()) {
- chip_ids.emplace_back(kChipId);
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
-}
-
-std::pair<WifiStatus, sp<IWifiChip>> Wifi::getChipInternal(ChipId chip_id) {
- if (!chip_.get()) {
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_STARTED), nullptr};
- }
- if (chip_id != kChipId) {
- return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), chip_};
-}
-
-WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
- if (!mode_controller_->initialize()) {
- LOG(ERROR) << "Failed to initialize firmware mode controller";
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
- }
- legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to initialize legacy HAL: "
- << legacyErrorToString(legacy_status);
- return createWifiStatusFromLegacyError(legacy_status);
- }
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
- /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
- run_state_ = RunState::STOPPING;
- legacy_hal::wifi_error legacy_status =
- legacy_hal_->stop(lock, [&]() { run_state_ = RunState::STOPPED; });
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to stop legacy HAL: "
- << legacyErrorToString(legacy_status);
- return createWifiStatusFromLegacyError(legacy_status);
- }
- if (!mode_controller_->deinitialize()) {
- LOG(ERROR) << "Failed to deinitialize firmware mode controller";
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
- }
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi.h b/wifi/1.3/default/wifi.h
deleted file mode 100644
index 1c2a154..0000000
--- a/wifi/1.3/default/wifi.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_H_
-#define WIFI_H_
-
-#include <functional>
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.3/IWifi.h>
-#include <utils/Looper.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_chip.h"
-#include "wifi_feature_flags.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_mode_controller.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-/**
- * Root HIDL interface object used to control the Wifi HAL.
- */
-class Wifi : public V1_3::IWifi {
- public:
- Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
- const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::shared_ptr<mode_controller::WifiModeController>
- mode_controller,
- const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
- const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags);
-
- bool isValid();
-
- // HIDL methods exposed.
- Return<void> registerEventCallback(
- const sp<IWifiEventCallback>& event_callback,
- registerEventCallback_cb hidl_status_cb) override;
- Return<bool> isStarted() override;
- Return<void> start(start_cb hidl_status_cb) override;
- Return<void> stop(stop_cb hidl_status_cb) override;
- Return<void> getChipIds(getChipIds_cb hidl_status_cb) override;
- Return<void> getChip(ChipId chip_id, getChip_cb hidl_status_cb) override;
- Return<void> debug(const hidl_handle& handle,
- const hidl_vec<hidl_string>& options) override;
-
- private:
- enum class RunState { STOPPED, STARTED, STOPPING };
-
- // Corresponding worker functions for the HIDL methods.
- WifiStatus registerEventCallbackInternal(
- const sp<IWifiEventCallback>& event_callback);
- WifiStatus startInternal();
- WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
- std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
- std::pair<WifiStatus, sp<IWifiChip>> getChipInternal(ChipId chip_id);
-
- WifiStatus initializeModeControllerAndLegacyHal();
- WifiStatus stopLegacyHalAndDeinitializeModeController(
- std::unique_lock<std::recursive_mutex>* lock);
-
- // Instance is created in this root level |IWifi| HIDL interface object
- // and shared with all the child HIDL interface objects.
- std::shared_ptr<wifi_system::InterfaceTool> iface_tool_;
- std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
- std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
- std::shared_ptr<iface_util::WifiIfaceUtil> iface_util_;
- std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
- RunState run_state_;
- sp<WifiChip> chip_;
- hidl_callback_util::HidlCallbackHandler<IWifiEventCallback>
- event_cb_handler_;
-
- DISALLOW_COPY_AND_ASSIGN(Wifi);
-};
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_H_
diff --git a/wifi/1.3/default/wifi_ap_iface.cpp b/wifi/1.3/default/wifi_ap_iface.cpp
deleted file mode 100644
index 9a8681a..0000000
--- a/wifi/1.3/default/wifi_ap_iface.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_ap_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiApIface::WifiApIface(
- const std::string& ifname,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
- const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
- : ifname_(ifname),
- legacy_hal_(legacy_hal),
- iface_util_(iface_util),
- feature_flags_(feature_flags),
- is_valid_(true) {
- if (feature_flags_.lock()->isApMacRandomizationDisabled()) {
- LOG(INFO) << "AP MAC randomization disabled";
- return;
- }
- LOG(INFO) << "AP MAC randomization enabled";
- // Set random MAC address
- std::array<uint8_t, 6> randomized_mac =
- iface_util_.lock()->getOrCreateRandomMacAddress();
- bool status = iface_util_.lock()->setMacAddress(ifname_, randomized_mac);
- if (!status) {
- LOG(ERROR) << "Failed to set random mac address";
- }
-}
-
-void WifiApIface::invalidate() {
- legacy_hal_.reset();
- is_valid_ = false;
-}
-
-bool WifiApIface::isValid() { return is_valid_; }
-
-std::string WifiApIface::getName() { return ifname_; }
-
-Return<void> WifiApIface::getName(getName_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiApIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiApIface::getType(getType_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiApIface::getTypeInternal, hidl_status_cb);
-}
-
-Return<void> WifiApIface::setCountryCode(const hidl_array<int8_t, 2>& code,
- setCountryCode_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiApIface::setCountryCodeInternal, hidl_status_cb,
- code);
-}
-
-Return<void> WifiApIface::getValidFrequenciesForBand(
- WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiApIface::getValidFrequenciesForBandInternal,
- hidl_status_cb, band);
-}
-
-std::pair<WifiStatus, std::string> WifiApIface::getNameInternal() {
- return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiApIface::getTypeInternal() {
- return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::AP};
-}
-
-WifiStatus WifiApIface::setCountryCodeInternal(
- const std::array<int8_t, 2>& code) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->setCountryCode(ifname_, code);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-WifiApIface::getValidFrequenciesForBandInternal(WifiBand band) {
- static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
- "Size mismatch");
- legacy_hal::wifi_error legacy_status;
- std::vector<uint32_t> valid_frequencies;
- std::tie(legacy_status, valid_frequencies) =
- legacy_hal_.lock()->getValidFrequenciesForBand(
- ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
- return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
-}
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi_ap_iface.h b/wifi/1.3/default/wifi_ap_iface.h
deleted file mode 100644
index 98c5c9c..0000000
--- a/wifi/1.3/default/wifi_ap_iface.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_AP_IFACE_H_
-#define WIFI_AP_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiApIface.h>
-
-#include "wifi_feature_flags.h"
-#include "wifi_iface_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a AP Iface instance.
- */
-class WifiApIface : public V1_0::IWifiApIface {
- public:
- WifiApIface(
- const std::string& ifname,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
- const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
- // Refer to |WifiChip::invalidate()|.
- void invalidate();
- bool isValid();
- std::string getName();
-
- // HIDL methods exposed.
- Return<void> getName(getName_cb hidl_status_cb) override;
- Return<void> getType(getType_cb hidl_status_cb) override;
- Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
- setCountryCode_cb hidl_status_cb) override;
- Return<void> getValidFrequenciesForBand(
- WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override;
-
- private:
- // Corresponding worker functions for the HIDL methods.
- std::pair<WifiStatus, std::string> getNameInternal();
- std::pair<WifiStatus, IfaceType> getTypeInternal();
- WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
- std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
- getValidFrequenciesForBandInternal(WifiBand band);
-
- std::string ifname_;
- std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
- std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
- std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
- bool is_valid_;
-
- DISALLOW_COPY_AND_ASSIGN(WifiApIface);
-};
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_AP_IFACE_H_
diff --git a/wifi/1.3/default/wifi_chip.cpp b/wifi/1.3/default/wifi_chip.cpp
deleted file mode 100644
index e9991dc..0000000
--- a/wifi/1.3/default/wifi_chip.cpp
+++ /dev/null
@@ -1,1545 +0,0 @@
-/*
- * 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.
- */
-
-#include <fcntl.h>
-
-#include <android-base/logging.h>
-#include <android-base/unique_fd.h>
-#include <cutils/properties.h>
-#include <sys/stat.h>
-#include <sys/sysmacros.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_chip.h"
-#include "wifi_status_util.h"
-
-namespace {
-using android::sp;
-using android::base::unique_fd;
-using android::hardware::hidl_string;
-using android::hardware::hidl_vec;
-using android::hardware::wifi::V1_0::ChipModeId;
-using android::hardware::wifi::V1_0::IfaceType;
-using android::hardware::wifi::V1_0::IWifiChip;
-
-constexpr char kCpioMagic[] = "070701";
-constexpr size_t kMaxBufferSizeBytes = 1024 * 1024 * 3;
-constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60 * 10;
-constexpr uint32_t kMaxRingBufferFileNum = 20;
-constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/";
-constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface";
-constexpr char kNoActiveWlanIfaceNamePropertyValue[] = "";
-constexpr unsigned kMaxWlanIfaces = 5;
-
-template <typename Iface>
-void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
- iface->invalidate();
- ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface),
- ifaces.end());
-}
-
-template <typename Iface>
-void invalidateAndClearAll(std::vector<sp<Iface>>& ifaces) {
- for (const auto& iface : ifaces) {
- iface->invalidate();
- }
- ifaces.clear();
-}
-
-template <typename Iface>
-std::vector<hidl_string> getNames(std::vector<sp<Iface>>& ifaces) {
- std::vector<hidl_string> names;
- for (const auto& iface : ifaces) {
- names.emplace_back(iface->getName());
- }
- return names;
-}
-
-template <typename Iface>
-sp<Iface> findUsingName(std::vector<sp<Iface>>& ifaces,
- const std::string& name) {
- std::vector<hidl_string> names;
- for (const auto& iface : ifaces) {
- if (name == iface->getName()) {
- return iface;
- }
- }
- return nullptr;
-}
-
-std::string getWlanIfaceName(unsigned idx) {
- if (idx >= kMaxWlanIfaces) {
- CHECK(false) << "Requested interface beyond wlan" << kMaxWlanIfaces;
- return {};
- }
-
- std::array<char, PROPERTY_VALUE_MAX> buffer;
- if (idx == 0 || idx == 1) {
- const char* altPropName =
- (idx == 0) ? "wifi.interface" : "wifi.concurrent.interface";
- auto res = property_get(altPropName, buffer.data(), nullptr);
- if (res > 0) return buffer.data();
- }
- std::string propName = "wifi.interface." + std::to_string(idx);
- auto res = property_get(propName.c_str(), buffer.data(), nullptr);
- if (res > 0) return buffer.data();
-
- return "wlan" + std::to_string(idx);
-}
-
-std::string getP2pIfaceName() {
- std::array<char, PROPERTY_VALUE_MAX> buffer;
- property_get("wifi.direct.interface", buffer.data(), "p2p0");
- return buffer.data();
-}
-
-void setActiveWlanIfaceNameProperty(const std::string& ifname) {
- auto res = property_set(kActiveWlanIfaceNameProperty, ifname.data());
- if (res != 0) {
- PLOG(ERROR) << "Failed to set active wlan iface name property";
- }
-}
-
-// delete files that meet either conditions:
-// 1. older than a predefined time in the wifi tombstone dir.
-// 2. Files in excess to a predefined amount, starting from the oldest ones
-bool removeOldFilesInternal() {
- time_t now = time(0);
- const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
- std::unique_ptr<DIR, decltype(&closedir)> dir_dump(
- opendir(kTombstoneFolderPath), closedir);
- if (!dir_dump) {
- PLOG(ERROR) << "Failed to open directory";
- return false;
- }
- struct dirent* dp;
- bool success = true;
- std::list<std::pair<const time_t, std::string>> valid_files;
- while ((dp = readdir(dir_dump.get()))) {
- if (dp->d_type != DT_REG) {
- continue;
- }
- std::string cur_file_name(dp->d_name);
- struct stat cur_file_stat;
- std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
- if (stat(cur_file_path.c_str(), &cur_file_stat) == -1) {
- PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
- success = false;
- continue;
- }
- const time_t cur_file_time = cur_file_stat.st_mtime;
- valid_files.push_back(
- std::pair<const time_t, std::string>(cur_file_time, cur_file_path));
- }
- valid_files.sort(); // sort the list of files by last modified time from
- // small to big.
- uint32_t cur_file_count = valid_files.size();
- for (auto cur_file : valid_files) {
- if (cur_file_count > kMaxRingBufferFileNum ||
- cur_file.first < delete_files_before) {
- if (unlink(cur_file.second.c_str()) != 0) {
- PLOG(ERROR) << "Error deleting file";
- success = false;
- }
- cur_file_count--;
- } else {
- break;
- }
- }
- return success;
-}
-
-// Helper function for |cpioArchiveFilesInDir|
-bool cpioWriteHeader(int out_fd, struct stat& st, const char* file_name,
- size_t file_name_len) {
- std::array<char, 32 * 1024> read_buf;
- ssize_t llen =
- sprintf(read_buf.data(),
- "%s%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
- kCpioMagic, static_cast<int>(st.st_ino), st.st_mode, st.st_uid,
- st.st_gid, static_cast<int>(st.st_nlink),
- static_cast<int>(st.st_mtime), static_cast<int>(st.st_size),
- major(st.st_dev), minor(st.st_dev), major(st.st_rdev),
- minor(st.st_rdev), static_cast<uint32_t>(file_name_len), 0);
- if (write(out_fd, read_buf.data(), llen) == -1) {
- PLOG(ERROR) << "Error writing cpio header to file " << file_name;
- return false;
- }
- if (write(out_fd, file_name, file_name_len) == -1) {
- PLOG(ERROR) << "Error writing filename to file " << file_name;
- return false;
- }
-
- // NUL Pad header up to 4 multiple bytes.
- llen = (llen + file_name_len) % 4;
- if (llen != 0) {
- const uint32_t zero = 0;
- if (write(out_fd, &zero, 4 - llen) == -1) {
- PLOG(ERROR) << "Error padding 0s to file " << file_name;
- return false;
- }
- }
- return true;
-}
-
-// Helper function for |cpioArchiveFilesInDir|
-size_t cpioWriteFileContent(int fd_read, int out_fd, struct stat& st) {
- // writing content of file
- std::array<char, 32 * 1024> read_buf;
- ssize_t llen = st.st_size;
- size_t n_error = 0;
- while (llen > 0) {
- ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size());
- if (bytes_read == -1) {
- PLOG(ERROR) << "Error reading file";
- return ++n_error;
- }
- llen -= bytes_read;
- if (write(out_fd, read_buf.data(), bytes_read) == -1) {
- PLOG(ERROR) << "Error writing data to file";
- return ++n_error;
- }
- if (bytes_read == 0) { // this should never happen, but just in case
- // to unstuck from while loop
- PLOG(ERROR) << "Unexpected read result";
- n_error++;
- break;
- }
- }
- llen = st.st_size % 4;
- if (llen != 0) {
- const uint32_t zero = 0;
- if (write(out_fd, &zero, 4 - llen) == -1) {
- PLOG(ERROR) << "Error padding 0s to file";
- return ++n_error;
- }
- }
- return n_error;
-}
-
-// Helper function for |cpioArchiveFilesInDir|
-bool cpioWriteFileTrailer(int out_fd) {
- std::array<char, 4096> read_buf;
- read_buf.fill(0);
- if (write(out_fd, read_buf.data(),
- sprintf(read_buf.data(), "070701%040X%056X%08XTRAILER!!!", 1,
- 0x0b, 0) +
- 4) == -1) {
- PLOG(ERROR) << "Error writing trailing bytes";
- return false;
- }
- return true;
-}
-
-// Archives all files in |input_dir| and writes result into |out_fd|
-// Logic obtained from //external/toybox/toys/posix/cpio.c "Output cpio archive"
-// portion
-size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
- struct dirent* dp;
- size_t n_error = 0;
- std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir),
- closedir);
- if (!dir_dump) {
- PLOG(ERROR) << "Failed to open directory";
- return ++n_error;
- }
- while ((dp = readdir(dir_dump.get()))) {
- if (dp->d_type != DT_REG) {
- continue;
- }
- std::string cur_file_name(dp->d_name);
- // string.size() does not include the null terminator. The cpio FreeBSD
- // file header expects the null character to be included in the length.
- const size_t file_name_len = cur_file_name.size() + 1;
- struct stat st;
- const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
- if (stat(cur_file_path.c_str(), &st) == -1) {
- PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
- n_error++;
- continue;
- }
- const int fd_read = open(cur_file_path.c_str(), O_RDONLY);
- if (fd_read == -1) {
- PLOG(ERROR) << "Failed to open file " << cur_file_path;
- n_error++;
- continue;
- }
- unique_fd file_auto_closer(fd_read);
- if (!cpioWriteHeader(out_fd, st, cur_file_name.c_str(),
- file_name_len)) {
- return ++n_error;
- }
- size_t write_error = cpioWriteFileContent(fd_read, out_fd, st);
- if (write_error) {
- return n_error + write_error;
- }
- }
- if (!cpioWriteFileTrailer(out_fd)) {
- return ++n_error;
- }
- return n_error;
-}
-
-// Helper function to create a non-const char*.
-std::vector<char> makeCharVec(const std::string& str) {
- std::vector<char> vec(str.size() + 1);
- vec.assign(str.begin(), str.end());
- vec.push_back('\0');
- return vec;
-}
-
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-using hidl_return_util::validateAndCallWithLock;
-
-WifiChip::WifiChip(
- ChipId chip_id, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
- const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
- : chip_id_(chip_id),
- legacy_hal_(legacy_hal),
- mode_controller_(mode_controller),
- iface_util_(iface_util),
- feature_flags_(feature_flags),
- is_valid_(true),
- current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
- modes_(feature_flags.lock()->getChipModes()),
- debug_ring_buffer_cb_registered_(false) {
- setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
-}
-
-void WifiChip::invalidate() {
- if (!writeRingbufferFilesInternal()) {
- LOG(ERROR) << "Error writing files to flash";
- }
- invalidateAndRemoveAllIfaces();
- setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
- legacy_hal_.reset();
- event_cb_handler_.invalidate();
- is_valid_ = false;
-}
-
-bool WifiChip::isValid() { return is_valid_; }
-
-std::set<sp<V1_2::IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
- return event_cb_handler_.getCallbacks();
-}
-
-Return<void> WifiChip::getId(getId_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getIdInternal, hidl_status_cb);
-}
-
-// Deprecated support for this callback
-Return<void> WifiChip::registerEventCallback(
- const sp<V1_0::IWifiChipEventCallback>& event_callback,
- registerEventCallback_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::registerEventCallbackInternal,
- hidl_status_cb, event_callback);
-}
-
-Return<void> WifiChip::getCapabilities(getCapabilities_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getAvailableModes(getAvailableModes_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getAvailableModesInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiChip::configureChip(ChipModeId mode_id,
- configureChip_cb hidl_status_cb) {
- return validateAndCallWithLock(
- this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::configureChipInternal, hidl_status_cb, mode_id);
-}
-
-Return<void> WifiChip::getMode(getMode_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getModeInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::requestChipDebugInfo(
- requestChipDebugInfo_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::requestChipDebugInfoInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiChip::requestDriverDebugDump(
- requestDriverDebugDump_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::requestDriverDebugDumpInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiChip::requestFirmwareDebugDump(
- requestFirmwareDebugDump_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::requestFirmwareDebugDumpInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiChip::createApIface(createApIface_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::createApIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getApIfaceNames(getApIfaceNames_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getApIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getApIface(const hidl_string& ifname,
- getApIface_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getApIfaceInternal, hidl_status_cb,
- ifname);
-}
-
-Return<void> WifiChip::removeApIface(const hidl_string& ifname,
- removeApIface_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::removeApIfaceInternal, hidl_status_cb,
- ifname);
-}
-
-Return<void> WifiChip::createNanIface(createNanIface_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::createNanIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getNanIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getNanIface(const hidl_string& ifname,
- getNanIface_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getNanIfaceInternal, hidl_status_cb,
- ifname);
-}
-
-Return<void> WifiChip::removeNanIface(const hidl_string& ifname,
- removeNanIface_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::removeNanIfaceInternal, hidl_status_cb,
- ifname);
-}
-
-Return<void> WifiChip::createP2pIface(createP2pIface_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::createP2pIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getP2pIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getP2pIface(const hidl_string& ifname,
- getP2pIface_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getP2pIfaceInternal, hidl_status_cb,
- ifname);
-}
-
-Return<void> WifiChip::removeP2pIface(const hidl_string& ifname,
- removeP2pIface_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::removeP2pIfaceInternal, hidl_status_cb,
- ifname);
-}
-
-Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::createStaIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getStaIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getStaIface(const hidl_string& ifname,
- getStaIface_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getStaIfaceInternal, hidl_status_cb,
- ifname);
-}
-
-Return<void> WifiChip::removeStaIface(const hidl_string& ifname,
- removeStaIface_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::removeStaIfaceInternal, hidl_status_cb,
- ifname);
-}
-
-Return<void> WifiChip::createRttController(
- const sp<IWifiIface>& bound_iface, createRttController_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::createRttControllerInternal,
- hidl_status_cb, bound_iface);
-}
-
-Return<void> WifiChip::getDebugRingBuffersStatus(
- getDebugRingBuffersStatus_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getDebugRingBuffersStatusInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiChip::startLoggingToDebugRingBuffer(
- const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
- uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
- startLoggingToDebugRingBuffer_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::startLoggingToDebugRingBufferInternal,
- hidl_status_cb, ring_name, verbose_level,
- max_interval_in_sec, min_data_size_in_bytes);
-}
-
-Return<void> WifiChip::forceDumpToDebugRingBuffer(
- const hidl_string& ring_name,
- forceDumpToDebugRingBuffer_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::forceDumpToDebugRingBufferInternal,
- hidl_status_cb, ring_name);
-}
-
-Return<void> WifiChip::flushRingBufferToFile(
- flushRingBufferToFile_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::flushRingBufferToFileInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiChip::stopLoggingToDebugRingBuffer(
- stopLoggingToDebugRingBuffer_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::stopLoggingToDebugRingBufferInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiChip::getDebugHostWakeReasonStats(
- getDebugHostWakeReasonStats_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getDebugHostWakeReasonStatsInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiChip::enableDebugErrorAlerts(
- bool enable, enableDebugErrorAlerts_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::enableDebugErrorAlertsInternal,
- hidl_status_cb, enable);
-}
-
-Return<void> WifiChip::selectTxPowerScenario(
- V1_1::IWifiChip::TxPowerScenario scenario,
- selectTxPowerScenario_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::selectTxPowerScenarioInternal,
- hidl_status_cb, scenario);
-}
-
-Return<void> WifiChip::resetTxPowerScenario(
- resetTxPowerScenario_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::resetTxPowerScenarioInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiChip::setLatencyMode(LatencyMode mode,
- setLatencyMode_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::setLatencyModeInternal, hidl_status_cb,
- mode);
-}
-
-Return<void> WifiChip::registerEventCallback_1_2(
- const sp<V1_2::IWifiChipEventCallback>& event_callback,
- registerEventCallback_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::registerEventCallbackInternal_1_2,
- hidl_status_cb, event_callback);
-}
-
-Return<void> WifiChip::selectTxPowerScenario_1_2(
- TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::selectTxPowerScenarioInternal_1_2,
- hidl_status_cb, scenario);
-}
-
-Return<void> WifiChip::getCapabilities_1_3(getCapabilities_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
- &WifiChip::getCapabilitiesInternal_1_3,
- hidl_status_cb);
-}
-
-Return<void> WifiChip::debug(const hidl_handle& handle,
- const hidl_vec<hidl_string>&) {
- if (handle != nullptr && handle->numFds >= 1) {
- int fd = handle->data[0];
- if (!writeRingbufferFilesInternal()) {
- LOG(ERROR) << "Error writing files to flash";
- }
- uint32_t n_error = cpioArchiveFilesInDir(fd, kTombstoneFolderPath);
- if (n_error != 0) {
- LOG(ERROR) << n_error << " errors occured in cpio function";
- }
- fsync(fd);
- } else {
- LOG(ERROR) << "File handle error";
- }
- return Void();
-}
-
-void WifiChip::invalidateAndRemoveAllIfaces() {
- invalidateAndClearAll(ap_ifaces_);
- invalidateAndClearAll(nan_ifaces_);
- invalidateAndClearAll(p2p_ifaces_);
- invalidateAndClearAll(sta_ifaces_);
- // Since all the ifaces are invalid now, all RTT controller objects
- // using those ifaces also need to be invalidated.
- for (const auto& rtt : rtt_controllers_) {
- rtt->invalidate();
- }
- rtt_controllers_.clear();
-}
-
-void WifiChip::invalidateAndRemoveDependencies(
- const std::string& removed_iface_name) {
- for (const auto& nan_iface : nan_ifaces_) {
- if (nan_iface->getName() == removed_iface_name) {
- invalidateAndClear(nan_ifaces_, nan_iface);
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback
- ->onIfaceRemoved(IfaceType::NAN, removed_iface_name)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
- }
- }
- }
- }
- for (const auto& rtt : rtt_controllers_) {
- if (rtt->getIfaceName() == removed_iface_name) {
- invalidateAndClear(rtt_controllers_, rtt);
- }
- }
-}
-
-std::pair<WifiStatus, ChipId> WifiChip::getIdInternal() {
- return {createWifiStatus(WifiStatusCode::SUCCESS), chip_id_};
-}
-
-WifiStatus WifiChip::registerEventCallbackInternal(
- const sp<V1_0::IWifiChipEventCallback>& /* event_callback */) {
- // Deprecated support for this callback.
- return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
- // Deprecated support for this callback.
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_3() {
- legacy_hal::wifi_error legacy_status;
- uint32_t legacy_feature_set;
- uint32_t legacy_logger_feature_set;
- const auto ifname = getFirstActiveWlanIfaceName();
- std::tie(legacy_status, legacy_feature_set) =
- legacy_hal_.lock()->getSupportedFeatureSet(ifname);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- return {createWifiStatusFromLegacyError(legacy_status), 0};
- }
- 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::convertLegacyFeaturesToHidlChipCapabilities(
- legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
- return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, std::vector<IWifiChip::ChipMode>>
-WifiChip::getAvailableModesInternal() {
- return {createWifiStatus(WifiStatusCode::SUCCESS), modes_};
-}
-
-WifiStatus WifiChip::configureChipInternal(
- /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
- ChipModeId mode_id) {
- if (!isValidModeId(mode_id)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- if (mode_id == current_mode_id_) {
- LOG(DEBUG) << "Already in the specified mode " << mode_id;
- return createWifiStatus(WifiStatusCode::SUCCESS);
- }
- WifiStatus status = handleChipConfiguration(lock, mode_id);
- if (status.code != WifiStatusCode::SUCCESS) {
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onChipReconfigureFailure(status).isOk()) {
- LOG(ERROR)
- << "Failed to invoke onChipReconfigureFailure callback";
- }
- }
- return status;
- }
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onChipReconfigured(mode_id).isOk()) {
- LOG(ERROR) << "Failed to invoke onChipReconfigured callback";
- }
- }
- current_mode_id_ = mode_id;
- LOG(INFO) << "Configured chip in mode " << mode_id;
- setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
- return status;
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
- if (!isValidModeId(current_mode_id_)) {
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE),
- current_mode_id_};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
-}
-
-std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
-WifiChip::requestChipDebugInfoInternal() {
- IWifiChip::ChipDebugInfo result;
- legacy_hal::wifi_error legacy_status;
- std::string driver_desc;
- const auto ifname = getFirstActiveWlanIfaceName();
- std::tie(legacy_status, driver_desc) =
- legacy_hal_.lock()->getDriverVersion(ifname);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to get driver version: "
- << legacyErrorToString(legacy_status);
- WifiStatus status = createWifiStatusFromLegacyError(
- legacy_status, "failed to get driver version");
- return {status, result};
- }
- result.driverDescription = driver_desc.c_str();
-
- std::string firmware_desc;
- std::tie(legacy_status, firmware_desc) =
- legacy_hal_.lock()->getFirmwareVersion(ifname);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to get firmware version: "
- << legacyErrorToString(legacy_status);
- WifiStatus status = createWifiStatusFromLegacyError(
- legacy_status, "failed to get firmware version");
- return {status, result};
- }
- result.firmwareDescription = firmware_desc.c_str();
-
- return {createWifiStatus(WifiStatusCode::SUCCESS), result};
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>>
-WifiChip::requestDriverDebugDumpInternal() {
- legacy_hal::wifi_error legacy_status;
- std::vector<uint8_t> driver_dump;
- std::tie(legacy_status, driver_dump) =
- legacy_hal_.lock()->requestDriverMemoryDump(
- getFirstActiveWlanIfaceName());
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to get driver debug dump: "
- << legacyErrorToString(legacy_status);
- return {createWifiStatusFromLegacyError(legacy_status),
- std::vector<uint8_t>()};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), driver_dump};
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>>
-WifiChip::requestFirmwareDebugDumpInternal() {
- legacy_hal::wifi_error legacy_status;
- std::vector<uint8_t> firmware_dump;
- std::tie(legacy_status, firmware_dump) =
- legacy_hal_.lock()->requestFirmwareMemoryDump(
- getFirstActiveWlanIfaceName());
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to get firmware debug dump: "
- << legacyErrorToString(legacy_status);
- return {createWifiStatusFromLegacyError(legacy_status), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), firmware_dump};
-}
-
-std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::createApIfaceInternal() {
- if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
- }
- std::string ifname = allocateApIfaceName();
- sp<WifiApIface> iface =
- new WifiApIface(ifname, legacy_hal_, iface_util_, feature_flags_);
- ap_ifaces_.push_back(iface);
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
- LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
- }
- }
- setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
- return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getApIfaceNamesInternal() {
- if (ap_ifaces_.empty()) {
- return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(ap_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::getApIfaceInternal(
- const std::string& ifname) {
- const auto iface = findUsingName(ap_ifaces_, ifname);
- if (!iface.get()) {
- return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) {
- const auto iface = findUsingName(ap_ifaces_, ifname);
- if (!iface.get()) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- // Invalidate & remove any dependent objects first.
- // Note: This is probably not required because we never create
- // nan/rtt objects over AP iface. But, there is no harm to do it
- // here and not make that assumption all over the place.
- invalidateAndRemoveDependencies(ifname);
- invalidateAndClear(ap_ifaces_, iface);
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
- LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
- }
- }
- setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::createNanIfaceInternal() {
- if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) {
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
- }
- // These are still assumed to be based on wlan0.
- std::string ifname = getFirstActiveWlanIfaceName();
- sp<WifiNanIface> iface = new WifiNanIface(ifname, legacy_hal_, iface_util_);
- nan_ifaces_.push_back(iface);
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) {
- LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
- }
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getNanIfaceNamesInternal() {
- if (nan_ifaces_.empty()) {
- return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::getNanIfaceInternal(
- const std::string& ifname) {
- const auto iface = findUsingName(nan_ifaces_, ifname);
- if (!iface.get()) {
- return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) {
- const auto iface = findUsingName(nan_ifaces_, ifname);
- if (!iface.get()) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- invalidateAndClear(nan_ifaces_, iface);
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onIfaceRemoved(IfaceType::NAN, ifname).isOk()) {
- LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
- }
- }
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
- if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::P2P)) {
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
- }
- std::string ifname = getP2pIfaceName();
- sp<WifiP2pIface> iface = new WifiP2pIface(ifname, legacy_hal_);
- p2p_ifaces_.push_back(iface);
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) {
- LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
- }
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getP2pIfaceNamesInternal() {
- if (p2p_ifaces_.empty()) {
- return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(p2p_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::getP2pIfaceInternal(
- const std::string& ifname) {
- const auto iface = findUsingName(p2p_ifaces_, ifname);
- if (!iface.get()) {
- return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) {
- const auto iface = findUsingName(p2p_ifaces_, ifname);
- if (!iface.get()) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- invalidateAndClear(p2p_ifaces_, iface);
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) {
- LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
- }
- }
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::createStaIfaceInternal() {
- if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) {
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
- }
- std::string ifname = allocateStaIfaceName();
- sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_, iface_util_);
- sta_ifaces_.push_back(iface);
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {
- LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
- }
- }
- setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
- return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getStaIfaceNamesInternal() {
- if (sta_ifaces_.empty()) {
- return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::getStaIfaceInternal(
- const std::string& ifname) {
- const auto iface = findUsingName(sta_ifaces_, ifname);
- if (!iface.get()) {
- return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) {
- const auto iface = findUsingName(sta_ifaces_, ifname);
- if (!iface.get()) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- // Invalidate & remove any dependent objects first.
- invalidateAndRemoveDependencies(ifname);
- invalidateAndClear(sta_ifaces_, iface);
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
- LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
- }
- }
- setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiRttController>>
-WifiChip::createRttControllerInternal(const sp<IWifiIface>& bound_iface) {
- if (sta_ifaces_.size() == 0 &&
- !canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
- LOG(ERROR) << "createRttControllerInternal: Chip cannot support STAs "
- "(and RTT by extension)";
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
- }
- sp<WifiRttController> rtt = new WifiRttController(
- getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
- rtt_controllers_.emplace_back(rtt);
- return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
-WifiChip::getDebugRingBuffersStatusInternal() {
- legacy_hal::wifi_error legacy_status;
- std::vector<legacy_hal::wifi_ring_buffer_status>
- legacy_ring_buffer_status_vec;
- std::tie(legacy_status, legacy_ring_buffer_status_vec) =
- legacy_hal_.lock()->getRingBuffersStatus(getFirstActiveWlanIfaceName());
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- return {createWifiStatusFromLegacyError(legacy_status), {}};
- }
- std::vector<WifiDebugRingBufferStatus> hidl_ring_buffer_status_vec;
- if (!hidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToHidl(
- legacy_ring_buffer_status_vec, &hidl_ring_buffer_status_vec)) {
- return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS),
- hidl_ring_buffer_status_vec};
-}
-
-WifiStatus WifiChip::startLoggingToDebugRingBufferInternal(
- const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
- uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes) {
- WifiStatus status = registerDebugRingBufferCallback();
- if (status.code != WifiStatusCode::SUCCESS) {
- return status;
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->startRingBufferLogging(
- getFirstActiveWlanIfaceName(), ring_name,
- static_cast<
- std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(
- verbose_level),
- max_interval_in_sec, min_data_size_in_bytes);
- ringbuffer_map_.insert(std::pair<std::string, Ringbuffer>(
- ring_name, Ringbuffer(kMaxBufferSizeBytes)));
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::forceDumpToDebugRingBufferInternal(
- const hidl_string& ring_name) {
- WifiStatus status = registerDebugRingBufferCallback();
- if (status.code != WifiStatusCode::SUCCESS) {
- return status;
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->getRingBufferData(getFirstActiveWlanIfaceName(),
- ring_name);
-
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::flushRingBufferToFileInternal() {
- if (!writeRingbufferFilesInternal()) {
- LOG(ERROR) << "Error writing files to flash";
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
- }
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::stopLoggingToDebugRingBufferInternal() {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->deregisterRingBufferCallbackHandler(
- getFirstActiveWlanIfaceName());
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
-WifiChip::getDebugHostWakeReasonStatsInternal() {
- legacy_hal::wifi_error legacy_status;
- legacy_hal::WakeReasonStats legacy_stats;
- std::tie(legacy_status, legacy_stats) =
- legacy_hal_.lock()->getWakeReasonStats(getFirstActiveWlanIfaceName());
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- return {createWifiStatusFromLegacyError(legacy_status), {}};
- }
- WifiDebugHostWakeReasonStats hidl_stats;
- if (!hidl_struct_util::convertLegacyWakeReasonStatsToHidl(legacy_stats,
- &hidl_stats)) {
- return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
-}
-
-WifiStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
- legacy_hal::wifi_error legacy_status;
- if (enable) {
- android::wp<WifiChip> weak_ptr_this(this);
- const auto& on_alert_callback = [weak_ptr_this](
- int32_t error_code,
- std::vector<uint8_t> debug_data) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->onDebugErrorAlert(error_code, debug_data)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke onDebugErrorAlert callback";
- }
- }
- };
- legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
- getFirstActiveWlanIfaceName(), on_alert_callback);
- } else {
- legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler(
- getFirstActiveWlanIfaceName());
- }
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::selectTxPowerScenarioInternal(
- V1_1::IWifiChip::TxPowerScenario scenario) {
- auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
- getFirstActiveWlanIfaceName(),
- hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::resetTxPowerScenarioInternal() {
- auto legacy_status =
- legacy_hal_.lock()->resetTxPowerScenario(getFirstActiveWlanIfaceName());
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::setLatencyModeInternal(LatencyMode mode) {
- auto legacy_status = legacy_hal_.lock()->setLatencyMode(
- getFirstActiveWlanIfaceName(),
- hidl_struct_util::convertHidlLatencyModeToLegacy(mode));
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::registerEventCallbackInternal_1_2(
- const sp<V1_2::IWifiChipEventCallback>& event_callback) {
- if (!event_cb_handler_.addCallback(event_callback)) {
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
- }
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(
- TxPowerScenario scenario) {
- auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
- getFirstActiveWlanIfaceName(),
- hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::handleChipConfiguration(
- /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
- ChipModeId mode_id) {
- // If the chip is already configured in a different mode, stop
- // the legacy HAL and then start it after firmware mode change.
- if (isValidModeId(current_mode_id_)) {
- LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_
- << " to mode " << mode_id;
- invalidateAndRemoveAllIfaces();
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->stop(lock, []() {});
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to stop legacy HAL: "
- << legacyErrorToString(legacy_status);
- return createWifiStatusFromLegacyError(legacy_status);
- }
- }
- // Firmware mode change not needed for V2 devices.
- bool success = true;
- if (mode_id == feature_flags::chip_mode_ids::kV1Sta) {
- success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
- } else if (mode_id == feature_flags::chip_mode_ids::kV1Ap) {
- success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
- }
- if (!success) {
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
- }
- legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to start legacy HAL: "
- << legacyErrorToString(legacy_status);
- return createWifiStatusFromLegacyError(legacy_status);
- }
- // Every time the HAL is restarted, we need to register the
- // radio mode change callback.
- WifiStatus status = registerRadioModeChangeCallback();
- if (status.code != WifiStatusCode::SUCCESS) {
- // This probably is not a critical failure?
- LOG(ERROR) << "Failed to register radio mode change callback";
- }
- // Extract and save the version information into property.
- std::pair<WifiStatus, IWifiChip::ChipDebugInfo> version_info;
- version_info = WifiChip::requestChipDebugInfoInternal();
- if (WifiStatusCode::SUCCESS == version_info.first.code) {
- property_set("vendor.wlan.firmware.version",
- version_info.second.firmwareDescription.c_str());
- property_set("vendor.wlan.driver.version",
- version_info.second.driverDescription.c_str());
- }
-
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::registerDebugRingBufferCallback() {
- if (debug_ring_buffer_cb_registered_) {
- return createWifiStatus(WifiStatusCode::SUCCESS);
- }
-
- android::wp<WifiChip> weak_ptr_this(this);
- const auto& on_ring_buffer_data_callback =
- [weak_ptr_this](const std::string& name,
- const std::vector<uint8_t>& data,
- const legacy_hal::wifi_ring_buffer_status& status) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- WifiDebugRingBufferStatus hidl_status;
- if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(
- status, &hidl_status)) {
- LOG(ERROR) << "Error converting ring buffer status";
- return;
- }
- const auto& target = shared_ptr_this->ringbuffer_map_.find(name);
- if (target != shared_ptr_this->ringbuffer_map_.end()) {
- Ringbuffer& cur_buffer = target->second;
- cur_buffer.append(data);
- } else {
- LOG(ERROR) << "Ringname " << name << " not found";
- return;
- }
- };
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->registerRingBufferCallbackHandler(
- getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
-
- if (legacy_status == legacy_hal::WIFI_SUCCESS) {
- debug_ring_buffer_cb_registered_ = true;
- }
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::registerRadioModeChangeCallback() {
- android::wp<WifiChip> weak_ptr_this(this);
- const auto& on_radio_mode_change_callback =
- [weak_ptr_this](const std::vector<legacy_hal::WifiMacInfo>& mac_infos) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>
- hidl_radio_mode_infos;
- if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(
- mac_infos, &hidl_radio_mode_infos)) {
- LOG(ERROR) << "Error converting wifi mac info";
- return;
- }
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->onRadioModeChange(hidl_radio_mode_infos)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke onRadioModeChange"
- << " callback on: " << toString(callback);
- }
- }
- };
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
- getFirstActiveWlanIfaceName(), on_radio_mode_change_callback);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::vector<IWifiChip::ChipIfaceCombination>
-WifiChip::getCurrentModeIfaceCombinations() {
- if (!isValidModeId(current_mode_id_)) {
- LOG(ERROR) << "Chip not configured in a mode yet";
- return {};
- }
- for (const auto& mode : modes_) {
- if (mode.id == current_mode_id_) {
- return mode.availableCombinations;
- }
- }
- CHECK(0) << "Expected to find iface combinations for current mode!";
- return {};
-}
-
-// Returns a map indexed by IfaceType with the number of ifaces currently
-// created of the corresponding type.
-std::map<IfaceType, size_t> WifiChip::getCurrentIfaceCombination() {
- std::map<IfaceType, size_t> iface_counts;
- iface_counts[IfaceType::AP] = ap_ifaces_.size();
- iface_counts[IfaceType::NAN] = nan_ifaces_.size();
- iface_counts[IfaceType::P2P] = p2p_ifaces_.size();
- iface_counts[IfaceType::STA] = sta_ifaces_.size();
- return iface_counts;
-}
-
-// This expands the provided iface combinations to a more parseable
-// form. Returns a vector of available combinations possible with the number
-// of ifaces of each type in the combination.
-// This method is a port of HalDeviceManager.expandIfaceCombos() from framework.
-std::vector<std::map<IfaceType, size_t>> WifiChip::expandIfaceCombinations(
- const IWifiChip::ChipIfaceCombination& combination) {
- uint32_t num_expanded_combos = 1;
- for (const auto& limit : combination.limits) {
- for (uint32_t i = 0; i < limit.maxIfaces; i++) {
- num_expanded_combos *= limit.types.size();
- }
- }
-
- // Allocate the vector of expanded combos and reset all iface counts to 0
- // in each combo.
- std::vector<std::map<IfaceType, size_t>> expanded_combos;
- expanded_combos.resize(num_expanded_combos);
- for (auto& expanded_combo : expanded_combos) {
- for (const auto type :
- {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
- expanded_combo[type] = 0;
- }
- }
- uint32_t span = num_expanded_combos;
- for (const auto& limit : combination.limits) {
- for (uint32_t i = 0; i < limit.maxIfaces; i++) {
- span /= limit.types.size();
- for (uint32_t k = 0; k < num_expanded_combos; ++k) {
- const auto iface_type =
- limit.types[(k / span) % limit.types.size()];
- expanded_combos[k][iface_type]++;
- }
- }
- }
- return expanded_combos;
-}
-
-bool WifiChip::canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
- const std::map<IfaceType, size_t>& expanded_combo,
- IfaceType requested_type) {
- const auto current_combo = getCurrentIfaceCombination();
-
- // Check if we have space for 1 more iface of |type| in this combo
- for (const auto type :
- {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
- size_t num_ifaces_needed = current_combo.at(type);
- if (type == requested_type) {
- num_ifaces_needed++;
- }
- size_t num_ifaces_allowed = expanded_combo.at(type);
- if (num_ifaces_needed > num_ifaces_allowed) {
- return false;
- }
- }
- return true;
-}
-
-// This method does the following:
-// a) Enumerate all possible iface combos by expanding the current
-// ChipIfaceCombination.
-// b) Check if the requested iface type can be added to the current mode
-// with the iface combination that is already active.
-bool WifiChip::canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
- IfaceType requested_type) {
- if (!isValidModeId(current_mode_id_)) {
- LOG(ERROR) << "Chip not configured in a mode yet";
- return false;
- }
- const auto combinations = getCurrentModeIfaceCombinations();
- for (const auto& combination : combinations) {
- const auto expanded_combos = expandIfaceCombinations(combination);
- for (const auto& expanded_combo : expanded_combos) {
- if (canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
- expanded_combo, requested_type)) {
- return true;
- }
- }
- }
- return false;
-}
-
-// Note: This does not consider ifaces already active. It only checks if the
-// provided expanded iface combination can support the requested combo.
-bool WifiChip::canExpandedIfaceComboSupportIfaceCombo(
- const std::map<IfaceType, size_t>& expanded_combo,
- const std::map<IfaceType, size_t>& req_combo) {
- // Check if we have space for 1 more iface of |type| in this combo
- for (const auto type :
- {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
- if (req_combo.count(type) == 0) {
- // Iface of "type" not in the req_combo.
- continue;
- }
- size_t num_ifaces_needed = req_combo.at(type);
- size_t num_ifaces_allowed = expanded_combo.at(type);
- if (num_ifaces_needed > num_ifaces_allowed) {
- return false;
- }
- }
- return true;
-}
-// This method does the following:
-// a) Enumerate all possible iface combos by expanding the current
-// ChipIfaceCombination.
-// b) Check if the requested iface combo can be added to the current mode.
-// Note: This does not consider ifaces already active. It only checks if the
-// current mode can support the requested combo.
-bool WifiChip::canCurrentModeSupportIfaceCombo(
- const std::map<IfaceType, size_t>& req_combo) {
- if (!isValidModeId(current_mode_id_)) {
- LOG(ERROR) << "Chip not configured in a mode yet";
- return false;
- }
- const auto combinations = getCurrentModeIfaceCombinations();
- for (const auto& combination : combinations) {
- const auto expanded_combos = expandIfaceCombinations(combination);
- for (const auto& expanded_combo : expanded_combos) {
- if (canExpandedIfaceComboSupportIfaceCombo(expanded_combo,
- req_combo)) {
- return true;
- }
- }
- }
- return false;
-}
-
-// This method does the following:
-// a) Enumerate all possible iface combos by expanding the current
-// ChipIfaceCombination.
-// b) Check if the requested iface type can be added to the current mode.
-bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType requested_type) {
- // Check if we can support atleast 1 iface of type.
- std::map<IfaceType, size_t> req_iface_combo;
- req_iface_combo[requested_type] = 1;
- return canCurrentModeSupportIfaceCombo(req_iface_combo);
-}
-
-bool WifiChip::isValidModeId(ChipModeId mode_id) {
- for (const auto& mode : modes_) {
- if (mode.id == mode_id) {
- return true;
- }
- }
- return false;
-}
-
-bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() {
- // Check if we can support atleast 1 STA & 1 AP concurrently.
- std::map<IfaceType, size_t> req_iface_combo;
- req_iface_combo[IfaceType::AP] = 1;
- req_iface_combo[IfaceType::STA] = 1;
- return canCurrentModeSupportIfaceCombo(req_iface_combo);
-}
-
-bool WifiChip::isDualApAllowedInCurrentMode() {
- // Check if we can support atleast 1 STA & 1 AP concurrently.
- std::map<IfaceType, size_t> req_iface_combo;
- req_iface_combo[IfaceType::AP] = 2;
- return canCurrentModeSupportIfaceCombo(req_iface_combo);
-}
-
-std::string WifiChip::getFirstActiveWlanIfaceName() {
- if (sta_ifaces_.size() > 0) return sta_ifaces_[0]->getName();
- if (ap_ifaces_.size() > 0) return ap_ifaces_[0]->getName();
- // This could happen if the chip call is made before any STA/AP
- // iface is created. Default to wlan0 for such cases.
- LOG(WARNING) << "No active wlan interfaces in use! Using default";
- return getWlanIfaceName(0);
-}
-
-// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
-// not already in use.
-// Note: This doesn't check the actual presence of these interfaces.
-std::string WifiChip::allocateApOrStaIfaceName(uint32_t start_idx) {
- for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
- const auto ifname = getWlanIfaceName(idx);
- if (findUsingName(ap_ifaces_, ifname)) continue;
- if (findUsingName(sta_ifaces_, ifname)) continue;
- return ifname;
- }
- // This should never happen. We screwed up somewhere if it did.
- CHECK(false) << "All wlan interfaces in use already!";
- return {};
-}
-
-// AP iface names start with idx 1 for modes supporting
-// concurrent STA and not dual AP, else start with idx 0.
-std::string WifiChip::allocateApIfaceName() {
- return allocateApOrStaIfaceName((isStaApConcurrencyAllowedInCurrentMode() &&
- !isDualApAllowedInCurrentMode())
- ? 1
- : 0);
-}
-
-// STA iface names start with idx 0.
-// Primary STA iface will always be 0.
-std::string WifiChip::allocateStaIfaceName() {
- return allocateApOrStaIfaceName(0);
-}
-
-bool WifiChip::writeRingbufferFilesInternal() {
- if (!removeOldFilesInternal()) {
- LOG(ERROR) << "Error occurred while deleting old tombstone files";
- return false;
- }
- // write ringbuffers to file
- for (const auto& item : ringbuffer_map_) {
- const Ringbuffer& cur_buffer = item.second;
- if (cur_buffer.getData().empty()) {
- continue;
- }
- const std::string file_path_raw =
- kTombstoneFolderPath + item.first + "XXXXXXXXXX";
- const int dump_fd = mkstemp(makeCharVec(file_path_raw).data());
- if (dump_fd == -1) {
- PLOG(ERROR) << "create file failed";
- return false;
- }
- unique_fd file_auto_closer(dump_fd);
- for (const auto& cur_block : cur_buffer.getData()) {
- if (write(dump_fd, cur_block.data(),
- sizeof(cur_block[0]) * cur_block.size()) == -1) {
- PLOG(ERROR) << "Error writing to file";
- }
- }
- }
- return true;
-}
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi_chip.h b/wifi/1.3/default/wifi_chip.h
deleted file mode 100644
index 153ca6a..0000000
--- a/wifi/1.3/default/wifi_chip.h
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_CHIP_H_
-#define WIFI_CHIP_H_
-
-#include <list>
-#include <map>
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.3/IWifiChip.h>
-
-#include "hidl_callback_util.h"
-#include "ringbuffer.h"
-#include "wifi_ap_iface.h"
-#include "wifi_feature_flags.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_mode_controller.h"
-#include "wifi_nan_iface.h"
-#include "wifi_p2p_iface.h"
-#include "wifi_rtt_controller.h"
-#include "wifi_sta_iface.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a Wifi HAL chip instance.
- * Since there is only a single chip instance used today, there is no
- * identifying handle information stored here.
- */
-class WifiChip : public V1_3::IWifiChip {
- public:
- WifiChip(
- ChipId chip_id,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<mode_controller::WifiModeController>
- mode_controller,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
- const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
- // HIDL does not provide a built-in mechanism to let the server invalidate
- // a HIDL interface object after creation. If any client process holds onto
- // a reference to the object in their context, any method calls on that
- // reference will continue to be directed to the server.
- //
- // However Wifi HAL needs to control the lifetime of these objects. So, add
- // a public |invalidate| method to |WifiChip| and it's child objects. This
- // will be used to mark an object invalid when either:
- // a) Wifi HAL is stopped, or
- // b) Wifi Chip is reconfigured.
- //
- // All HIDL method implementations should check if the object is still
- // marked valid before processing them.
- void invalidate();
- bool isValid();
- std::set<sp<V1_2::IWifiChipEventCallback>> getEventCallbacks();
-
- // HIDL methods exposed.
- Return<void> getId(getId_cb hidl_status_cb) override;
- // Deprecated support for this callback
- Return<void> registerEventCallback(
- const sp<V1_0::IWifiChipEventCallback>& event_callback,
- registerEventCallback_cb hidl_status_cb) override;
- Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
- Return<void> getAvailableModes(
- getAvailableModes_cb hidl_status_cb) override;
- Return<void> configureChip(ChipModeId mode_id,
- configureChip_cb hidl_status_cb) override;
- Return<void> getMode(getMode_cb hidl_status_cb) override;
- Return<void> requestChipDebugInfo(
- requestChipDebugInfo_cb hidl_status_cb) override;
- Return<void> requestDriverDebugDump(
- requestDriverDebugDump_cb hidl_status_cb) override;
- Return<void> requestFirmwareDebugDump(
- requestFirmwareDebugDump_cb hidl_status_cb) override;
- Return<void> createApIface(createApIface_cb hidl_status_cb) override;
- Return<void> getApIfaceNames(getApIfaceNames_cb hidl_status_cb) override;
- Return<void> getApIface(const hidl_string& ifname,
- getApIface_cb hidl_status_cb) override;
- Return<void> removeApIface(const hidl_string& ifname,
- removeApIface_cb hidl_status_cb) override;
- Return<void> createNanIface(createNanIface_cb hidl_status_cb) override;
- Return<void> getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) override;
- Return<void> getNanIface(const hidl_string& ifname,
- getNanIface_cb hidl_status_cb) override;
- Return<void> removeNanIface(const hidl_string& ifname,
- removeNanIface_cb hidl_status_cb) override;
- Return<void> createP2pIface(createP2pIface_cb hidl_status_cb) override;
- Return<void> getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) override;
- Return<void> getP2pIface(const hidl_string& ifname,
- getP2pIface_cb hidl_status_cb) override;
- Return<void> removeP2pIface(const hidl_string& ifname,
- removeP2pIface_cb hidl_status_cb) override;
- Return<void> createStaIface(createStaIface_cb hidl_status_cb) override;
- Return<void> getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) override;
- Return<void> getStaIface(const hidl_string& ifname,
- getStaIface_cb hidl_status_cb) override;
- Return<void> removeStaIface(const hidl_string& ifname,
- removeStaIface_cb hidl_status_cb) override;
- Return<void> createRttController(
- const sp<IWifiIface>& bound_iface,
- createRttController_cb hidl_status_cb) override;
- Return<void> getDebugRingBuffersStatus(
- getDebugRingBuffersStatus_cb hidl_status_cb) override;
- Return<void> startLoggingToDebugRingBuffer(
- const hidl_string& ring_name,
- WifiDebugRingBufferVerboseLevel verbose_level,
- uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
- startLoggingToDebugRingBuffer_cb hidl_status_cb) override;
- Return<void> forceDumpToDebugRingBuffer(
- const hidl_string& ring_name,
- forceDumpToDebugRingBuffer_cb hidl_status_cb) override;
- Return<void> flushRingBufferToFile(
- flushRingBufferToFile_cb hidl_status_cb) override;
- Return<void> stopLoggingToDebugRingBuffer(
- stopLoggingToDebugRingBuffer_cb hidl_status_cb) override;
- Return<void> getDebugHostWakeReasonStats(
- getDebugHostWakeReasonStats_cb hidl_status_cb) override;
- Return<void> enableDebugErrorAlerts(
- bool enable, enableDebugErrorAlerts_cb hidl_status_cb) override;
- Return<void> selectTxPowerScenario(
- V1_1::IWifiChip::TxPowerScenario scenario,
- selectTxPowerScenario_cb hidl_status_cb) override;
- Return<void> resetTxPowerScenario(
- resetTxPowerScenario_cb hidl_status_cb) override;
- Return<void> setLatencyMode(LatencyMode mode,
- setLatencyMode_cb hidl_status_cb) override;
- Return<void> registerEventCallback_1_2(
- const sp<V1_2::IWifiChipEventCallback>& event_callback,
- registerEventCallback_1_2_cb hidl_status_cb) override;
- Return<void> selectTxPowerScenario_1_2(
- TxPowerScenario scenario,
- selectTxPowerScenario_cb hidl_status_cb) override;
- Return<void> getCapabilities_1_3(
- getCapabilities_cb hidl_status_cb) override;
- Return<void> debug(const hidl_handle& handle,
- const hidl_vec<hidl_string>& options) override;
-
- private:
- void invalidateAndRemoveAllIfaces();
- // When a STA iface is removed any dependent NAN-ifaces/RTT-controllers are
- // invalidated & removed.
- void invalidateAndRemoveDependencies(const std::string& removed_iface_name);
-
- // Corresponding worker functions for the HIDL methods.
- std::pair<WifiStatus, ChipId> getIdInternal();
- // Deprecated support for this callback
- WifiStatus registerEventCallbackInternal(
- const sp<V1_0::IWifiChipEventCallback>& event_callback);
- std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
- std::pair<WifiStatus, std::vector<ChipMode>> getAvailableModesInternal();
- WifiStatus configureChipInternal(
- std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
- std::pair<WifiStatus, uint32_t> getModeInternal();
- std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
- requestChipDebugInfoInternal();
- std::pair<WifiStatus, std::vector<uint8_t>>
- requestDriverDebugDumpInternal();
- std::pair<WifiStatus, std::vector<uint8_t>>
- requestFirmwareDebugDumpInternal();
- std::pair<WifiStatus, sp<IWifiApIface>> createApIfaceInternal();
- std::pair<WifiStatus, std::vector<hidl_string>> getApIfaceNamesInternal();
- std::pair<WifiStatus, sp<IWifiApIface>> getApIfaceInternal(
- const std::string& ifname);
- WifiStatus removeApIfaceInternal(const std::string& ifname);
- std::pair<WifiStatus, sp<IWifiNanIface>> createNanIfaceInternal();
- std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
- std::pair<WifiStatus, sp<IWifiNanIface>> getNanIfaceInternal(
- const std::string& ifname);
- WifiStatus removeNanIfaceInternal(const std::string& ifname);
- std::pair<WifiStatus, sp<IWifiP2pIface>> createP2pIfaceInternal();
- std::pair<WifiStatus, std::vector<hidl_string>> getP2pIfaceNamesInternal();
- 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, std::vector<hidl_string>> getStaIfaceNamesInternal();
- std::pair<WifiStatus, sp<IWifiStaIface>> getStaIfaceInternal(
- const std::string& ifname);
- WifiStatus removeStaIfaceInternal(const std::string& ifname);
- std::pair<WifiStatus, sp<IWifiRttController>> createRttControllerInternal(
- const sp<IWifiIface>& bound_iface);
- std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
- getDebugRingBuffersStatusInternal();
- WifiStatus startLoggingToDebugRingBufferInternal(
- const hidl_string& ring_name,
- WifiDebugRingBufferVerboseLevel verbose_level,
- uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes);
- WifiStatus forceDumpToDebugRingBufferInternal(const hidl_string& ring_name);
- WifiStatus flushRingBufferToFileInternal();
- WifiStatus stopLoggingToDebugRingBufferInternal();
- std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
- getDebugHostWakeReasonStatsInternal();
- WifiStatus enableDebugErrorAlertsInternal(bool enable);
- WifiStatus selectTxPowerScenarioInternal(
- V1_1::IWifiChip::TxPowerScenario scenario);
- WifiStatus resetTxPowerScenarioInternal();
- WifiStatus setLatencyModeInternal(LatencyMode mode);
- WifiStatus registerEventCallbackInternal_1_2(
- const sp<V1_2::IWifiChipEventCallback>& event_callback);
- WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
- std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_3();
- WifiStatus handleChipConfiguration(
- std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
- WifiStatus registerDebugRingBufferCallback();
- WifiStatus registerRadioModeChangeCallback();
-
- std::vector<IWifiChip::ChipIfaceCombination>
- getCurrentModeIfaceCombinations();
- std::map<IfaceType, size_t> getCurrentIfaceCombination();
- std::vector<std::map<IfaceType, size_t>> expandIfaceCombinations(
- const IWifiChip::ChipIfaceCombination& combination);
- bool canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
- const std::map<IfaceType, size_t>& expanded_combo,
- IfaceType requested_type);
- bool canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
- IfaceType requested_type);
- bool canExpandedIfaceComboSupportIfaceCombo(
- const std::map<IfaceType, size_t>& expanded_combo,
- const std::map<IfaceType, size_t>& req_combo);
- bool canCurrentModeSupportIfaceCombo(
- const std::map<IfaceType, size_t>& req_combo);
- bool canCurrentModeSupportIfaceOfType(IfaceType requested_type);
- bool isValidModeId(ChipModeId mode_id);
- bool isStaApConcurrencyAllowedInCurrentMode();
- bool isDualApAllowedInCurrentMode();
- std::string getFirstActiveWlanIfaceName();
- std::string allocateApOrStaIfaceName(uint32_t start_idx);
- std::string allocateApIfaceName();
- std::string allocateStaIfaceName();
- bool writeRingbufferFilesInternal();
-
- ChipId chip_id_;
- std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
- std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
- std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
- std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
- std::vector<sp<WifiApIface>> ap_ifaces_;
- std::vector<sp<WifiNanIface>> nan_ifaces_;
- std::vector<sp<WifiP2pIface>> p2p_ifaces_;
- std::vector<sp<WifiStaIface>> sta_ifaces_;
- std::vector<sp<WifiRttController>> rtt_controllers_;
- std::map<std::string, Ringbuffer> ringbuffer_map_;
- bool is_valid_;
- // Members pertaining to chip configuration.
- uint32_t current_mode_id_;
- std::vector<IWifiChip::ChipMode> modes_;
- // The legacy ring buffer callback API has only a global callback
- // registration mechanism. Use this to check if we have already
- // registered a callback.
- bool debug_ring_buffer_cb_registered_;
- hidl_callback_util::HidlCallbackHandler<V1_2::IWifiChipEventCallback>
- event_cb_handler_;
-
- DISALLOW_COPY_AND_ASSIGN(WifiChip);
-};
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_CHIP_H_
diff --git a/wifi/1.3/default/wifi_feature_flags.cpp b/wifi/1.3/default/wifi_feature_flags.cpp
deleted file mode 100644
index 7212cfa..0000000
--- a/wifi/1.3/default/wifi_feature_flags.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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.
- */
-
-#include "wifi_feature_flags.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace feature_flags {
-
-using V1_0::ChipModeId;
-using V1_0::IfaceType;
-using V1_0::IWifiChip;
-
-/* The chip may either have a single mode supporting any number of combinations,
- * or a fixed dual-mode (so it involves firmware loading to switch between
- * modes) setting. If there is a need to support more modes, it needs to be
- * implemented manually in WiFi HAL (see changeFirmwareMode in
- * WifiChip::handleChipConfiguration).
- *
- * Supported combinations are defined in device's makefile, for example:
- * WIFI_HAL_INTERFACE_COMBINATIONS := {{{STA, AP}, 1}, {{P2P, NAN}, 1}},
- * WIFI_HAL_INTERFACE_COMBINATIONS += {{{STA}, 1}, {{AP}, 2}}
- * What means:
- * Interface combination 1: 1 STA or AP and 1 P2P or NAN concurrent iface
- * operations.
- * Interface combination 2: 1 STA and 2 AP concurrent iface operations.
- *
- * For backward compatibility, the following makefile flags can be used to
- * generate combinations list:
- * - WIFI_HIDL_FEATURE_DUAL_INTERFACE
- * - WIFI_HIDL_FEATURE_DISABLE_AP
- * - WIFI_HIDL_FEATURE_AWARE
- * However, they are ignored if WIFI_HAL_INTERFACE_COMBINATIONS was provided.
- * With WIFI_HIDL_FEATURE_DUAL_INTERFACE flag set, there is a single mode with
- * two interface combinations:
- * Interface Combination 1: Will support 1 STA and 1 P2P or NAN (optional)
- * concurrent iface operations.
- * Interface Combination 2: Will support 1 STA and 1 AP concurrent
- * iface operations.
- *
- * The only dual-mode configuration supported is for alternating STA and AP
- * mode, that may involve firmware reloading. In such case, there are 2 separate
- * modes of operation with 1 interface combination each:
- * Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN (optional)
- * concurrent iface operations.
- * Mode 2 (AP mode): Will support 1 AP iface operation.
- *
- * If Aware is enabled, the iface combination will be modified to support either
- * P2P or NAN in place of just P2P.
- */
-// clang-format off
-#ifdef WIFI_HAL_INTERFACE_COMBINATIONS
-constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
-#elif defined(WIFI_HIDL_FEATURE_DUAL_INTERFACE)
-// former V2 (fixed dual interface) setup expressed as V3
-constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
-# ifdef WIFI_HIDL_FEATURE_DISABLE_AP
-# ifdef WIFI_HIDL_FEATURE_AWARE
-// 1 STA + 1 of (P2P or NAN)
-# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
-# else
-// 1 STA + 1 P2P
-# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
-# endif
-# else
-# ifdef WIFI_HIDL_FEATURE_AWARE
-// (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
-# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
- {{{STA}, 1}, {{P2P, NAN}, 1}}
-# else
-// (1 STA + 1 AP) or (1 STA + 1 P2P)
-# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
- {{{STA}, 1}, {{P2P}, 1}}
-# endif
-# endif
-#else
-// V1 (fixed single interface, dual-mode chip)
-constexpr ChipModeId kMainModeId = chip_mode_ids::kV1Sta;
-# ifdef WIFI_HIDL_FEATURE_AWARE
-// 1 STA + 1 of (P2P or NAN)
-# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
-# else
-// 1 STA + 1 P2P
-# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
-# endif
-
-# ifndef WIFI_HIDL_FEATURE_DISABLE_AP
-# define WIFI_HAL_INTERFACE_COMBINATIONS_AP {{{AP}, 1}}
-# endif
-#endif
-// clang-format on
-
-/**
- * Helper class to convert a collection of combination limits to a combination.
- *
- * The main point here is to simplify the syntax required by
- * WIFI_HAL_INTERFACE_COMBINATIONS.
- */
-struct ChipIfaceCombination
- : public hidl_vec<IWifiChip::ChipIfaceCombinationLimit> {
- ChipIfaceCombination(
- const std::initializer_list<IWifiChip::ChipIfaceCombinationLimit> list)
- : hidl_vec(list) {}
-
- operator IWifiChip::ChipIfaceCombination() const { return {*this}; }
-
- static hidl_vec<IWifiChip::ChipIfaceCombination> make_vec(
- const std::initializer_list<ChipIfaceCombination> list) {
- return hidl_vec<IWifiChip::ChipIfaceCombination>( //
- std::begin(list), std::end(list));
- }
-};
-
-#define STA IfaceType::STA
-#define AP IfaceType::AP
-#define P2P IfaceType::P2P
-#define NAN IfaceType::NAN
-static const std::vector<IWifiChip::ChipMode> kChipModes{
- {kMainModeId,
- ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS})},
-#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP
- {chip_mode_ids::kV1Ap,
- ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
-#endif
-};
-#undef STA
-#undef AP
-#undef P2P
-#undef NAN
-
-#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-static const bool wifiHidlFeatureDisableApMacRandomization = true;
-#else
-static const bool wifiHidlFeatureDisableApMacRandomization = false;
-#endif // WIFI_HIDL_FEATURE_DISABLE_AP
-
-WifiFeatureFlags::WifiFeatureFlags() {}
-
-std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes() {
- return kChipModes;
-}
-
-bool WifiFeatureFlags::isApMacRandomizationDisabled() {
- return wifiHidlFeatureDisableApMacRandomization;
-}
-
-} // namespace feature_flags
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi_feature_flags.h b/wifi/1.3/default/wifi_feature_flags.h
deleted file mode 100644
index 3ae6920..0000000
--- a/wifi/1.3/default/wifi_feature_flags.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_FEATURE_FLAGS_H_
-#define WIFI_FEATURE_FLAGS_H_
-
-#include <android/hardware/wifi/1.2/IWifiChip.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace feature_flags {
-
-namespace chip_mode_ids {
-// These mode ID's should be unique (even across combo versions). Refer to
-// handleChipConfiguration() for it's usage.
-constexpr V1_0::ChipModeId kInvalid = UINT32_MAX;
-// Mode ID's for V1
-constexpr V1_0::ChipModeId kV1Sta = 0;
-constexpr V1_0::ChipModeId kV1Ap = 1;
-// Mode ID for V3
-constexpr V1_0::ChipModeId kV3 = 3;
-} // namespace chip_mode_ids
-
-class WifiFeatureFlags {
- public:
- WifiFeatureFlags();
- virtual ~WifiFeatureFlags() = default;
-
- virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes();
- virtual bool isApMacRandomizationDisabled();
-};
-
-} // namespace feature_flags
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.3/default/wifi_iface_util.cpp b/wifi/1.3/default/wifi_iface_util.cpp
deleted file mode 100644
index 34bc02d..0000000
--- a/wifi/1.3/default/wifi_iface_util.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cstddef>
-#include <iostream>
-#include <limits>
-#include <random>
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <private/android_filesystem_config.h>
-
-#undef NAN
-#include "wifi_iface_util.h"
-
-namespace {
-// Constants to set the local bit & clear the multicast bit.
-constexpr uint8_t kMacAddressMulticastMask = 0x01;
-constexpr uint8_t kMacAddressLocallyAssignedMask = 0x02;
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace iface_util {
-
-WifiIfaceUtil::WifiIfaceUtil(
- const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
- : iface_tool_(iface_tool),
- random_mac_address_(nullptr),
- event_handlers_map_() {}
-
-std::array<uint8_t, 6> WifiIfaceUtil::getFactoryMacAddress(
- const std::string& iface_name) {
- return iface_tool_.lock()->GetFactoryMacAddress(iface_name.c_str());
-}
-
-bool WifiIfaceUtil::setMacAddress(const std::string& iface_name,
- const std::array<uint8_t, 6>& mac) {
- if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
- LOG(ERROR) << "SetUpState(false) failed.";
- return false;
- }
- if (!iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac)) {
- LOG(ERROR) << "SetMacAddress failed.";
- return false;
- }
- if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
- LOG(ERROR) << "SetUpState(true) failed.";
- return false;
- }
- IfaceEventHandlers event_handlers = {};
- const auto it = event_handlers_map_.find(iface_name);
- if (it != event_handlers_map_.end()) {
- event_handlers = it->second;
- }
- if (event_handlers.on_state_toggle_off_on != nullptr) {
- event_handlers.on_state_toggle_off_on(iface_name);
- }
- LOG(DEBUG) << "Successfully SetMacAddress.";
- return true;
-}
-
-std::array<uint8_t, 6> WifiIfaceUtil::getOrCreateRandomMacAddress() {
- if (random_mac_address_) {
- return *random_mac_address_.get();
- }
- random_mac_address_ =
- std::make_unique<std::array<uint8_t, 6>>(createRandomMacAddress());
- return *random_mac_address_.get();
-}
-
-void WifiIfaceUtil::registerIfaceEventHandlers(const std::string& iface_name,
- IfaceEventHandlers handlers) {
- event_handlers_map_[iface_name] = handlers;
-}
-
-void WifiIfaceUtil::unregisterIfaceEventHandlers(
- const std::string& iface_name) {
- event_handlers_map_.erase(iface_name);
-}
-
-std::array<uint8_t, 6> WifiIfaceUtil::createRandomMacAddress() {
- std::array<uint8_t, 6> address = {};
- std::random_device rd;
- std::default_random_engine engine(rd());
- std::uniform_int_distribution<uint8_t> dist(
- std::numeric_limits<uint8_t>::min(),
- std::numeric_limits<uint8_t>::max());
- for (size_t i = 0; i < address.size(); i++) {
- address[i] = dist(engine);
- }
- // Set the local bit and clear the multicast bit.
- address[0] |= kMacAddressLocallyAssignedMask;
- address[0] &= ~kMacAddressMulticastMask;
- return address;
-}
-} // namespace iface_util
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi_iface_util.h b/wifi/1.3/default/wifi_iface_util.h
deleted file mode 100644
index 98073e0..0000000
--- a/wifi/1.3/default/wifi_iface_util.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_IFACE_UTIL_H_
-#define WIFI_IFACE_UTIL_H_
-
-#include <wifi_system/interface_tool.h>
-
-#include <android/hardware/wifi/1.0/IWifi.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace iface_util {
-
-// Iface event handlers.
-struct IfaceEventHandlers {
- // Callback to be invoked when the iface is set down & up for MAC address
- // change.
- std::function<void(const std::string& iface_name)> on_state_toggle_off_on;
-};
-
-/**
- * Util class for common iface operations.
- */
-class WifiIfaceUtil {
- public:
- WifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
- virtual ~WifiIfaceUtil() = default;
-
- virtual std::array<uint8_t, 6> getFactoryMacAddress(
- const std::string& iface_name);
- virtual bool setMacAddress(const std::string& iface_name,
- const std::array<uint8_t, 6>& mac);
- // Get or create a random MAC address. The MAC address returned from
- // this method will remain the same throughout the lifetime of the HAL
- // daemon. (So, changes on every reboot)
- virtual std::array<uint8_t, 6> getOrCreateRandomMacAddress();
-
- // Register for any iface event callbacks for the provided interface.
- virtual void registerIfaceEventHandlers(const std::string& iface_name,
- IfaceEventHandlers handlers);
- virtual void unregisterIfaceEventHandlers(const std::string& iface_name);
-
- private:
- std::array<uint8_t, 6> createRandomMacAddress();
-
- std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
- std::unique_ptr<std::array<uint8_t, 6>> random_mac_address_;
- std::map<std::string, IfaceEventHandlers> event_handlers_map_;
-};
-
-} // namespace iface_util
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.3/default/wifi_legacy_hal.cpp b/wifi/1.3/default/wifi_legacy_hal.cpp
deleted file mode 100644
index 485bd16..0000000
--- a/wifi/1.3/default/wifi_legacy_hal.cpp
+++ /dev/null
@@ -1,1455 +0,0 @@
-/*
- * 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.
- */
-
-#include <array>
-#include <chrono>
-
-#include <android-base/logging.h>
-#include <cutils/properties.h>
-
-#include "hidl_sync_util.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_legacy_hal_stubs.h"
-
-namespace {
-// Constants ported over from the legacy HAL calling code
-// (com_android_server_wifi_WifiNative.cpp). This will all be thrown
-// away when this shim layer is replaced by the real vendor
-// implementation.
-static constexpr uint32_t kMaxVersionStringLength = 256;
-static constexpr uint32_t kMaxCachedGscanResults = 64;
-static constexpr uint32_t kMaxGscanFrequenciesForBand = 64;
-static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
-static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
-static constexpr uint32_t kMaxRingBuffers = 10;
-static constexpr uint32_t kMaxStopCompleteWaitMs = 100;
-static constexpr char kDriverPropName[] = "wlan.driver.status";
-
-// Helper function to create a non-const char* for legacy Hal API's.
-std::vector<char> makeCharVec(const std::string& str) {
- std::vector<char> vec(str.size() + 1);
- vec.assign(str.begin(), str.end());
- vec.push_back('\0');
- return vec;
-}
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace legacy_hal {
-// Legacy HAL functions accept "C" style function pointers, so use global
-// functions to pass to the legacy HAL function and store the corresponding
-// std::function methods to be invoked.
-//
-// Callback to be invoked once |stop| is complete
-std::function<void(wifi_handle handle)> on_stop_complete_internal_callback;
-void onAsyncStopComplete(wifi_handle handle) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_stop_complete_internal_callback) {
- on_stop_complete_internal_callback(handle);
- // Invalidate this callback since we don't want this firing again.
- on_stop_complete_internal_callback = nullptr;
- }
-}
-
-// Callback to be invoked for driver dump.
-std::function<void(char*, int)> on_driver_memory_dump_internal_callback;
-void onSyncDriverMemoryDump(char* buffer, int buffer_size) {
- if (on_driver_memory_dump_internal_callback) {
- on_driver_memory_dump_internal_callback(buffer, buffer_size);
- }
-}
-
-// Callback to be invoked for firmware dump.
-std::function<void(char*, int)> on_firmware_memory_dump_internal_callback;
-void onSyncFirmwareMemoryDump(char* buffer, int buffer_size) {
- if (on_firmware_memory_dump_internal_callback) {
- on_firmware_memory_dump_internal_callback(buffer, buffer_size);
- }
-}
-
-// Callback to be invoked for Gscan events.
-std::function<void(wifi_request_id, wifi_scan_event)>
- on_gscan_event_internal_callback;
-void onAsyncGscanEvent(wifi_request_id id, wifi_scan_event event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_gscan_event_internal_callback) {
- on_gscan_event_internal_callback(id, event);
- }
-}
-
-// Callback to be invoked for Gscan full results.
-std::function<void(wifi_request_id, wifi_scan_result*, uint32_t)>
- on_gscan_full_result_internal_callback;
-void onAsyncGscanFullResult(wifi_request_id id, wifi_scan_result* result,
- uint32_t buckets_scanned) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_gscan_full_result_internal_callback) {
- on_gscan_full_result_internal_callback(id, result, buckets_scanned);
- }
-}
-
-// Callback to be invoked for link layer stats results.
-std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
- on_link_layer_stats_result_internal_callback;
-void onSyncLinkLayerStatsResult(wifi_request_id id, wifi_iface_stat* iface_stat,
- int num_radios, wifi_radio_stat* radio_stat) {
- if (on_link_layer_stats_result_internal_callback) {
- on_link_layer_stats_result_internal_callback(id, iface_stat, num_radios,
- radio_stat);
- }
-}
-
-// Callback to be invoked for rssi threshold breach.
-std::function<void((wifi_request_id, uint8_t*, int8_t))>
- on_rssi_threshold_breached_internal_callback;
-void onAsyncRssiThresholdBreached(wifi_request_id id, uint8_t* bssid,
- int8_t rssi) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_rssi_threshold_breached_internal_callback) {
- on_rssi_threshold_breached_internal_callback(id, bssid, rssi);
- }
-}
-
-// Callback to be invoked for ring buffer data indication.
-std::function<void(char*, char*, int, wifi_ring_buffer_status*)>
- on_ring_buffer_data_internal_callback;
-void onAsyncRingBufferData(char* ring_name, char* buffer, int buffer_size,
- wifi_ring_buffer_status* status) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_ring_buffer_data_internal_callback) {
- on_ring_buffer_data_internal_callback(ring_name, buffer, buffer_size,
- status);
- }
-}
-
-// Callback to be invoked for error alert indication.
-std::function<void(wifi_request_id, char*, int, int)>
- on_error_alert_internal_callback;
-void onAsyncErrorAlert(wifi_request_id id, char* buffer, int buffer_size,
- int err_code) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_error_alert_internal_callback) {
- on_error_alert_internal_callback(id, buffer, buffer_size, err_code);
- }
-}
-
-// Callback to be invoked for radio mode change indication.
-std::function<void(wifi_request_id, uint32_t, wifi_mac_info*)>
- on_radio_mode_change_internal_callback;
-void onAsyncRadioModeChange(wifi_request_id id, uint32_t num_macs,
- wifi_mac_info* mac_infos) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_radio_mode_change_internal_callback) {
- on_radio_mode_change_internal_callback(id, num_macs, mac_infos);
- }
-}
-
-// Callback to be invoked for rtt results results.
-std::function<void(wifi_request_id, unsigned num_results,
- wifi_rtt_result* rtt_results[])>
- on_rtt_results_internal_callback;
-void onAsyncRttResults(wifi_request_id id, unsigned num_results,
- wifi_rtt_result* rtt_results[]) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_rtt_results_internal_callback) {
- on_rtt_results_internal_callback(id, num_results, rtt_results);
- on_rtt_results_internal_callback = nullptr;
- }
-}
-
-// Callbacks for the various NAN operations.
-// NOTE: These have very little conversions to perform before invoking the user
-// callbacks.
-// So, handle all of them here directly to avoid adding an unnecessary layer.
-std::function<void(transaction_id, const NanResponseMsg&)>
- on_nan_notify_response_user_callback;
-void onAysncNanNotifyResponse(transaction_id id, NanResponseMsg* msg) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_notify_response_user_callback && msg) {
- on_nan_notify_response_user_callback(id, *msg);
- }
-}
-
-std::function<void(const NanPublishRepliedInd&)>
- on_nan_event_publish_replied_user_callback;
-void onAysncNanEventPublishReplied(NanPublishRepliedInd* /* event */) {
- LOG(ERROR) << "onAysncNanEventPublishReplied triggered";
-}
-
-std::function<void(const NanPublishTerminatedInd&)>
- on_nan_event_publish_terminated_user_callback;
-void onAysncNanEventPublishTerminated(NanPublishTerminatedInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_publish_terminated_user_callback && event) {
- on_nan_event_publish_terminated_user_callback(*event);
- }
-}
-
-std::function<void(const NanMatchInd&)> on_nan_event_match_user_callback;
-void onAysncNanEventMatch(NanMatchInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_match_user_callback && event) {
- on_nan_event_match_user_callback(*event);
- }
-}
-
-std::function<void(const NanMatchExpiredInd&)>
- on_nan_event_match_expired_user_callback;
-void onAysncNanEventMatchExpired(NanMatchExpiredInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_match_expired_user_callback && event) {
- on_nan_event_match_expired_user_callback(*event);
- }
-}
-
-std::function<void(const NanSubscribeTerminatedInd&)>
- on_nan_event_subscribe_terminated_user_callback;
-void onAysncNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_subscribe_terminated_user_callback && event) {
- on_nan_event_subscribe_terminated_user_callback(*event);
- }
-}
-
-std::function<void(const NanFollowupInd&)> on_nan_event_followup_user_callback;
-void onAysncNanEventFollowup(NanFollowupInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_followup_user_callback && event) {
- on_nan_event_followup_user_callback(*event);
- }
-}
-
-std::function<void(const NanDiscEngEventInd&)>
- on_nan_event_disc_eng_event_user_callback;
-void onAysncNanEventDiscEngEvent(NanDiscEngEventInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_disc_eng_event_user_callback && event) {
- on_nan_event_disc_eng_event_user_callback(*event);
- }
-}
-
-std::function<void(const NanDisabledInd&)> on_nan_event_disabled_user_callback;
-void onAysncNanEventDisabled(NanDisabledInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_disabled_user_callback && event) {
- on_nan_event_disabled_user_callback(*event);
- }
-}
-
-std::function<void(const NanTCAInd&)> on_nan_event_tca_user_callback;
-void onAysncNanEventTca(NanTCAInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_tca_user_callback && event) {
- on_nan_event_tca_user_callback(*event);
- }
-}
-
-std::function<void(const NanBeaconSdfPayloadInd&)>
- on_nan_event_beacon_sdf_payload_user_callback;
-void onAysncNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_beacon_sdf_payload_user_callback && event) {
- on_nan_event_beacon_sdf_payload_user_callback(*event);
- }
-}
-
-std::function<void(const NanDataPathRequestInd&)>
- on_nan_event_data_path_request_user_callback;
-void onAysncNanEventDataPathRequest(NanDataPathRequestInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_data_path_request_user_callback && event) {
- on_nan_event_data_path_request_user_callback(*event);
- }
-}
-std::function<void(const NanDataPathConfirmInd&)>
- on_nan_event_data_path_confirm_user_callback;
-void onAysncNanEventDataPathConfirm(NanDataPathConfirmInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_data_path_confirm_user_callback && event) {
- on_nan_event_data_path_confirm_user_callback(*event);
- }
-}
-
-std::function<void(const NanDataPathEndInd&)>
- on_nan_event_data_path_end_user_callback;
-void onAysncNanEventDataPathEnd(NanDataPathEndInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_data_path_end_user_callback && event) {
- on_nan_event_data_path_end_user_callback(*event);
- }
-}
-
-std::function<void(const NanTransmitFollowupInd&)>
- on_nan_event_transmit_follow_up_user_callback;
-void onAysncNanEventTransmitFollowUp(NanTransmitFollowupInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_transmit_follow_up_user_callback && event) {
- on_nan_event_transmit_follow_up_user_callback(*event);
- }
-}
-
-std::function<void(const NanRangeRequestInd&)>
- on_nan_event_range_request_user_callback;
-void onAysncNanEventRangeRequest(NanRangeRequestInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_range_request_user_callback && event) {
- on_nan_event_range_request_user_callback(*event);
- }
-}
-
-std::function<void(const NanRangeReportInd&)>
- on_nan_event_range_report_user_callback;
-void onAysncNanEventRangeReport(NanRangeReportInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_range_report_user_callback && event) {
- on_nan_event_range_report_user_callback(*event);
- }
-}
-
-std::function<void(const NanDataPathScheduleUpdateInd&)>
- on_nan_event_schedule_update_user_callback;
-void onAsyncNanEventScheduleUpdate(NanDataPathScheduleUpdateInd* event) {
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (on_nan_event_schedule_update_user_callback && event) {
- on_nan_event_schedule_update_user_callback(*event);
- }
-}
-// End of the free-standing "C" style callbacks.
-
-WifiLegacyHal::WifiLegacyHal(
- const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
- : global_handle_(nullptr),
- awaiting_event_loop_termination_(false),
- is_started_(false),
- iface_tool_(iface_tool) {}
-
-wifi_error WifiLegacyHal::initialize() {
- LOG(DEBUG) << "Initialize legacy HAL";
- // TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
- // for now is this function call which we can directly call.
- if (!initHalFuncTableWithStubs(&global_func_table_)) {
- LOG(ERROR)
- << "Failed to initialize legacy hal function table with stubs";
- return WIFI_ERROR_UNKNOWN;
- }
- wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
- if (status != WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to initialize legacy hal function table";
- }
- return status;
-}
-
-wifi_error WifiLegacyHal::start() {
- // Ensure that we're starting in a good state.
- CHECK(global_func_table_.wifi_initialize && !global_handle_ &&
- iface_name_to_handle_.empty() && !awaiting_event_loop_termination_);
- if (is_started_) {
- LOG(DEBUG) << "Legacy HAL already started";
- return WIFI_SUCCESS;
- }
- LOG(DEBUG) << "Waiting for the driver ready";
- wifi_error status = global_func_table_.wifi_wait_for_driver_ready();
- if (status == WIFI_ERROR_TIMED_OUT) {
- LOG(ERROR) << "Timed out awaiting driver ready";
- return status;
- }
- property_set(kDriverPropName, "ok");
-
- LOG(DEBUG) << "Starting legacy HAL";
- if (!iface_tool_.lock()->SetWifiUpState(true)) {
- LOG(ERROR) << "Failed to set WiFi interface up";
- return WIFI_ERROR_UNKNOWN;
- }
- status = global_func_table_.wifi_initialize(&global_handle_);
- if (status != WIFI_SUCCESS || !global_handle_) {
- LOG(ERROR) << "Failed to retrieve global handle";
- return status;
- }
- std::thread(&WifiLegacyHal::runEventLoop, this).detach();
- status = retrieveIfaceHandles();
- if (status != WIFI_SUCCESS || iface_name_to_handle_.empty()) {
- LOG(ERROR) << "Failed to retrieve wlan interface handle";
- return status;
- }
- LOG(DEBUG) << "Legacy HAL start complete";
- is_started_ = true;
- return WIFI_SUCCESS;
-}
-
-wifi_error WifiLegacyHal::stop(
- /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
- const std::function<void()>& on_stop_complete_user_callback) {
- if (!is_started_) {
- LOG(DEBUG) << "Legacy HAL already stopped";
- on_stop_complete_user_callback();
- return WIFI_SUCCESS;
- }
- LOG(DEBUG) << "Stopping legacy HAL";
- on_stop_complete_internal_callback = [on_stop_complete_user_callback,
- this](wifi_handle handle) {
- CHECK_EQ(global_handle_, handle) << "Handle mismatch";
- LOG(INFO) << "Legacy HAL stop complete callback received";
- // Invalidate all the internal pointers now that the HAL is
- // stopped.
- invalidate();
- iface_tool_.lock()->SetWifiUpState(false);
- on_stop_complete_user_callback();
- is_started_ = false;
- };
- awaiting_event_loop_termination_ = true;
- global_func_table_.wifi_cleanup(global_handle_, onAsyncStopComplete);
- const auto status = stop_wait_cv_.wait_for(
- *lock, std::chrono::milliseconds(kMaxStopCompleteWaitMs),
- [this] { return !awaiting_event_loop_termination_; });
- if (!status) {
- LOG(ERROR) << "Legacy HAL stop failed or timed out";
- return WIFI_ERROR_UNKNOWN;
- }
- LOG(DEBUG) << "Legacy HAL stop complete";
- return WIFI_SUCCESS;
-}
-
-bool WifiLegacyHal::isStarted() { return is_started_; }
-
-std::pair<wifi_error, std::string> WifiLegacyHal::getDriverVersion(
- const std::string& iface_name) {
- std::array<char, kMaxVersionStringLength> buffer;
- buffer.fill(0);
- wifi_error status = global_func_table_.wifi_get_driver_version(
- getIfaceHandle(iface_name), buffer.data(), buffer.size());
- return {status, buffer.data()};
-}
-
-std::pair<wifi_error, std::string> WifiLegacyHal::getFirmwareVersion(
- const std::string& iface_name) {
- std::array<char, kMaxVersionStringLength> buffer;
- buffer.fill(0);
- wifi_error status = global_func_table_.wifi_get_firmware_version(
- getIfaceHandle(iface_name), buffer.data(), buffer.size());
- return {status, buffer.data()};
-}
-
-std::pair<wifi_error, std::vector<uint8_t>>
-WifiLegacyHal::requestDriverMemoryDump(const std::string& iface_name) {
- std::vector<uint8_t> driver_dump;
- on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer,
- int buffer_size) {
- driver_dump.insert(driver_dump.end(),
- reinterpret_cast<uint8_t*>(buffer),
- reinterpret_cast<uint8_t*>(buffer) + buffer_size);
- };
- wifi_error status = global_func_table_.wifi_get_driver_memory_dump(
- getIfaceHandle(iface_name), {onSyncDriverMemoryDump});
- on_driver_memory_dump_internal_callback = nullptr;
- return {status, std::move(driver_dump)};
-}
-
-std::pair<wifi_error, std::vector<uint8_t>>
-WifiLegacyHal::requestFirmwareMemoryDump(const std::string& iface_name) {
- std::vector<uint8_t> firmware_dump;
- on_firmware_memory_dump_internal_callback =
- [&firmware_dump](char* buffer, int buffer_size) {
- firmware_dump.insert(
- firmware_dump.end(), reinterpret_cast<uint8_t*>(buffer),
- reinterpret_cast<uint8_t*>(buffer) + buffer_size);
- };
- wifi_error status = global_func_table_.wifi_get_firmware_memory_dump(
- getIfaceHandle(iface_name), {onSyncFirmwareMemoryDump});
- on_firmware_memory_dump_internal_callback = nullptr;
- return {status, std::move(firmware_dump)};
-}
-
-std::pair<wifi_error, uint32_t> WifiLegacyHal::getSupportedFeatureSet(
- const std::string& iface_name) {
- feature_set set;
- static_assert(sizeof(set) == sizeof(uint32_t),
- "Some feature_flags can not be represented in output");
- wifi_error status = global_func_table_.wifi_get_supported_feature_set(
- getIfaceHandle(iface_name), &set);
- return {status, static_cast<uint32_t>(set)};
-}
-
-std::pair<wifi_error, PacketFilterCapabilities>
-WifiLegacyHal::getPacketFilterCapabilities(const std::string& iface_name) {
- PacketFilterCapabilities caps;
- wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
- getIfaceHandle(iface_name), &caps.version, &caps.max_len);
- return {status, caps};
-}
-
-wifi_error WifiLegacyHal::setPacketFilter(const std::string& iface_name,
- const std::vector<uint8_t>& program) {
- return global_func_table_.wifi_set_packet_filter(
- getIfaceHandle(iface_name), program.data(), program.size());
-}
-
-std::pair<wifi_error, std::vector<uint8_t>>
-WifiLegacyHal::readApfPacketFilterData(const std::string& iface_name) {
- PacketFilterCapabilities caps;
- wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
- getIfaceHandle(iface_name), &caps.version, &caps.max_len);
- if (status != WIFI_SUCCESS) {
- return {status, {}};
- }
-
- // Size the buffer to read the entire program & work memory.
- std::vector<uint8_t> buffer(caps.max_len);
-
- status = global_func_table_.wifi_read_packet_filter(
- getIfaceHandle(iface_name), /*src_offset=*/0, buffer.data(),
- buffer.size());
- return {status, move(buffer)};
-}
-
-std::pair<wifi_error, wifi_gscan_capabilities>
-WifiLegacyHal::getGscanCapabilities(const std::string& iface_name) {
- wifi_gscan_capabilities caps;
- wifi_error status = global_func_table_.wifi_get_gscan_capabilities(
- getIfaceHandle(iface_name), &caps);
- return {status, caps};
-}
-
-wifi_error WifiLegacyHal::startGscan(
- const std::string& iface_name, wifi_request_id id,
- const wifi_scan_cmd_params& params,
- const std::function<void(wifi_request_id)>& on_failure_user_callback,
- const on_gscan_results_callback& on_results_user_callback,
- const on_gscan_full_result_callback& on_full_result_user_callback) {
- // If there is already an ongoing background scan, reject new scan requests.
- if (on_gscan_event_internal_callback ||
- on_gscan_full_result_internal_callback) {
- return WIFI_ERROR_NOT_AVAILABLE;
- }
-
- // This callback will be used to either trigger |on_results_user_callback|
- // or |on_failure_user_callback|.
- on_gscan_event_internal_callback =
- [iface_name, on_failure_user_callback, on_results_user_callback, this](
- wifi_request_id id, wifi_scan_event event) {
- switch (event) {
- case WIFI_SCAN_RESULTS_AVAILABLE:
- case WIFI_SCAN_THRESHOLD_NUM_SCANS:
- case WIFI_SCAN_THRESHOLD_PERCENT: {
- wifi_error status;
- std::vector<wifi_cached_scan_results> cached_scan_results;
- std::tie(status, cached_scan_results) =
- getGscanCachedResults(iface_name);
- if (status == WIFI_SUCCESS) {
- on_results_user_callback(id, cached_scan_results);
- return;
- }
- FALLTHROUGH_INTENDED;
- }
- // Fall through if failed. Failure to retrieve cached scan
- // results should trigger a background scan failure.
- case WIFI_SCAN_FAILED:
- on_failure_user_callback(id);
- on_gscan_event_internal_callback = nullptr;
- on_gscan_full_result_internal_callback = nullptr;
- return;
- }
- LOG(FATAL) << "Unexpected gscan event received: " << event;
- };
-
- on_gscan_full_result_internal_callback = [on_full_result_user_callback](
- wifi_request_id id,
- wifi_scan_result* result,
- uint32_t buckets_scanned) {
- if (result) {
- on_full_result_user_callback(id, result, buckets_scanned);
- }
- };
-
- wifi_scan_result_handler handler = {onAsyncGscanFullResult,
- onAsyncGscanEvent};
- wifi_error status = global_func_table_.wifi_start_gscan(
- id, getIfaceHandle(iface_name), params, handler);
- if (status != WIFI_SUCCESS) {
- on_gscan_event_internal_callback = nullptr;
- on_gscan_full_result_internal_callback = nullptr;
- }
- return status;
-}
-
-wifi_error WifiLegacyHal::stopGscan(const std::string& iface_name,
- wifi_request_id id) {
- // If there is no an ongoing background scan, reject stop requests.
- // TODO(b/32337212): This needs to be handled by the HIDL object because we
- // need to return the NOT_STARTED error code.
- if (!on_gscan_event_internal_callback &&
- !on_gscan_full_result_internal_callback) {
- return WIFI_ERROR_NOT_AVAILABLE;
- }
- wifi_error status =
- global_func_table_.wifi_stop_gscan(id, getIfaceHandle(iface_name));
- // If the request Id is wrong, don't stop the ongoing background scan. Any
- // other error should be treated as the end of background scan.
- if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
- on_gscan_event_internal_callback = nullptr;
- on_gscan_full_result_internal_callback = nullptr;
- }
- return status;
-}
-
-std::pair<wifi_error, std::vector<uint32_t>>
-WifiLegacyHal::getValidFrequenciesForBand(const std::string& iface_name,
- wifi_band band) {
- static_assert(sizeof(uint32_t) >= sizeof(wifi_channel),
- "Wifi Channel cannot be represented in output");
- std::vector<uint32_t> freqs;
- freqs.resize(kMaxGscanFrequenciesForBand);
- int32_t num_freqs = 0;
- wifi_error status = global_func_table_.wifi_get_valid_channels(
- getIfaceHandle(iface_name), band, freqs.size(),
- reinterpret_cast<wifi_channel*>(freqs.data()), &num_freqs);
- CHECK(num_freqs >= 0 &&
- static_cast<uint32_t>(num_freqs) <= kMaxGscanFrequenciesForBand);
- freqs.resize(num_freqs);
- return {status, std::move(freqs)};
-}
-
-wifi_error WifiLegacyHal::setDfsFlag(const std::string& iface_name,
- bool dfs_on) {
- return global_func_table_.wifi_set_nodfs_flag(getIfaceHandle(iface_name),
- dfs_on ? 0 : 1);
-}
-
-wifi_error WifiLegacyHal::enableLinkLayerStats(const std::string& iface_name,
- bool debug) {
- wifi_link_layer_params params;
- params.mpdu_size_threshold = kLinkLayerStatsDataMpduSizeThreshold;
- params.aggressive_statistics_gathering = debug;
- return global_func_table_.wifi_set_link_stats(getIfaceHandle(iface_name),
- params);
-}
-
-wifi_error WifiLegacyHal::disableLinkLayerStats(const std::string& iface_name) {
- // TODO: Do we care about these responses?
- uint32_t clear_mask_rsp;
- uint8_t stop_rsp;
- return global_func_table_.wifi_clear_link_stats(
- getIfaceHandle(iface_name), 0xFFFFFFFF, &clear_mask_rsp, 1, &stop_rsp);
-}
-
-std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats(
- const std::string& iface_name) {
- LinkLayerStats link_stats{};
- LinkLayerStats* link_stats_ptr = &link_stats;
-
- on_link_layer_stats_result_internal_callback =
- [&link_stats_ptr](wifi_request_id /* id */,
- wifi_iface_stat* iface_stats_ptr, int num_radios,
- wifi_radio_stat* radio_stats_ptr) {
- wifi_radio_stat* l_radio_stats_ptr;
-
- if (iface_stats_ptr != nullptr) {
- link_stats_ptr->iface = *iface_stats_ptr;
- link_stats_ptr->iface.num_peers = 0;
- } else {
- LOG(ERROR) << "Invalid iface stats in link layer stats";
- }
- if (num_radios <= 0 || radio_stats_ptr == nullptr) {
- LOG(ERROR) << "Invalid radio stats in link layer stats";
- return;
- }
- l_radio_stats_ptr = radio_stats_ptr;
- for (int i = 0; i < num_radios; i++) {
- LinkLayerRadioStats radio;
-
- radio.stats = *l_radio_stats_ptr;
- // Copy over the tx level array to the separate vector.
- if (l_radio_stats_ptr->num_tx_levels > 0 &&
- l_radio_stats_ptr->tx_time_per_levels != nullptr) {
- radio.tx_time_per_levels.assign(
- l_radio_stats_ptr->tx_time_per_levels,
- l_radio_stats_ptr->tx_time_per_levels +
- l_radio_stats_ptr->num_tx_levels);
- }
- radio.stats.num_tx_levels = 0;
- radio.stats.tx_time_per_levels = nullptr;
- /* Copy over the channel stat to separate vector */
- if (l_radio_stats_ptr->num_channels > 0) {
- /* Copy the channel stats */
- radio.channel_stats.assign(
- l_radio_stats_ptr->channels,
- l_radio_stats_ptr->channels +
- l_radio_stats_ptr->num_channels);
- }
- link_stats_ptr->radios.push_back(radio);
- l_radio_stats_ptr =
- (wifi_radio_stat*)((u8*)l_radio_stats_ptr +
- sizeof(wifi_radio_stat) +
- (sizeof(wifi_channel_stat) *
- l_radio_stats_ptr->num_channels));
- }
- };
-
- wifi_error status = global_func_table_.wifi_get_link_stats(
- 0, getIfaceHandle(iface_name), {onSyncLinkLayerStatsResult});
- on_link_layer_stats_result_internal_callback = nullptr;
- return {status, link_stats};
-}
-
-wifi_error WifiLegacyHal::startRssiMonitoring(
- const std::string& iface_name, wifi_request_id id, int8_t max_rssi,
- int8_t min_rssi,
- const on_rssi_threshold_breached_callback&
- on_threshold_breached_user_callback) {
- if (on_rssi_threshold_breached_internal_callback) {
- return WIFI_ERROR_NOT_AVAILABLE;
- }
- on_rssi_threshold_breached_internal_callback =
- [on_threshold_breached_user_callback](wifi_request_id id,
- uint8_t* bssid_ptr, int8_t rssi) {
- if (!bssid_ptr) {
- return;
- }
- std::array<uint8_t, 6> bssid_arr;
- // |bssid_ptr| pointer is assumed to have 6 bytes for the mac
- // address.
- std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr));
- on_threshold_breached_user_callback(id, bssid_arr, rssi);
- };
- wifi_error status = global_func_table_.wifi_start_rssi_monitoring(
- id, getIfaceHandle(iface_name), max_rssi, min_rssi,
- {onAsyncRssiThresholdBreached});
- if (status != WIFI_SUCCESS) {
- on_rssi_threshold_breached_internal_callback = nullptr;
- }
- return status;
-}
-
-wifi_error WifiLegacyHal::stopRssiMonitoring(const std::string& iface_name,
- wifi_request_id id) {
- if (!on_rssi_threshold_breached_internal_callback) {
- return WIFI_ERROR_NOT_AVAILABLE;
- }
- wifi_error status = global_func_table_.wifi_stop_rssi_monitoring(
- id, getIfaceHandle(iface_name));
- // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any
- // other error should be treated as the end of background scan.
- if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
- on_rssi_threshold_breached_internal_callback = nullptr;
- }
- return status;
-}
-
-std::pair<wifi_error, wifi_roaming_capabilities>
-WifiLegacyHal::getRoamingCapabilities(const std::string& iface_name) {
- wifi_roaming_capabilities caps;
- wifi_error status = global_func_table_.wifi_get_roaming_capabilities(
- getIfaceHandle(iface_name), &caps);
- return {status, caps};
-}
-
-wifi_error WifiLegacyHal::configureRoaming(const std::string& iface_name,
- const wifi_roaming_config& config) {
- wifi_roaming_config config_internal = config;
- return global_func_table_.wifi_configure_roaming(getIfaceHandle(iface_name),
- &config_internal);
-}
-
-wifi_error WifiLegacyHal::enableFirmwareRoaming(const std::string& iface_name,
- fw_roaming_state_t state) {
- return global_func_table_.wifi_enable_firmware_roaming(
- getIfaceHandle(iface_name), state);
-}
-
-wifi_error WifiLegacyHal::configureNdOffload(const std::string& iface_name,
- bool enable) {
- return global_func_table_.wifi_configure_nd_offload(
- getIfaceHandle(iface_name), enable);
-}
-
-wifi_error WifiLegacyHal::startSendingOffloadedPacket(
- const std::string& iface_name, uint32_t cmd_id, uint16_t ether_type,
- const std::vector<uint8_t>& ip_packet_data,
- const std::array<uint8_t, 6>& src_address,
- const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
- std::vector<uint8_t> ip_packet_data_internal(ip_packet_data);
- std::vector<uint8_t> src_address_internal(
- src_address.data(), src_address.data() + src_address.size());
- std::vector<uint8_t> dst_address_internal(
- dst_address.data(), dst_address.data() + dst_address.size());
- return global_func_table_.wifi_start_sending_offloaded_packet(
- cmd_id, getIfaceHandle(iface_name), ether_type,
- ip_packet_data_internal.data(), ip_packet_data_internal.size(),
- src_address_internal.data(), dst_address_internal.data(), period_in_ms);
-}
-
-wifi_error WifiLegacyHal::stopSendingOffloadedPacket(
- const std::string& iface_name, uint32_t cmd_id) {
- return global_func_table_.wifi_stop_sending_offloaded_packet(
- cmd_id, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::setScanningMacOui(const std::string& iface_name,
- const std::array<uint8_t, 3>& oui) {
- std::vector<uint8_t> oui_internal(oui.data(), oui.data() + oui.size());
- return global_func_table_.wifi_set_scanning_mac_oui(
- getIfaceHandle(iface_name), oui_internal.data());
-}
-
-wifi_error WifiLegacyHal::selectTxPowerScenario(const std::string& iface_name,
- wifi_power_scenario scenario) {
- return global_func_table_.wifi_select_tx_power_scenario(
- getIfaceHandle(iface_name), scenario);
-}
-
-wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) {
- return global_func_table_.wifi_reset_tx_power_scenario(
- getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::setLatencyMode(const std::string& iface_name,
- wifi_latency_mode mode) {
- return global_func_table_.wifi_set_latency_mode(getIfaceHandle(iface_name),
- mode);
-}
-
-std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
- const std::string& iface_name) {
- uint32_t supported_feature_flags;
- wifi_error status =
- global_func_table_.wifi_get_logger_supported_feature_set(
- getIfaceHandle(iface_name), &supported_feature_flags);
- return {status, supported_feature_flags};
-}
-
-wifi_error WifiLegacyHal::startPktFateMonitoring(
- const std::string& iface_name) {
- return global_func_table_.wifi_start_pkt_fate_monitoring(
- getIfaceHandle(iface_name));
-}
-
-std::pair<wifi_error, std::vector<wifi_tx_report>> WifiLegacyHal::getTxPktFates(
- const std::string& iface_name) {
- std::vector<wifi_tx_report> tx_pkt_fates;
- tx_pkt_fates.resize(MAX_FATE_LOG_LEN);
- size_t num_fates = 0;
- wifi_error status = global_func_table_.wifi_get_tx_pkt_fates(
- getIfaceHandle(iface_name), tx_pkt_fates.data(), tx_pkt_fates.size(),
- &num_fates);
- CHECK(num_fates <= MAX_FATE_LOG_LEN);
- tx_pkt_fates.resize(num_fates);
- return {status, std::move(tx_pkt_fates)};
-}
-
-std::pair<wifi_error, std::vector<wifi_rx_report>> WifiLegacyHal::getRxPktFates(
- const std::string& iface_name) {
- std::vector<wifi_rx_report> rx_pkt_fates;
- rx_pkt_fates.resize(MAX_FATE_LOG_LEN);
- size_t num_fates = 0;
- wifi_error status = global_func_table_.wifi_get_rx_pkt_fates(
- getIfaceHandle(iface_name), rx_pkt_fates.data(), rx_pkt_fates.size(),
- &num_fates);
- CHECK(num_fates <= MAX_FATE_LOG_LEN);
- rx_pkt_fates.resize(num_fates);
- return {status, std::move(rx_pkt_fates)};
-}
-
-std::pair<wifi_error, WakeReasonStats> WifiLegacyHal::getWakeReasonStats(
- const std::string& iface_name) {
- WakeReasonStats stats;
- stats.cmd_event_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
- stats.driver_fw_local_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
-
- // This legacy struct needs separate memory to store the variable sized wake
- // reason types.
- stats.wake_reason_cnt.cmd_event_wake_cnt =
- reinterpret_cast<int32_t*>(stats.cmd_event_wake_cnt.data());
- stats.wake_reason_cnt.cmd_event_wake_cnt_sz =
- stats.cmd_event_wake_cnt.size();
- stats.wake_reason_cnt.cmd_event_wake_cnt_used = 0;
- stats.wake_reason_cnt.driver_fw_local_wake_cnt =
- reinterpret_cast<int32_t*>(stats.driver_fw_local_wake_cnt.data());
- stats.wake_reason_cnt.driver_fw_local_wake_cnt_sz =
- stats.driver_fw_local_wake_cnt.size();
- stats.wake_reason_cnt.driver_fw_local_wake_cnt_used = 0;
-
- wifi_error status = global_func_table_.wifi_get_wake_reason_stats(
- getIfaceHandle(iface_name), &stats.wake_reason_cnt);
-
- CHECK(
- stats.wake_reason_cnt.cmd_event_wake_cnt_used >= 0 &&
- static_cast<uint32_t>(stats.wake_reason_cnt.cmd_event_wake_cnt_used) <=
- kMaxWakeReasonStatsArraySize);
- stats.cmd_event_wake_cnt.resize(
- stats.wake_reason_cnt.cmd_event_wake_cnt_used);
- stats.wake_reason_cnt.cmd_event_wake_cnt = nullptr;
-
- CHECK(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used >= 0 &&
- static_cast<uint32_t>(
- stats.wake_reason_cnt.driver_fw_local_wake_cnt_used) <=
- kMaxWakeReasonStatsArraySize);
- stats.driver_fw_local_wake_cnt.resize(
- stats.wake_reason_cnt.driver_fw_local_wake_cnt_used);
- stats.wake_reason_cnt.driver_fw_local_wake_cnt = nullptr;
-
- return {status, stats};
-}
-
-wifi_error WifiLegacyHal::registerRingBufferCallbackHandler(
- const std::string& iface_name,
- const on_ring_buffer_data_callback& on_user_data_callback) {
- if (on_ring_buffer_data_internal_callback) {
- return WIFI_ERROR_NOT_AVAILABLE;
- }
- on_ring_buffer_data_internal_callback =
- [on_user_data_callback](char* ring_name, char* buffer, int buffer_size,
- wifi_ring_buffer_status* status) {
- if (status && buffer) {
- std::vector<uint8_t> buffer_vector(
- reinterpret_cast<uint8_t*>(buffer),
- reinterpret_cast<uint8_t*>(buffer) + buffer_size);
- on_user_data_callback(ring_name, buffer_vector, *status);
- }
- };
- wifi_error status = global_func_table_.wifi_set_log_handler(
- 0, getIfaceHandle(iface_name), {onAsyncRingBufferData});
- if (status != WIFI_SUCCESS) {
- on_ring_buffer_data_internal_callback = nullptr;
- }
- return status;
-}
-
-wifi_error WifiLegacyHal::deregisterRingBufferCallbackHandler(
- const std::string& iface_name) {
- if (!on_ring_buffer_data_internal_callback) {
- return WIFI_ERROR_NOT_AVAILABLE;
- }
- on_ring_buffer_data_internal_callback = nullptr;
- return global_func_table_.wifi_reset_log_handler(
- 0, getIfaceHandle(iface_name));
-}
-
-std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
-WifiLegacyHal::getRingBuffersStatus(const std::string& iface_name) {
- std::vector<wifi_ring_buffer_status> ring_buffers_status;
- ring_buffers_status.resize(kMaxRingBuffers);
- uint32_t num_rings = kMaxRingBuffers;
- wifi_error status = global_func_table_.wifi_get_ring_buffers_status(
- getIfaceHandle(iface_name), &num_rings, ring_buffers_status.data());
- CHECK(num_rings <= kMaxRingBuffers);
- ring_buffers_status.resize(num_rings);
- return {status, std::move(ring_buffers_status)};
-}
-
-wifi_error WifiLegacyHal::startRingBufferLogging(const std::string& iface_name,
- const std::string& ring_name,
- uint32_t verbose_level,
- uint32_t max_interval_sec,
- uint32_t min_data_size) {
- return global_func_table_.wifi_start_logging(
- getIfaceHandle(iface_name), verbose_level, 0, max_interval_sec,
- min_data_size, makeCharVec(ring_name).data());
-}
-
-wifi_error WifiLegacyHal::getRingBufferData(const std::string& iface_name,
- const std::string& ring_name) {
- return global_func_table_.wifi_get_ring_data(getIfaceHandle(iface_name),
- makeCharVec(ring_name).data());
-}
-
-wifi_error WifiLegacyHal::registerErrorAlertCallbackHandler(
- const std::string& iface_name,
- const on_error_alert_callback& on_user_alert_callback) {
- if (on_error_alert_internal_callback) {
- return WIFI_ERROR_NOT_AVAILABLE;
- }
- on_error_alert_internal_callback = [on_user_alert_callback](
- wifi_request_id id, char* buffer,
- int buffer_size, int err_code) {
- if (buffer) {
- CHECK(id == 0);
- on_user_alert_callback(
- err_code,
- std::vector<uint8_t>(
- reinterpret_cast<uint8_t*>(buffer),
- reinterpret_cast<uint8_t*>(buffer) + buffer_size));
- }
- };
- wifi_error status = global_func_table_.wifi_set_alert_handler(
- 0, getIfaceHandle(iface_name), {onAsyncErrorAlert});
- if (status != WIFI_SUCCESS) {
- on_error_alert_internal_callback = nullptr;
- }
- return status;
-}
-
-wifi_error WifiLegacyHal::deregisterErrorAlertCallbackHandler(
- const std::string& iface_name) {
- if (!on_error_alert_internal_callback) {
- return WIFI_ERROR_NOT_AVAILABLE;
- }
- on_error_alert_internal_callback = nullptr;
- return global_func_table_.wifi_reset_alert_handler(
- 0, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::registerRadioModeChangeCallbackHandler(
- const std::string& iface_name,
- const on_radio_mode_change_callback& on_user_change_callback) {
- if (on_radio_mode_change_internal_callback) {
- return WIFI_ERROR_NOT_AVAILABLE;
- }
- on_radio_mode_change_internal_callback = [on_user_change_callback](
- wifi_request_id /* id */,
- uint32_t num_macs,
- wifi_mac_info* mac_infos_arr) {
- if (num_macs > 0 && mac_infos_arr) {
- std::vector<WifiMacInfo> mac_infos_vec;
- for (uint32_t i = 0; i < num_macs; i++) {
- WifiMacInfo mac_info;
- mac_info.wlan_mac_id = mac_infos_arr[i].wlan_mac_id;
- mac_info.mac_band = mac_infos_arr[i].mac_band;
- for (int32_t j = 0; j < mac_infos_arr[i].num_iface; j++) {
- WifiIfaceInfo iface_info;
- iface_info.name = mac_infos_arr[i].iface_info[j].iface_name;
- iface_info.channel = mac_infos_arr[i].iface_info[j].channel;
- mac_info.iface_infos.push_back(iface_info);
- }
- mac_infos_vec.push_back(mac_info);
- }
- on_user_change_callback(mac_infos_vec);
- }
- };
- wifi_error status = global_func_table_.wifi_set_radio_mode_change_handler(
- 0, getIfaceHandle(iface_name), {onAsyncRadioModeChange});
- if (status != WIFI_SUCCESS) {
- on_radio_mode_change_internal_callback = nullptr;
- }
- return status;
-}
-
-wifi_error WifiLegacyHal::startRttRangeRequest(
- const std::string& iface_name, wifi_request_id id,
- const std::vector<wifi_rtt_config>& rtt_configs,
- const on_rtt_results_callback& on_results_user_callback) {
- if (on_rtt_results_internal_callback) {
- return WIFI_ERROR_NOT_AVAILABLE;
- }
-
- on_rtt_results_internal_callback =
- [on_results_user_callback](wifi_request_id id, unsigned num_results,
- wifi_rtt_result* rtt_results[]) {
- if (num_results > 0 && !rtt_results) {
- LOG(ERROR) << "Unexpected nullptr in RTT results";
- return;
- }
- std::vector<const wifi_rtt_result*> rtt_results_vec;
- std::copy_if(rtt_results, rtt_results + num_results,
- back_inserter(rtt_results_vec),
- [](wifi_rtt_result* rtt_result) {
- return rtt_result != nullptr;
- });
- on_results_user_callback(id, rtt_results_vec);
- };
-
- std::vector<wifi_rtt_config> rtt_configs_internal(rtt_configs);
- wifi_error status = global_func_table_.wifi_rtt_range_request(
- id, getIfaceHandle(iface_name), rtt_configs.size(),
- rtt_configs_internal.data(), {onAsyncRttResults});
- if (status != WIFI_SUCCESS) {
- on_rtt_results_internal_callback = nullptr;
- }
- return status;
-}
-
-wifi_error WifiLegacyHal::cancelRttRangeRequest(
- const std::string& iface_name, wifi_request_id id,
- const std::vector<std::array<uint8_t, 6>>& mac_addrs) {
- if (!on_rtt_results_internal_callback) {
- return WIFI_ERROR_NOT_AVAILABLE;
- }
- static_assert(sizeof(mac_addr) == sizeof(std::array<uint8_t, 6>),
- "MAC address size mismatch");
- // TODO: How do we handle partial cancels (i.e only a subset of enabled mac
- // addressed are cancelled).
- std::vector<std::array<uint8_t, 6>> mac_addrs_internal(mac_addrs);
- wifi_error status = global_func_table_.wifi_rtt_range_cancel(
- id, getIfaceHandle(iface_name), mac_addrs.size(),
- reinterpret_cast<mac_addr*>(mac_addrs_internal.data()));
- // If the request Id is wrong, don't stop the ongoing range request. Any
- // other error should be treated as the end of rtt ranging.
- if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
- on_rtt_results_internal_callback = nullptr;
- }
- return status;
-}
-
-std::pair<wifi_error, wifi_rtt_capabilities> WifiLegacyHal::getRttCapabilities(
- const std::string& iface_name) {
- wifi_rtt_capabilities rtt_caps;
- wifi_error status = global_func_table_.wifi_get_rtt_capabilities(
- getIfaceHandle(iface_name), &rtt_caps);
- return {status, rtt_caps};
-}
-
-std::pair<wifi_error, wifi_rtt_responder> WifiLegacyHal::getRttResponderInfo(
- const std::string& iface_name) {
- wifi_rtt_responder rtt_responder;
- wifi_error status = global_func_table_.wifi_rtt_get_responder_info(
- getIfaceHandle(iface_name), &rtt_responder);
- return {status, rtt_responder};
-}
-
-wifi_error WifiLegacyHal::enableRttResponder(
- const std::string& iface_name, wifi_request_id id,
- const wifi_channel_info& channel_hint, uint32_t max_duration_secs,
- const wifi_rtt_responder& info) {
- wifi_rtt_responder info_internal(info);
- return global_func_table_.wifi_enable_responder(
- id, getIfaceHandle(iface_name), channel_hint, max_duration_secs,
- &info_internal);
-}
-
-wifi_error WifiLegacyHal::disableRttResponder(const std::string& iface_name,
- wifi_request_id id) {
- return global_func_table_.wifi_disable_responder(
- id, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::setRttLci(const std::string& iface_name,
- wifi_request_id id,
- const wifi_lci_information& info) {
- wifi_lci_information info_internal(info);
- return global_func_table_.wifi_set_lci(id, getIfaceHandle(iface_name),
- &info_internal);
-}
-
-wifi_error WifiLegacyHal::setRttLcr(const std::string& iface_name,
- wifi_request_id id,
- const wifi_lcr_information& info) {
- wifi_lcr_information info_internal(info);
- return global_func_table_.wifi_set_lcr(id, getIfaceHandle(iface_name),
- &info_internal);
-}
-
-wifi_error WifiLegacyHal::nanRegisterCallbackHandlers(
- const std::string& iface_name, const NanCallbackHandlers& user_callbacks) {
- on_nan_notify_response_user_callback = user_callbacks.on_notify_response;
- on_nan_event_publish_terminated_user_callback =
- user_callbacks.on_event_publish_terminated;
- on_nan_event_match_user_callback = user_callbacks.on_event_match;
- on_nan_event_match_expired_user_callback =
- user_callbacks.on_event_match_expired;
- on_nan_event_subscribe_terminated_user_callback =
- user_callbacks.on_event_subscribe_terminated;
- on_nan_event_followup_user_callback = user_callbacks.on_event_followup;
- on_nan_event_disc_eng_event_user_callback =
- user_callbacks.on_event_disc_eng_event;
- on_nan_event_disabled_user_callback = user_callbacks.on_event_disabled;
- on_nan_event_tca_user_callback = user_callbacks.on_event_tca;
- on_nan_event_beacon_sdf_payload_user_callback =
- user_callbacks.on_event_beacon_sdf_payload;
- on_nan_event_data_path_request_user_callback =
- user_callbacks.on_event_data_path_request;
- on_nan_event_data_path_confirm_user_callback =
- user_callbacks.on_event_data_path_confirm;
- on_nan_event_data_path_end_user_callback =
- user_callbacks.on_event_data_path_end;
- on_nan_event_transmit_follow_up_user_callback =
- user_callbacks.on_event_transmit_follow_up;
- on_nan_event_range_request_user_callback =
- user_callbacks.on_event_range_request;
- on_nan_event_range_report_user_callback =
- user_callbacks.on_event_range_report;
- on_nan_event_schedule_update_user_callback =
- user_callbacks.on_event_schedule_update;
-
- return global_func_table_.wifi_nan_register_handler(
- getIfaceHandle(iface_name),
- {onAysncNanNotifyResponse, onAysncNanEventPublishReplied,
- onAysncNanEventPublishTerminated, onAysncNanEventMatch,
- onAysncNanEventMatchExpired, onAysncNanEventSubscribeTerminated,
- onAysncNanEventFollowup, onAysncNanEventDiscEngEvent,
- onAysncNanEventDisabled, onAysncNanEventTca,
- onAysncNanEventBeaconSdfPayload, onAysncNanEventDataPathRequest,
- onAysncNanEventDataPathConfirm, onAysncNanEventDataPathEnd,
- onAysncNanEventTransmitFollowUp, onAysncNanEventRangeRequest,
- onAysncNanEventRangeReport, onAsyncNanEventScheduleUpdate});
-}
-
-wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name,
- transaction_id id,
- const NanEnableRequest& msg) {
- NanEnableRequest msg_internal(msg);
- return global_func_table_.wifi_nan_enable_request(
- id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanDisableRequest(const std::string& iface_name,
- transaction_id id) {
- return global_func_table_.wifi_nan_disable_request(
- id, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::nanPublishRequest(const std::string& iface_name,
- transaction_id id,
- const NanPublishRequest& msg) {
- NanPublishRequest msg_internal(msg);
- return global_func_table_.wifi_nan_publish_request(
- id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanPublishCancelRequest(
- const std::string& iface_name, transaction_id id,
- const NanPublishCancelRequest& msg) {
- NanPublishCancelRequest msg_internal(msg);
- return global_func_table_.wifi_nan_publish_cancel_request(
- id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanSubscribeRequest(const std::string& iface_name,
- transaction_id id,
- const NanSubscribeRequest& msg) {
- NanSubscribeRequest msg_internal(msg);
- return global_func_table_.wifi_nan_subscribe_request(
- id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanSubscribeCancelRequest(
- const std::string& iface_name, transaction_id id,
- const NanSubscribeCancelRequest& msg) {
- NanSubscribeCancelRequest msg_internal(msg);
- return global_func_table_.wifi_nan_subscribe_cancel_request(
- id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanTransmitFollowupRequest(
- const std::string& iface_name, transaction_id id,
- const NanTransmitFollowupRequest& msg) {
- NanTransmitFollowupRequest msg_internal(msg);
- return global_func_table_.wifi_nan_transmit_followup_request(
- id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanStatsRequest(const std::string& iface_name,
- transaction_id id,
- const NanStatsRequest& msg) {
- NanStatsRequest msg_internal(msg);
- return global_func_table_.wifi_nan_stats_request(
- id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanConfigRequest(const std::string& iface_name,
- transaction_id id,
- const NanConfigRequest& msg) {
- NanConfigRequest msg_internal(msg);
- return global_func_table_.wifi_nan_config_request(
- id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanTcaRequest(const std::string& iface_name,
- transaction_id id,
- const NanTCARequest& msg) {
- NanTCARequest msg_internal(msg);
- return global_func_table_.wifi_nan_tca_request(
- id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanBeaconSdfPayloadRequest(
- const std::string& iface_name, transaction_id id,
- const NanBeaconSdfPayloadRequest& msg) {
- NanBeaconSdfPayloadRequest msg_internal(msg);
- return global_func_table_.wifi_nan_beacon_sdf_payload_request(
- id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-std::pair<wifi_error, NanVersion> WifiLegacyHal::nanGetVersion() {
- NanVersion version;
- wifi_error status =
- global_func_table_.wifi_nan_get_version(global_handle_, &version);
- return {status, version};
-}
-
-wifi_error WifiLegacyHal::nanGetCapabilities(const std::string& iface_name,
- transaction_id id) {
- return global_func_table_.wifi_nan_get_capabilities(
- id, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::nanDataInterfaceCreate(
- const std::string& iface_name, transaction_id id,
- const std::string& data_iface_name) {
- return global_func_table_.wifi_nan_data_interface_create(
- id, getIfaceHandle(iface_name), makeCharVec(data_iface_name).data());
-}
-
-wifi_error WifiLegacyHal::nanDataInterfaceDelete(
- const std::string& iface_name, transaction_id id,
- const std::string& data_iface_name) {
- return global_func_table_.wifi_nan_data_interface_delete(
- id, getIfaceHandle(iface_name), makeCharVec(data_iface_name).data());
-}
-
-wifi_error WifiLegacyHal::nanDataRequestInitiator(
- const std::string& iface_name, transaction_id id,
- const NanDataPathInitiatorRequest& msg) {
- NanDataPathInitiatorRequest msg_internal(msg);
- return global_func_table_.wifi_nan_data_request_initiator(
- id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanDataIndicationResponse(
- const std::string& iface_name, transaction_id id,
- const NanDataPathIndicationResponse& msg) {
- NanDataPathIndicationResponse msg_internal(msg);
- return global_func_table_.wifi_nan_data_indication_response(
- id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-typedef struct {
- u8 num_ndp_instances;
- NanDataPathId ndp_instance_id;
-} NanDataPathEndSingleNdpIdRequest;
-
-wifi_error WifiLegacyHal::nanDataEnd(const std::string& iface_name,
- transaction_id id,
- uint32_t ndpInstanceId) {
- NanDataPathEndSingleNdpIdRequest msg;
- msg.num_ndp_instances = 1;
- msg.ndp_instance_id = ndpInstanceId;
- wifi_error status = global_func_table_.wifi_nan_data_end(
- id, getIfaceHandle(iface_name), (NanDataPathEndRequest*)&msg);
- return status;
-}
-
-wifi_error WifiLegacyHal::setCountryCode(const std::string& iface_name,
- std::array<int8_t, 2> code) {
- std::string code_str(code.data(), code.data() + code.size());
- return global_func_table_.wifi_set_country_code(getIfaceHandle(iface_name),
- code_str.c_str());
-}
-
-wifi_error WifiLegacyHal::retrieveIfaceHandles() {
- wifi_interface_handle* iface_handles = nullptr;
- int num_iface_handles = 0;
- wifi_error status = global_func_table_.wifi_get_ifaces(
- global_handle_, &num_iface_handles, &iface_handles);
- if (status != WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to enumerate interface handles";
- return status;
- }
- for (int i = 0; i < num_iface_handles; ++i) {
- std::array<char, IFNAMSIZ> iface_name_arr = {};
- status = global_func_table_.wifi_get_iface_name(
- iface_handles[i], iface_name_arr.data(), iface_name_arr.size());
- if (status != WIFI_SUCCESS) {
- LOG(WARNING) << "Failed to get interface handle name";
- continue;
- }
- // Assuming the interface name is null terminated since the legacy HAL
- // API does not return a size.
- std::string iface_name(iface_name_arr.data());
- LOG(INFO) << "Adding interface handle for " << iface_name;
- iface_name_to_handle_[iface_name] = iface_handles[i];
- }
- return WIFI_SUCCESS;
-}
-
-wifi_interface_handle WifiLegacyHal::getIfaceHandle(
- const std::string& iface_name) {
- const auto iface_handle_iter = iface_name_to_handle_.find(iface_name);
- if (iface_handle_iter == iface_name_to_handle_.end()) {
- LOG(ERROR) << "Unknown iface name: " << iface_name;
- return nullptr;
- }
- return iface_handle_iter->second;
-}
-
-void WifiLegacyHal::runEventLoop() {
- LOG(DEBUG) << "Starting legacy HAL event loop";
- global_func_table_.wifi_event_loop(global_handle_);
- const auto lock = hidl_sync_util::acquireGlobalLock();
- if (!awaiting_event_loop_termination_) {
- LOG(FATAL)
- << "Legacy HAL event loop terminated, but HAL was not stopping";
- }
- LOG(DEBUG) << "Legacy HAL event loop terminated";
- awaiting_event_loop_termination_ = false;
- stop_wait_cv_.notify_one();
-}
-
-std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
-WifiLegacyHal::getGscanCachedResults(const std::string& iface_name) {
- std::vector<wifi_cached_scan_results> cached_scan_results;
- cached_scan_results.resize(kMaxCachedGscanResults);
- int32_t num_results = 0;
- wifi_error status = global_func_table_.wifi_get_cached_gscan_results(
- getIfaceHandle(iface_name), true /* always flush */,
- cached_scan_results.size(), cached_scan_results.data(), &num_results);
- CHECK(num_results >= 0 &&
- static_cast<uint32_t>(num_results) <= kMaxCachedGscanResults);
- cached_scan_results.resize(num_results);
- // Check for invalid IE lengths in these cached scan results and correct it.
- for (auto& cached_scan_result : cached_scan_results) {
- int num_scan_results = cached_scan_result.num_results;
- for (int i = 0; i < num_scan_results; i++) {
- auto& scan_result = cached_scan_result.results[i];
- if (scan_result.ie_length > 0) {
- LOG(DEBUG) << "Cached scan result has non-zero IE length "
- << scan_result.ie_length;
- scan_result.ie_length = 0;
- }
- }
- }
- return {status, std::move(cached_scan_results)};
-}
-
-void WifiLegacyHal::invalidate() {
- global_handle_ = nullptr;
- iface_name_to_handle_.clear();
- on_driver_memory_dump_internal_callback = nullptr;
- on_firmware_memory_dump_internal_callback = nullptr;
- on_gscan_event_internal_callback = nullptr;
- on_gscan_full_result_internal_callback = nullptr;
- on_link_layer_stats_result_internal_callback = nullptr;
- on_rssi_threshold_breached_internal_callback = nullptr;
- on_ring_buffer_data_internal_callback = nullptr;
- on_error_alert_internal_callback = nullptr;
- on_radio_mode_change_internal_callback = nullptr;
- on_rtt_results_internal_callback = nullptr;
- on_nan_notify_response_user_callback = nullptr;
- on_nan_event_publish_terminated_user_callback = nullptr;
- on_nan_event_match_user_callback = nullptr;
- on_nan_event_match_expired_user_callback = nullptr;
- on_nan_event_subscribe_terminated_user_callback = nullptr;
- on_nan_event_followup_user_callback = nullptr;
- on_nan_event_disc_eng_event_user_callback = nullptr;
- on_nan_event_disabled_user_callback = nullptr;
- on_nan_event_tca_user_callback = nullptr;
- on_nan_event_beacon_sdf_payload_user_callback = nullptr;
- on_nan_event_data_path_request_user_callback = nullptr;
- on_nan_event_data_path_confirm_user_callback = nullptr;
- on_nan_event_data_path_end_user_callback = nullptr;
- on_nan_event_transmit_follow_up_user_callback = nullptr;
- on_nan_event_range_request_user_callback = nullptr;
- on_nan_event_range_report_user_callback = nullptr;
- on_nan_event_schedule_update_user_callback = nullptr;
-}
-
-} // namespace legacy_hal
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi_legacy_hal.h b/wifi/1.3/default/wifi_legacy_hal.h
deleted file mode 100644
index 9cfa172..0000000
--- a/wifi/1.3/default/wifi_legacy_hal.h
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_LEGACY_HAL_H_
-#define WIFI_LEGACY_HAL_H_
-
-#include <condition_variable>
-#include <functional>
-#include <map>
-#include <thread>
-#include <vector>
-
-#include <wifi_system/interface_tool.h>
-
-// HACK: The include inside the namespace below also transitively includes a
-// bunch of libc headers into the namespace, which leads to functions like
-// socketpair being defined in
-// android::hardware::wifi::V1_1::implementation::legacy_hal. Include this one
-// particular header as a hacky workaround until that's fixed.
-#include <sys/socket.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-// This is in a separate namespace to prevent typename conflicts between
-// the legacy HAL types and the HIDL interface types.
-namespace legacy_hal {
-// Wrap all the types defined inside the legacy HAL header files inside this
-// namespace.
-#include <hardware_legacy/wifi_hal.h>
-
-// APF capabilities supported by the iface.
-struct PacketFilterCapabilities {
- uint32_t version;
- uint32_t max_len;
-};
-
-// WARNING: We don't care about the variable sized members of either
-// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma
-// to escape the compiler warnings regarding this.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
-// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
-// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
-// into a separate return element to avoid passing pointers around.
-struct LinkLayerRadioStats {
- wifi_radio_stat stats;
- std::vector<uint32_t> tx_time_per_levels;
- std::vector<wifi_channel_stat> channel_stats;
-};
-
-struct LinkLayerStats {
- wifi_iface_stat iface;
- std::vector<LinkLayerRadioStats> radios;
-};
-#pragma GCC diagnostic pop
-
-// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
-// |WLAN_DRIVER_WAKE_REASON_CNT.driver_fw_local_wake_cnt| stats is provided
-// as a pointer in |WLAN_DRIVER_WAKE_REASON_CNT| structure in the legacy HAL
-// API. Separate that out into a separate return elements to avoid passing
-// pointers around.
-struct WakeReasonStats {
- WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt;
- std::vector<uint32_t> cmd_event_wake_cnt;
- std::vector<uint32_t> driver_fw_local_wake_cnt;
-};
-
-// NAN response and event callbacks struct.
-struct NanCallbackHandlers {
- // NotifyResponse invoked to notify the status of the Request.
- std::function<void(transaction_id, const NanResponseMsg&)>
- on_notify_response;
- // Various event callbacks.
- std::function<void(const NanPublishTerminatedInd&)>
- on_event_publish_terminated;
- std::function<void(const NanMatchInd&)> on_event_match;
- std::function<void(const NanMatchExpiredInd&)> on_event_match_expired;
- std::function<void(const NanSubscribeTerminatedInd&)>
- on_event_subscribe_terminated;
- std::function<void(const NanFollowupInd&)> on_event_followup;
- std::function<void(const NanDiscEngEventInd&)> on_event_disc_eng_event;
- std::function<void(const NanDisabledInd&)> on_event_disabled;
- std::function<void(const NanTCAInd&)> on_event_tca;
- std::function<void(const NanBeaconSdfPayloadInd&)>
- on_event_beacon_sdf_payload;
- std::function<void(const NanDataPathRequestInd&)>
- on_event_data_path_request;
- std::function<void(const NanDataPathConfirmInd&)>
- on_event_data_path_confirm;
- std::function<void(const NanDataPathEndInd&)> on_event_data_path_end;
- std::function<void(const NanTransmitFollowupInd&)>
- on_event_transmit_follow_up;
- std::function<void(const NanRangeRequestInd&)> on_event_range_request;
- std::function<void(const NanRangeReportInd&)> on_event_range_report;
- std::function<void(const NanDataPathScheduleUpdateInd&)>
- on_event_schedule_update;
-};
-
-// Full scan results contain IE info and are hence passed by reference, to
-// preserve the variable length array member |ie_data|. Callee must not retain
-// the pointer.
-using on_gscan_full_result_callback =
- std::function<void(wifi_request_id, const wifi_scan_result*, uint32_t)>;
-// These scan results don't contain any IE info, so no need to pass by
-// reference.
-using on_gscan_results_callback = std::function<void(
- wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
-
-// Invoked when the rssi value breaches the thresholds set.
-using on_rssi_threshold_breached_callback =
- std::function<void(wifi_request_id, std::array<uint8_t, 6>, int8_t)>;
-
-// Callback for RTT range request results.
-// Rtt results contain IE info and are hence passed by reference, to
-// preserve the |LCI| and |LCR| pointers. Callee must not retain
-// the pointer.
-using on_rtt_results_callback = std::function<void(
- wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
-
-// Callback for ring buffer data.
-using on_ring_buffer_data_callback =
- std::function<void(const std::string&, const std::vector<uint8_t>&,
- const wifi_ring_buffer_status&)>;
-
-// Callback for alerts.
-using on_error_alert_callback =
- std::function<void(int32_t, const std::vector<uint8_t>&)>;
-
-// Struct for the mac info from the legacy HAL. This is a cleaner version
-// of the |wifi_mac_info| & |wifi_iface_info|.
-typedef struct {
- std::string name;
- wifi_channel channel;
-} WifiIfaceInfo;
-
-typedef struct {
- uint32_t wlan_mac_id;
- /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
- uint32_t mac_band;
- /* Represents the connected Wi-Fi interfaces associated with each MAC */
- std::vector<WifiIfaceInfo> iface_infos;
-} WifiMacInfo;
-
-// Callback for radio mode change
-using on_radio_mode_change_callback =
- std::function<void(const std::vector<WifiMacInfo>&)>;
-
-/**
- * Class that encapsulates all legacy HAL interactions.
- * This class manages the lifetime of the event loop thread used by legacy HAL.
- *
- * Note: There will only be a single instance of this class created in the Wifi
- * object and will be valid for the lifetime of the process.
- */
-class WifiLegacyHal {
- public:
- WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
- virtual ~WifiLegacyHal() = default;
-
- // Initialize the legacy HAL function table.
- virtual wifi_error initialize();
- // Start the legacy HAL and the event looper thread.
- virtual wifi_error start();
- // Deinitialize the legacy HAL and wait for the event loop thread to exit
- // using a predefined timeout.
- virtual wifi_error stop(std::unique_lock<std::recursive_mutex>* lock,
- const std::function<void()>& on_complete_callback);
- // Checks if legacy HAL has successfully started
- bool isStarted();
- // Wrappers for all the functions in the legacy HAL function table.
- virtual std::pair<wifi_error, std::string> getDriverVersion(
- const std::string& iface_name);
- virtual std::pair<wifi_error, std::string> getFirmwareVersion(
- const std::string& iface_name);
- std::pair<wifi_error, std::vector<uint8_t>> requestDriverMemoryDump(
- const std::string& iface_name);
- std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
- const std::string& iface_name);
- std::pair<wifi_error, uint32_t> getSupportedFeatureSet(
- const std::string& iface_name);
- // APF functions.
- std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
- const std::string& iface_name);
- wifi_error setPacketFilter(const std::string& iface_name,
- const std::vector<uint8_t>& program);
- std::pair<wifi_error, std::vector<uint8_t>> readApfPacketFilterData(
- const std::string& iface_name);
- // Gscan functions.
- std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities(
- const std::string& iface_name);
- // These API's provides a simplified interface over the legacy Gscan API's:
- // a) All scan events from the legacy HAL API other than the
- // |WIFI_SCAN_FAILED| are treated as notification of results.
- // This method then retrieves the cached scan results from the legacy
- // HAL API and triggers the externally provided
- // |on_results_user_callback| on success.
- // b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan
- // results
- // triggers the externally provided |on_failure_user_callback|.
- // c) Full scan result event triggers the externally provided
- // |on_full_result_user_callback|.
- wifi_error startGscan(
- const std::string& iface_name, wifi_request_id id,
- const wifi_scan_cmd_params& params,
- const std::function<void(wifi_request_id)>& on_failure_callback,
- const on_gscan_results_callback& on_results_callback,
- const on_gscan_full_result_callback& on_full_result_callback);
- wifi_error stopGscan(const std::string& iface_name, wifi_request_id id);
- std::pair<wifi_error, std::vector<uint32_t>> getValidFrequenciesForBand(
- const std::string& iface_name, wifi_band band);
- virtual wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on);
- // Link layer stats functions.
- wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug);
- wifi_error disableLinkLayerStats(const std::string& iface_name);
- std::pair<wifi_error, LinkLayerStats> getLinkLayerStats(
- const std::string& iface_name);
- // RSSI monitor functions.
- wifi_error startRssiMonitoring(const std::string& iface_name,
- wifi_request_id id, int8_t max_rssi,
- int8_t min_rssi,
- const on_rssi_threshold_breached_callback&
- on_threshold_breached_callback);
- wifi_error stopRssiMonitoring(const std::string& iface_name,
- wifi_request_id id);
- std::pair<wifi_error, wifi_roaming_capabilities> getRoamingCapabilities(
- const std::string& iface_name);
- wifi_error configureRoaming(const std::string& iface_name,
- const wifi_roaming_config& config);
- wifi_error enableFirmwareRoaming(const std::string& iface_name,
- fw_roaming_state_t state);
- wifi_error configureNdOffload(const std::string& iface_name, bool enable);
- wifi_error startSendingOffloadedPacket(
- const std::string& iface_name, uint32_t cmd_id, uint16_t ether_type,
- const std::vector<uint8_t>& ip_packet_data,
- const std::array<uint8_t, 6>& src_address,
- const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
- wifi_error stopSendingOffloadedPacket(const std::string& iface_name,
- uint32_t cmd_id);
- wifi_error setScanningMacOui(const std::string& iface_name,
- const std::array<uint8_t, 3>& oui);
- virtual wifi_error selectTxPowerScenario(const std::string& iface_name,
- wifi_power_scenario scenario);
- virtual wifi_error resetTxPowerScenario(const std::string& iface_name);
- wifi_error setLatencyMode(const std::string& iface_name,
- wifi_latency_mode mode);
- // Logger/debug functions.
- std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(
- const std::string& iface_name);
- wifi_error startPktFateMonitoring(const std::string& iface_name);
- std::pair<wifi_error, std::vector<wifi_tx_report>> getTxPktFates(
- const std::string& iface_name);
- std::pair<wifi_error, std::vector<wifi_rx_report>> getRxPktFates(
- const std::string& iface_name);
- std::pair<wifi_error, WakeReasonStats> getWakeReasonStats(
- const std::string& iface_name);
- wifi_error registerRingBufferCallbackHandler(
- const std::string& iface_name,
- const on_ring_buffer_data_callback& on_data_callback);
- wifi_error deregisterRingBufferCallbackHandler(
- const std::string& iface_name);
- std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
- getRingBuffersStatus(const std::string& iface_name);
- wifi_error startRingBufferLogging(const std::string& iface_name,
- const std::string& ring_name,
- uint32_t verbose_level,
- uint32_t max_interval_sec,
- uint32_t min_data_size);
- wifi_error getRingBufferData(const std::string& iface_name,
- const std::string& ring_name);
- wifi_error registerErrorAlertCallbackHandler(
- const std::string& iface_name,
- const on_error_alert_callback& on_alert_callback);
- wifi_error deregisterErrorAlertCallbackHandler(
- const std::string& iface_name);
- // Radio mode functions.
- virtual wifi_error registerRadioModeChangeCallbackHandler(
- const std::string& iface_name,
- const on_radio_mode_change_callback& on_user_change_callback);
- // RTT functions.
- wifi_error startRttRangeRequest(
- const std::string& iface_name, wifi_request_id id,
- const std::vector<wifi_rtt_config>& rtt_configs,
- const on_rtt_results_callback& on_results_callback);
- wifi_error cancelRttRangeRequest(
- const std::string& iface_name, wifi_request_id id,
- const std::vector<std::array<uint8_t, 6>>& mac_addrs);
- std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities(
- const std::string& iface_name);
- std::pair<wifi_error, wifi_rtt_responder> getRttResponderInfo(
- const std::string& iface_name);
- wifi_error enableRttResponder(const std::string& iface_name,
- wifi_request_id id,
- const wifi_channel_info& channel_hint,
- uint32_t max_duration_secs,
- const wifi_rtt_responder& info);
- wifi_error disableRttResponder(const std::string& iface_name,
- wifi_request_id id);
- wifi_error setRttLci(const std::string& iface_name, wifi_request_id id,
- const wifi_lci_information& info);
- wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id,
- const wifi_lcr_information& info);
- // NAN functions.
- virtual wifi_error nanRegisterCallbackHandlers(
- const std::string& iface_name, const NanCallbackHandlers& callbacks);
- wifi_error nanEnableRequest(const std::string& iface_name,
- transaction_id id, const NanEnableRequest& msg);
- virtual wifi_error nanDisableRequest(const std::string& iface_name,
- transaction_id id);
- wifi_error nanPublishRequest(const std::string& iface_name,
- transaction_id id,
- const NanPublishRequest& msg);
- wifi_error nanPublishCancelRequest(const std::string& iface_name,
- transaction_id id,
- const NanPublishCancelRequest& msg);
- wifi_error nanSubscribeRequest(const std::string& iface_name,
- transaction_id id,
- const NanSubscribeRequest& msg);
- wifi_error nanSubscribeCancelRequest(const std::string& iface_name,
- transaction_id id,
- const NanSubscribeCancelRequest& msg);
- wifi_error nanTransmitFollowupRequest(
- const std::string& iface_name, transaction_id id,
- const NanTransmitFollowupRequest& msg);
- wifi_error nanStatsRequest(const std::string& iface_name, transaction_id id,
- const NanStatsRequest& msg);
- wifi_error nanConfigRequest(const std::string& iface_name,
- transaction_id id, const NanConfigRequest& msg);
- wifi_error nanTcaRequest(const std::string& iface_name, transaction_id id,
- const NanTCARequest& msg);
- wifi_error nanBeaconSdfPayloadRequest(
- const std::string& iface_name, transaction_id id,
- const NanBeaconSdfPayloadRequest& msg);
- std::pair<wifi_error, NanVersion> nanGetVersion();
- wifi_error nanGetCapabilities(const std::string& iface_name,
- transaction_id id);
- wifi_error nanDataInterfaceCreate(const std::string& iface_name,
- transaction_id id,
- const std::string& data_iface_name);
- virtual wifi_error nanDataInterfaceDelete(
- const std::string& iface_name, transaction_id id,
- const std::string& data_iface_name);
- wifi_error nanDataRequestInitiator(const std::string& iface_name,
- transaction_id id,
- const NanDataPathInitiatorRequest& msg);
- wifi_error nanDataIndicationResponse(
- const std::string& iface_name, transaction_id id,
- const NanDataPathIndicationResponse& msg);
- wifi_error nanDataEnd(const std::string& iface_name, transaction_id id,
- uint32_t ndpInstanceId);
- // AP functions.
- wifi_error setCountryCode(const std::string& iface_name,
- std::array<int8_t, 2> code);
-
- private:
- // Retrieve interface handles for all the available interfaces.
- wifi_error retrieveIfaceHandles();
- wifi_interface_handle getIfaceHandle(const std::string& iface_name);
- // Run the legacy HAL event loop thread.
- void runEventLoop();
- // Retrieve the cached gscan results to pass the results back to the
- // external callbacks.
- std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
- getGscanCachedResults(const std::string& iface_name);
- void invalidate();
-
- // Global function table of legacy HAL.
- wifi_hal_fn global_func_table_;
- // Opaque handle to be used for all global operations.
- wifi_handle global_handle_;
- // Map of interface name to handle that is to be used for all interface
- // specific operations.
- std::map<std::string, wifi_interface_handle> iface_name_to_handle_;
- // Flag to indicate if we have initiated the cleanup of legacy HAL.
- std::atomic<bool> awaiting_event_loop_termination_;
- std::condition_variable_any stop_wait_cv_;
- // Flag to indicate if the legacy HAL has been started.
- bool is_started_;
- std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
-};
-
-} // namespace legacy_hal
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.3/default/wifi_legacy_hal_stubs.cpp b/wifi/1.3/default/wifi_legacy_hal_stubs.cpp
deleted file mode 100644
index dedd2d4..0000000
--- a/wifi/1.3/default/wifi_legacy_hal_stubs.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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.
- */
-
-#include "wifi_legacy_hal_stubs.h"
-
-// TODO: Remove these stubs from HalTool in libwifi-system.
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace legacy_hal {
-template <typename>
-struct stubFunction;
-
-template <typename R, typename... Args>
-struct stubFunction<R (*)(Args...)> {
- static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; }
-};
-template <typename... Args>
-struct stubFunction<void (*)(Args...)> {
- static constexpr void invoke(Args...) {}
-};
-
-template <typename T>
-void populateStubFor(T* val) {
- *val = &stubFunction<T>::invoke;
-}
-
-bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) {
- if (hal_fn == nullptr) {
- return false;
- }
- populateStubFor(&hal_fn->wifi_initialize);
- populateStubFor(&hal_fn->wifi_wait_for_driver_ready);
- populateStubFor(&hal_fn->wifi_cleanup);
- populateStubFor(&hal_fn->wifi_event_loop);
- populateStubFor(&hal_fn->wifi_get_error_info);
- populateStubFor(&hal_fn->wifi_get_supported_feature_set);
- populateStubFor(&hal_fn->wifi_get_concurrency_matrix);
- populateStubFor(&hal_fn->wifi_set_scanning_mac_oui);
- populateStubFor(&hal_fn->wifi_get_supported_channels);
- populateStubFor(&hal_fn->wifi_is_epr_supported);
- populateStubFor(&hal_fn->wifi_get_ifaces);
- populateStubFor(&hal_fn->wifi_get_iface_name);
- populateStubFor(&hal_fn->wifi_set_iface_event_handler);
- populateStubFor(&hal_fn->wifi_reset_iface_event_handler);
- populateStubFor(&hal_fn->wifi_start_gscan);
- populateStubFor(&hal_fn->wifi_stop_gscan);
- populateStubFor(&hal_fn->wifi_get_cached_gscan_results);
- populateStubFor(&hal_fn->wifi_set_bssid_hotlist);
- populateStubFor(&hal_fn->wifi_reset_bssid_hotlist);
- populateStubFor(&hal_fn->wifi_set_significant_change_handler);
- populateStubFor(&hal_fn->wifi_reset_significant_change_handler);
- populateStubFor(&hal_fn->wifi_get_gscan_capabilities);
- populateStubFor(&hal_fn->wifi_set_link_stats);
- populateStubFor(&hal_fn->wifi_get_link_stats);
- populateStubFor(&hal_fn->wifi_clear_link_stats);
- populateStubFor(&hal_fn->wifi_get_valid_channels);
- populateStubFor(&hal_fn->wifi_rtt_range_request);
- populateStubFor(&hal_fn->wifi_rtt_range_cancel);
- populateStubFor(&hal_fn->wifi_get_rtt_capabilities);
- populateStubFor(&hal_fn->wifi_rtt_get_responder_info);
- populateStubFor(&hal_fn->wifi_enable_responder);
- populateStubFor(&hal_fn->wifi_disable_responder);
- populateStubFor(&hal_fn->wifi_set_nodfs_flag);
- populateStubFor(&hal_fn->wifi_start_logging);
- populateStubFor(&hal_fn->wifi_set_epno_list);
- populateStubFor(&hal_fn->wifi_reset_epno_list);
- populateStubFor(&hal_fn->wifi_set_country_code);
- populateStubFor(&hal_fn->wifi_get_firmware_memory_dump);
- populateStubFor(&hal_fn->wifi_set_log_handler);
- populateStubFor(&hal_fn->wifi_reset_log_handler);
- populateStubFor(&hal_fn->wifi_set_alert_handler);
- populateStubFor(&hal_fn->wifi_reset_alert_handler);
- populateStubFor(&hal_fn->wifi_get_firmware_version);
- populateStubFor(&hal_fn->wifi_get_ring_buffers_status);
- populateStubFor(&hal_fn->wifi_get_logger_supported_feature_set);
- populateStubFor(&hal_fn->wifi_get_ring_data);
- populateStubFor(&hal_fn->wifi_enable_tdls);
- populateStubFor(&hal_fn->wifi_disable_tdls);
- populateStubFor(&hal_fn->wifi_get_tdls_status);
- populateStubFor(&hal_fn->wifi_get_tdls_capabilities);
- populateStubFor(&hal_fn->wifi_get_driver_version);
- populateStubFor(&hal_fn->wifi_set_passpoint_list);
- populateStubFor(&hal_fn->wifi_reset_passpoint_list);
- populateStubFor(&hal_fn->wifi_set_lci);
- populateStubFor(&hal_fn->wifi_set_lcr);
- populateStubFor(&hal_fn->wifi_start_sending_offloaded_packet);
- populateStubFor(&hal_fn->wifi_stop_sending_offloaded_packet);
- populateStubFor(&hal_fn->wifi_start_rssi_monitoring);
- populateStubFor(&hal_fn->wifi_stop_rssi_monitoring);
- populateStubFor(&hal_fn->wifi_get_wake_reason_stats);
- populateStubFor(&hal_fn->wifi_configure_nd_offload);
- populateStubFor(&hal_fn->wifi_get_driver_memory_dump);
- populateStubFor(&hal_fn->wifi_start_pkt_fate_monitoring);
- populateStubFor(&hal_fn->wifi_get_tx_pkt_fates);
- populateStubFor(&hal_fn->wifi_get_rx_pkt_fates);
- populateStubFor(&hal_fn->wifi_nan_enable_request);
- populateStubFor(&hal_fn->wifi_nan_disable_request);
- populateStubFor(&hal_fn->wifi_nan_publish_request);
- populateStubFor(&hal_fn->wifi_nan_publish_cancel_request);
- populateStubFor(&hal_fn->wifi_nan_subscribe_request);
- populateStubFor(&hal_fn->wifi_nan_subscribe_cancel_request);
- populateStubFor(&hal_fn->wifi_nan_transmit_followup_request);
- populateStubFor(&hal_fn->wifi_nan_stats_request);
- populateStubFor(&hal_fn->wifi_nan_config_request);
- populateStubFor(&hal_fn->wifi_nan_tca_request);
- populateStubFor(&hal_fn->wifi_nan_beacon_sdf_payload_request);
- populateStubFor(&hal_fn->wifi_nan_register_handler);
- populateStubFor(&hal_fn->wifi_nan_get_version);
- populateStubFor(&hal_fn->wifi_nan_get_capabilities);
- populateStubFor(&hal_fn->wifi_nan_data_interface_create);
- populateStubFor(&hal_fn->wifi_nan_data_interface_delete);
- populateStubFor(&hal_fn->wifi_nan_data_request_initiator);
- populateStubFor(&hal_fn->wifi_nan_data_indication_response);
- populateStubFor(&hal_fn->wifi_nan_data_end);
- populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities);
- populateStubFor(&hal_fn->wifi_set_packet_filter);
- populateStubFor(&hal_fn->wifi_read_packet_filter);
- populateStubFor(&hal_fn->wifi_get_roaming_capabilities);
- populateStubFor(&hal_fn->wifi_enable_firmware_roaming);
- populateStubFor(&hal_fn->wifi_configure_roaming);
- populateStubFor(&hal_fn->wifi_select_tx_power_scenario);
- populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
- populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
- populateStubFor(&hal_fn->wifi_set_latency_mode);
- return true;
-}
-} // namespace legacy_hal
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi_legacy_hal_stubs.h b/wifi/1.3/default/wifi_legacy_hal_stubs.h
deleted file mode 100644
index 64854e0..0000000
--- a/wifi/1.3/default/wifi_legacy_hal_stubs.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_LEGACY_HAL_STUBS_H_
-#define WIFI_LEGACY_HAL_STUBS_H_
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace legacy_hal {
-#include <hardware_legacy/wifi_hal.h>
-
-bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
-} // namespace legacy_hal
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/wifi/1.3/default/wifi_mode_controller.cpp b/wifi/1.3/default/wifi_mode_controller.cpp
deleted file mode 100644
index c392486..0000000
--- a/wifi/1.3/default/wifi_mode_controller.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <private/android_filesystem_config.h>
-
-#include "wifi_mode_controller.h"
-
-using android::hardware::wifi::V1_0::IfaceType;
-using android::wifi_hal::DriverTool;
-
-namespace {
-int convertIfaceTypeToFirmwareMode(IfaceType type) {
- int mode;
- switch (type) {
- case IfaceType::AP:
- mode = DriverTool::kFirmwareModeAp;
- break;
- case IfaceType::P2P:
- mode = DriverTool::kFirmwareModeP2p;
- break;
- case IfaceType::NAN:
- // NAN is exposed in STA mode currently.
- mode = DriverTool::kFirmwareModeSta;
- break;
- case IfaceType::STA:
- mode = DriverTool::kFirmwareModeSta;
- break;
- }
- return mode;
-}
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace mode_controller {
-
-WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
-
-bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
- return driver_tool_->IsFirmwareModeChangeNeeded(
- convertIfaceTypeToFirmwareMode(type));
-}
-
-bool WifiModeController::initialize() {
- if (!driver_tool_->LoadDriver()) {
- LOG(ERROR) << "Failed to load WiFi driver";
- return false;
- }
- return true;
-}
-
-bool WifiModeController::changeFirmwareMode(IfaceType type) {
- if (!driver_tool_->ChangeFirmwareMode(
- convertIfaceTypeToFirmwareMode(type))) {
- LOG(ERROR) << "Failed to change firmware mode";
- return false;
- }
- return true;
-}
-
-bool WifiModeController::deinitialize() {
- if (!driver_tool_->UnloadDriver()) {
- LOG(ERROR) << "Failed to unload WiFi driver";
- return false;
- }
- return true;
-}
-} // namespace mode_controller
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi_mode_controller.h b/wifi/1.3/default/wifi_mode_controller.h
deleted file mode 100644
index ace5a52..0000000
--- a/wifi/1.3/default/wifi_mode_controller.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_MODE_CONTROLLER_H_
-#define WIFI_MODE_CONTROLLER_H_
-
-#include <wifi_hal/driver_tool.h>
-
-#include <android/hardware/wifi/1.0/IWifi.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace mode_controller {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * Class that encapsulates all firmware mode configuration.
- * This class will perform the necessary firmware reloads to put the chip in the
- * required state (essentially a wrapper over DriverTool).
- */
-class WifiModeController {
- public:
- WifiModeController();
- virtual ~WifiModeController() = default;
-
- // Checks if a firmware mode change is necessary to support the specified
- // iface type operations.
- virtual bool isFirmwareModeChangeNeeded(IfaceType type);
- virtual bool initialize();
- // Change the firmware mode to support the specified iface type operations.
- virtual bool changeFirmwareMode(IfaceType type);
- // Unload the driver. This should be invoked whenever |IWifi.stop()| is
- // invoked.
- virtual bool deinitialize();
-
- private:
- std::unique_ptr<wifi_hal::DriverTool> driver_tool_;
-};
-
-} // namespace mode_controller
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.3/default/wifi_nan_iface.cpp b/wifi/1.3/default/wifi_nan_iface.cpp
deleted file mode 100644
index ff9f422..0000000
--- a/wifi/1.3/default/wifi_nan_iface.cpp
+++ /dev/null
@@ -1,887 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_nan_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiNanIface::WifiNanIface(
- const std::string& ifname,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
- : ifname_(ifname),
- legacy_hal_(legacy_hal),
- iface_util_(iface_util),
- is_valid_(true) {
- // Register all the callbacks here. these should be valid for the lifetime
- // of the object. Whenever the mode changes legacy HAL will remove
- // all of these callbacks.
- legacy_hal::NanCallbackHandlers callback_handlers;
- android::wp<WifiNanIface> weak_ptr_this(this);
-
- // Callback for response.
- callback_handlers
- .on_notify_response = [weak_ptr_this](
- legacy_hal::transaction_id id,
- const legacy_hal::NanResponseMsg& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- WifiNanStatus wifiNanStatus;
- if (!hidl_struct_util::convertLegacyNanResponseHeaderToHidl(
- msg, &wifiNanStatus)) {
- LOG(ERROR) << "Failed to convert nan response header";
- return;
- }
-
- switch (msg.response_type) {
- case legacy_hal::NAN_RESPONSE_ENABLED: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback->notifyEnableResponse(id, wifiNanStatus)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_RESPONSE_DISABLED: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback->notifyDisableResponse(id, wifiNanStatus)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_RESPONSE_PUBLISH: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->notifyStartPublishResponse(
- id, wifiNanStatus,
- msg.body.publish_response.publish_id)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback->notifyStopPublishResponse(id, wifiNanStatus)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->notifyTransmitFollowupResponse(id, wifiNanStatus)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_RESPONSE_SUBSCRIBE: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->notifyStartSubscribeResponse(
- id, wifiNanStatus,
- msg.body.subscribe_response.subscribe_id)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->notifyStopSubscribeResponse(id, wifiNanStatus)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_RESPONSE_CONFIG: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback->notifyConfigResponse(id, wifiNanStatus)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_GET_CAPABILITIES: {
- NanCapabilities hidl_struct;
- if (!hidl_struct_util::
- convertLegacyNanCapabilitiesResponseToHidl(
- msg.body.nan_capabilities, &hidl_struct)) {
- LOG(ERROR) << "Failed to convert nan capabilities response";
- return;
- }
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->notifyCapabilitiesResponse(id, wifiNanStatus,
- hidl_struct)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_DP_INTERFACE_CREATE: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->notifyCreateDataInterfaceResponse(id,
- wifiNanStatus)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_DP_INTERFACE_DELETE: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->notifyDeleteDataInterfaceResponse(id,
- wifiNanStatus)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_DP_INITIATOR_RESPONSE: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->notifyInitiateDataPathResponse(
- id, wifiNanStatus,
- msg.body.data_request_response.ndp_instance_id)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_DP_RESPONDER_RESPONSE: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->notifyRespondToDataPathIndicationResponse(
- id, wifiNanStatus)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_DP_END: {
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->notifyTerminateDataPathResponse(id,
- wifiNanStatus)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- break;
- }
- case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
- /* fall through */
- case legacy_hal::NAN_RESPONSE_TCA:
- /* fall through */
- case legacy_hal::NAN_RESPONSE_STATS:
- /* fall through */
- case legacy_hal::NAN_RESPONSE_ERROR:
- /* fall through */
- default:
- LOG(ERROR) << "Unknown or unhandled response type: "
- << msg.response_type;
- return;
- }
- };
-
- callback_handlers.on_event_disc_eng_event =
- [weak_ptr_this](const legacy_hal::NanDiscEngEventInd& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- NanClusterEventInd hidl_struct;
- // event types defined identically - hence can be cast
- hidl_struct.eventType = (NanClusterEventType)msg.event_type;
- hidl_struct.addr = msg.data.mac_addr.addr;
-
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->eventClusterEvent(hidl_struct).isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- };
-
- callback_handlers.on_event_disabled =
- [weak_ptr_this](const legacy_hal::NanDisabledInd& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- WifiNanStatus status;
- hidl_struct_util::convertToWifiNanStatus(
- msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
-
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->eventDisabled(status).isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- };
-
- callback_handlers.on_event_publish_terminated =
- [weak_ptr_this](const legacy_hal::NanPublishTerminatedInd& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- WifiNanStatus status;
- hidl_struct_util::convertToWifiNanStatus(
- msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
-
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->eventPublishTerminated(msg.publish_id, status)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- };
-
- callback_handlers.on_event_subscribe_terminated =
- [weak_ptr_this](const legacy_hal::NanSubscribeTerminatedInd& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- WifiNanStatus status;
- hidl_struct_util::convertToWifiNanStatus(
- msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
-
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->eventSubscribeTerminated(msg.subscribe_id, status)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- };
-
- callback_handlers.on_event_match =
- [weak_ptr_this](const legacy_hal::NanMatchInd& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- NanMatchInd hidl_struct;
- if (!hidl_struct_util::convertLegacyNanMatchIndToHidl(
- msg, &hidl_struct)) {
- LOG(ERROR) << "Failed to convert nan capabilities response";
- return;
- }
-
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->eventMatch(hidl_struct).isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- };
-
- callback_handlers.on_event_match_expired =
- [weak_ptr_this](const legacy_hal::NanMatchExpiredInd& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->eventMatchExpired(msg.publish_subscribe_id,
- msg.requestor_instance_id)
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- };
-
- callback_handlers.on_event_followup =
- [weak_ptr_this](const legacy_hal::NanFollowupInd& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- NanFollowupReceivedInd hidl_struct;
- if (!hidl_struct_util::convertLegacyNanFollowupIndToHidl(
- msg, &hidl_struct)) {
- LOG(ERROR) << "Failed to convert nan capabilities response";
- return;
- }
-
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->eventFollowupReceived(hidl_struct).isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- };
-
- callback_handlers.on_event_transmit_follow_up =
- [weak_ptr_this](const legacy_hal::NanTransmitFollowupInd& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- WifiNanStatus status;
- hidl_struct_util::convertToWifiNanStatus(
- msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
-
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->eventTransmitFollowup(msg.id, status).isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- };
-
- callback_handlers.on_event_data_path_request =
- [weak_ptr_this](const legacy_hal::NanDataPathRequestInd& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- NanDataPathRequestInd hidl_struct;
- if (!hidl_struct_util::convertLegacyNanDataPathRequestIndToHidl(
- msg, &hidl_struct)) {
- LOG(ERROR) << "Failed to convert nan capabilities response";
- return;
- }
-
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->eventDataPathRequest(hidl_struct).isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- };
-
- callback_handlers.on_event_data_path_confirm =
- [weak_ptr_this](const legacy_hal::NanDataPathConfirmInd& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- V1_2::NanDataPathConfirmInd hidl_struct;
- if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl(
- msg, &hidl_struct)) {
- LOG(ERROR) << "Failed to convert nan capabilities response";
- return;
- }
-
- for (const auto& callback :
- shared_ptr_this->getEventCallbacks_1_2()) {
- if (!callback->eventDataPathConfirm_1_2(hidl_struct).isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- };
-
- callback_handlers.on_event_data_path_end =
- [weak_ptr_this](const legacy_hal::NanDataPathEndInd& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- for (int i = 0; i < msg.num_ndp_instances; ++i) {
- if (!callback
- ->eventDataPathTerminated(msg.ndp_instance_id[i])
- .isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- }
- };
-
- callback_handlers.on_event_beacon_sdf_payload =
- [weak_ptr_this](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
- LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
- };
-
- callback_handlers.on_event_range_request =
- [weak_ptr_this](const legacy_hal::NanRangeRequestInd& /* msg */) {
- LOG(ERROR) << "on_event_range_request - should not be called";
- };
-
- callback_handlers.on_event_range_report =
- [weak_ptr_this](const legacy_hal::NanRangeReportInd& /* msg */) {
- LOG(ERROR) << "on_event_range_report - should not be called";
- };
-
- callback_handlers
- .on_event_schedule_update = [weak_ptr_this](
- const legacy_hal::
- NanDataPathScheduleUpdateInd& msg) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- V1_2::NanDataPathScheduleUpdateInd hidl_struct;
- if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
- msg, &hidl_struct)) {
- LOG(ERROR) << "Failed to convert nan capabilities response";
- return;
- }
-
- for (const auto& callback : shared_ptr_this->getEventCallbacks_1_2()) {
- if (!callback->eventDataPathScheduleUpdate(hidl_struct).isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- };
-
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_,
- callback_handlers);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to register nan callbacks. Invalidating object";
- invalidate();
- }
-
- // Register for iface state toggle events.
- iface_util::IfaceEventHandlers event_handlers = {};
- event_handlers.on_state_toggle_off_on =
- [weak_ptr_this](const std::string& /* iface_name */) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- // Tell framework that NAN has been disabled.
- WifiNanStatus status = {
- NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->eventDisabled(status).isOk()) {
- LOG(ERROR) << "Failed to invoke the callback";
- }
- }
- };
- iface_util_.lock()->registerIfaceEventHandlers(ifname_, event_handlers);
-}
-
-void WifiNanIface::invalidate() {
- // send commands to HAL to actually disable and destroy interfaces
- legacy_hal_.lock()->nanDisableRequest(ifname_, 0xFFFF);
- legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFE, "aware_data0");
- legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFD, "aware_data1");
- iface_util_.lock()->unregisterIfaceEventHandlers(ifname_);
- legacy_hal_.reset();
- event_cb_handler_.invalidate();
- event_cb_handler_1_2_.invalidate();
- is_valid_ = false;
-}
-
-bool WifiNanIface::isValid() { return is_valid_; }
-
-std::string WifiNanIface::getName() { return ifname_; }
-
-std::set<sp<V1_0::IWifiNanIfaceEventCallback>>
-WifiNanIface::getEventCallbacks() {
- return event_cb_handler_.getCallbacks();
-}
-
-std::set<sp<V1_2::IWifiNanIfaceEventCallback>>
-WifiNanIface::getEventCallbacks_1_2() {
- return event_cb_handler_1_2_.getCallbacks();
-}
-
-Return<void> WifiNanIface::getName(getName_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiNanIface::getType(getType_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::getTypeInternal, hidl_status_cb);
-}
-
-Return<void> WifiNanIface::registerEventCallback(
- const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
- registerEventCallback_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::registerEventCallbackInternal,
- hidl_status_cb, callback);
-}
-
-Return<void> WifiNanIface::getCapabilitiesRequest(
- uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::getCapabilitiesRequestInternal,
- hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiNanIface::enableRequest(uint16_t cmd_id,
- const NanEnableRequest& msg,
- enableRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::enableRequestInternal, hidl_status_cb,
- cmd_id, msg);
-}
-
-Return<void> WifiNanIface::configRequest(uint16_t cmd_id,
- const NanConfigRequest& msg,
- configRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::configRequestInternal, hidl_status_cb,
- cmd_id, msg);
-}
-
-Return<void> WifiNanIface::disableRequest(uint16_t cmd_id,
- disableRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::disableRequestInternal,
- hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiNanIface::startPublishRequest(
- uint16_t cmd_id, const NanPublishRequest& msg,
- startPublishRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::startPublishRequestInternal,
- hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::stopPublishRequest(
- uint16_t cmd_id, uint8_t sessionId, stopPublishRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::stopPublishRequestInternal,
- hidl_status_cb, cmd_id, sessionId);
-}
-
-Return<void> WifiNanIface::startSubscribeRequest(
- uint16_t cmd_id, const NanSubscribeRequest& msg,
- startSubscribeRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::startSubscribeRequestInternal,
- hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::stopSubscribeRequest(
- uint16_t cmd_id, uint8_t sessionId,
- stopSubscribeRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::stopSubscribeRequestInternal,
- hidl_status_cb, cmd_id, sessionId);
-}
-
-Return<void> WifiNanIface::transmitFollowupRequest(
- uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
- transmitFollowupRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::transmitFollowupRequestInternal,
- hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::createDataInterfaceRequest(
- uint16_t cmd_id, const hidl_string& iface_name,
- createDataInterfaceRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::createDataInterfaceRequestInternal,
- hidl_status_cb, cmd_id, iface_name);
-}
-
-Return<void> WifiNanIface::deleteDataInterfaceRequest(
- uint16_t cmd_id, const hidl_string& iface_name,
- deleteDataInterfaceRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::deleteDataInterfaceRequestInternal,
- hidl_status_cb, cmd_id, iface_name);
-}
-
-Return<void> WifiNanIface::initiateDataPathRequest(
- uint16_t cmd_id, const NanInitiateDataPathRequest& msg,
- initiateDataPathRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::initiateDataPathRequestInternal,
- hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::respondToDataPathIndicationRequest(
- uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg,
- respondToDataPathIndicationRequest_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::respondToDataPathIndicationRequestInternal,
- hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::terminateDataPathRequest(
- uint16_t cmd_id, uint32_t ndpInstanceId,
- terminateDataPathRequest_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::terminateDataPathRequestInternal,
- hidl_status_cb, cmd_id, ndpInstanceId);
-}
-
-Return<void> WifiNanIface::registerEventCallback_1_2(
- const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
- registerEventCallback_1_2_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::registerEventCallback_1_2Internal,
- hidl_status_cb, callback);
-}
-
-Return<void> WifiNanIface::enableRequest_1_2(
- uint16_t cmd_id, const NanEnableRequest& msg1,
- const V1_2::NanConfigRequestSupplemental& msg2,
- enableRequest_1_2_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::enableRequest_1_2Internal,
- hidl_status_cb, cmd_id, msg1, msg2);
-}
-
-Return<void> WifiNanIface::configRequest_1_2(
- uint16_t cmd_id, const NanConfigRequest& msg1,
- const V1_2::NanConfigRequestSupplemental& msg2,
- configRequest_1_2_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiNanIface::configRequest_1_2Internal,
- hidl_status_cb, cmd_id, msg1, msg2);
-}
-
-std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
- return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiNanIface::getTypeInternal() {
- return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::NAN};
-}
-
-WifiStatus WifiNanIface::registerEventCallbackInternal(
- const sp<V1_0::IWifiNanIfaceEventCallback>& callback) {
- if (!event_cb_handler_.addCallback(callback)) {
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
- }
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t cmd_id) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::enableRequestInternal(
- uint16_t /* cmd_id */, const NanEnableRequest& /* msg */) {
- return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::configRequestInternal(
- uint16_t /* cmd_id */, const NanConfigRequest& /* msg */) {
- return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::disableRequestInternal(uint16_t cmd_id) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanDisableRequest(ifname_, cmd_id);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::startPublishRequestInternal(
- uint16_t cmd_id, const NanPublishRequest& msg) {
- legacy_hal::NanPublishRequest legacy_msg;
- if (!hidl_struct_util::convertHidlNanPublishRequestToLegacy(msg,
- &legacy_msg)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanPublishRequest(ifname_, cmd_id, legacy_msg);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::stopPublishRequestInternal(uint16_t cmd_id,
- uint8_t sessionId) {
- legacy_hal::NanPublishCancelRequest legacy_msg;
- legacy_msg.publish_id = sessionId;
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanPublishCancelRequest(ifname_, cmd_id,
- legacy_msg);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::startSubscribeRequestInternal(
- uint16_t cmd_id, const NanSubscribeRequest& msg) {
- legacy_hal::NanSubscribeRequest legacy_msg;
- if (!hidl_struct_util::convertHidlNanSubscribeRequestToLegacy(
- msg, &legacy_msg)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanSubscribeRequest(ifname_, cmd_id, legacy_msg);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::stopSubscribeRequestInternal(uint16_t cmd_id,
- uint8_t sessionId) {
- legacy_hal::NanSubscribeCancelRequest legacy_msg;
- legacy_msg.subscribe_id = sessionId;
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanSubscribeCancelRequest(ifname_, cmd_id,
- legacy_msg);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::transmitFollowupRequestInternal(
- uint16_t cmd_id, const NanTransmitFollowupRequest& msg) {
- legacy_hal::NanTransmitFollowupRequest legacy_msg;
- if (!hidl_struct_util::convertHidlNanTransmitFollowupRequestToLegacy(
- msg, &legacy_msg)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanTransmitFollowupRequest(ifname_, cmd_id,
- legacy_msg);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::createDataInterfaceRequestInternal(
- uint16_t cmd_id, const std::string& iface_name) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanDataInterfaceCreate(ifname_, cmd_id, iface_name);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::deleteDataInterfaceRequestInternal(
- uint16_t cmd_id, const std::string& iface_name) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, cmd_id, iface_name);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::initiateDataPathRequestInternal(
- uint16_t cmd_id, const NanInitiateDataPathRequest& msg) {
- legacy_hal::NanDataPathInitiatorRequest legacy_msg;
- if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequestToLegacy(
- msg, &legacy_msg)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id,
- legacy_msg);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::respondToDataPathIndicationRequestInternal(
- uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg) {
- legacy_hal::NanDataPathIndicationResponse legacy_msg;
- if (!hidl_struct_util::convertHidlNanDataPathIndicationResponseToLegacy(
- msg, &legacy_msg)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id,
- legacy_msg);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::terminateDataPathRequestInternal(
- uint16_t cmd_id, uint32_t ndpInstanceId) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::registerEventCallback_1_2Internal(
- const sp<V1_2::IWifiNanIfaceEventCallback>& callback) {
- sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
- if (!event_cb_handler_.addCallback(callback_1_0)) {
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
- }
- if (!event_cb_handler_1_2_.addCallback(callback)) {
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
- }
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiNanIface::enableRequest_1_2Internal(
- uint16_t cmd_id, const NanEnableRequest& msg1,
- const V1_2::NanConfigRequestSupplemental& msg2) {
- legacy_hal::NanEnableRequest legacy_msg;
- if (!hidl_struct_util::convertHidlNanEnableRequest_1_2ToLegacy(
- msg1, msg2, &legacy_msg)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::configRequest_1_2Internal(
- uint16_t cmd_id, const NanConfigRequest& msg1,
- const V1_2::NanConfigRequestSupplemental& msg2) {
- legacy_hal::NanConfigRequest legacy_msg;
- if (!hidl_struct_util::convertHidlNanConfigRequest_1_2ToLegacy(
- msg1, msg2, &legacy_msg)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi_nan_iface.h b/wifi/1.3/default/wifi_nan_iface.h
deleted file mode 100644
index 737be93..0000000
--- a/wifi/1.3/default/wifi_nan_iface.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_NAN_IFACE_H_
-#define WIFI_NAN_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
-#include <android/hardware/wifi/1.2/IWifiNanIface.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_iface_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a NAN Iface instance.
- */
-class WifiNanIface : public V1_2::IWifiNanIface {
- public:
- WifiNanIface(const std::string& ifname,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
- // Refer to |WifiChip::invalidate()|.
- void invalidate();
- bool isValid();
- std::string getName();
-
- // HIDL methods exposed.
- Return<void> getName(getName_cb hidl_status_cb) override;
- Return<void> getType(getType_cb hidl_status_cb) override;
- Return<void> registerEventCallback(
- const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
- 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,
- enableRequest_cb hidl_status_cb) override;
- Return<void> configRequest(uint16_t cmd_id, const NanConfigRequest& msg,
- configRequest_cb hidl_status_cb) override;
- Return<void> disableRequest(uint16_t cmd_id,
- disableRequest_cb hidl_status_cb) override;
- Return<void> startPublishRequest(
- uint16_t cmd_id, const NanPublishRequest& msg,
- startPublishRequest_cb hidl_status_cb) override;
- Return<void> stopPublishRequest(
- uint16_t cmd_id, uint8_t sessionId,
- stopPublishRequest_cb hidl_status_cb) override;
- Return<void> startSubscribeRequest(
- uint16_t cmd_id, const NanSubscribeRequest& msg,
- startSubscribeRequest_cb hidl_status_cb) override;
- Return<void> stopSubscribeRequest(
- uint16_t cmd_id, uint8_t sessionId,
- stopSubscribeRequest_cb hidl_status_cb) override;
- Return<void> transmitFollowupRequest(
- uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
- transmitFollowupRequest_cb hidl_status_cb) override;
- Return<void> createDataInterfaceRequest(
- uint16_t cmd_id, const hidl_string& iface_name,
- createDataInterfaceRequest_cb hidl_status_cb) override;
- Return<void> deleteDataInterfaceRequest(
- uint16_t cmd_id, const hidl_string& iface_name,
- deleteDataInterfaceRequest_cb hidl_status_cb) override;
- Return<void> initiateDataPathRequest(
- uint16_t cmd_id, const NanInitiateDataPathRequest& msg,
- initiateDataPathRequest_cb hidl_status_cb) override;
- Return<void> respondToDataPathIndicationRequest(
- uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg,
- respondToDataPathIndicationRequest_cb hidl_status_cb) override;
- Return<void> terminateDataPathRequest(
- uint16_t cmd_id, uint32_t ndpInstanceId,
- terminateDataPathRequest_cb hidl_status_cb) override;
-
- Return<void> registerEventCallback_1_2(
- 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,
- const V1_2::NanConfigRequestSupplemental& msg2,
- enableRequest_1_2_cb hidl_status_cb) override;
- Return<void> configRequest_1_2(
- uint16_t cmd_id, const NanConfigRequest& msg1,
- const V1_2::NanConfigRequestSupplemental& msg2,
- configRequest_1_2_cb hidl_status_cb) override;
-
- private:
- // Corresponding worker functions for the HIDL methods.
- std::pair<WifiStatus, std::string> getNameInternal();
- std::pair<WifiStatus, IfaceType> getTypeInternal();
- WifiStatus registerEventCallbackInternal(
- const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
- WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
- WifiStatus enableRequestInternal(uint16_t cmd_id,
- const NanEnableRequest& msg);
- WifiStatus configRequestInternal(uint16_t cmd_id,
- const NanConfigRequest& msg);
- WifiStatus disableRequestInternal(uint16_t cmd_id);
- WifiStatus startPublishRequestInternal(uint16_t cmd_id,
- const NanPublishRequest& msg);
- WifiStatus stopPublishRequestInternal(uint16_t cmd_id, uint8_t sessionId);
- WifiStatus startSubscribeRequestInternal(uint16_t cmd_id,
- const NanSubscribeRequest& msg);
- WifiStatus stopSubscribeRequestInternal(uint16_t cmd_id, uint8_t sessionId);
- WifiStatus transmitFollowupRequestInternal(
- uint16_t cmd_id, const NanTransmitFollowupRequest& msg);
- WifiStatus createDataInterfaceRequestInternal(
- uint16_t cmd_id, const std::string& iface_name);
- WifiStatus deleteDataInterfaceRequestInternal(
- uint16_t cmd_id, const std::string& iface_name);
- WifiStatus initiateDataPathRequestInternal(
- uint16_t cmd_id, const NanInitiateDataPathRequest& msg);
- WifiStatus respondToDataPathIndicationRequestInternal(
- uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg);
- WifiStatus terminateDataPathRequestInternal(uint16_t cmd_id,
- uint32_t ndpInstanceId);
-
- WifiStatus registerEventCallback_1_2Internal(
- const sp<V1_2::IWifiNanIfaceEventCallback>& callback);
- WifiStatus enableRequest_1_2Internal(
- uint16_t cmd_id, const NanEnableRequest& msg1,
- const V1_2::NanConfigRequestSupplemental& msg2);
- WifiStatus configRequest_1_2Internal(
- uint16_t cmd_id, const NanConfigRequest& msg,
- const V1_2::NanConfigRequestSupplemental& msg2);
-
- // all 1_0 and descendant callbacks
- std::set<sp<V1_0::IWifiNanIfaceEventCallback>> getEventCallbacks();
- // all 1_2 and descendant callbacks
- std::set<sp<V1_2::IWifiNanIfaceEventCallback>> getEventCallbacks_1_2();
-
- std::string ifname_;
- std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
- std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
- bool is_valid_;
- hidl_callback_util::HidlCallbackHandler<V1_0::IWifiNanIfaceEventCallback>
- event_cb_handler_;
- hidl_callback_util::HidlCallbackHandler<V1_2::IWifiNanIfaceEventCallback>
- event_cb_handler_1_2_;
-
- DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
-};
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_NAN_IFACE_H_
diff --git a/wifi/1.3/default/wifi_p2p_iface.cpp b/wifi/1.3/default/wifi_p2p_iface.cpp
deleted file mode 100644
index b5d5886..0000000
--- a/wifi/1.3/default/wifi_p2p_iface.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "wifi_p2p_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiP2pIface::WifiP2pIface(
- const std::string& ifname,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
- : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
-
-void WifiP2pIface::invalidate() {
- legacy_hal_.reset();
- is_valid_ = false;
-}
-
-bool WifiP2pIface::isValid() { return is_valid_; }
-
-std::string WifiP2pIface::getName() { return ifname_; }
-
-Return<void> WifiP2pIface::getName(getName_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiP2pIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiP2pIface::getType(getType_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiP2pIface::getTypeInternal, hidl_status_cb);
-}
-
-std::pair<WifiStatus, std::string> WifiP2pIface::getNameInternal() {
- return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiP2pIface::getTypeInternal() {
- return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::P2P};
-}
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi_p2p_iface.h b/wifi/1.3/default/wifi_p2p_iface.h
deleted file mode 100644
index 8a7207a..0000000
--- a/wifi/1.3/default/wifi_p2p_iface.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_P2P_IFACE_H_
-#define WIFI_P2P_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiP2pIface.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a P2P Iface instance.
- */
-class WifiP2pIface : public V1_0::IWifiP2pIface {
- public:
- WifiP2pIface(const std::string& ifname,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
- // Refer to |WifiChip::invalidate()|.
- void invalidate();
- bool isValid();
- std::string getName();
-
- // HIDL methods exposed.
- Return<void> getName(getName_cb hidl_status_cb) override;
- Return<void> getType(getType_cb hidl_status_cb) override;
-
- private:
- // Corresponding worker functions for the HIDL methods.
- std::pair<WifiStatus, std::string> getNameInternal();
- std::pair<WifiStatus, IfaceType> getTypeInternal();
-
- std::string ifname_;
- std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
- bool is_valid_;
-
- DISALLOW_COPY_AND_ASSIGN(WifiP2pIface);
-};
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_P2P_IFACE_H_
diff --git a/wifi/1.3/default/wifi_rtt_controller.cpp b/wifi/1.3/default/wifi_rtt_controller.cpp
deleted file mode 100644
index 3dcbee6..0000000
--- a/wifi/1.3/default/wifi_rtt_controller.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_rtt_controller.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiRttController::WifiRttController(
- const std::string& iface_name, const sp<IWifiIface>& bound_iface,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
- : ifname_(iface_name),
- bound_iface_(bound_iface),
- legacy_hal_(legacy_hal),
- is_valid_(true) {}
-
-void WifiRttController::invalidate() {
- legacy_hal_.reset();
- event_callbacks_.clear();
- is_valid_ = false;
-}
-
-bool WifiRttController::isValid() { return is_valid_; }
-
-std::vector<sp<IWifiRttControllerEventCallback>>
-WifiRttController::getEventCallbacks() {
- return event_callbacks_;
-}
-
-std::string WifiRttController::getIfaceName() { return ifname_; }
-
-Return<void> WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
- &WifiRttController::getBoundIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiRttController::registerEventCallback(
- const sp<IWifiRttControllerEventCallback>& callback,
- registerEventCallback_cb hidl_status_cb) {
- return validateAndCall(this,
- WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
- &WifiRttController::registerEventCallbackInternal,
- hidl_status_cb, callback);
-}
-
-Return<void> WifiRttController::rangeRequest(
- uint32_t cmd_id, const hidl_vec<RttConfig>& rtt_configs,
- rangeRequest_cb hidl_status_cb) {
- return validateAndCall(this,
- WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
- &WifiRttController::rangeRequestInternal,
- hidl_status_cb, cmd_id, rtt_configs);
-}
-
-Return<void> WifiRttController::rangeCancel(
- uint32_t cmd_id, const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
- rangeCancel_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
- &WifiRttController::rangeCancelInternal, hidl_status_cb, cmd_id, addrs);
-}
-
-Return<void> WifiRttController::getCapabilities(
- getCapabilities_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
- &WifiRttController::getCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiRttController::setLci(uint32_t cmd_id,
- const RttLciInformation& lci,
- setLci_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
- &WifiRttController::setLciInternal, hidl_status_cb, cmd_id, lci);
-}
-
-Return<void> WifiRttController::setLcr(uint32_t cmd_id,
- const RttLcrInformation& lcr,
- setLcr_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
- &WifiRttController::setLcrInternal, hidl_status_cb, cmd_id, lcr);
-}
-
-Return<void> WifiRttController::getResponderInfo(
- getResponderInfo_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
- &WifiRttController::getResponderInfoInternal, hidl_status_cb);
-}
-
-Return<void> WifiRttController::enableResponder(
- uint32_t cmd_id, const WifiChannelInfo& channel_hint,
- uint32_t max_duration_seconds, const RttResponder& info,
- enableResponder_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
- &WifiRttController::enableResponderInternal, hidl_status_cb, cmd_id,
- channel_hint, max_duration_seconds, info);
-}
-
-Return<void> WifiRttController::disableResponder(
- uint32_t cmd_id, disableResponder_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
- &WifiRttController::disableResponderInternal, hidl_status_cb, cmd_id);
-}
-
-std::pair<WifiStatus, sp<IWifiIface>>
-WifiRttController::getBoundIfaceInternal() {
- return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_};
-}
-
-WifiStatus WifiRttController::registerEventCallbackInternal(
- const sp<IWifiRttControllerEventCallback>& callback) {
- // TODO(b/31632518): remove the callback when the client is destroyed
- event_callbacks_.emplace_back(callback);
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiRttController::rangeRequestInternal(
- uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs) {
- std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
- if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(
- rtt_configs, &legacy_configs)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- android::wp<WifiRttController> weak_ptr_this(this);
- const auto& on_results_callback =
- [weak_ptr_this](
- legacy_hal::wifi_request_id id,
- const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- std::vector<RttResult> hidl_results;
- if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(
- results, &hidl_results)) {
- LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
- return;
- }
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- callback->onResults(id, hidl_results);
- }
- };
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->startRttRangeRequest(
- ifname_, cmd_id, legacy_configs, on_results_callback);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiRttController::rangeCancelInternal(
- uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs) {
- std::vector<std::array<uint8_t, 6>> legacy_addrs;
- for (const auto& addr : addrs) {
- legacy_addrs.push_back(addr);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id,
- legacy_addrs);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, RttCapabilities>
-WifiRttController::getCapabilitiesInternal() {
- legacy_hal::wifi_error legacy_status;
- legacy_hal::wifi_rtt_capabilities legacy_caps;
- std::tie(legacy_status, legacy_caps) =
- legacy_hal_.lock()->getRttCapabilities(ifname_);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- return {createWifiStatusFromLegacyError(legacy_status), {}};
- }
- RttCapabilities hidl_caps;
- if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps,
- &hidl_caps)) {
- return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id,
- const RttLciInformation& lci) {
- legacy_hal::wifi_lci_information legacy_lci;
- if (!hidl_struct_util::convertHidlRttLciInformationToLegacy(lci,
- &legacy_lci)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->setRttLci(ifname_, cmd_id, legacy_lci);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id,
- const RttLcrInformation& lcr) {
- legacy_hal::wifi_lcr_information legacy_lcr;
- if (!hidl_struct_util::convertHidlRttLcrInformationToLegacy(lcr,
- &legacy_lcr)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->setRttLcr(ifname_, cmd_id, legacy_lcr);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, RttResponder>
-WifiRttController::getResponderInfoInternal() {
- legacy_hal::wifi_error legacy_status;
- legacy_hal::wifi_rtt_responder legacy_responder;
- std::tie(legacy_status, legacy_responder) =
- legacy_hal_.lock()->getRttResponderInfo(ifname_);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- return {createWifiStatusFromLegacyError(legacy_status), {}};
- }
- RttResponder hidl_responder;
- if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder,
- &hidl_responder)) {
- return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
-}
-
-WifiStatus WifiRttController::enableResponderInternal(
- uint32_t cmd_id, const WifiChannelInfo& channel_hint,
- uint32_t max_duration_seconds, const RttResponder& info) {
- legacy_hal::wifi_channel_info legacy_channel_info;
- if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(
- channel_hint, &legacy_channel_info)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_rtt_responder legacy_responder;
- if (!hidl_struct_util::convertHidlRttResponderToLegacy(info,
- &legacy_responder)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->enableRttResponder(
- ifname_, cmd_id, legacy_channel_info, max_duration_seconds,
- legacy_responder);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi_rtt_controller.h b/wifi/1.3/default/wifi_rtt_controller.h
deleted file mode 100644
index eedd22a..0000000
--- a/wifi/1.3/default/wifi_rtt_controller.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_RTT_CONTROLLER_H_
-#define WIFI_RTT_CONTROLLER_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiIface.h>
-#include <android/hardware/wifi/1.0/IWifiRttController.h>
-#include <android/hardware/wifi/1.0/IWifiRttControllerEventCallback.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-/**
- * HIDL interface object used to control all RTT operations.
- */
-class WifiRttController : public V1_0::IWifiRttController {
- public:
- WifiRttController(
- const std::string& iface_name, const sp<IWifiIface>& bound_iface,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
- // Refer to |WifiChip::invalidate()|.
- void invalidate();
- bool isValid();
- std::vector<sp<IWifiRttControllerEventCallback>> getEventCallbacks();
- std::string getIfaceName();
-
- // HIDL methods exposed.
- Return<void> getBoundIface(getBoundIface_cb hidl_status_cb) override;
- Return<void> registerEventCallback(
- const sp<IWifiRttControllerEventCallback>& callback,
- registerEventCallback_cb hidl_status_cb) override;
- Return<void> rangeRequest(uint32_t cmd_id,
- const hidl_vec<RttConfig>& rtt_configs,
- rangeRequest_cb hidl_status_cb) override;
- Return<void> rangeCancel(uint32_t cmd_id,
- const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
- rangeCancel_cb hidl_status_cb) override;
- Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
- Return<void> setLci(uint32_t cmd_id, const RttLciInformation& lci,
- setLci_cb hidl_status_cb) override;
- Return<void> setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
- setLcr_cb hidl_status_cb) override;
- Return<void> getResponderInfo(getResponderInfo_cb hidl_status_cb) override;
- Return<void> enableResponder(uint32_t cmd_id,
- const WifiChannelInfo& channel_hint,
- uint32_t max_duration_seconds,
- const RttResponder& info,
- enableResponder_cb hidl_status_cb) override;
- Return<void> disableResponder(uint32_t cmd_id,
- disableResponder_cb hidl_status_cb) override;
-
- private:
- // Corresponding worker functions for the HIDL methods.
- std::pair<WifiStatus, sp<IWifiIface>> getBoundIfaceInternal();
- WifiStatus registerEventCallbackInternal(
- const sp<IWifiRttControllerEventCallback>& callback);
- WifiStatus rangeRequestInternal(uint32_t cmd_id,
- const std::vector<RttConfig>& rtt_configs);
- WifiStatus rangeCancelInternal(
- uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs);
- std::pair<WifiStatus, RttCapabilities> getCapabilitiesInternal();
- WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci);
- WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr);
- std::pair<WifiStatus, RttResponder> getResponderInfoInternal();
- WifiStatus enableResponderInternal(uint32_t cmd_id,
- const WifiChannelInfo& channel_hint,
- uint32_t max_duration_seconds,
- const RttResponder& info);
- WifiStatus disableResponderInternal(uint32_t cmd_id);
-
- std::string ifname_;
- sp<IWifiIface> bound_iface_;
- std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
- std::vector<sp<IWifiRttControllerEventCallback>> event_callbacks_;
- bool is_valid_;
-
- DISALLOW_COPY_AND_ASSIGN(WifiRttController);
-};
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_RTT_CONTROLLER_H_
diff --git a/wifi/1.3/default/wifi_sta_iface.cpp b/wifi/1.3/default/wifi_sta_iface.cpp
deleted file mode 100644
index a6539e5..0000000
--- a/wifi/1.3/default/wifi_sta_iface.cpp
+++ /dev/null
@@ -1,647 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_sta_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiStaIface::WifiStaIface(
- const std::string& ifname,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
- : ifname_(ifname),
- legacy_hal_(legacy_hal),
- iface_util_(iface_util),
- is_valid_(true) {
- // Turn on DFS channel usage for STA iface.
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->setDfsFlag(ifname_, true);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR)
- << "Failed to set DFS flag; DFS channels may be unavailable.";
- }
-}
-
-void WifiStaIface::invalidate() {
- legacy_hal_.reset();
- event_cb_handler_.invalidate();
- is_valid_ = false;
-}
-
-bool WifiStaIface::isValid() { return is_valid_; }
-
-std::string WifiStaIface::getName() { return ifname_; }
-
-std::set<sp<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
- return event_cb_handler_.getCallbacks();
-}
-
-Return<void> WifiStaIface::getName(getName_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getType(getType_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getTypeInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::registerEventCallback(
- const sp<IWifiStaIfaceEventCallback>& callback,
- registerEventCallback_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::registerEventCallbackInternal,
- hidl_status_cb, callback);
-}
-
-Return<void> WifiStaIface::getCapabilities(getCapabilities_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getCapabilitiesInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getApfPacketFilterCapabilities(
- getApfPacketFilterCapabilities_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getApfPacketFilterCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::installApfPacketFilter(
- uint32_t cmd_id, const hidl_vec<uint8_t>& program,
- installApfPacketFilter_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::installApfPacketFilterInternal,
- hidl_status_cb, cmd_id, program);
-}
-
-Return<void> WifiStaIface::readApfPacketFilterData(
- readApfPacketFilterData_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::readApfPacketFilterDataInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getBackgroundScanCapabilities(
- getBackgroundScanCapabilities_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getBackgroundScanCapabilitiesInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getValidFrequenciesForBand(
- WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getValidFrequenciesForBandInternal,
- hidl_status_cb, band);
-}
-
-Return<void> WifiStaIface::startBackgroundScan(
- uint32_t cmd_id, const StaBackgroundScanParameters& params,
- startBackgroundScan_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::startBackgroundScanInternal,
- hidl_status_cb, cmd_id, params);
-}
-
-Return<void> WifiStaIface::stopBackgroundScan(
- uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::stopBackgroundScanInternal,
- hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiStaIface::enableLinkLayerStatsCollection(
- bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::enableLinkLayerStatsCollectionInternal, hidl_status_cb,
- debug);
-}
-
-Return<void> WifiStaIface::disableLinkLayerStatsCollection(
- disableLinkLayerStatsCollection_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::disableLinkLayerStatsCollectionInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getLinkLayerStats(
- getLinkLayerStats_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getLinkLayerStatsInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getLinkLayerStats_1_3(
- getLinkLayerStats_1_3_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getLinkLayerStatsInternal_1_3,
- hidl_status_cb);
-}
-
-Return<void> WifiStaIface::startRssiMonitoring(
- uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
- startRssiMonitoring_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::startRssiMonitoringInternal,
- hidl_status_cb, cmd_id, max_rssi, min_rssi);
-}
-
-Return<void> WifiStaIface::stopRssiMonitoring(
- uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::stopRssiMonitoringInternal,
- hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiStaIface::getRoamingCapabilities(
- getRoamingCapabilities_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getRoamingCapabilitiesInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiStaIface::configureRoaming(
- const StaRoamingConfig& config, configureRoaming_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::configureRoamingInternal,
- hidl_status_cb, config);
-}
-
-Return<void> WifiStaIface::setRoamingState(StaRoamingState state,
- setRoamingState_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::setRoamingStateInternal,
- hidl_status_cb, state);
-}
-
-Return<void> WifiStaIface::enableNdOffload(bool enable,
- enableNdOffload_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::enableNdOffloadInternal,
- hidl_status_cb, enable);
-}
-
-Return<void> WifiStaIface::startSendingKeepAlivePackets(
- uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data,
- uint16_t ether_type, const hidl_array<uint8_t, 6>& src_address,
- const hidl_array<uint8_t, 6>& dst_address, uint32_t period_in_ms,
- startSendingKeepAlivePackets_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::startSendingKeepAlivePacketsInternal,
- hidl_status_cb, cmd_id, ip_packet_data, ether_type,
- src_address, dst_address, period_in_ms);
-}
-
-Return<void> WifiStaIface::stopSendingKeepAlivePackets(
- uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::stopSendingKeepAlivePacketsInternal,
- hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiStaIface::setScanningMacOui(
- const hidl_array<uint8_t, 3>& oui, setScanningMacOui_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::setScanningMacOuiInternal,
- hidl_status_cb, oui);
-}
-
-Return<void> WifiStaIface::startDebugPacketFateMonitoring(
- startDebugPacketFateMonitoring_cb hidl_status_cb) {
- return validateAndCall(
- this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::startDebugPacketFateMonitoringInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getDebugTxPacketFates(
- getDebugTxPacketFates_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getDebugTxPacketFatesInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getDebugRxPacketFates(
- getDebugRxPacketFates_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getDebugRxPacketFatesInternal,
- hidl_status_cb);
-}
-
-Return<void> WifiStaIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
- setMacAddress_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::setMacAddressInternal, hidl_status_cb,
- mac);
-}
-
-Return<void> WifiStaIface::getFactoryMacAddress(
- getFactoryMacAddress_cb hidl_status_cb) {
- return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
- &WifiStaIface::getFactoryMacAddressInternal,
- hidl_status_cb);
-}
-
-std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
- return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiStaIface::getTypeInternal() {
- return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::STA};
-}
-
-WifiStatus WifiStaIface::registerEventCallbackInternal(
- const sp<IWifiStaIfaceEventCallback>& callback) {
- if (!event_cb_handler_.addCallback(callback)) {
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
- }
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
- legacy_hal::wifi_error legacy_status;
- uint32_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>
-WifiStaIface::getApfPacketFilterCapabilitiesInternal() {
- legacy_hal::wifi_error legacy_status;
- legacy_hal::PacketFilterCapabilities legacy_caps;
- std::tie(legacy_status, legacy_caps) =
- legacy_hal_.lock()->getPacketFilterCapabilities(ifname_);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- return {createWifiStatusFromLegacyError(legacy_status), {}};
- }
- StaApfPacketFilterCapabilities hidl_caps;
- if (!hidl_struct_util::convertLegacyApfCapabilitiesToHidl(legacy_caps,
- &hidl_caps)) {
- return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiStaIface::installApfPacketFilterInternal(
- uint32_t /* cmd_id */, const std::vector<uint8_t>& program) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->setPacketFilter(ifname_, program);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>>
-WifiStaIface::readApfPacketFilterDataInternal() {
- const std::pair<legacy_hal::wifi_error, std::vector<uint8_t>>
- legacy_status_and_data =
- legacy_hal_.lock()->readApfPacketFilterData(ifname_);
- return {createWifiStatusFromLegacyError(legacy_status_and_data.first),
- std::move(legacy_status_and_data.second)};
-}
-
-std::pair<WifiStatus, StaBackgroundScanCapabilities>
-WifiStaIface::getBackgroundScanCapabilitiesInternal() {
- legacy_hal::wifi_error legacy_status;
- legacy_hal::wifi_gscan_capabilities legacy_caps;
- std::tie(legacy_status, legacy_caps) =
- legacy_hal_.lock()->getGscanCapabilities(ifname_);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- return {createWifiStatusFromLegacyError(legacy_status), {}};
- }
- StaBackgroundScanCapabilities hidl_caps;
- if (!hidl_struct_util::convertLegacyGscanCapabilitiesToHidl(legacy_caps,
- &hidl_caps)) {
- return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-WifiStaIface::getValidFrequenciesForBandInternal(WifiBand band) {
- static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
- "Size mismatch");
- legacy_hal::wifi_error legacy_status;
- std::vector<uint32_t> valid_frequencies;
- std::tie(legacy_status, valid_frequencies) =
- legacy_hal_.lock()->getValidFrequenciesForBand(
- ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
- return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
-}
-
-WifiStatus WifiStaIface::startBackgroundScanInternal(
- uint32_t cmd_id, const StaBackgroundScanParameters& params) {
- legacy_hal::wifi_scan_cmd_params legacy_params;
- if (!hidl_struct_util::convertHidlGscanParamsToLegacy(params,
- &legacy_params)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- android::wp<WifiStaIface> weak_ptr_this(this);
- const auto& on_failure_callback =
- [weak_ptr_this](legacy_hal::wifi_request_id id) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->onBackgroundScanFailure(id).isOk()) {
- LOG(ERROR)
- << "Failed to invoke onBackgroundScanFailure callback";
- }
- }
- };
- const auto& on_results_callback =
- [weak_ptr_this](
- legacy_hal::wifi_request_id id,
- const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- std::vector<StaScanData> hidl_scan_datas;
- if (!hidl_struct_util::
- convertLegacyVectorOfCachedGscanResultsToHidl(
- results, &hidl_scan_datas)) {
- LOG(ERROR) << "Failed to convert scan results to HIDL structs";
- return;
- }
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->onBackgroundScanResults(id, hidl_scan_datas)
- .isOk()) {
- LOG(ERROR)
- << "Failed to invoke onBackgroundScanResults callback";
- }
- }
- };
- const auto& on_full_result_callback = [weak_ptr_this](
- legacy_hal::wifi_request_id id,
- const legacy_hal::
- wifi_scan_result* result,
- uint32_t buckets_scanned) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- StaScanResult hidl_scan_result;
- if (!hidl_struct_util::convertLegacyGscanResultToHidl(
- *result, true, &hidl_scan_result)) {
- LOG(ERROR) << "Failed to convert full scan results to HIDL structs";
- return;
- }
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback
- ->onBackgroundFullScanResult(id, buckets_scanned,
- hidl_scan_result)
- .isOk()) {
- LOG(ERROR)
- << "Failed to invoke onBackgroundFullScanResult callback";
- }
- }
- };
- legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startGscan(
- ifname_, cmd_id, legacy_params, on_failure_callback,
- on_results_callback, on_full_result_callback);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::stopBackgroundScanInternal(uint32_t cmd_id) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->stopGscan(ifname_, cmd_id);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->enableLinkLayerStats(ifname_, debug);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->disableLinkLayerStats(ifname_);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, V1_0::StaLinkLayerStats>
-WifiStaIface::getLinkLayerStatsInternal() {
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-std::pair<WifiStatus, V1_3::StaLinkLayerStats>
-WifiStaIface::getLinkLayerStatsInternal_1_3() {
- legacy_hal::wifi_error legacy_status;
- legacy_hal::LinkLayerStats legacy_stats;
- std::tie(legacy_status, legacy_stats) =
- legacy_hal_.lock()->getLinkLayerStats(ifname_);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- return {createWifiStatusFromLegacyError(legacy_status), {}};
- }
- V1_3::StaLinkLayerStats hidl_stats;
- if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
- &hidl_stats)) {
- return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
-}
-
-WifiStatus WifiStaIface::startRssiMonitoringInternal(uint32_t cmd_id,
- int32_t max_rssi,
- int32_t min_rssi) {
- android::wp<WifiStaIface> weak_ptr_this(this);
- const auto& on_threshold_breached_callback =
- [weak_ptr_this](legacy_hal::wifi_request_id id,
- std::array<uint8_t, 6> bssid, int8_t rssi) {
- const auto shared_ptr_this = weak_ptr_this.promote();
- if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
- LOG(ERROR) << "Callback invoked on an invalid object";
- return;
- }
- for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
- if (!callback->onRssiThresholdBreached(id, bssid, rssi)
- .isOk()) {
- LOG(ERROR)
- << "Failed to invoke onRssiThresholdBreached callback";
- }
- }
- };
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->startRssiMonitoring(ifname_, cmd_id, max_rssi,
- min_rssi,
- on_threshold_breached_callback);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::stopRssiMonitoringInternal(uint32_t cmd_id) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->stopRssiMonitoring(ifname_, cmd_id);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, StaRoamingCapabilities>
-WifiStaIface::getRoamingCapabilitiesInternal() {
- legacy_hal::wifi_error legacy_status;
- legacy_hal::wifi_roaming_capabilities legacy_caps;
- std::tie(legacy_status, legacy_caps) =
- legacy_hal_.lock()->getRoamingCapabilities(ifname_);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- return {createWifiStatusFromLegacyError(legacy_status), {}};
- }
- StaRoamingCapabilities hidl_caps;
- if (!hidl_struct_util::convertLegacyRoamingCapabilitiesToHidl(legacy_caps,
- &hidl_caps)) {
- return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiStaIface::configureRoamingInternal(
- const StaRoamingConfig& config) {
- legacy_hal::wifi_roaming_config legacy_config;
- if (!hidl_struct_util::convertHidlRoamingConfigToLegacy(config,
- &legacy_config)) {
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
- }
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->configureRoaming(ifname_, legacy_config);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->enableFirmwareRoaming(
- ifname_, hidl_struct_util::convertHidlRoamingStateToLegacy(state));
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::enableNdOffloadInternal(bool enable) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->configureNdOffload(ifname_, enable);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
- uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
- uint16_t ether_type, const std::array<uint8_t, 6>& src_address,
- const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->startSendingOffloadedPacket(
- ifname_, cmd_id, ether_type, ip_packet_data, src_address,
- dst_address, period_in_ms);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(uint32_t cmd_id) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->stopSendingOffloadedPacket(ifname_, cmd_id);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::setScanningMacOuiInternal(
- const std::array<uint8_t, 3>& oui) {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->setScanningMacOui(ifname_, oui);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->startPktFateMonitoring(ifname_);
- return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
-WifiStaIface::getDebugTxPacketFatesInternal() {
- legacy_hal::wifi_error legacy_status;
- std::vector<legacy_hal::wifi_tx_report> legacy_fates;
- std::tie(legacy_status, legacy_fates) =
- legacy_hal_.lock()->getTxPktFates(ifname_);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- return {createWifiStatusFromLegacyError(legacy_status), {}};
- }
- std::vector<WifiDebugTxPacketFateReport> hidl_fates;
- if (!hidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToHidl(
- legacy_fates, &hidl_fates)) {
- return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
-WifiStaIface::getDebugRxPacketFatesInternal() {
- legacy_hal::wifi_error legacy_status;
- std::vector<legacy_hal::wifi_rx_report> legacy_fates;
- std::tie(legacy_status, legacy_fates) =
- legacy_hal_.lock()->getRxPktFates(ifname_);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- return {createWifiStatusFromLegacyError(legacy_status), {}};
- }
- std::vector<WifiDebugRxPacketFateReport> hidl_fates;
- if (!hidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToHidl(
- legacy_fates, &hidl_fates)) {
- return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
-}
-
-WifiStatus WifiStaIface::setMacAddressInternal(
- const std::array<uint8_t, 6>& mac) {
- bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
- if (!status) {
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
- }
- return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, std::array<uint8_t, 6>>
-WifiStaIface::getFactoryMacAddressInternal() {
- std::array<uint8_t, 6> mac =
- iface_util_.lock()->getFactoryMacAddress(ifname_);
- return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
-}
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi_sta_iface.h b/wifi/1.3/default/wifi_sta_iface.h
deleted file mode 100644
index 9224939..0000000
--- a/wifi/1.3/default/wifi_sta_iface.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_STA_IFACE_H_
-#define WIFI_STA_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
-#include <android/hardware/wifi/1.3/IWifiStaIface.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_iface_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a STA Iface instance.
- */
-class WifiStaIface : public V1_3::IWifiStaIface {
- public:
- WifiStaIface(const std::string& ifname,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
- // Refer to |WifiChip::invalidate()|.
- void invalidate();
- bool isValid();
- std::set<sp<IWifiStaIfaceEventCallback>> getEventCallbacks();
- std::string getName();
-
- // HIDL methods exposed.
- Return<void> getName(getName_cb hidl_status_cb) override;
- Return<void> getType(getType_cb hidl_status_cb) override;
- Return<void> registerEventCallback(
- const sp<IWifiStaIfaceEventCallback>& callback,
- registerEventCallback_cb hidl_status_cb) override;
- Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
- Return<void> getApfPacketFilterCapabilities(
- getApfPacketFilterCapabilities_cb hidl_status_cb) override;
- Return<void> installApfPacketFilter(
- uint32_t cmd_id, const hidl_vec<uint8_t>& program,
- installApfPacketFilter_cb hidl_status_cb) override;
- Return<void> readApfPacketFilterData(
- readApfPacketFilterData_cb hidl_status_cb) override;
- Return<void> getBackgroundScanCapabilities(
- getBackgroundScanCapabilities_cb hidl_status_cb) override;
- Return<void> getValidFrequenciesForBand(
- WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override;
- Return<void> startBackgroundScan(
- uint32_t cmd_id, const StaBackgroundScanParameters& params,
- startBackgroundScan_cb hidl_status_cb) override;
- Return<void> stopBackgroundScan(
- uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) override;
- Return<void> enableLinkLayerStatsCollection(
- bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) override;
- Return<void> disableLinkLayerStatsCollection(
- disableLinkLayerStatsCollection_cb hidl_status_cb) override;
- Return<void> getLinkLayerStats(
- getLinkLayerStats_cb hidl_status_cb) override;
- Return<void> getLinkLayerStats_1_3(
- getLinkLayerStats_1_3_cb hidl_status_cb) override;
- Return<void> startRssiMonitoring(
- uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
- startRssiMonitoring_cb hidl_status_cb) override;
- Return<void> stopRssiMonitoring(
- uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
- Return<void> getRoamingCapabilities(
- getRoamingCapabilities_cb hidl_status_cb) override;
- Return<void> configureRoaming(const StaRoamingConfig& config,
- configureRoaming_cb hidl_status_cb) override;
- Return<void> setRoamingState(StaRoamingState state,
- setRoamingState_cb hidl_status_cb) override;
- Return<void> enableNdOffload(bool enable,
- enableNdOffload_cb hidl_status_cb) override;
- Return<void> startSendingKeepAlivePackets(
- uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data,
- uint16_t ether_type, const hidl_array<uint8_t, 6>& src_address,
- const hidl_array<uint8_t, 6>& dst_address, uint32_t period_in_ms,
- startSendingKeepAlivePackets_cb hidl_status_cb) override;
- Return<void> stopSendingKeepAlivePackets(
- uint32_t cmd_id,
- stopSendingKeepAlivePackets_cb hidl_status_cb) override;
- Return<void> setScanningMacOui(
- const hidl_array<uint8_t, 3>& oui,
- setScanningMacOui_cb hidl_status_cb) override;
- Return<void> startDebugPacketFateMonitoring(
- startDebugPacketFateMonitoring_cb hidl_status_cb) override;
- Return<void> getDebugTxPacketFates(
- getDebugTxPacketFates_cb hidl_status_cb) override;
- Return<void> getDebugRxPacketFates(
- getDebugRxPacketFates_cb hidl_status_cb) override;
- Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
- setMacAddress_cb hidl_status_cb) override;
- Return<void> getFactoryMacAddress(
- getFactoryMacAddress_cb hidl_status_cb) override;
-
- private:
- // Corresponding worker functions for the HIDL methods.
- std::pair<WifiStatus, std::string> getNameInternal();
- std::pair<WifiStatus, IfaceType> getTypeInternal();
- WifiStatus registerEventCallbackInternal(
- const sp<IWifiStaIfaceEventCallback>& callback);
- std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
- std::pair<WifiStatus, StaApfPacketFilterCapabilities>
- getApfPacketFilterCapabilitiesInternal();
- WifiStatus installApfPacketFilterInternal(
- uint32_t cmd_id, const std::vector<uint8_t>& program);
- std::pair<WifiStatus, std::vector<uint8_t>>
- readApfPacketFilterDataInternal();
- std::pair<WifiStatus, StaBackgroundScanCapabilities>
- getBackgroundScanCapabilitiesInternal();
- std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
- getValidFrequenciesForBandInternal(WifiBand band);
- WifiStatus startBackgroundScanInternal(
- uint32_t cmd_id, const StaBackgroundScanParameters& params);
- WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
- WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
- WifiStatus disableLinkLayerStatsCollectionInternal();
- std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal();
- std::pair<WifiStatus, V1_3::StaLinkLayerStats>
- getLinkLayerStatsInternal_1_3();
- WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi,
- int32_t min_rssi);
- WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
- std::pair<WifiStatus, StaRoamingCapabilities>
- getRoamingCapabilitiesInternal();
- WifiStatus configureRoamingInternal(const StaRoamingConfig& config);
- WifiStatus setRoamingStateInternal(StaRoamingState state);
- WifiStatus enableNdOffloadInternal(bool enable);
- WifiStatus startSendingKeepAlivePacketsInternal(
- uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
- uint16_t ether_type, const std::array<uint8_t, 6>& src_address,
- const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
- WifiStatus stopSendingKeepAlivePacketsInternal(uint32_t cmd_id);
- WifiStatus setScanningMacOuiInternal(const std::array<uint8_t, 3>& oui);
- WifiStatus startDebugPacketFateMonitoringInternal();
- std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
- getDebugTxPacketFatesInternal();
- std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
- getDebugRxPacketFatesInternal();
- WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
- std::pair<WifiStatus, std::array<uint8_t, 6>>
- getFactoryMacAddressInternal();
-
- std::string ifname_;
- std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
- std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
- bool is_valid_;
- hidl_callback_util::HidlCallbackHandler<IWifiStaIfaceEventCallback>
- event_cb_handler_;
-
- DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
-};
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_STA_IFACE_H_
diff --git a/wifi/1.3/default/wifi_status_util.cpp b/wifi/1.3/default/wifi_status_util.cpp
deleted file mode 100644
index 0a5bb13..0000000
--- a/wifi/1.3/default/wifi_status_util.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.
- */
-
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-std::string legacyErrorToString(legacy_hal::wifi_error error) {
- switch (error) {
- case legacy_hal::WIFI_SUCCESS:
- return "SUCCESS";
- case legacy_hal::WIFI_ERROR_UNINITIALIZED:
- return "UNINITIALIZED";
- case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
- return "NOT_AVAILABLE";
- case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
- return "NOT_SUPPORTED";
- case legacy_hal::WIFI_ERROR_INVALID_ARGS:
- return "INVALID_ARGS";
- case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
- return "INVALID_REQUEST_ID";
- case legacy_hal::WIFI_ERROR_TIMED_OUT:
- return "TIMED_OUT";
- case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
- return "TOO_MANY_REQUESTS";
- case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
- return "OUT_OF_MEMORY";
- case legacy_hal::WIFI_ERROR_BUSY:
- return "BUSY";
- case legacy_hal::WIFI_ERROR_UNKNOWN:
- return "UNKNOWN";
- }
-}
-
-WifiStatus createWifiStatus(WifiStatusCode code,
- const std::string& description) {
- return {code, description};
-}
-
-WifiStatus createWifiStatus(WifiStatusCode code) {
- return createWifiStatus(code, "");
-}
-
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
- const std::string& desc) {
- switch (error) {
- case legacy_hal::WIFI_ERROR_UNINITIALIZED:
- case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
- return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, desc);
-
- case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
- return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED, desc);
-
- case legacy_hal::WIFI_ERROR_INVALID_ARGS:
- case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
- return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS, desc);
-
- case legacy_hal::WIFI_ERROR_TIMED_OUT:
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
- desc + ", timed out");
-
- case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
- desc + ", too many requests");
-
- case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
- desc + ", out of memory");
-
- case legacy_hal::WIFI_ERROR_BUSY:
- return createWifiStatus(WifiStatusCode::ERROR_BUSY);
-
- case legacy_hal::WIFI_ERROR_NONE:
- return createWifiStatus(WifiStatusCode::SUCCESS, desc);
-
- case legacy_hal::WIFI_ERROR_UNKNOWN:
- return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
- }
-}
-
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) {
- return createWifiStatusFromLegacyError(error, "");
-}
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/wifi/1.3/default/wifi_status_util.h b/wifi/1.3/default/wifi_status_util.h
deleted file mode 100644
index bc8baa9..0000000
--- a/wifi/1.3/default/wifi_status_util.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_STATUS_UTIL_H_
-#define WIFI_STATUS_UTIL_H_
-
-#include <android/hardware/wifi/1.0/IWifi.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-std::string legacyErrorToString(legacy_hal::wifi_error error);
-WifiStatus createWifiStatus(WifiStatusCode code,
- const std::string& description);
-WifiStatus createWifiStatus(WifiStatusCode code);
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
- const std::string& description);
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // WIFI_STATUS_UTIL_H_
diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp
index 9ffda8b..fe9c791 100644
--- a/wifi/1.3/vts/functional/Android.bp
+++ b/wifi/1.3/vts/functional/Android.bp
@@ -30,4 +30,6 @@
"android.hardware.wifi@1.3",
"libwifi-system-iface"
],
+ disable_framework: true,
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
index faf426e..52c7a4a 100644
--- a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
+++ b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
@@ -14,37 +14,8 @@
* limitations under the License.
*/
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.3/IWifi.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
-#include "wifi_hidl_test_utils.h"
-
-using ::android::hardware::wifi::V1_3::IWifi;
-
-// Test environment for Wifi HIDL HAL.
-class WifiHidlEnvironment_1_3 : public WifiHidlEnvironment {
- public:
- // get the test environment singleton
- static WifiHidlEnvironment_1_3* Instance() {
- static WifiHidlEnvironment_1_3* instance = new WifiHidlEnvironment_1_3;
- return instance;
- }
-
- virtual void registerTestServices() override {
- registerTestService<android::hardware::wifi::V1_3::IWifi>();
- }
-
- private:
- WifiHidlEnvironment_1_3() {}
-};
-
-WifiHidlEnvironment_1_3* gEnv = WifiHidlEnvironment_1_3::Instance();
-
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(gEnv);
- ::testing::InitGoogleTest(&argc, argv);
- gEnv->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+// 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/1.3/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
index d980fcb..e99b34a 100644
--- a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
@@ -16,9 +16,11 @@
#include <android-base/logging.h>
+#include <android/hardware/wifi/1.3/IWifi.h>
#include <android/hardware/wifi/1.3/IWifiChip.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "wifi_hidl_call_util.h"
#include "wifi_hidl_test_utils.h"
@@ -39,14 +41,17 @@
/**
* Fixture to use for all Wifi chip HIDL interface tests.
*/
-class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- wifi_chip_ = IWifiChip::castFrom(getWifiChip());
+ // Make sure to start with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
ASSERT_NE(nullptr, wifi_chip_.get());
}
- virtual void TearDown() override { stopWifi(); }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
protected:
// Helper function to configure the Chip in one of the supported modes.
@@ -70,6 +75,9 @@
}
sp<IWifiChip> wifi_chip_;
+
+ private:
+ std::string GetInstanceName() { return GetParam(); }
};
/*
@@ -77,7 +85,7 @@
* This test case tests the setLatencyMode() API with
* Latency mode NORMAL
*/
-TEST_F(WifiChipHidlTest, SetLatencyMode_normal) {
+TEST_P(WifiChipHidlTest, SetLatencyMode_normal) {
uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
const auto& status =
HIDL_INVOKE(wifi_chip_, setLatencyMode, kLatencyModeNormal);
@@ -92,7 +100,7 @@
* SetLatencyMode_low
* This test case tests the setLatencyMode() API with Latency mode LOW
*/
-TEST_F(WifiChipHidlTest, SetLatencyMode_low) {
+TEST_P(WifiChipHidlTest, SetLatencyMode_low) {
uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
const auto& status =
HIDL_INVOKE(wifi_chip_, setLatencyMode, kLatencyModeLow);
@@ -106,7 +114,7 @@
/*
* GetCapabilities_1_3
*/
-TEST_F(WifiChipHidlTest, GetCapabilities_1_3) {
+TEST_P(WifiChipHidlTest, GetCapabilities_1_3) {
configureChipForIfaceType(IfaceType::STA, true);
const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities_1_3);
if (status_and_caps.first.code != WifiStatusCode::SUCCESS) {
@@ -116,3 +124,9 @@
}
EXPECT_NE(0u, status_and_caps.second);
}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiChipHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ ::android::hardware::wifi::V1_3::IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
index 71e90ac..41d4ebb 100644
--- a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -19,28 +19,36 @@
#include <android-base/logging.h>
+#include <android/hardware/wifi/1.3/IWifi.h>
#include <android/hardware/wifi/1.3/IWifiStaIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#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::hidl_array;
+using ::android::hardware::wifi::V1_0::WifiStatus;
using ::android::hardware::wifi::V1_0::WifiStatusCode;
using ::android::hardware::wifi::V1_3::IWifiStaIface;
/**
* Fixture to use for all STA Iface HIDL interface tests.
*/
-class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface());
+ // Make sure to start with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_sta_iface_ =
+ IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName()));
ASSERT_NE(nullptr, wifi_sta_iface_.get());
}
- virtual void TearDown() override { stopWifi(); }
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
protected:
bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) {
@@ -51,6 +59,9 @@
}
sp<IWifiStaIface> wifi_sta_iface_;
+
+ private:
+ std::string GetInstanceName() { return GetParam(); }
};
/*
@@ -58,15 +69,12 @@
* Ensures that calls to get factory MAC address will retrieve a non-zero MAC
* and return a success status code.
*/
-TEST_F(WifiStaIfaceHidlTest, GetFactoryMacAddress) {
- const auto& status_and_mac =
+TEST_P(WifiStaIfaceHidlTest, GetFactoryMacAddress) {
+ std::pair<WifiStatus, hidl_array<uint8_t, 6> > status_and_mac =
HIDL_INVOKE(wifi_sta_iface_, getFactoryMacAddress);
EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code);
- const int num_elements = sizeof(status_and_mac.second) / sizeof(uint8_t);
- EXPECT_EQ(6, num_elements);
- for (int i = 0; i < num_elements; i++) {
- EXPECT_NE(0, status_and_mac.second[i]);
- }
+ hidl_array<uint8_t, 6> all_zero{};
+ EXPECT_NE(all_zero, status_and_mac.second);
}
/*
@@ -74,7 +82,7 @@
* Ensures that calls to get link layer stats V1_3 will retrieve a non-empty
* StaLinkLayerStats after link layer stats collection is enabled.
*/
-TEST_F(WifiStaIfaceHidlTest, GetLinkLayerStats_1_3) {
+TEST_P(WifiStaIfaceHidlTest, GetLinkLayerStats_1_3) {
if (!isCapabilitySupported(
IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) {
// No-op if link layer stats is not supported.
@@ -95,3 +103,9 @@
WifiStatusCode::SUCCESS,
HIDL_INVOKE(wifi_sta_iface_, disableLinkLayerStatsCollection).code);
}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiStaIfaceHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ ::android::hardware::wifi::V1_3::IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp
new file mode 100644
index 0000000..3b94619
--- /dev/null
+++ b/wifi/1.4/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.wifi@1.4",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IWifi.hal",
+ "IWifiApIface.hal",
+ "IWifiChip.hal",
+ "IWifiChipEventCallback.hal",
+ "IWifiNanIface.hal",
+ "IWifiRttController.hal",
+ "IWifiRttControllerEventCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/wifi/1.4/IWifi.hal b/wifi/1.4/IWifi.hal
new file mode 100644
index 0000000..765e09d
--- /dev/null
+++ b/wifi/1.4/IWifi.hal
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.4;
+
+import @1.3::IWifi;
+
+/**
+ * This is the root of the HAL module and is the interface returned when
+ * loading an implementation of the Wi-Fi HAL. There must be at most one
+ * module loaded in the system.
+ * IWifi.getChip() must return @1.2::IWifiChip
+ */
+interface IWifi extends @1.3::IWifi {};
diff --git a/wifi/1.4/IWifiApIface.hal b/wifi/1.4/IWifiApIface.hal
new file mode 100644
index 0000000..80c576d
--- /dev/null
+++ b/wifi/1.4/IWifiApIface.hal
@@ -0,0 +1,53 @@
+/*
+ * 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::IWifiApIface;
+import @1.0::MacAddress;
+import @1.0::WifiStatus;
+
+/**
+ * Represents a network interface in AP mode.
+ *
+ * This can be obtained through @1.0::IWifiChip.getApIface() and casting
+ * IWifiApIface up to 1.4.
+ */
+interface IWifiApIface extends @1.0::IWifiApIface {
+ /**
+ * Changes the MAC address of the interface to the given MAC address.
+ *
+ * @param mac MAC address to change to.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ setMacAddress(MacAddress mac) generates (WifiStatus status);
+
+ /**
+ * Gets the factory MAC address of the interface.
+ *
+ * @return status WifiStatus of the operation
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ * @return mac factory MAC address of the interface
+ */
+ getFactoryMacAddress() generates (WifiStatus status, MacAddress mac);
+};
diff --git a/wifi/1.4/IWifiChip.hal b/wifi/1.4/IWifiChip.hal
new file mode 100644
index 0000000..07f4a65
--- /dev/null
+++ b/wifi/1.4/IWifiChip.hal
@@ -0,0 +1,62 @@
+/*
+ * 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::IWifiIface;
+import @1.3::IWifiChip;
+import IWifiChipEventCallback;
+import IWifiRttController;
+
+/**
+ * Interface that represents a chip that must be configured as a single unit.
+ */
+interface IWifiChip extends @1.3::IWifiChip {
+ /**
+ * Requests notifications of significant events on this chip. Multiple calls
+ * to this must register multiple callbacks each of which must receive all
+ * events.
+ *
+ * @param callback An instance of the |IWifiChipEventCallback| HIDL interface
+ * object.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+ */
+ registerEventCallback_1_4(IWifiChipEventCallback callback) generates (WifiStatus status);
+
+ /**
+ * Create a RTTController instance.
+ *
+ * RTT controller can be either:
+ * a) Bound to a specific iface by passing in the corresponding |IWifiIface|
+ * object in |iface| param, OR
+ * b) Let the implementation decide the iface to use for RTT operations by
+ * passing null in |iface| param.
+ *
+ * @param boundIface HIDL interface object representing the iface if
+ * the responder must be bound to a specific iface, null otherwise.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+ */
+ createRttController_1_4(IWifiIface boundIface)
+ generates (WifiStatus status, IWifiRttController rtt);
+};
diff --git a/wifi/1.4/IWifiChipEventCallback.hal b/wifi/1.4/IWifiChipEventCallback.hal
new file mode 100644
index 0000000..9ead344
--- /dev/null
+++ b/wifi/1.4/IWifiChipEventCallback.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@1.4;
+
+import @1.2::IWifiChipEventCallback;
+import WifiBand;
+
+/**
+ * Wifi chip event callbacks.
+ */
+interface IWifiChipEventCallback extends @1.2::IWifiChipEventCallback {
+ /**
+ * Struct describing the state of each hardware radio chain (hardware MAC)
+ * on the device.
+ */
+ struct RadioModeInfo {
+ /**
+ * Identifier for this radio chain. This is vendor dependent & used
+ * only for debugging purposes.
+ */
+ uint32_t radioId;
+
+ /**
+ * List of bands on which this radio chain is operating.
+ * Can be one of:
+ * a) WifiBand.BAND_24GHZ => 2.4Ghz.
+ * b) WifiBand.BAND_5GHZ => 5Ghz.
+ * c) WifiBand.BAND_24GHZ_5GHZ = 2.4Ghz + 5Ghz (Radio is time sharing
+ * across the 2 bands).
+ * d) WifiBand.BAND_6GHZ => 6Ghz.
+ * e) WifiBand.BAND_5GHZ_6GHZ => 5Ghz + 6Ghz (Radio is time sharing
+ * across the 2 bands).
+ * f) WifiBand.BAND_24GHZ_5GHZ_6GHZ => 2.4Ghz + 5Ghz + 6Ghz (Radio is
+ * time sharing across the 3 bands).
+ */
+ WifiBand bandInfo;
+
+ /**
+ * List of interfaces on this radio chain (hardware MAC).
+ */
+ vec<IfaceInfo> ifaceInfos;
+ };
+
+ /**
+ * Asynchronous callback indicating a radio mode change.
+ * Radio mode change could be a result of:
+ * a) Bringing up concurrent interfaces (For ex: STA + AP).
+ * b) Change in operating band of one of the concurrent interfaces (For ex:
+ * STA connection moved from 2.4G to 5G)
+ *
+ * @param radioModeInfos List of RadioModeInfo structures for each
+ * radio chain (hardware MAC) on the device.
+ */
+ oneway onRadioModeChange_1_4(vec<RadioModeInfo> radioModeInfos);
+};
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/IWifiRttController.hal b/wifi/1.4/IWifiRttController.hal
new file mode 100644
index 0000000..5c71975
--- /dev/null
+++ b/wifi/1.4/IWifiRttController.hal
@@ -0,0 +1,102 @@
+/*
+ * 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::IWifiRttController;
+import @1.0::CommandId;
+import @1.0::WifiChannelInfo;
+import @1.0::WifiStatus;
+import IWifiRttControllerEventCallback;
+
+/**
+ * Interface used to perform RTT(Round trip time) operations.
+ */
+interface IWifiRttController extends @1.0::IWifiRttController {
+ /**
+ * Requests notifications of significant events on this rtt controller.
+ * Multiple calls to this must register multiple callbacks each of which must
+ * receive all events.
+ *
+ * @param callback An instance of the |IWifiRttControllerEventCallback| HIDL
+ * interface object.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+ */
+ registerEventCallback_1_4(IWifiRttControllerEventCallback callback)
+ generates (WifiStatus status);
+
+ /**
+ * API to request RTT measurement.
+ *
+ * @param cmdId command Id to use for this invocation.
+ * @param rttConfigs Vector of |RttConfig| parameters.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ rangeRequest_1_4(CommandId cmdId, vec<RttConfig> rttConfigs) generates (WifiStatus status);
+
+ /**
+ * RTT capabilities of the device.
+ *
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ * @return capabilities Instance of |RttCapabilities|.
+ */
+ getCapabilities_1_4() generates (WifiStatus status, RttCapabilities capabilities);
+
+ /**
+ * Get RTT responder information e.g. WiFi channel to enable responder on.
+ *
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ * @return info Instance of |RttResponderInfo|.
+ */
+ getResponderInfo_1_4() generates (WifiStatus status, RttResponder info);
+
+ /**
+ * Enable RTT responder mode.
+ *
+ * @param cmdId command Id to use for this invocation.
+ * @parm channelHint Hint of the channel information where RTT responder must
+ * be enabled on.
+ * @param maxDurationInSeconds Timeout of responder mode.
+ * @param info Instance of |RttResponderInfo|.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ enableResponder_1_4(CommandId cmdId, WifiChannelInfo channelHint,
+ uint32_t maxDurationInSeconds, RttResponder info) generates (WifiStatus status);
+};
diff --git a/wifi/1.4/IWifiRttControllerEventCallback.hal b/wifi/1.4/IWifiRttControllerEventCallback.hal
new file mode 100644
index 0000000..75de3d4
--- /dev/null
+++ b/wifi/1.4/IWifiRttControllerEventCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * 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::IWifiRttControllerEventCallback;
+import @1.0::CommandId;
+
+/**
+ * RTT Response and Event Callbacks.
+ */
+interface IWifiRttControllerEventCallback extends @1.0::IWifiRttControllerEventCallback {
+ /*
+ * Invoked when an RTT result is available.
+ *
+ * @param cmdId command Id corresponding to the original request.
+ * @param results Vector of |RttResult| instances.
+ */
+ oneway onResults_1_4(CommandId cmdId, vec<RttResult> results);
+};
diff --git a/wifi/1.4/default/Android.mk b/wifi/1.4/default/Android.mk
new file mode 100644
index 0000000..ab76ff6
--- /dev/null
+++ b/wifi/1.4/default/Android.mk
@@ -0,0 +1,174 @@
+# 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.
+LOCAL_PATH := $(call my-dir)
+
+###
+### android.hardware.wifi static library
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service-lib
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+ifdef WIFI_HAL_INTERFACE_COMBINATIONS
+LOCAL_CPPFLAGS += -DWIFI_HAL_INTERFACE_COMBINATIONS="$(WIFI_HAL_INTERFACE_COMBINATIONS)"
+endif
+ifdef WIFI_HIDL_FEATURE_AWARE
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_AWARE
+endif
+ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DUAL_INTERFACE
+endif
+ifdef WIFI_HIDL_FEATURE_DISABLE_AP
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP
+endif
+ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+endif
+# Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
+LOCAL_CFLAGS += -Wno-error=implicit-fallthrough
+LOCAL_SRC_FILES := \
+ hidl_struct_util.cpp \
+ hidl_sync_util.cpp \
+ ringbuffer.cpp \
+ wifi.cpp \
+ wifi_ap_iface.cpp \
+ wifi_chip.cpp \
+ wifi_feature_flags.cpp \
+ wifi_iface_util.cpp \
+ wifi_legacy_hal.cpp \
+ wifi_legacy_hal_stubs.cpp \
+ wifi_mode_controller.cpp \
+ wifi_nan_iface.cpp \
+ wifi_p2p_iface.cpp \
+ wifi_rtt_controller.cpp \
+ wifi_sta_iface.cpp \
+ wifi_status_util.cpp
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libcutils \
+ libhidlbase \
+ liblog \
+ libnl \
+ libutils \
+ libwifi-hal \
+ libwifi-system-iface \
+ android.hardware.wifi@1.0 \
+ android.hardware.wifi@1.1 \
+ android.hardware.wifi@1.2 \
+ android.hardware.wifi@1.3 \
+ android.hardware.wifi@1.4
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_STATIC_LIBRARY)
+
+###
+### android.hardware.wifi daemon
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service
+LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+LOCAL_SRC_FILES := \
+ service.cpp
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libcutils \
+ libhidlbase \
+ liblog \
+ libnl \
+ libutils \
+ libwifi-hal \
+ libwifi-system-iface \
+ android.hardware.wifi@1.0 \
+ android.hardware.wifi@1.1 \
+ android.hardware.wifi@1.2 \
+ android.hardware.wifi@1.3 \
+ android.hardware.wifi@1.4
+LOCAL_STATIC_LIBRARIES := \
+ android.hardware.wifi@1.0-service-lib
+LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
+include $(BUILD_EXECUTABLE)
+
+###
+### android.hardware.wifi daemon
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service-lazy
+LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml
+LOCAL_OVERRIDES_MODULES := android.hardware.wifi@1.0-service
+LOCAL_CFLAGS := -DLAZY_SERVICE
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+LOCAL_SRC_FILES := \
+ service.cpp
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libcutils \
+ libhidlbase \
+ liblog \
+ libnl \
+ libutils \
+ libwifi-hal \
+ libwifi-system-iface \
+ android.hardware.wifi@1.0 \
+ android.hardware.wifi@1.1 \
+ android.hardware.wifi@1.2 \
+ android.hardware.wifi@1.3 \
+ android.hardware.wifi@1.4
+LOCAL_STATIC_LIBRARIES := \
+ android.hardware.wifi@1.0-service-lib
+LOCAL_INIT_RC := android.hardware.wifi@1.0-service-lazy.rc
+include $(BUILD_EXECUTABLE)
+
+###
+### android.hardware.wifi unit tests.
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service-tests
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+LOCAL_SRC_FILES := \
+ tests/hidl_struct_util_unit_tests.cpp \
+ tests/main.cpp \
+ tests/mock_interface_tool.cpp \
+ tests/mock_wifi_feature_flags.cpp \
+ tests/mock_wifi_iface_util.cpp \
+ tests/mock_wifi_legacy_hal.cpp \
+ tests/mock_wifi_mode_controller.cpp \
+ tests/ringbuffer_unit_tests.cpp \
+ tests/wifi_nan_iface_unit_tests.cpp \
+ tests/wifi_chip_unit_tests.cpp \
+ tests/wifi_iface_util_unit_tests.cpp
+LOCAL_STATIC_LIBRARIES := \
+ libgmock \
+ libgtest \
+ android.hardware.wifi@1.0-service-lib
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libcutils \
+ libhidlbase \
+ liblog \
+ libnl \
+ libutils \
+ libwifi-hal \
+ libwifi-system-iface \
+ android.hardware.wifi@1.0 \
+ android.hardware.wifi@1.1 \
+ android.hardware.wifi@1.2 \
+ android.hardware.wifi@1.3 \
+ android.hardware.wifi@1.4
+include $(BUILD_NATIVE_TEST)
diff --git a/wifi/1.3/default/OWNERS b/wifi/1.4/default/OWNERS
similarity index 100%
rename from wifi/1.3/default/OWNERS
rename to wifi/1.4/default/OWNERS
diff --git a/wifi/1.3/default/THREADING.README b/wifi/1.4/default/THREADING.README
similarity index 100%
rename from wifi/1.3/default/THREADING.README
rename to wifi/1.4/default/THREADING.README
diff --git a/wifi/1.3/default/android.hardware.wifi@1.0-service-lazy.rc b/wifi/1.4/default/android.hardware.wifi@1.0-service-lazy.rc
similarity index 100%
rename from wifi/1.3/default/android.hardware.wifi@1.0-service-lazy.rc
rename to wifi/1.4/default/android.hardware.wifi@1.0-service-lazy.rc
diff --git a/wifi/1.3/default/android.hardware.wifi@1.0-service.rc b/wifi/1.4/default/android.hardware.wifi@1.0-service.rc
similarity index 100%
rename from wifi/1.3/default/android.hardware.wifi@1.0-service.rc
rename to wifi/1.4/default/android.hardware.wifi@1.0-service.rc
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml b/wifi/1.4/default/android.hardware.wifi@1.0-service.xml
new file mode 100644
index 0000000..b5d25cd
--- /dev/null
+++ b/wifi/1.4/default/android.hardware.wifi@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.wifi</name>
+ <transport>hwbinder</transport>
+ <version>1.4</version>
+ <interface>
+ <name>IWifi</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/wifi/1.4/default/hidl_callback_util.h b/wifi/1.4/default/hidl_callback_util.h
new file mode 100644
index 0000000..fc601b8
--- /dev/null
+++ b/wifi/1.4/default/hidl_callback_util.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_CALLBACK_UTIL_H_
+#define HIDL_CALLBACK_UTIL_H_
+
+#include <set>
+
+#include <hidl/HidlSupport.h>
+
+namespace {
+// Type of callback invoked by the death handler.
+using on_death_cb_function = std::function<void(uint64_t)>;
+
+// Private class used to keep track of death of individual
+// callbacks stored in HidlCallbackHandler.
+template <typename CallbackType>
+class HidlDeathHandler : public android::hardware::hidl_death_recipient {
+ public:
+ HidlDeathHandler(const on_death_cb_function& user_cb_function)
+ : cb_function_(user_cb_function) {}
+ ~HidlDeathHandler() = default;
+
+ // Death notification for callbacks.
+ void serviceDied(
+ uint64_t cookie,
+ const android::wp<android::hidl::base::V1_0::IBase>& /* who */)
+ override {
+ cb_function_(cookie);
+ }
+
+ private:
+ on_death_cb_function cb_function_;
+
+ DISALLOW_COPY_AND_ASSIGN(HidlDeathHandler);
+};
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace hidl_callback_util {
+template <typename CallbackType>
+// Provides a class to manage callbacks for the various HIDL interfaces and
+// handle the death of the process hosting each callback.
+class HidlCallbackHandler {
+ public:
+ HidlCallbackHandler()
+ : death_handler_(new HidlDeathHandler<CallbackType>(
+ std::bind(&HidlCallbackHandler::onObjectDeath, this,
+ std::placeholders::_1))) {}
+ ~HidlCallbackHandler() = default;
+
+ bool addCallback(const sp<CallbackType>& cb) {
+ // TODO(b/33818800): Can't compare proxies yet. So, use the cookie
+ // (callback proxy's raw pointer) to track the death of individual
+ // clients.
+ uint64_t cookie = reinterpret_cast<uint64_t>(cb.get());
+ if (cb_set_.find(cb) != cb_set_.end()) {
+ LOG(WARNING) << "Duplicate death notification registration";
+ return true;
+ }
+ if (!cb->linkToDeath(death_handler_, cookie)) {
+ LOG(ERROR) << "Failed to register death notification";
+ return false;
+ }
+ cb_set_.insert(cb);
+ return true;
+ }
+
+ const std::set<android::sp<CallbackType>>& getCallbacks() {
+ return cb_set_;
+ }
+
+ // Death notification for callbacks.
+ void onObjectDeath(uint64_t cookie) {
+ CallbackType* cb = reinterpret_cast<CallbackType*>(cookie);
+ const auto& iter = cb_set_.find(cb);
+ if (iter == cb_set_.end()) {
+ LOG(ERROR) << "Unknown callback death notification received";
+ return;
+ }
+ cb_set_.erase(iter);
+ LOG(DEBUG) << "Dead callback removed from list";
+ }
+
+ void invalidate() {
+ for (const sp<CallbackType>& cb : cb_set_) {
+ if (!cb->unlinkToDeath(death_handler_)) {
+ LOG(ERROR) << "Failed to deregister death notification";
+ }
+ }
+ cb_set_.clear();
+ }
+
+ private:
+ std::set<sp<CallbackType>> cb_set_;
+ sp<HidlDeathHandler<CallbackType>> death_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(HidlCallbackHandler);
+};
+
+} // namespace hidl_callback_util
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+#endif // HIDL_CALLBACK_UTIL_H_
diff --git a/wifi/1.4/default/hidl_return_util.h b/wifi/1.4/default/hidl_return_util.h
new file mode 100644
index 0000000..99c7092
--- /dev/null
+++ b/wifi/1.4/default/hidl_return_util.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_RETURN_UTIL_H_
+#define HIDL_RETURN_UTIL_H_
+
+#include "hidl_sync_util.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace hidl_return_util {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * These utility functions are used to invoke a method on the provided
+ * HIDL interface object.
+ * These functions checks if the provided HIDL interface object is valid.
+ * a) if valid, Invokes the corresponding internal implementation function of
+ * the HIDL method. It then invokes the HIDL continuation callback with
+ * the status and any returned values.
+ * b) if invalid, invokes the HIDL continuation callback with the
+ * provided error status and default values.
+ */
+// Use for HIDL methods which return only an instance of WifiStatus.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+Return<void> validateAndCall(
+ ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const WifiStatus&)>& hidl_cb, Args&&... args) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (obj->isValid()) {
+ hidl_cb((obj->*work)(std::forward<Args>(args)...));
+ } else {
+ hidl_cb(createWifiStatus(status_code_if_invalid));
+ }
+ return Void();
+}
+
+// Use for HIDL methods which return only an instance of WifiStatus.
+// This version passes the global lock acquired to the body of the method.
+// Note: Only used by IWifi::stop() currently.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+Return<void> validateAndCallWithLock(
+ ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const WifiStatus&)>& hidl_cb, Args&&... args) {
+ auto lock = hidl_sync_util::acquireGlobalLock();
+ if (obj->isValid()) {
+ hidl_cb((obj->*work)(&lock, std::forward<Args>(args)...));
+ } else {
+ hidl_cb(createWifiStatus(status_code_if_invalid));
+ }
+ return Void();
+}
+
+// Use for HIDL methods which return instance of WifiStatus and a single return
+// value.
+template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
+Return<void> validateAndCall(
+ ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const WifiStatus&, ReturnT)>& hidl_cb,
+ Args&&... args) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (obj->isValid()) {
+ const auto& ret_pair = (obj->*work)(std::forward<Args>(args)...);
+ const WifiStatus& status = std::get<0>(ret_pair);
+ const auto& ret_value = std::get<1>(ret_pair);
+ hidl_cb(status, ret_value);
+ } else {
+ hidl_cb(createWifiStatus(status_code_if_invalid),
+ typename std::remove_reference<ReturnT>::type());
+ }
+ return Void();
+}
+
+// Use for HIDL methods which return instance of WifiStatus and 2 return
+// values.
+template <typename ObjT, typename WorkFuncT, typename ReturnT1,
+ typename ReturnT2, typename... Args>
+Return<void> validateAndCall(
+ ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const WifiStatus&, ReturnT1, ReturnT2)>& hidl_cb,
+ Args&&... args) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (obj->isValid()) {
+ const auto& ret_tuple = (obj->*work)(std::forward<Args>(args)...);
+ const WifiStatus& status = std::get<0>(ret_tuple);
+ const auto& ret_value1 = std::get<1>(ret_tuple);
+ const auto& ret_value2 = std::get<2>(ret_tuple);
+ hidl_cb(status, ret_value1, ret_value2);
+ } else {
+ hidl_cb(createWifiStatus(status_code_if_invalid),
+ typename std::remove_reference<ReturnT1>::type(),
+ typename std::remove_reference<ReturnT2>::type());
+ }
+ return Void();
+}
+
+} // namespace hidl_return_util
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+#endif // HIDL_RETURN_UTIL_H_
diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp
new file mode 100644
index 0000000..4996e35
--- /dev/null
+++ b/wifi/1.4/default/hidl_struct_util.cpp
@@ -0,0 +1,2723 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <utils/SystemClock.h>
+
+#include "hidl_struct_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace hidl_struct_util {
+
+WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
+ legacy_hal::wifi_channel_width type);
+
+hidl_string safeConvertChar(const char* str, size_t max_len) {
+ const char* c = str;
+ size_t size = 0;
+ while (*c && (unsigned char)*c < 128 && size < max_len) {
+ ++size;
+ ++c;
+ }
+ return hidl_string(str, size);
+}
+
+IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToHidlChipCapability(
+ uint32_t feature) {
+ using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+ switch (feature) {
+ case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED:
+ return HidlChipCaps::DEBUG_MEMORY_FIRMWARE_DUMP;
+ case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED:
+ return HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP;
+ case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED:
+ return HidlChipCaps::DEBUG_RING_BUFFER_CONNECT_EVENT;
+ case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED:
+ return HidlChipCaps::DEBUG_RING_BUFFER_POWER_EVENT;
+ case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED:
+ return HidlChipCaps::DEBUG_RING_BUFFER_WAKELOCK_EVENT;
+ };
+ CHECK(false) << "Unknown legacy feature: " << feature;
+ return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask
+convertLegacyLoggerFeatureToHidlStaIfaceCapability(uint32_t feature) {
+ using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+ switch (feature) {
+ case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED:
+ return HidlStaIfaceCaps::DEBUG_PACKET_FATE;
+ };
+ CHECK(false) << "Unknown legacy feature: " << feature;
+ return {};
+}
+
+V1_3::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
+ uint32_t feature) {
+ using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
+ switch (feature) {
+ case WIFI_FEATURE_SET_TX_POWER_LIMIT:
+ return HidlChipCaps::SET_TX_POWER_LIMIT;
+ case WIFI_FEATURE_USE_BODY_HEAD_SAR:
+ return HidlChipCaps::USE_BODY_HEAD_SAR;
+ case WIFI_FEATURE_D2D_RTT:
+ return HidlChipCaps::D2D_RTT;
+ case WIFI_FEATURE_D2AP_RTT:
+ return HidlChipCaps::D2AP_RTT;
+ case WIFI_FEATURE_SET_LATENCY_MODE:
+ return HidlChipCaps::SET_LATENCY_MODE;
+ case WIFI_FEATURE_P2P_RAND_MAC:
+ return HidlChipCaps::P2P_RAND_MAC;
+ };
+ CHECK(false) << "Unknown legacy feature: " << feature;
+ return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask
+convertLegacyFeatureToHidlStaIfaceCapability(uint64_t feature) {
+ using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+ switch (feature) {
+ case WIFI_FEATURE_GSCAN:
+ return HidlStaIfaceCaps::BACKGROUND_SCAN;
+ case WIFI_FEATURE_LINK_LAYER_STATS:
+ return HidlStaIfaceCaps::LINK_LAYER_STATS;
+ case WIFI_FEATURE_RSSI_MONITOR:
+ return HidlStaIfaceCaps::RSSI_MONITOR;
+ case WIFI_FEATURE_CONTROL_ROAMING:
+ return HidlStaIfaceCaps::CONTROL_ROAMING;
+ case WIFI_FEATURE_IE_WHITELIST:
+ return HidlStaIfaceCaps::PROBE_IE_WHITELIST;
+ case WIFI_FEATURE_SCAN_RAND:
+ return HidlStaIfaceCaps::SCAN_RAND;
+ case WIFI_FEATURE_INFRA_5G:
+ return HidlStaIfaceCaps::STA_5G;
+ case WIFI_FEATURE_HOTSPOT:
+ return HidlStaIfaceCaps::HOTSPOT;
+ case WIFI_FEATURE_PNO:
+ return HidlStaIfaceCaps::PNO;
+ case WIFI_FEATURE_TDLS:
+ return HidlStaIfaceCaps::TDLS;
+ case WIFI_FEATURE_TDLS_OFFCHANNEL:
+ return HidlStaIfaceCaps::TDLS_OFFCHANNEL;
+ case WIFI_FEATURE_CONFIG_NDO:
+ return HidlStaIfaceCaps::ND_OFFLOAD;
+ case WIFI_FEATURE_MKEEP_ALIVE:
+ return HidlStaIfaceCaps::KEEP_ALIVE;
+ };
+ CHECK(false) << "Unknown legacy feature: " << feature;
+ return {};
+}
+
+bool convertLegacyFeaturesToHidlChipCapabilities(
+ uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+ uint32_t* hidl_caps) {
+ if (!hidl_caps) {
+ return false;
+ }
+ *hidl_caps = {};
+ using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+ for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
+ legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
+ legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED,
+ legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED,
+ legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED}) {
+ if (feature & legacy_logger_feature_set) {
+ *hidl_caps |=
+ convertLegacyLoggerFeatureToHidlChipCapability(feature);
+ }
+ }
+ std::vector<uint32_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT,
+ WIFI_FEATURE_USE_BODY_HEAD_SAR,
+ WIFI_FEATURE_D2D_RTT,
+ WIFI_FEATURE_D2AP_RTT,
+ WIFI_FEATURE_SET_LATENCY_MODE,
+ WIFI_FEATURE_P2P_RAND_MAC};
+ for (const auto feature : features) {
+ if (feature & legacy_feature_set) {
+ *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
+ }
+ }
+
+ // There are no flags for these 3 in the legacy feature set. Adding them to
+ // the set because all the current devices support it.
+ *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA;
+ *hidl_caps |= HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS;
+ *hidl_caps |= HidlChipCaps::DEBUG_ERROR_ALERTS;
+ return true;
+}
+
+WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToHidl(
+ uint32_t flag) {
+ switch (flag) {
+ case WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES:
+ return WifiDebugRingBufferFlags::HAS_BINARY_ENTRIES;
+ case WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES:
+ return WifiDebugRingBufferFlags::HAS_ASCII_ENTRIES;
+ };
+ CHECK(false) << "Unknown legacy flag: " << flag;
+ return {};
+}
+
+bool convertLegacyDebugRingBufferStatusToHidl(
+ const legacy_hal::wifi_ring_buffer_status& legacy_status,
+ WifiDebugRingBufferStatus* hidl_status) {
+ if (!hidl_status) {
+ return false;
+ }
+ *hidl_status = {};
+ hidl_status->ringName =
+ safeConvertChar(reinterpret_cast<const char*>(legacy_status.name),
+ sizeof(legacy_status.name));
+ hidl_status->flags = 0;
+ for (const auto flag : {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES,
+ WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES}) {
+ if (flag & legacy_status.flags) {
+ hidl_status->flags |= static_cast<
+ std::underlying_type<WifiDebugRingBufferFlags>::type>(
+ convertLegacyDebugRingBufferFlagsToHidl(flag));
+ }
+ }
+ hidl_status->ringId = legacy_status.ring_id;
+ hidl_status->sizeInBytes = legacy_status.ring_buffer_byte_size;
+ // Calculate free size of the ring the buffer. We don't need to send the
+ // exact read/write pointers that were there in the legacy HAL interface.
+ if (legacy_status.written_bytes >= legacy_status.read_bytes) {
+ hidl_status->freeSizeInBytes =
+ legacy_status.ring_buffer_byte_size -
+ (legacy_status.written_bytes - legacy_status.read_bytes);
+ } else {
+ hidl_status->freeSizeInBytes =
+ legacy_status.read_bytes - legacy_status.written_bytes;
+ }
+ hidl_status->verboseLevel = legacy_status.verbose_level;
+ return true;
+}
+
+bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
+ const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+ std::vector<WifiDebugRingBufferStatus>* hidl_status_vec) {
+ if (!hidl_status_vec) {
+ return false;
+ }
+ *hidl_status_vec = {};
+ for (const auto& legacy_status : legacy_status_vec) {
+ WifiDebugRingBufferStatus hidl_status;
+ if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status,
+ &hidl_status)) {
+ return false;
+ }
+ hidl_status_vec->push_back(hidl_status);
+ }
+ return true;
+}
+
+bool convertLegacyWakeReasonStatsToHidl(
+ const legacy_hal::WakeReasonStats& legacy_stats,
+ WifiDebugHostWakeReasonStats* hidl_stats) {
+ if (!hidl_stats) {
+ return false;
+ }
+ *hidl_stats = {};
+ hidl_stats->totalCmdEventWakeCnt =
+ legacy_stats.wake_reason_cnt.total_cmd_event_wake;
+ hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
+ hidl_stats->totalDriverFwLocalWakeCnt =
+ legacy_stats.wake_reason_cnt.total_driver_fw_local_wake;
+ hidl_stats->driverFwLocalWakeCntPerType =
+ legacy_stats.driver_fw_local_wake_cnt;
+ hidl_stats->totalRxPacketWakeCnt =
+ legacy_stats.wake_reason_cnt.total_rx_data_wake;
+ hidl_stats->rxPktWakeDetails.rxUnicastCnt =
+ legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt;
+ hidl_stats->rxPktWakeDetails.rxMulticastCnt =
+ legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt;
+ hidl_stats->rxPktWakeDetails.rxBroadcastCnt =
+ legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt;
+ hidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt =
+ legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
+ .ipv4_rx_multicast_addr_cnt;
+ hidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt =
+ legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
+ .ipv6_rx_multicast_addr_cnt;
+ hidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt =
+ legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
+ .other_rx_multicast_addr_cnt;
+ hidl_stats->rxIcmpPkWakeDetails.icmpPkt =
+ legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt;
+ hidl_stats->rxIcmpPkWakeDetails.icmp6Pkt =
+ legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt;
+ hidl_stats->rxIcmpPkWakeDetails.icmp6Ra =
+ legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra;
+ hidl_stats->rxIcmpPkWakeDetails.icmp6Na =
+ legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na;
+ hidl_stats->rxIcmpPkWakeDetails.icmp6Ns =
+ legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns;
+ return true;
+}
+
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
+ V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
+ switch (hidl_scenario) {
+ // This is the only supported scenario for V1_1
+ case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
+ return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+ };
+ CHECK(false);
+}
+
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+ V1_2::IWifiChip::TxPowerScenario hidl_scenario) {
+ switch (hidl_scenario) {
+ // This is the only supported scenario for V1_1
+ case V1_2::IWifiChip::TxPowerScenario::VOICE_CALL:
+ return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+ // Those are the supported scenarios for V1_2
+ case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
+ return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
+ case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
+ return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
+ case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
+ return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
+ case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
+ return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
+ };
+ CHECK(false);
+}
+
+legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
+ V1_3::IWifiChip::LatencyMode hidl_latency_mode) {
+ switch (hidl_latency_mode) {
+ case V1_3::IWifiChip::LatencyMode::NORMAL:
+ return legacy_hal::WIFI_LATENCY_MODE_NORMAL;
+ case V1_3::IWifiChip::LatencyMode::LOW:
+ return legacy_hal::WIFI_LATENCY_MODE_LOW;
+ }
+ CHECK(false);
+}
+
+bool convertLegacyWifiMacInfoToHidl(
+ const legacy_hal::WifiMacInfo& legacy_mac_info,
+ IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
+ if (!hidl_radio_mode_info) {
+ return false;
+ }
+ *hidl_radio_mode_info = {};
+
+ hidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id;
+ // Convert from bitmask of bands in the legacy HAL to enum value in
+ // the HIDL interface.
+ if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
+ legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND &&
+ legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
+ hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ_6GHZ;
+ } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
+ legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+ hidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ_6GHZ;
+ } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND) {
+ hidl_radio_mode_info->bandInfo = WifiBand::BAND_6GHZ;
+ } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
+ legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+ hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ;
+ } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
+ hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ;
+ } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+ hidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ;
+ } else {
+ hidl_radio_mode_info->bandInfo = WifiBand::BAND_UNSPECIFIED;
+ }
+ std::vector<V1_2::IWifiChipEventCallback::IfaceInfo> iface_info_vec;
+ for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
+ V1_2::IWifiChipEventCallback::IfaceInfo iface_info;
+ iface_info.name = legacy_iface_info.name;
+ iface_info.channel = legacy_iface_info.channel;
+ iface_info_vec.push_back(iface_info);
+ }
+ hidl_radio_mode_info->ifaceInfos = iface_info_vec;
+ return true;
+}
+
+bool convertLegacyWifiMacInfosToHidl(
+ const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+ std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos) {
+ if (!hidl_radio_mode_infos) {
+ return false;
+ }
+ *hidl_radio_mode_infos = {};
+
+ for (const auto& legacy_mac_info : legacy_mac_infos) {
+ IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
+ if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info,
+ &hidl_radio_mode_info)) {
+ return false;
+ }
+ hidl_radio_mode_infos->push_back(hidl_radio_mode_info);
+ }
+ return true;
+}
+
+bool convertLegacyFeaturesToHidlStaCapabilities(
+ uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+ uint32_t* hidl_caps) {
+ if (!hidl_caps) {
+ return false;
+ }
+ *hidl_caps = {};
+ using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+ for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
+ if (feature & legacy_logger_feature_set) {
+ *hidl_caps |=
+ convertLegacyLoggerFeatureToHidlStaIfaceCapability(feature);
+ }
+ }
+ for (const auto feature :
+ {WIFI_FEATURE_GSCAN, WIFI_FEATURE_LINK_LAYER_STATS,
+ WIFI_FEATURE_RSSI_MONITOR, WIFI_FEATURE_CONTROL_ROAMING,
+ 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}) {
+ if (feature & legacy_feature_set) {
+ *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
+ }
+ }
+ // There is no flag for this one in the legacy feature set. Adding it to the
+ // set because all the current devices support it.
+ *hidl_caps |= HidlStaIfaceCaps::APF;
+ return true;
+}
+
+bool convertLegacyApfCapabilitiesToHidl(
+ const legacy_hal::PacketFilterCapabilities& legacy_caps,
+ StaApfPacketFilterCapabilities* hidl_caps) {
+ if (!hidl_caps) {
+ return false;
+ }
+ *hidl_caps = {};
+ hidl_caps->version = legacy_caps.version;
+ hidl_caps->maxLength = legacy_caps.max_len;
+ return true;
+}
+
+uint8_t convertHidlGscanReportEventFlagToLegacy(
+ StaBackgroundScanBucketEventReportSchemeMask hidl_flag) {
+ using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
+ switch (hidl_flag) {
+ case HidlFlag::EACH_SCAN:
+ return REPORT_EVENTS_EACH_SCAN;
+ case HidlFlag::FULL_RESULTS:
+ return REPORT_EVENTS_FULL_RESULTS;
+ case HidlFlag::NO_BATCH:
+ return REPORT_EVENTS_NO_BATCH;
+ };
+ CHECK(false);
+}
+
+StaScanDataFlagMask convertLegacyGscanDataFlagToHidl(uint8_t legacy_flag) {
+ switch (legacy_flag) {
+ case legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED:
+ return StaScanDataFlagMask::INTERRUPTED;
+ };
+ CHECK(false) << "Unknown legacy flag: " << legacy_flag;
+ // To silence the compiler warning about reaching the end of non-void
+ // function.
+ return {};
+}
+
+bool convertLegacyGscanCapabilitiesToHidl(
+ const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+ StaBackgroundScanCapabilities* hidl_caps) {
+ if (!hidl_caps) {
+ return false;
+ }
+ *hidl_caps = {};
+ hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
+ hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
+ hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
+ hidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold;
+ return true;
+}
+
+legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band) {
+ switch (band) {
+ case V1_0::WifiBand::BAND_UNSPECIFIED:
+ return legacy_hal::WIFI_BAND_UNSPECIFIED;
+ case V1_0::WifiBand::BAND_24GHZ:
+ return legacy_hal::WIFI_BAND_BG;
+ case V1_0::WifiBand::BAND_5GHZ:
+ return legacy_hal::WIFI_BAND_A;
+ case V1_0::WifiBand::BAND_5GHZ_DFS:
+ return legacy_hal::WIFI_BAND_A_DFS;
+ case V1_0::WifiBand::BAND_5GHZ_WITH_DFS:
+ return legacy_hal::WIFI_BAND_A_WITH_DFS;
+ case V1_0::WifiBand::BAND_24GHZ_5GHZ:
+ return legacy_hal::WIFI_BAND_ABG;
+ case V1_0::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
+ return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
+ };
+ CHECK(false);
+}
+
+bool convertHidlGscanParamsToLegacy(
+ const StaBackgroundScanParameters& hidl_scan_params,
+ legacy_hal::wifi_scan_cmd_params* legacy_scan_params) {
+ if (!legacy_scan_params) {
+ return false;
+ }
+ *legacy_scan_params = {};
+ legacy_scan_params->base_period = hidl_scan_params.basePeriodInMs;
+ legacy_scan_params->max_ap_per_scan = hidl_scan_params.maxApPerScan;
+ legacy_scan_params->report_threshold_percent =
+ hidl_scan_params.reportThresholdPercent;
+ legacy_scan_params->report_threshold_num_scans =
+ hidl_scan_params.reportThresholdNumScans;
+ if (hidl_scan_params.buckets.size() > MAX_BUCKETS) {
+ return false;
+ }
+ legacy_scan_params->num_buckets = hidl_scan_params.buckets.size();
+ for (uint32_t bucket_idx = 0; bucket_idx < hidl_scan_params.buckets.size();
+ bucket_idx++) {
+ const StaBackgroundScanBucketParameters& hidl_bucket_spec =
+ hidl_scan_params.buckets[bucket_idx];
+ legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
+ legacy_scan_params->buckets[bucket_idx];
+ if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
+ return false;
+ }
+ legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
+ legacy_bucket_spec.band =
+ convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
+ legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
+ legacy_bucket_spec.max_period =
+ hidl_bucket_spec.exponentialMaxPeriodInMs;
+ legacy_bucket_spec.base = hidl_bucket_spec.exponentialBase;
+ legacy_bucket_spec.step_count = hidl_bucket_spec.exponentialStepCount;
+ legacy_bucket_spec.report_events = 0;
+ using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
+ for (const auto flag : {HidlFlag::EACH_SCAN, HidlFlag::FULL_RESULTS,
+ HidlFlag::NO_BATCH}) {
+ if (hidl_bucket_spec.eventReportScheme &
+ static_cast<std::underlying_type<HidlFlag>::type>(flag)) {
+ legacy_bucket_spec.report_events |=
+ convertHidlGscanReportEventFlagToLegacy(flag);
+ }
+ }
+ if (hidl_bucket_spec.frequencies.size() > MAX_CHANNELS) {
+ return false;
+ }
+ legacy_bucket_spec.num_channels = hidl_bucket_spec.frequencies.size();
+ for (uint32_t freq_idx = 0;
+ freq_idx < hidl_bucket_spec.frequencies.size(); freq_idx++) {
+ legacy_bucket_spec.channels[freq_idx].channel =
+ hidl_bucket_spec.frequencies[freq_idx];
+ }
+ }
+ return true;
+}
+
+bool convertLegacyIeToHidl(
+ const legacy_hal::wifi_information_element& legacy_ie,
+ WifiInformationElement* hidl_ie) {
+ if (!hidl_ie) {
+ return false;
+ }
+ *hidl_ie = {};
+ hidl_ie->id = legacy_ie.id;
+ hidl_ie->data =
+ std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
+ return true;
+}
+
+bool convertLegacyIeBlobToHidl(const uint8_t* ie_blob, uint32_t ie_blob_len,
+ std::vector<WifiInformationElement>* hidl_ies) {
+ if (!ie_blob || !hidl_ies) {
+ return false;
+ }
+ *hidl_ies = {};
+ const uint8_t* ies_begin = ie_blob;
+ const uint8_t* ies_end = ie_blob + ie_blob_len;
+ const uint8_t* next_ie = ies_begin;
+ using wifi_ie = legacy_hal::wifi_information_element;
+ constexpr size_t kIeHeaderLen = sizeof(wifi_ie);
+ // Each IE should atleast have the header (i.e |id| & |len| fields).
+ while (next_ie + kIeHeaderLen <= ies_end) {
+ const wifi_ie& legacy_ie = (*reinterpret_cast<const wifi_ie*>(next_ie));
+ uint32_t curr_ie_len = kIeHeaderLen + legacy_ie.len;
+ if (next_ie + curr_ie_len > ies_end) {
+ LOG(ERROR) << "Error parsing IE blob. Next IE: " << (void*)next_ie
+ << ", Curr IE len: " << curr_ie_len
+ << ", IEs End: " << (void*)ies_end;
+ break;
+ }
+ WifiInformationElement hidl_ie;
+ if (!convertLegacyIeToHidl(legacy_ie, &hidl_ie)) {
+ LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id
+ << ", len: " << legacy_ie.len;
+ break;
+ }
+ hidl_ies->push_back(std::move(hidl_ie));
+ next_ie += curr_ie_len;
+ }
+ // Check if the blob has been fully consumed.
+ if (next_ie != ies_end) {
+ LOG(ERROR) << "Failed to fully parse IE blob. Next IE: "
+ << (void*)next_ie << ", IEs End: " << (void*)ies_end;
+ }
+ return true;
+}
+
+bool convertLegacyGscanResultToHidl(
+ const legacy_hal::wifi_scan_result& legacy_scan_result, bool has_ie_data,
+ StaScanResult* hidl_scan_result) {
+ if (!hidl_scan_result) {
+ return false;
+ }
+ *hidl_scan_result = {};
+ hidl_scan_result->timeStampInUs = legacy_scan_result.ts;
+ hidl_scan_result->ssid = std::vector<uint8_t>(
+ legacy_scan_result.ssid,
+ legacy_scan_result.ssid + strnlen(legacy_scan_result.ssid,
+ sizeof(legacy_scan_result.ssid) - 1));
+ memcpy(hidl_scan_result->bssid.data(), legacy_scan_result.bssid,
+ hidl_scan_result->bssid.size());
+ hidl_scan_result->frequency = legacy_scan_result.channel;
+ hidl_scan_result->rssi = legacy_scan_result.rssi;
+ hidl_scan_result->beaconPeriodInMs = legacy_scan_result.beacon_period;
+ hidl_scan_result->capability = legacy_scan_result.capability;
+ if (has_ie_data) {
+ std::vector<WifiInformationElement> ies;
+ if (!convertLegacyIeBlobToHidl(
+ reinterpret_cast<const uint8_t*>(legacy_scan_result.ie_data),
+ legacy_scan_result.ie_length, &ies)) {
+ return false;
+ }
+ hidl_scan_result->informationElements = std::move(ies);
+ }
+ return true;
+}
+
+bool convertLegacyCachedGscanResultsToHidl(
+ const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result,
+ StaScanData* hidl_scan_data) {
+ if (!hidl_scan_data) {
+ return false;
+ }
+ *hidl_scan_data = {};
+ hidl_scan_data->flags = 0;
+ for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
+ if (legacy_cached_scan_result.flags & flag) {
+ hidl_scan_data->flags |=
+ static_cast<std::underlying_type<StaScanDataFlagMask>::type>(
+ convertLegacyGscanDataFlagToHidl(flag));
+ }
+ }
+ hidl_scan_data->bucketsScanned = legacy_cached_scan_result.buckets_scanned;
+
+ CHECK(legacy_cached_scan_result.num_results >= 0 &&
+ legacy_cached_scan_result.num_results <= MAX_AP_CACHE_PER_SCAN);
+ std::vector<StaScanResult> hidl_scan_results;
+ for (int32_t result_idx = 0;
+ result_idx < legacy_cached_scan_result.num_results; result_idx++) {
+ StaScanResult hidl_scan_result;
+ if (!convertLegacyGscanResultToHidl(
+ legacy_cached_scan_result.results[result_idx], false,
+ &hidl_scan_result)) {
+ return false;
+ }
+ hidl_scan_results.push_back(hidl_scan_result);
+ }
+ hidl_scan_data->results = std::move(hidl_scan_results);
+ return true;
+}
+
+bool convertLegacyVectorOfCachedGscanResultsToHidl(
+ const std::vector<legacy_hal::wifi_cached_scan_results>&
+ legacy_cached_scan_results,
+ std::vector<StaScanData>* hidl_scan_datas) {
+ if (!hidl_scan_datas) {
+ return false;
+ }
+ *hidl_scan_datas = {};
+ for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
+ StaScanData hidl_scan_data;
+ if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result,
+ &hidl_scan_data)) {
+ return false;
+ }
+ hidl_scan_datas->push_back(hidl_scan_data);
+ }
+ return true;
+}
+
+WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToHidl(
+ legacy_hal::wifi_tx_packet_fate fate) {
+ switch (fate) {
+ case legacy_hal::TX_PKT_FATE_ACKED:
+ return WifiDebugTxPacketFate::ACKED;
+ case legacy_hal::TX_PKT_FATE_SENT:
+ return WifiDebugTxPacketFate::SENT;
+ case legacy_hal::TX_PKT_FATE_FW_QUEUED:
+ return WifiDebugTxPacketFate::FW_QUEUED;
+ case legacy_hal::TX_PKT_FATE_FW_DROP_INVALID:
+ return WifiDebugTxPacketFate::FW_DROP_INVALID;
+ case legacy_hal::TX_PKT_FATE_FW_DROP_NOBUFS:
+ return WifiDebugTxPacketFate::FW_DROP_NOBUFS;
+ case legacy_hal::TX_PKT_FATE_FW_DROP_OTHER:
+ return WifiDebugTxPacketFate::FW_DROP_OTHER;
+ case legacy_hal::TX_PKT_FATE_DRV_QUEUED:
+ return WifiDebugTxPacketFate::DRV_QUEUED;
+ case legacy_hal::TX_PKT_FATE_DRV_DROP_INVALID:
+ return WifiDebugTxPacketFate::DRV_DROP_INVALID;
+ case legacy_hal::TX_PKT_FATE_DRV_DROP_NOBUFS:
+ return WifiDebugTxPacketFate::DRV_DROP_NOBUFS;
+ case legacy_hal::TX_PKT_FATE_DRV_DROP_OTHER:
+ return WifiDebugTxPacketFate::DRV_DROP_OTHER;
+ };
+ CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugRxPacketFate convertLegacyDebugRxPacketFateToHidl(
+ legacy_hal::wifi_rx_packet_fate fate) {
+ switch (fate) {
+ case legacy_hal::RX_PKT_FATE_SUCCESS:
+ return WifiDebugRxPacketFate::SUCCESS;
+ case legacy_hal::RX_PKT_FATE_FW_QUEUED:
+ return WifiDebugRxPacketFate::FW_QUEUED;
+ case legacy_hal::RX_PKT_FATE_FW_DROP_FILTER:
+ return WifiDebugRxPacketFate::FW_DROP_FILTER;
+ case legacy_hal::RX_PKT_FATE_FW_DROP_INVALID:
+ return WifiDebugRxPacketFate::FW_DROP_INVALID;
+ case legacy_hal::RX_PKT_FATE_FW_DROP_NOBUFS:
+ return WifiDebugRxPacketFate::FW_DROP_NOBUFS;
+ case legacy_hal::RX_PKT_FATE_FW_DROP_OTHER:
+ return WifiDebugRxPacketFate::FW_DROP_OTHER;
+ case legacy_hal::RX_PKT_FATE_DRV_QUEUED:
+ return WifiDebugRxPacketFate::DRV_QUEUED;
+ case legacy_hal::RX_PKT_FATE_DRV_DROP_FILTER:
+ return WifiDebugRxPacketFate::DRV_DROP_FILTER;
+ case legacy_hal::RX_PKT_FATE_DRV_DROP_INVALID:
+ return WifiDebugRxPacketFate::DRV_DROP_INVALID;
+ case legacy_hal::RX_PKT_FATE_DRV_DROP_NOBUFS:
+ return WifiDebugRxPacketFate::DRV_DROP_NOBUFS;
+ case legacy_hal::RX_PKT_FATE_DRV_DROP_OTHER:
+ return WifiDebugRxPacketFate::DRV_DROP_OTHER;
+ };
+ CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugPacketFateFrameType convertLegacyDebugPacketFateFrameTypeToHidl(
+ legacy_hal::frame_type type) {
+ switch (type) {
+ case legacy_hal::FRAME_TYPE_UNKNOWN:
+ return WifiDebugPacketFateFrameType::UNKNOWN;
+ case legacy_hal::FRAME_TYPE_ETHERNET_II:
+ return WifiDebugPacketFateFrameType::ETHERNET_II;
+ case legacy_hal::FRAME_TYPE_80211_MGMT:
+ return WifiDebugPacketFateFrameType::MGMT_80211;
+ };
+ CHECK(false) << "Unknown legacy frame type: " << type;
+}
+
+bool convertLegacyDebugPacketFateFrameToHidl(
+ const legacy_hal::frame_info& legacy_frame,
+ WifiDebugPacketFateFrameInfo* hidl_frame) {
+ if (!hidl_frame) {
+ return false;
+ }
+ *hidl_frame = {};
+ hidl_frame->frameType =
+ convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
+ hidl_frame->frameLen = legacy_frame.frame_len;
+ hidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec;
+ hidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec;
+ const uint8_t* frame_begin = reinterpret_cast<const uint8_t*>(
+ legacy_frame.frame_content.ethernet_ii_bytes);
+ hidl_frame->frameContent =
+ std::vector<uint8_t>(frame_begin, frame_begin + legacy_frame.frame_len);
+ return true;
+}
+
+bool convertLegacyDebugTxPacketFateToHidl(
+ const legacy_hal::wifi_tx_report& legacy_fate,
+ WifiDebugTxPacketFateReport* hidl_fate) {
+ if (!hidl_fate) {
+ return false;
+ }
+ *hidl_fate = {};
+ hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
+ return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
+ &hidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugTxPacketFateToHidl(
+ const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+ std::vector<WifiDebugTxPacketFateReport>* hidl_fates) {
+ if (!hidl_fates) {
+ return false;
+ }
+ *hidl_fates = {};
+ for (const auto& legacy_fate : legacy_fates) {
+ WifiDebugTxPacketFateReport hidl_fate;
+ if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
+ return false;
+ }
+ hidl_fates->push_back(hidl_fate);
+ }
+ return true;
+}
+
+bool convertLegacyDebugRxPacketFateToHidl(
+ const legacy_hal::wifi_rx_report& legacy_fate,
+ WifiDebugRxPacketFateReport* hidl_fate) {
+ if (!hidl_fate) {
+ return false;
+ }
+ *hidl_fate = {};
+ hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
+ return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
+ &hidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugRxPacketFateToHidl(
+ const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+ std::vector<WifiDebugRxPacketFateReport>* hidl_fates) {
+ if (!hidl_fates) {
+ return false;
+ }
+ *hidl_fates = {};
+ for (const auto& legacy_fate : legacy_fates) {
+ WifiDebugRxPacketFateReport hidl_fate;
+ if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
+ return false;
+ }
+ hidl_fates->push_back(hidl_fate);
+ }
+ return true;
+}
+
+bool convertLegacyLinkLayerRadioStatsToHidl(
+ const legacy_hal::LinkLayerRadioStats& legacy_radio_stat,
+ V1_3::StaLinkLayerRadioStats* hidl_radio_stat) {
+ if (!hidl_radio_stat) {
+ return false;
+ }
+ *hidl_radio_stat = {};
+
+ hidl_radio_stat->V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
+ hidl_radio_stat->V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
+ hidl_radio_stat->V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
+ hidl_radio_stat->V1_0.onTimeInMsForScan =
+ legacy_radio_stat.stats.on_time_scan;
+ hidl_radio_stat->V1_0.txTimeInMsPerLevel =
+ legacy_radio_stat.tx_time_per_levels;
+ hidl_radio_stat->onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd;
+ hidl_radio_stat->onTimeInMsForBgScan =
+ legacy_radio_stat.stats.on_time_gscan;
+ hidl_radio_stat->onTimeInMsForRoamScan =
+ legacy_radio_stat.stats.on_time_roam_scan;
+ hidl_radio_stat->onTimeInMsForPnoScan =
+ legacy_radio_stat.stats.on_time_pno_scan;
+ hidl_radio_stat->onTimeInMsForHs20Scan =
+ legacy_radio_stat.stats.on_time_hs20;
+
+ std::vector<V1_3::WifiChannelStats> hidl_channel_stats;
+
+ for (const auto& channel_stat : legacy_radio_stat.channel_stats) {
+ V1_3::WifiChannelStats hidl_channel_stat;
+ hidl_channel_stat.onTimeInMs = channel_stat.on_time;
+ hidl_channel_stat.ccaBusyTimeInMs = channel_stat.cca_busy_time;
+ /*
+ * TODO once b/119142899 is fixed,
+ * replace below code with convertLegacyWifiChannelInfoToHidl()
+ */
+ hidl_channel_stat.channel.width = WifiChannelWidthInMhz::WIDTH_20;
+ hidl_channel_stat.channel.centerFreq = channel_stat.channel.center_freq;
+ hidl_channel_stat.channel.centerFreq0 =
+ channel_stat.channel.center_freq0;
+ hidl_channel_stat.channel.centerFreq1 =
+ channel_stat.channel.center_freq1;
+ hidl_channel_stats.push_back(hidl_channel_stat);
+ }
+
+ hidl_radio_stat->channelStats = hidl_channel_stats;
+
+ return true;
+}
+
+bool convertLegacyLinkLayerStatsToHidl(
+ const legacy_hal::LinkLayerStats& legacy_stats,
+ V1_3::StaLinkLayerStats* hidl_stats) {
+ if (!hidl_stats) {
+ return false;
+ }
+ *hidl_stats = {};
+ // iface legacy_stats conversion.
+ hidl_stats->iface.beaconRx = legacy_stats.iface.beacon_rx;
+ hidl_stats->iface.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
+ hidl_stats->iface.wmeBePktStats.rxMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
+ hidl_stats->iface.wmeBePktStats.txMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
+ hidl_stats->iface.wmeBePktStats.lostMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
+ hidl_stats->iface.wmeBePktStats.retries =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
+ hidl_stats->iface.wmeBkPktStats.rxMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
+ hidl_stats->iface.wmeBkPktStats.txMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
+ hidl_stats->iface.wmeBkPktStats.lostMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
+ hidl_stats->iface.wmeBkPktStats.retries =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
+ hidl_stats->iface.wmeViPktStats.rxMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
+ hidl_stats->iface.wmeViPktStats.txMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
+ hidl_stats->iface.wmeViPktStats.lostMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
+ hidl_stats->iface.wmeViPktStats.retries =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
+ hidl_stats->iface.wmeVoPktStats.rxMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
+ hidl_stats->iface.wmeVoPktStats.txMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
+ hidl_stats->iface.wmeVoPktStats.lostMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
+ hidl_stats->iface.wmeVoPktStats.retries =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
+ // radio legacy_stats conversion.
+ std::vector<V1_3::StaLinkLayerRadioStats> hidl_radios_stats;
+ for (const auto& legacy_radio_stats : legacy_stats.radios) {
+ V1_3::StaLinkLayerRadioStats hidl_radio_stats;
+ if (!convertLegacyLinkLayerRadioStatsToHidl(legacy_radio_stats,
+ &hidl_radio_stats)) {
+ return false;
+ }
+ hidl_radios_stats.push_back(hidl_radio_stats);
+ }
+ hidl_stats->radios = hidl_radios_stats;
+ // Timestamp in the HAL wrapper here since it's not provided in the legacy
+ // HAL API.
+ hidl_stats->timeStampInMs = uptimeMillis();
+ return true;
+}
+
+bool convertLegacyRoamingCapabilitiesToHidl(
+ const legacy_hal::wifi_roaming_capabilities& legacy_caps,
+ StaRoamingCapabilities* hidl_caps) {
+ if (!hidl_caps) {
+ return false;
+ }
+ *hidl_caps = {};
+ hidl_caps->maxBlacklistSize = legacy_caps.max_blacklist_size;
+ hidl_caps->maxWhitelistSize = legacy_caps.max_whitelist_size;
+ return true;
+}
+
+bool convertHidlRoamingConfigToLegacy(
+ const StaRoamingConfig& hidl_config,
+ legacy_hal::wifi_roaming_config* legacy_config) {
+ if (!legacy_config) {
+ return false;
+ }
+ *legacy_config = {};
+ if (hidl_config.bssidBlacklist.size() > MAX_BLACKLIST_BSSID ||
+ hidl_config.ssidWhitelist.size() > MAX_WHITELIST_SSID) {
+ return false;
+ }
+ legacy_config->num_blacklist_bssid = hidl_config.bssidBlacklist.size();
+ uint32_t i = 0;
+ for (const auto& bssid : hidl_config.bssidBlacklist) {
+ CHECK(bssid.size() == sizeof(legacy_hal::mac_addr));
+ memcpy(legacy_config->blacklist_bssid[i++], bssid.data(), bssid.size());
+ }
+ legacy_config->num_whitelist_ssid = hidl_config.ssidWhitelist.size();
+ i = 0;
+ for (const auto& ssid : hidl_config.ssidWhitelist) {
+ CHECK(ssid.size() <= sizeof(legacy_hal::ssid_t::ssid_str));
+ legacy_config->whitelist_ssid[i].length = ssid.size();
+ memcpy(legacy_config->whitelist_ssid[i].ssid_str, ssid.data(),
+ ssid.size());
+ i++;
+ }
+ return true;
+}
+
+legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
+ StaRoamingState state) {
+ switch (state) {
+ case StaRoamingState::ENABLED:
+ return legacy_hal::ROAMING_ENABLE;
+ case StaRoamingState::DISABLED:
+ return legacy_hal::ROAMING_DISABLE;
+ };
+ CHECK(false);
+}
+
+legacy_hal::NanMatchAlg convertHidlNanMatchAlgToLegacy(NanMatchAlg type) {
+ switch (type) {
+ case NanMatchAlg::MATCH_ONCE:
+ return legacy_hal::NAN_MATCH_ALG_MATCH_ONCE;
+ case NanMatchAlg::MATCH_CONTINUOUS:
+ return legacy_hal::NAN_MATCH_ALG_MATCH_CONTINUOUS;
+ case NanMatchAlg::MATCH_NEVER:
+ return legacy_hal::NAN_MATCH_ALG_MATCH_NEVER;
+ }
+ CHECK(false);
+}
+
+legacy_hal::NanPublishType convertHidlNanPublishTypeToLegacy(
+ NanPublishType type) {
+ switch (type) {
+ case NanPublishType::UNSOLICITED:
+ return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED;
+ case NanPublishType::SOLICITED:
+ return legacy_hal::NAN_PUBLISH_TYPE_SOLICITED;
+ case NanPublishType::UNSOLICITED_SOLICITED:
+ return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
+ }
+ CHECK(false);
+}
+
+legacy_hal::NanTxType convertHidlNanTxTypeToLegacy(NanTxType type) {
+ switch (type) {
+ case NanTxType::BROADCAST:
+ return legacy_hal::NAN_TX_TYPE_BROADCAST;
+ case NanTxType::UNICAST:
+ return legacy_hal::NAN_TX_TYPE_UNICAST;
+ }
+ CHECK(false);
+}
+
+legacy_hal::NanSubscribeType convertHidlNanSubscribeTypeToLegacy(
+ NanSubscribeType type) {
+ switch (type) {
+ case NanSubscribeType::PASSIVE:
+ return legacy_hal::NAN_SUBSCRIBE_TYPE_PASSIVE;
+ case NanSubscribeType::ACTIVE:
+ return legacy_hal::NAN_SUBSCRIBE_TYPE_ACTIVE;
+ }
+ CHECK(false);
+}
+
+legacy_hal::NanSRFType convertHidlNanSrfTypeToLegacy(NanSrfType type) {
+ switch (type) {
+ case NanSrfType::BLOOM_FILTER:
+ return legacy_hal::NAN_SRF_ATTR_BLOOM_FILTER;
+ case NanSrfType::PARTIAL_MAC_ADDR:
+ return legacy_hal::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
+ }
+ CHECK(false);
+}
+
+legacy_hal::NanDataPathChannelCfg convertHidlNanDataPathChannelCfgToLegacy(
+ NanDataPathChannelCfg type) {
+ switch (type) {
+ case NanDataPathChannelCfg::CHANNEL_NOT_REQUESTED:
+ return legacy_hal::NAN_DP_CHANNEL_NOT_REQUESTED;
+ case NanDataPathChannelCfg::REQUEST_CHANNEL_SETUP:
+ return legacy_hal::NAN_DP_REQUEST_CHANNEL_SETUP;
+ case NanDataPathChannelCfg::FORCE_CHANNEL_SETUP:
+ return legacy_hal::NAN_DP_FORCE_CHANNEL_SETUP;
+ }
+ CHECK(false);
+}
+
+NanStatusType convertLegacyNanStatusTypeToHidl(legacy_hal::NanStatusType type) {
+ switch (type) {
+ case legacy_hal::NAN_STATUS_SUCCESS:
+ return NanStatusType::SUCCESS;
+ case legacy_hal::NAN_STATUS_INTERNAL_FAILURE:
+ return NanStatusType::INTERNAL_FAILURE;
+ case legacy_hal::NAN_STATUS_PROTOCOL_FAILURE:
+ return NanStatusType::PROTOCOL_FAILURE;
+ case legacy_hal::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
+ return NanStatusType::INVALID_SESSION_ID;
+ case legacy_hal::NAN_STATUS_NO_RESOURCE_AVAILABLE:
+ return NanStatusType::NO_RESOURCES_AVAILABLE;
+ case legacy_hal::NAN_STATUS_INVALID_PARAM:
+ return NanStatusType::INVALID_ARGS;
+ case legacy_hal::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
+ return NanStatusType::INVALID_PEER_ID;
+ case legacy_hal::NAN_STATUS_INVALID_NDP_ID:
+ return NanStatusType::INVALID_NDP_ID;
+ case legacy_hal::NAN_STATUS_NAN_NOT_ALLOWED:
+ return NanStatusType::NAN_NOT_ALLOWED;
+ case legacy_hal::NAN_STATUS_NO_OTA_ACK:
+ return NanStatusType::NO_OTA_ACK;
+ case legacy_hal::NAN_STATUS_ALREADY_ENABLED:
+ return NanStatusType::ALREADY_ENABLED;
+ case legacy_hal::NAN_STATUS_FOLLOWUP_QUEUE_FULL:
+ return NanStatusType::FOLLOWUP_TX_QUEUE_FULL;
+ case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
+ return NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
+ }
+ CHECK(false);
+}
+
+void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
+ size_t max_len, WifiNanStatus* wifiNanStatus) {
+ wifiNanStatus->status = convertLegacyNanStatusTypeToHidl(type);
+ wifiNanStatus->description = safeConvertChar(str, max_len);
+}
+
+bool convertHidlNanEnableRequestToLegacy(
+ const NanEnableRequest& hidl_request,
+ legacy_hal::NanEnableRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR)
+ << "convertHidlNanEnableRequestToLegacy: null legacy_request";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->config_2dot4g_support = 1;
+ legacy_request->support_2dot4g_val =
+ hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+ legacy_request->config_support_5g = 1;
+ legacy_request->support_5g_val =
+ hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+ legacy_request->config_hop_count_limit = 1;
+ legacy_request->hop_count_limit_val = hidl_request.hopCountMax;
+ legacy_request->master_pref = hidl_request.configParams.masterPref;
+ legacy_request->discovery_indication_cfg = 0;
+ legacy_request->discovery_indication_cfg |=
+ hidl_request.configParams.disableDiscoveryAddressChangeIndication ? 0x1
+ : 0x0;
+ legacy_request->discovery_indication_cfg |=
+ hidl_request.configParams.disableStartedClusterIndication ? 0x2 : 0x0;
+ legacy_request->discovery_indication_cfg |=
+ hidl_request.configParams.disableJoinedClusterIndication ? 0x4 : 0x0;
+ legacy_request->config_sid_beacon = 1;
+ if (hidl_request.configParams.numberOfPublishServiceIdsInBeacon > 127) {
+ LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+ "numberOfPublishServiceIdsInBeacon > 127";
+ return false;
+ }
+ legacy_request->sid_beacon_val =
+ (hidl_request.configParams.includePublishServiceIdsInBeacon ? 0x1
+ : 0x0) |
+ (hidl_request.configParams.numberOfPublishServiceIdsInBeacon << 1);
+ legacy_request->config_subscribe_sid_beacon = 1;
+ if (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon > 127) {
+ LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+ "numberOfSubscribeServiceIdsInBeacon > 127";
+ return false;
+ }
+ legacy_request->subscribe_sid_beacon_val =
+ (hidl_request.configParams.includeSubscribeServiceIdsInBeacon ? 0x1
+ : 0x0) |
+ (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon << 1);
+ legacy_request->config_rssi_window_size = 1;
+ legacy_request->rssi_window_size_val =
+ hidl_request.configParams.rssiWindowSize;
+ legacy_request->config_disc_mac_addr_randomization = 1;
+ 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() != 3) {
+ LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+ "bandSpecificConfig.size() != 3";
+ return false;
+ }
+ legacy_request->rssi_close_2dot4g_val =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .rssiClose;
+ legacy_request->config_2dot4g_rssi_middle = 1;
+ legacy_request->rssi_middle_2dot4g_val =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .rssiMiddle;
+ legacy_request->config_2dot4g_rssi_proximity = 1;
+ legacy_request->rssi_proximity_2dot4g_val =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .rssiCloseProximity;
+ legacy_request->config_scan_params = 1;
+ legacy_request->scan_params_val
+ .dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .dwellTimeMs;
+ legacy_request->scan_params_val
+ .scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .scanPeriodSec;
+ legacy_request->config_dw.config_2dot4g_dw_band =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .validDiscoveryWindowIntervalVal;
+ legacy_request->config_dw.dw_2dot4g_interval_val =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .discoveryWindowIntervalVal;
+ legacy_request->config_5g_rssi_close = 1;
+ legacy_request->rssi_close_5g_val =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .rssiClose;
+ legacy_request->config_5g_rssi_middle = 1;
+ legacy_request->rssi_middle_5g_val =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .rssiMiddle;
+ legacy_request->config_5g_rssi_close_proximity = 1;
+ legacy_request->rssi_close_proximity_5g_val =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .rssiCloseProximity;
+ legacy_request->scan_params_val
+ .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .dwellTimeMs;
+ legacy_request->scan_params_val
+ .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .scanPeriodSec;
+ legacy_request->scan_params_val
+ .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .dwellTimeMs;
+ legacy_request->scan_params_val
+ .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .scanPeriodSec;
+ legacy_request->config_dw.config_5g_dw_band =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .validDiscoveryWindowIntervalVal;
+ legacy_request->config_dw.dw_5g_interval_val =
+ hidl_request.configParams
+ .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .discoveryWindowIntervalVal;
+ if (hidl_request.debugConfigs.validClusterIdVals) {
+ legacy_request->cluster_low =
+ hidl_request.debugConfigs.clusterIdBottomRangeVal;
+ legacy_request->cluster_high =
+ hidl_request.debugConfigs.clusterIdTopRangeVal;
+ } else { // need 'else' since not configurable in legacy HAL
+ legacy_request->cluster_low = 0x0000;
+ legacy_request->cluster_high = 0xFFFF;
+ }
+ legacy_request->config_intf_addr =
+ hidl_request.debugConfigs.validIntfAddrVal;
+ memcpy(legacy_request->intf_addr_val,
+ hidl_request.debugConfigs.intfAddrVal.data(), 6);
+ legacy_request->config_oui = hidl_request.debugConfigs.validOuiVal;
+ legacy_request->oui_val = hidl_request.debugConfigs.ouiVal;
+ legacy_request->config_random_factor_force =
+ hidl_request.debugConfigs.validRandomFactorForceVal;
+ legacy_request->random_factor_force_val =
+ hidl_request.debugConfigs.randomFactorForceVal;
+ legacy_request->config_hop_count_force =
+ hidl_request.debugConfigs.validHopCountForceVal;
+ legacy_request->hop_count_force_val =
+ hidl_request.debugConfigs.hopCountForceVal;
+ legacy_request->config_24g_channel =
+ hidl_request.debugConfigs.validDiscoveryChannelVal;
+ legacy_request->channel_24g_val =
+ hidl_request.debugConfigs
+ .discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+ legacy_request->config_5g_channel =
+ hidl_request.debugConfigs.validDiscoveryChannelVal;
+ legacy_request->channel_5g_val =
+ hidl_request.debugConfigs
+ .discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+ legacy_request->config_2dot4g_beacons =
+ hidl_request.debugConfigs.validUseBeaconsInBandVal;
+ legacy_request->beacon_2dot4g_val =
+ hidl_request.debugConfigs
+ .useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+ legacy_request->config_5g_beacons =
+ hidl_request.debugConfigs.validUseBeaconsInBandVal;
+ legacy_request->beacon_5g_val =
+ hidl_request.debugConfigs
+ .useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+ legacy_request->config_2dot4g_sdf =
+ hidl_request.debugConfigs.validUseSdfInBandVal;
+ legacy_request->sdf_2dot4g_val =
+ hidl_request.debugConfigs
+ .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+ legacy_request->config_5g_sdf =
+ hidl_request.debugConfigs.validUseSdfInBandVal;
+ legacy_request->sdf_5g_val =
+ 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_4ToLegacy(
+ const NanEnableRequest& hidl_request1,
+ const V1_2::NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanEnableRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR)
+ << "convertHidlNanEnableRequest_1_4ToLegacy: null legacy_request";
+ return false;
+ }
+
+ *legacy_request = {};
+ if (!convertHidlNanEnableRequestToLegacy(hidl_request1, legacy_request)) {
+ return false;
+ }
+
+ legacy_request->config_discovery_beacon_int = 1;
+ legacy_request->discovery_beacon_interval =
+ hidl_request2.discoveryBeaconIntervalMs;
+ legacy_request->config_nss = 1;
+ legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
+ legacy_request->config_dw_early_termination = 1;
+ legacy_request->enable_dw_termination =
+ hidl_request2.enableDiscoveryWindowEarlyTermination;
+ legacy_request->config_enable_ranging = 1;
+ legacy_request->enable_ranging = hidl_request2.enableRanging;
+
+ return true;
+}
+
+bool convertHidlNanPublishRequestToLegacy(
+ const NanPublishRequest& hidl_request,
+ legacy_hal::NanPublishRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR)
+ << "convertHidlNanPublishRequestToLegacy: null legacy_request";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->publish_id = hidl_request.baseConfigs.sessionId;
+ legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
+ legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
+ legacy_request->publish_count = hidl_request.baseConfigs.discoveryCount;
+ legacy_request->service_name_len =
+ hidl_request.baseConfigs.serviceName.size();
+ if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: service_name_len "
+ "too large";
+ return false;
+ }
+ memcpy(legacy_request->service_name,
+ hidl_request.baseConfigs.serviceName.data(),
+ legacy_request->service_name_len);
+ legacy_request->publish_match_indicator = convertHidlNanMatchAlgToLegacy(
+ hidl_request.baseConfigs.discoveryMatchIndicator);
+ legacy_request->service_specific_info_len =
+ hidl_request.baseConfigs.serviceSpecificInfo.size();
+ if (legacy_request->service_specific_info_len >
+ NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+ "service_specific_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_specific_info,
+ hidl_request.baseConfigs.serviceSpecificInfo.data(),
+ legacy_request->service_specific_info_len);
+ legacy_request->sdea_service_specific_info_len =
+ hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
+ if (legacy_request->sdea_service_specific_info_len >
+ NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+ "sdea_service_specific_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->sdea_service_specific_info,
+ hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
+ legacy_request->sdea_service_specific_info_len);
+ legacy_request->rx_match_filter_len =
+ hidl_request.baseConfigs.rxMatchFilter.size();
+ if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+ "rx_match_filter_len too large";
+ return false;
+ }
+ memcpy(legacy_request->rx_match_filter,
+ hidl_request.baseConfigs.rxMatchFilter.data(),
+ legacy_request->rx_match_filter_len);
+ legacy_request->tx_match_filter_len =
+ hidl_request.baseConfigs.txMatchFilter.size();
+ if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+ "tx_match_filter_len too large";
+ return false;
+ }
+ memcpy(legacy_request->tx_match_filter,
+ hidl_request.baseConfigs.txMatchFilter.data(),
+ legacy_request->tx_match_filter_len);
+ legacy_request->rssi_threshold_flag =
+ hidl_request.baseConfigs.useRssiThreshold;
+ legacy_request->recv_indication_cfg = 0;
+ legacy_request->recv_indication_cfg |=
+ hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1
+ : 0x0;
+ legacy_request->recv_indication_cfg |=
+ hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
+ legacy_request->recv_indication_cfg |=
+ hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
+ legacy_request->recv_indication_cfg |= 0x8;
+ legacy_request->cipher_type =
+ (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
+ if (hidl_request.baseConfigs.securityConfig.securityType ==
+ NanDataPathSecurityType::PMK) {
+ legacy_request->key_info.key_type =
+ legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+ legacy_request->key_info.body.pmk_info.pmk_len =
+ hidl_request.baseConfigs.securityConfig.pmk.size();
+ if (legacy_request->key_info.body.pmk_info.pmk_len !=
+ NAN_PMK_INFO_LEN) {
+ LOG(ERROR)
+ << "convertHidlNanPublishRequestToLegacy: invalid pmk_len";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.pmk_info.pmk,
+ hidl_request.baseConfigs.securityConfig.pmk.data(),
+ legacy_request->key_info.body.pmk_info.pmk_len);
+ }
+ if (hidl_request.baseConfigs.securityConfig.securityType ==
+ NanDataPathSecurityType::PASSPHRASE) {
+ legacy_request->key_info.key_type =
+ legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+ legacy_request->key_info.body.passphrase_info.passphrase_len =
+ hidl_request.baseConfigs.securityConfig.passphrase.size();
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+ "passphrase_len too small";
+ return false;
+ }
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+ NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+ "passphrase_len too large";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+ hidl_request.baseConfigs.securityConfig.passphrase.data(),
+ legacy_request->key_info.body.passphrase_info.passphrase_len);
+ }
+ legacy_request->sdea_params.security_cfg =
+ (hidl_request.baseConfigs.securityConfig.securityType !=
+ NanDataPathSecurityType::OPEN)
+ ? legacy_hal::NAN_DP_CONFIG_SECURITY
+ : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+ legacy_request->sdea_params.ranging_state =
+ hidl_request.baseConfigs.rangingRequired
+ ? legacy_hal::NAN_RANGING_ENABLE
+ : legacy_hal::NAN_RANGING_DISABLE;
+ legacy_request->ranging_cfg.ranging_interval_msec =
+ hidl_request.baseConfigs.rangingIntervalMsec;
+ legacy_request->ranging_cfg.config_ranging_indications =
+ hidl_request.baseConfigs.configRangingIndications;
+ legacy_request->ranging_cfg.distance_ingress_mm =
+ hidl_request.baseConfigs.distanceIngressCm * 10;
+ legacy_request->ranging_cfg.distance_egress_mm =
+ hidl_request.baseConfigs.distanceEgressCm * 10;
+ legacy_request->ranging_auto_response =
+ hidl_request.baseConfigs.rangingRequired
+ ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
+ : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+ legacy_request->sdea_params.range_report =
+ legacy_hal::NAN_DISABLE_RANGE_REPORT;
+ legacy_request->publish_type =
+ convertHidlNanPublishTypeToLegacy(hidl_request.publishType);
+ legacy_request->tx_type = convertHidlNanTxTypeToLegacy(hidl_request.txType);
+ legacy_request->service_responder_policy =
+ hidl_request.autoAcceptDataPathRequests
+ ? legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL
+ : legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE;
+
+ return true;
+}
+
+bool convertHidlNanSubscribeRequestToLegacy(
+ const NanSubscribeRequest& hidl_request,
+ legacy_hal::NanSubscribeRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR)
+ << "convertHidlNanSubscribeRequestToLegacy: legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->subscribe_id = hidl_request.baseConfigs.sessionId;
+ legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
+ legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
+ legacy_request->subscribe_count = hidl_request.baseConfigs.discoveryCount;
+ legacy_request->service_name_len =
+ hidl_request.baseConfigs.serviceName.size();
+ if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "service_name_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_name,
+ hidl_request.baseConfigs.serviceName.data(),
+ legacy_request->service_name_len);
+ legacy_request->subscribe_match_indicator = convertHidlNanMatchAlgToLegacy(
+ hidl_request.baseConfigs.discoveryMatchIndicator);
+ legacy_request->service_specific_info_len =
+ hidl_request.baseConfigs.serviceSpecificInfo.size();
+ if (legacy_request->service_specific_info_len >
+ NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "service_specific_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_specific_info,
+ hidl_request.baseConfigs.serviceSpecificInfo.data(),
+ legacy_request->service_specific_info_len);
+ legacy_request->sdea_service_specific_info_len =
+ hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
+ if (legacy_request->sdea_service_specific_info_len >
+ NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "sdea_service_specific_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->sdea_service_specific_info,
+ hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
+ legacy_request->sdea_service_specific_info_len);
+ legacy_request->rx_match_filter_len =
+ hidl_request.baseConfigs.rxMatchFilter.size();
+ if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "rx_match_filter_len too large";
+ return false;
+ }
+ memcpy(legacy_request->rx_match_filter,
+ hidl_request.baseConfigs.rxMatchFilter.data(),
+ legacy_request->rx_match_filter_len);
+ legacy_request->tx_match_filter_len =
+ hidl_request.baseConfigs.txMatchFilter.size();
+ if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "tx_match_filter_len too large";
+ return false;
+ }
+ memcpy(legacy_request->tx_match_filter,
+ hidl_request.baseConfigs.txMatchFilter.data(),
+ legacy_request->tx_match_filter_len);
+ legacy_request->rssi_threshold_flag =
+ hidl_request.baseConfigs.useRssiThreshold;
+ legacy_request->recv_indication_cfg = 0;
+ legacy_request->recv_indication_cfg |=
+ hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1
+ : 0x0;
+ legacy_request->recv_indication_cfg |=
+ hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
+ legacy_request->recv_indication_cfg |=
+ hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
+ legacy_request->cipher_type =
+ (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
+ if (hidl_request.baseConfigs.securityConfig.securityType ==
+ NanDataPathSecurityType::PMK) {
+ legacy_request->key_info.key_type =
+ legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+ legacy_request->key_info.body.pmk_info.pmk_len =
+ hidl_request.baseConfigs.securityConfig.pmk.size();
+ if (legacy_request->key_info.body.pmk_info.pmk_len !=
+ NAN_PMK_INFO_LEN) {
+ LOG(ERROR)
+ << "convertHidlNanSubscribeRequestToLegacy: invalid pmk_len";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.pmk_info.pmk,
+ hidl_request.baseConfigs.securityConfig.pmk.data(),
+ legacy_request->key_info.body.pmk_info.pmk_len);
+ }
+ if (hidl_request.baseConfigs.securityConfig.securityType ==
+ NanDataPathSecurityType::PASSPHRASE) {
+ legacy_request->key_info.key_type =
+ legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+ legacy_request->key_info.body.passphrase_info.passphrase_len =
+ hidl_request.baseConfigs.securityConfig.passphrase.size();
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "passphrase_len too small";
+ return false;
+ }
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+ NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "passphrase_len too large";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+ hidl_request.baseConfigs.securityConfig.passphrase.data(),
+ legacy_request->key_info.body.passphrase_info.passphrase_len);
+ }
+ legacy_request->sdea_params.security_cfg =
+ (hidl_request.baseConfigs.securityConfig.securityType !=
+ NanDataPathSecurityType::OPEN)
+ ? legacy_hal::NAN_DP_CONFIG_SECURITY
+ : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+ legacy_request->sdea_params.ranging_state =
+ hidl_request.baseConfigs.rangingRequired
+ ? legacy_hal::NAN_RANGING_ENABLE
+ : legacy_hal::NAN_RANGING_DISABLE;
+ legacy_request->ranging_cfg.ranging_interval_msec =
+ hidl_request.baseConfigs.rangingIntervalMsec;
+ legacy_request->ranging_cfg.config_ranging_indications =
+ hidl_request.baseConfigs.configRangingIndications;
+ legacy_request->ranging_cfg.distance_ingress_mm =
+ hidl_request.baseConfigs.distanceIngressCm * 10;
+ legacy_request->ranging_cfg.distance_egress_mm =
+ hidl_request.baseConfigs.distanceEgressCm * 10;
+ legacy_request->ranging_auto_response =
+ hidl_request.baseConfigs.rangingRequired
+ ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
+ : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+ legacy_request->sdea_params.range_report =
+ legacy_hal::NAN_DISABLE_RANGE_REPORT;
+ legacy_request->subscribe_type =
+ convertHidlNanSubscribeTypeToLegacy(hidl_request.subscribeType);
+ legacy_request->serviceResponseFilter =
+ convertHidlNanSrfTypeToLegacy(hidl_request.srfType);
+ legacy_request->serviceResponseInclude =
+ hidl_request.srfRespondIfInAddressSet
+ ? legacy_hal::NAN_SRF_INCLUDE_RESPOND
+ : legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
+ legacy_request->useServiceResponseFilter =
+ hidl_request.shouldUseSrf ? legacy_hal::NAN_USE_SRF
+ : legacy_hal::NAN_DO_NOT_USE_SRF;
+ legacy_request->ssiRequiredForMatchIndication =
+ hidl_request.isSsiRequiredForMatch
+ ? legacy_hal::NAN_SSI_REQUIRED_IN_MATCH_IND
+ : legacy_hal::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
+ legacy_request->num_intf_addr_present = hidl_request.intfAddr.size();
+ if (legacy_request->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "num_intf_addr_present - too many";
+ return false;
+ }
+ for (int i = 0; i < legacy_request->num_intf_addr_present; i++) {
+ memcpy(legacy_request->intf_addr[i], hidl_request.intfAddr[i].data(),
+ 6);
+ }
+
+ return true;
+}
+
+bool convertHidlNanTransmitFollowupRequestToLegacy(
+ const NanTransmitFollowupRequest& hidl_request,
+ legacy_hal::NanTransmitFollowupRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+ "legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->publish_subscribe_id = hidl_request.discoverySessionId;
+ legacy_request->requestor_instance_id = hidl_request.peerId;
+ memcpy(legacy_request->addr, hidl_request.addr.data(), 6);
+ legacy_request->priority = hidl_request.isHighPriority
+ ? legacy_hal::NAN_TX_PRIORITY_HIGH
+ : legacy_hal::NAN_TX_PRIORITY_NORMAL;
+ legacy_request->dw_or_faw = hidl_request.shouldUseDiscoveryWindow
+ ? legacy_hal::NAN_TRANSMIT_IN_DW
+ : legacy_hal::NAN_TRANSMIT_IN_FAW;
+ legacy_request->service_specific_info_len =
+ hidl_request.serviceSpecificInfo.size();
+ if (legacy_request->service_specific_info_len >
+ NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+ "service_specific_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_specific_info,
+ hidl_request.serviceSpecificInfo.data(),
+ legacy_request->service_specific_info_len);
+ legacy_request->sdea_service_specific_info_len =
+ hidl_request.extendedServiceSpecificInfo.size();
+ if (legacy_request->sdea_service_specific_info_len >
+ NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+ "sdea_service_specific_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->sdea_service_specific_info,
+ hidl_request.extendedServiceSpecificInfo.data(),
+ legacy_request->sdea_service_specific_info_len);
+ legacy_request->recv_indication_cfg =
+ hidl_request.disableFollowupResultIndication ? 0x1 : 0x0;
+
+ return true;
+}
+
+bool convertHidlNanConfigRequestToLegacy(
+ const NanConfigRequest& hidl_request,
+ legacy_hal::NanConfigRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR)
+ << "convertHidlNanConfigRequestToLegacy: legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ // TODO: b/34059183 tracks missing configurations in legacy HAL or uknown
+ // defaults
+ legacy_request->master_pref = hidl_request.masterPref;
+ legacy_request->discovery_indication_cfg = 0;
+ legacy_request->discovery_indication_cfg |=
+ hidl_request.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
+ legacy_request->discovery_indication_cfg |=
+ hidl_request.disableStartedClusterIndication ? 0x2 : 0x0;
+ legacy_request->discovery_indication_cfg |=
+ hidl_request.disableJoinedClusterIndication ? 0x4 : 0x0;
+ legacy_request->config_sid_beacon = 1;
+ if (hidl_request.numberOfPublishServiceIdsInBeacon > 127) {
+ LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
+ "numberOfPublishServiceIdsInBeacon > 127";
+ return false;
+ }
+ legacy_request->sid_beacon =
+ (hidl_request.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
+ (hidl_request.numberOfPublishServiceIdsInBeacon << 1);
+ legacy_request->config_subscribe_sid_beacon = 1;
+ if (hidl_request.numberOfSubscribeServiceIdsInBeacon > 127) {
+ LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
+ "numberOfSubscribeServiceIdsInBeacon > 127";
+ return false;
+ }
+ legacy_request->subscribe_sid_beacon_val =
+ (hidl_request.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
+ (hidl_request.numberOfSubscribeServiceIdsInBeacon << 1);
+ legacy_request->config_rssi_window_size = 1;
+ legacy_request->rssi_window_size_val = hidl_request.rssiWindowSize;
+ legacy_request->config_disc_mac_addr_randomization = 1;
+ legacy_request->disc_mac_addr_rand_interval_sec =
+ hidl_request.macAddressRandomizationIntervalSec;
+ /* TODO : missing
+ legacy_request->config_2dot4g_rssi_close = 1;
+ legacy_request->rssi_close_2dot4g_val =
+ hidl_request.bandSpecificConfig[
+ (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiClose;
+ legacy_request->config_2dot4g_rssi_middle = 1;
+ legacy_request->rssi_middle_2dot4g_val =
+ hidl_request.bandSpecificConfig[
+ (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiMiddle;
+ legacy_request->config_2dot4g_rssi_proximity = 1;
+ legacy_request->rssi_proximity_2dot4g_val =
+ hidl_request.bandSpecificConfig[
+ (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiCloseProximity;
+ */
+ legacy_request->config_scan_params = 1;
+ legacy_request->scan_params_val
+ .dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .dwellTimeMs;
+ legacy_request->scan_params_val
+ .scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .scanPeriodSec;
+ legacy_request->config_dw.config_2dot4g_dw_band =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .validDiscoveryWindowIntervalVal;
+ legacy_request->config_dw.dw_2dot4g_interval_val =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .discoveryWindowIntervalVal;
+ /* TODO: missing
+ legacy_request->config_5g_rssi_close = 1;
+ legacy_request->rssi_close_5g_val =
+ hidl_request.bandSpecificConfig[
+ (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiClose;
+ legacy_request->config_5g_rssi_middle = 1;
+ legacy_request->rssi_middle_5g_val =
+ hidl_request.bandSpecificConfig[
+ (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiMiddle;
+ */
+ legacy_request->config_5g_rssi_close_proximity = 1;
+ legacy_request->rssi_close_proximity_5g_val =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .rssiCloseProximity;
+ legacy_request->scan_params_val
+ .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .dwellTimeMs;
+ legacy_request->scan_params_val
+ .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .scanPeriodSec;
+ legacy_request->scan_params_val
+ .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .dwellTimeMs;
+ legacy_request->scan_params_val
+ .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .scanPeriodSec;
+ legacy_request->config_dw.config_5g_dw_band =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .validDiscoveryWindowIntervalVal;
+ 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_4ToLegacy(
+ const NanConfigRequest& hidl_request1,
+ const V1_2::NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanConfigRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanConfigRequest_1_4ToLegacy: legacy_request "
+ "is null";
+ return false;
+ }
+
+ *legacy_request = {};
+ if (!convertHidlNanConfigRequestToLegacy(hidl_request1, legacy_request)) {
+ return false;
+ }
+
+ legacy_request->config_discovery_beacon_int = 1;
+ legacy_request->discovery_beacon_interval =
+ hidl_request2.discoveryBeaconIntervalMs;
+ legacy_request->config_nss = 1;
+ legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
+ legacy_request->config_dw_early_termination = 1;
+ legacy_request->enable_dw_termination =
+ hidl_request2.enableDiscoveryWindowEarlyTermination;
+ legacy_request->config_enable_ranging = 1;
+ legacy_request->enable_ranging = hidl_request2.enableRanging;
+
+ return true;
+}
+
+bool convertHidlNanDataPathInitiatorRequestToLegacy(
+ const NanInitiateDataPathRequest& hidl_request,
+ legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->requestor_instance_id = hidl_request.peerId;
+ memcpy(legacy_request->peer_disc_mac_addr,
+ hidl_request.peerDiscMacAddr.data(), 6);
+ legacy_request->channel_request_type =
+ convertHidlNanDataPathChannelCfgToLegacy(
+ hidl_request.channelRequestType);
+ legacy_request->channel = hidl_request.channel;
+ if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "ifaceName too long";
+ return false;
+ }
+ strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(),
+ IFNAMSIZ + 1);
+ legacy_request->ndp_cfg.security_cfg =
+ (hidl_request.securityConfig.securityType !=
+ NanDataPathSecurityType::OPEN)
+ ? legacy_hal::NAN_DP_CONFIG_SECURITY
+ : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+ legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+ if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "ndp_app_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+ legacy_request->app_info.ndp_app_info_len);
+ legacy_request->cipher_type =
+ (unsigned int)hidl_request.securityConfig.cipherType;
+ if (hidl_request.securityConfig.securityType ==
+ NanDataPathSecurityType::PMK) {
+ legacy_request->key_info.key_type =
+ legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+ legacy_request->key_info.body.pmk_info.pmk_len =
+ hidl_request.securityConfig.pmk.size();
+ if (legacy_request->key_info.body.pmk_info.pmk_len !=
+ NAN_PMK_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "invalid pmk_len";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.pmk_info.pmk,
+ hidl_request.securityConfig.pmk.data(),
+ legacy_request->key_info.body.pmk_info.pmk_len);
+ }
+ if (hidl_request.securityConfig.securityType ==
+ NanDataPathSecurityType::PASSPHRASE) {
+ legacy_request->key_info.key_type =
+ legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+ legacy_request->key_info.body.passphrase_info.passphrase_len =
+ hidl_request.securityConfig.passphrase.size();
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "passphrase_len too small";
+ return false;
+ }
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+ NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "passphrase_len too large";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+ hidl_request.securityConfig.passphrase.data(),
+ legacy_request->key_info.body.passphrase_info.passphrase_len);
+ }
+ legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+ if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "service_name_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_name,
+ hidl_request.serviceNameOutOfBand.data(),
+ legacy_request->service_name_len);
+
+ return true;
+}
+
+bool convertHidlNanDataPathIndicationResponseToLegacy(
+ const NanRespondToDataPathIndicationRequest& hidl_request,
+ legacy_hal::NanDataPathIndicationResponse* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->rsp_code = hidl_request.acceptRequest
+ ? legacy_hal::NAN_DP_REQUEST_ACCEPT
+ : legacy_hal::NAN_DP_REQUEST_REJECT;
+ legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
+ if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "ifaceName too long";
+ return false;
+ }
+ strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(),
+ IFNAMSIZ + 1);
+ legacy_request->ndp_cfg.security_cfg =
+ (hidl_request.securityConfig.securityType !=
+ NanDataPathSecurityType::OPEN)
+ ? legacy_hal::NAN_DP_CONFIG_SECURITY
+ : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+ legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+ if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "ndp_app_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+ legacy_request->app_info.ndp_app_info_len);
+ legacy_request->cipher_type =
+ (unsigned int)hidl_request.securityConfig.cipherType;
+ if (hidl_request.securityConfig.securityType ==
+ NanDataPathSecurityType::PMK) {
+ legacy_request->key_info.key_type =
+ legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+ legacy_request->key_info.body.pmk_info.pmk_len =
+ hidl_request.securityConfig.pmk.size();
+ if (legacy_request->key_info.body.pmk_info.pmk_len !=
+ NAN_PMK_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "invalid pmk_len";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.pmk_info.pmk,
+ hidl_request.securityConfig.pmk.data(),
+ legacy_request->key_info.body.pmk_info.pmk_len);
+ }
+ if (hidl_request.securityConfig.securityType ==
+ NanDataPathSecurityType::PASSPHRASE) {
+ legacy_request->key_info.key_type =
+ legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+ legacy_request->key_info.body.passphrase_info.passphrase_len =
+ hidl_request.securityConfig.passphrase.size();
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "passphrase_len too small";
+ return false;
+ }
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+ NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "passphrase_len too large";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+ hidl_request.securityConfig.passphrase.data(),
+ legacy_request->key_info.body.passphrase_info.passphrase_len);
+ }
+ legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+ if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "service_name_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_name,
+ hidl_request.serviceNameOutOfBand.data(),
+ legacy_request->service_name_len);
+
+ return true;
+}
+
+bool convertLegacyNanResponseHeaderToHidl(
+ const legacy_hal::NanResponseMsg& legacy_response,
+ WifiNanStatus* wifiNanStatus) {
+ if (!wifiNanStatus) {
+ LOG(ERROR)
+ << "convertLegacyNanResponseHeaderToHidl: wifiNanStatus is null";
+ return false;
+ }
+ *wifiNanStatus = {};
+
+ convertToWifiNanStatus(legacy_response.status, legacy_response.nan_error,
+ sizeof(legacy_response.nan_error), wifiNanStatus);
+ return true;
+}
+
+bool convertLegacyNanCapabilitiesResponseToHidl(
+ const legacy_hal::NanCapabilities& legacy_response,
+ NanCapabilities* hidl_response) {
+ if (!hidl_response) {
+ LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToHidl: "
+ "hidl_response is null";
+ return false;
+ }
+ *hidl_response = {};
+
+ hidl_response->maxConcurrentClusters =
+ legacy_response.max_concurrent_nan_clusters;
+ hidl_response->maxPublishes = legacy_response.max_publishes;
+ hidl_response->maxSubscribes = legacy_response.max_subscribes;
+ hidl_response->maxServiceNameLen = legacy_response.max_service_name_len;
+ hidl_response->maxMatchFilterLen = legacy_response.max_match_filter_len;
+ hidl_response->maxTotalMatchFilterLen =
+ legacy_response.max_total_match_filter_len;
+ hidl_response->maxServiceSpecificInfoLen =
+ legacy_response.max_service_specific_info_len;
+ hidl_response->maxExtendedServiceSpecificInfoLen =
+ legacy_response.max_sdea_service_specific_info_len;
+ hidl_response->maxNdiInterfaces = legacy_response.max_ndi_interfaces;
+ hidl_response->maxNdpSessions = legacy_response.max_ndp_sessions;
+ hidl_response->maxAppInfoLen = legacy_response.max_app_info_len;
+ hidl_response->maxQueuedTransmitFollowupMsgs =
+ legacy_response.max_queued_transmit_followup_msgs;
+ hidl_response->maxSubscribeInterfaceAddresses =
+ legacy_response.max_subscribe_address;
+ hidl_response->supportedCipherSuites =
+ legacy_response.cipher_suites_supported;
+
+ return true;
+}
+
+bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
+ NanMatchInd* hidl_ind) {
+ if (!hidl_ind) {
+ LOG(ERROR) << "convertLegacyNanMatchIndToHidl: hidl_ind is null";
+ return false;
+ }
+ *hidl_ind = {};
+
+ hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+ hidl_ind->peerId = legacy_ind.requestor_instance_id;
+ hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
+ hidl_ind->serviceSpecificInfo =
+ std::vector<uint8_t>(legacy_ind.service_specific_info,
+ legacy_ind.service_specific_info +
+ legacy_ind.service_specific_info_len);
+ hidl_ind->extendedServiceSpecificInfo =
+ std::vector<uint8_t>(legacy_ind.sdea_service_specific_info,
+ legacy_ind.sdea_service_specific_info +
+ legacy_ind.sdea_service_specific_info_len);
+ hidl_ind->matchFilter = std::vector<uint8_t>(
+ legacy_ind.sdf_match_filter,
+ legacy_ind.sdf_match_filter + legacy_ind.sdf_match_filter_len);
+ hidl_ind->matchOccuredInBeaconFlag = legacy_ind.match_occured_flag == 1;
+ hidl_ind->outOfResourceFlag = legacy_ind.out_of_resource_flag == 1;
+ hidl_ind->rssiValue = legacy_ind.rssi_value;
+ hidl_ind->peerCipherType = (NanCipherSuiteType)legacy_ind.peer_cipher_type;
+ hidl_ind->peerRequiresSecurityEnabledInNdp =
+ legacy_ind.peer_sdea_params.security_cfg ==
+ legacy_hal::NAN_DP_CONFIG_SECURITY;
+ hidl_ind->peerRequiresRanging = legacy_ind.peer_sdea_params.ranging_state ==
+ legacy_hal::NAN_RANGING_ENABLE;
+ hidl_ind->rangingMeasurementInCm =
+ legacy_ind.range_info.range_measurement_mm / 10;
+ hidl_ind->rangingIndicationType = legacy_ind.range_info.ranging_event_type;
+
+ return true;
+}
+
+bool convertLegacyNanFollowupIndToHidl(
+ const legacy_hal::NanFollowupInd& legacy_ind,
+ NanFollowupReceivedInd* hidl_ind) {
+ if (!hidl_ind) {
+ LOG(ERROR) << "convertLegacyNanFollowupIndToHidl: hidl_ind is null";
+ return false;
+ }
+ *hidl_ind = {};
+
+ hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+ hidl_ind->peerId = legacy_ind.requestor_instance_id;
+ hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
+ hidl_ind->receivedInFaw = legacy_ind.dw_or_faw == 1;
+ hidl_ind->serviceSpecificInfo =
+ std::vector<uint8_t>(legacy_ind.service_specific_info,
+ legacy_ind.service_specific_info +
+ legacy_ind.service_specific_info_len);
+ hidl_ind->extendedServiceSpecificInfo =
+ std::vector<uint8_t>(legacy_ind.sdea_service_specific_info,
+ legacy_ind.sdea_service_specific_info +
+ legacy_ind.sdea_service_specific_info_len);
+
+ return true;
+}
+
+bool convertLegacyNanDataPathRequestIndToHidl(
+ const legacy_hal::NanDataPathRequestInd& legacy_ind,
+ NanDataPathRequestInd* hidl_ind) {
+ if (!hidl_ind) {
+ LOG(ERROR)
+ << "convertLegacyNanDataPathRequestIndToHidl: hidl_ind is null";
+ return false;
+ }
+ *hidl_ind = {};
+
+ hidl_ind->discoverySessionId = legacy_ind.service_instance_id;
+ hidl_ind->peerDiscMacAddr =
+ hidl_array<uint8_t, 6>(legacy_ind.peer_disc_mac_addr);
+ hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
+ hidl_ind->securityRequired =
+ legacy_ind.ndp_cfg.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
+ hidl_ind->appInfo =
+ std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
+ legacy_ind.app_info.ndp_app_info +
+ legacy_ind.app_info.ndp_app_info_len);
+
+ return true;
+}
+
+bool convertLegacyNdpChannelInfoToHidl(
+ const legacy_hal::NanChannelInfo& legacy_struct,
+ V1_2::NanDataPathChannelInfo* hidl_struct) {
+ if (!hidl_struct) {
+ LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
+ return false;
+ }
+ *hidl_struct = {};
+
+ hidl_struct->channelFreq = legacy_struct.channel;
+ hidl_struct->channelBandwidth = convertLegacyWifiChannelWidthToHidl(
+ (legacy_hal::wifi_channel_width)legacy_struct.bandwidth);
+ hidl_struct->numSpatialStreams = legacy_struct.nss;
+
+ return true;
+}
+
+bool convertLegacyNanDataPathConfirmIndToHidl(
+ const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+ V1_2::NanDataPathConfirmInd* hidl_ind) {
+ if (!hidl_ind) {
+ LOG(ERROR)
+ << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
+ return false;
+ }
+ *hidl_ind = {};
+
+ hidl_ind->V1_0.ndpInstanceId = legacy_ind.ndp_instance_id;
+ hidl_ind->V1_0.dataPathSetupSuccess =
+ legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
+ hidl_ind->V1_0.peerNdiMacAddr =
+ hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
+ hidl_ind->V1_0.appInfo =
+ std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
+ legacy_ind.app_info.ndp_app_info +
+ legacy_ind.app_info.ndp_app_info_len);
+ hidl_ind->V1_0.status.status =
+ convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
+ hidl_ind->V1_0.status.description = ""; // TODO: b/34059183
+
+ std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
+ for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+ V1_2::NanDataPathChannelInfo hidl_struct;
+ if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
+ &hidl_struct)) {
+ return false;
+ }
+ channelInfo.push_back(hidl_struct);
+ }
+ hidl_ind->channelInfo = channelInfo;
+
+ return true;
+}
+
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+ const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+ V1_2::NanDataPathScheduleUpdateInd* hidl_ind) {
+ if (!hidl_ind) {
+ LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
+ "hidl_ind is null";
+ return false;
+ }
+ *hidl_ind = {};
+
+ hidl_ind->peerDiscoveryAddress =
+ hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
+ std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
+ for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+ V1_2::NanDataPathChannelInfo hidl_struct;
+ if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
+ &hidl_struct)) {
+ return false;
+ }
+ channelInfo.push_back(hidl_struct);
+ }
+ hidl_ind->channelInfo = channelInfo;
+ std::vector<uint32_t> ndpInstanceIds;
+ for (unsigned int i = 0; i < legacy_ind.num_ndp_instances; ++i) {
+ ndpInstanceIds.push_back(legacy_ind.ndp_instance_id[i]);
+ }
+ hidl_ind->ndpInstanceIds = ndpInstanceIds;
+
+ return true;
+}
+
+legacy_hal::wifi_rtt_type convertHidlRttTypeToLegacy(RttType type) {
+ switch (type) {
+ case RttType::ONE_SIDED:
+ return legacy_hal::RTT_TYPE_1_SIDED;
+ case RttType::TWO_SIDED:
+ return legacy_hal::RTT_TYPE_2_SIDED;
+ };
+ CHECK(false);
+}
+
+RttType convertLegacyRttTypeToHidl(legacy_hal::wifi_rtt_type type) {
+ switch (type) {
+ case legacy_hal::RTT_TYPE_1_SIDED:
+ return RttType::ONE_SIDED;
+ case legacy_hal::RTT_TYPE_2_SIDED:
+ return RttType::TWO_SIDED;
+ };
+ CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::rtt_peer_type convertHidlRttPeerTypeToLegacy(RttPeerType type) {
+ switch (type) {
+ case RttPeerType::AP:
+ return legacy_hal::RTT_PEER_AP;
+ case RttPeerType::STA:
+ return legacy_hal::RTT_PEER_STA;
+ case RttPeerType::P2P_GO:
+ return legacy_hal::RTT_PEER_P2P_GO;
+ case RttPeerType::P2P_CLIENT:
+ return legacy_hal::RTT_PEER_P2P_CLIENT;
+ case RttPeerType::NAN:
+ return legacy_hal::RTT_PEER_NAN;
+ };
+ CHECK(false);
+}
+
+legacy_hal::wifi_channel_width convertHidlWifiChannelWidthToLegacy(
+ WifiChannelWidthInMhz type) {
+ switch (type) {
+ case WifiChannelWidthInMhz::WIDTH_20:
+ return legacy_hal::WIFI_CHAN_WIDTH_20;
+ case WifiChannelWidthInMhz::WIDTH_40:
+ return legacy_hal::WIFI_CHAN_WIDTH_40;
+ case WifiChannelWidthInMhz::WIDTH_80:
+ return legacy_hal::WIFI_CHAN_WIDTH_80;
+ case WifiChannelWidthInMhz::WIDTH_160:
+ return legacy_hal::WIFI_CHAN_WIDTH_160;
+ case WifiChannelWidthInMhz::WIDTH_80P80:
+ return legacy_hal::WIFI_CHAN_WIDTH_80P80;
+ case WifiChannelWidthInMhz::WIDTH_5:
+ return legacy_hal::WIFI_CHAN_WIDTH_5;
+ case WifiChannelWidthInMhz::WIDTH_10:
+ return legacy_hal::WIFI_CHAN_WIDTH_10;
+ case WifiChannelWidthInMhz::WIDTH_INVALID:
+ return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
+ };
+ CHECK(false);
+}
+
+WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
+ legacy_hal::wifi_channel_width type) {
+ switch (type) {
+ case legacy_hal::WIFI_CHAN_WIDTH_20:
+ return WifiChannelWidthInMhz::WIDTH_20;
+ case legacy_hal::WIFI_CHAN_WIDTH_40:
+ return WifiChannelWidthInMhz::WIDTH_40;
+ case legacy_hal::WIFI_CHAN_WIDTH_80:
+ return WifiChannelWidthInMhz::WIDTH_80;
+ case legacy_hal::WIFI_CHAN_WIDTH_160:
+ return WifiChannelWidthInMhz::WIDTH_160;
+ case legacy_hal::WIFI_CHAN_WIDTH_80P80:
+ return WifiChannelWidthInMhz::WIDTH_80P80;
+ case legacy_hal::WIFI_CHAN_WIDTH_5:
+ return WifiChannelWidthInMhz::WIDTH_5;
+ case legacy_hal::WIFI_CHAN_WIDTH_10:
+ return WifiChannelWidthInMhz::WIDTH_10;
+ case legacy_hal::WIFI_CHAN_WIDTH_INVALID:
+ return WifiChannelWidthInMhz::WIDTH_INVALID;
+ };
+ CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(RttPreamble type) {
+ switch (type) {
+ case RttPreamble::LEGACY:
+ return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
+ case RttPreamble::HT:
+ return legacy_hal::WIFI_RTT_PREAMBLE_HT;
+ case RttPreamble::VHT:
+ return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
+ case RttPreamble::HE:
+ return legacy_hal::WIFI_RTT_PREAMBLE_HE;
+ };
+ CHECK(false);
+}
+
+RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
+ switch (type) {
+ case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
+ return RttPreamble::LEGACY;
+ case legacy_hal::WIFI_RTT_PREAMBLE_HT:
+ return RttPreamble::HT;
+ case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
+ return RttPreamble::VHT;
+ case legacy_hal::WIFI_RTT_PREAMBLE_HE:
+ return RttPreamble::HE;
+ };
+ CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_rtt_bw convertHidlRttBwToLegacy(RttBw type) {
+ switch (type) {
+ case RttBw::BW_5MHZ:
+ return legacy_hal::WIFI_RTT_BW_5;
+ case RttBw::BW_10MHZ:
+ return legacy_hal::WIFI_RTT_BW_10;
+ case RttBw::BW_20MHZ:
+ return legacy_hal::WIFI_RTT_BW_20;
+ case RttBw::BW_40MHZ:
+ return legacy_hal::WIFI_RTT_BW_40;
+ case RttBw::BW_80MHZ:
+ return legacy_hal::WIFI_RTT_BW_80;
+ case RttBw::BW_160MHZ:
+ return legacy_hal::WIFI_RTT_BW_160;
+ };
+ CHECK(false);
+}
+
+RttBw convertLegacyRttBwToHidl(legacy_hal::wifi_rtt_bw type) {
+ switch (type) {
+ case legacy_hal::WIFI_RTT_BW_5:
+ return RttBw::BW_5MHZ;
+ case legacy_hal::WIFI_RTT_BW_10:
+ return RttBw::BW_10MHZ;
+ case legacy_hal::WIFI_RTT_BW_20:
+ return RttBw::BW_20MHZ;
+ case legacy_hal::WIFI_RTT_BW_40:
+ return RttBw::BW_40MHZ;
+ case legacy_hal::WIFI_RTT_BW_80:
+ return RttBw::BW_80MHZ;
+ case legacy_hal::WIFI_RTT_BW_160:
+ return RttBw::BW_160MHZ;
+ };
+ CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_motion_pattern convertHidlRttMotionPatternToLegacy(
+ RttMotionPattern type) {
+ switch (type) {
+ case RttMotionPattern::NOT_EXPECTED:
+ return legacy_hal::WIFI_MOTION_NOT_EXPECTED;
+ case RttMotionPattern::EXPECTED:
+ return legacy_hal::WIFI_MOTION_EXPECTED;
+ case RttMotionPattern::UNKNOWN:
+ return legacy_hal::WIFI_MOTION_UNKNOWN;
+ };
+ CHECK(false);
+}
+
+WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
+ switch (preamble) {
+ case 0:
+ return WifiRatePreamble::OFDM;
+ case 1:
+ return WifiRatePreamble::CCK;
+ case 2:
+ return WifiRatePreamble::HT;
+ case 3:
+ return WifiRatePreamble::VHT;
+ case 4:
+ return WifiRatePreamble::HE;
+ default:
+ return WifiRatePreamble::RESERVED;
+ };
+ CHECK(false) << "Unknown legacy preamble: " << preamble;
+}
+
+WifiRateNss convertLegacyWifiRateNssToHidl(uint8_t nss) {
+ switch (nss) {
+ case 0:
+ return WifiRateNss::NSS_1x1;
+ case 1:
+ return WifiRateNss::NSS_2x2;
+ case 2:
+ return WifiRateNss::NSS_3x3;
+ case 3:
+ return WifiRateNss::NSS_4x4;
+ };
+ CHECK(false) << "Unknown legacy nss: " << nss;
+ return {};
+}
+
+RttStatus convertLegacyRttStatusToHidl(legacy_hal::wifi_rtt_status status) {
+ switch (status) {
+ case legacy_hal::RTT_STATUS_SUCCESS:
+ return RttStatus::SUCCESS;
+ case legacy_hal::RTT_STATUS_FAILURE:
+ return RttStatus::FAILURE;
+ case legacy_hal::RTT_STATUS_FAIL_NO_RSP:
+ return RttStatus::FAIL_NO_RSP;
+ case legacy_hal::RTT_STATUS_FAIL_REJECTED:
+ return RttStatus::FAIL_REJECTED;
+ case legacy_hal::RTT_STATUS_FAIL_NOT_SCHEDULED_YET:
+ return RttStatus::FAIL_NOT_SCHEDULED_YET;
+ case legacy_hal::RTT_STATUS_FAIL_TM_TIMEOUT:
+ return RttStatus::FAIL_TM_TIMEOUT;
+ case legacy_hal::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL:
+ return RttStatus::FAIL_AP_ON_DIFF_CHANNEL;
+ case legacy_hal::RTT_STATUS_FAIL_NO_CAPABILITY:
+ return RttStatus::FAIL_NO_CAPABILITY;
+ case legacy_hal::RTT_STATUS_ABORTED:
+ return RttStatus::ABORTED;
+ case legacy_hal::RTT_STATUS_FAIL_INVALID_TS:
+ return RttStatus::FAIL_INVALID_TS;
+ case legacy_hal::RTT_STATUS_FAIL_PROTOCOL:
+ return RttStatus::FAIL_PROTOCOL;
+ case legacy_hal::RTT_STATUS_FAIL_SCHEDULE:
+ return RttStatus::FAIL_SCHEDULE;
+ case legacy_hal::RTT_STATUS_FAIL_BUSY_TRY_LATER:
+ return RttStatus::FAIL_BUSY_TRY_LATER;
+ case legacy_hal::RTT_STATUS_INVALID_REQ:
+ return RttStatus::INVALID_REQ;
+ case legacy_hal::RTT_STATUS_NO_WIFI:
+ return RttStatus::NO_WIFI;
+ case legacy_hal::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE:
+ return RttStatus::FAIL_FTM_PARAM_OVERRIDE;
+ case legacy_hal::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE:
+ return RttStatus::FAILURE; // TODO: add HIDL enumeration
+ case legacy_hal::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED:
+ return RttStatus::FAILURE; // TODO: add HIDL enumeration
+ };
+ CHECK(false) << "Unknown legacy status: " << status;
+}
+
+bool convertHidlWifiChannelInfoToLegacy(
+ const WifiChannelInfo& hidl_info,
+ legacy_hal::wifi_channel_info* legacy_info) {
+ if (!legacy_info) {
+ return false;
+ }
+ *legacy_info = {};
+ legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
+ legacy_info->center_freq = hidl_info.centerFreq;
+ legacy_info->center_freq0 = hidl_info.centerFreq0;
+ legacy_info->center_freq1 = hidl_info.centerFreq1;
+ return true;
+}
+
+bool convertLegacyWifiChannelInfoToHidl(
+ const legacy_hal::wifi_channel_info& legacy_info,
+ WifiChannelInfo* hidl_info) {
+ if (!hidl_info) {
+ return false;
+ }
+ *hidl_info = {};
+ hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
+ hidl_info->centerFreq = legacy_info.center_freq;
+ hidl_info->centerFreq0 = legacy_info.center_freq0;
+ hidl_info->centerFreq1 = legacy_info.center_freq1;
+ return true;
+}
+
+bool convertHidlRttConfigToLegacy(const RttConfig& hidl_config,
+ legacy_hal::wifi_rtt_config* legacy_config) {
+ if (!legacy_config) {
+ return false;
+ }
+ *legacy_config = {};
+ CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
+ memcpy(legacy_config->addr, hidl_config.addr.data(),
+ hidl_config.addr.size());
+ legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
+ legacy_config->peer = convertHidlRttPeerTypeToLegacy(hidl_config.peer);
+ if (!convertHidlWifiChannelInfoToLegacy(hidl_config.channel,
+ &legacy_config->channel)) {
+ return false;
+ }
+ legacy_config->burst_period = hidl_config.burstPeriod;
+ legacy_config->num_burst = hidl_config.numBurst;
+ legacy_config->num_frames_per_burst = hidl_config.numFramesPerBurst;
+ legacy_config->num_retries_per_rtt_frame =
+ hidl_config.numRetriesPerRttFrame;
+ legacy_config->num_retries_per_ftmr = hidl_config.numRetriesPerFtmr;
+ legacy_config->LCI_request = hidl_config.mustRequestLci;
+ legacy_config->LCR_request = hidl_config.mustRequestLcr;
+ legacy_config->burst_duration = hidl_config.burstDuration;
+ legacy_config->preamble =
+ convertHidlRttPreambleToLegacy(hidl_config.preamble);
+ legacy_config->bw = convertHidlRttBwToLegacy(hidl_config.bw);
+ return true;
+}
+
+bool convertHidlVectorOfRttConfigToLegacy(
+ const std::vector<RttConfig>& hidl_configs,
+ std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
+ if (!legacy_configs) {
+ return false;
+ }
+ *legacy_configs = {};
+ for (const auto& hidl_config : hidl_configs) {
+ legacy_hal::wifi_rtt_config legacy_config;
+ if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
+ return false;
+ }
+ legacy_configs->push_back(legacy_config);
+ }
+ return true;
+}
+
+bool convertHidlRttLciInformationToLegacy(
+ const RttLciInformation& hidl_info,
+ legacy_hal::wifi_lci_information* legacy_info) {
+ if (!legacy_info) {
+ return false;
+ }
+ *legacy_info = {};
+ legacy_info->latitude = hidl_info.latitude;
+ legacy_info->longitude = hidl_info.longitude;
+ legacy_info->altitude = hidl_info.altitude;
+ legacy_info->latitude_unc = hidl_info.latitudeUnc;
+ legacy_info->longitude_unc = hidl_info.longitudeUnc;
+ legacy_info->altitude_unc = hidl_info.altitudeUnc;
+ legacy_info->motion_pattern =
+ convertHidlRttMotionPatternToLegacy(hidl_info.motionPattern);
+ legacy_info->floor = hidl_info.floor;
+ legacy_info->height_above_floor = hidl_info.heightAboveFloor;
+ legacy_info->height_unc = hidl_info.heightUnc;
+ return true;
+}
+
+bool convertHidlRttLcrInformationToLegacy(
+ const RttLcrInformation& hidl_info,
+ legacy_hal::wifi_lcr_information* legacy_info) {
+ if (!legacy_info) {
+ return false;
+ }
+ *legacy_info = {};
+ CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
+ memcpy(legacy_info->country_code, hidl_info.countryCode.data(),
+ hidl_info.countryCode.size());
+ if (hidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) {
+ return false;
+ }
+ legacy_info->length = hidl_info.civicInfo.size();
+ memcpy(legacy_info->civic_info, hidl_info.civicInfo.c_str(),
+ hidl_info.civicInfo.size());
+ return true;
+}
+
+bool convertHidlRttResponderToLegacy(
+ const RttResponder& hidl_responder,
+ legacy_hal::wifi_rtt_responder* legacy_responder) {
+ if (!legacy_responder) {
+ return false;
+ }
+ *legacy_responder = {};
+ if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel,
+ &legacy_responder->channel)) {
+ return false;
+ }
+ legacy_responder->preamble =
+ convertHidlRttPreambleToLegacy(hidl_responder.preamble);
+ return true;
+}
+
+bool convertLegacyRttResponderToHidl(
+ const legacy_hal::wifi_rtt_responder& legacy_responder,
+ RttResponder* hidl_responder) {
+ if (!hidl_responder) {
+ return false;
+ }
+ *hidl_responder = {};
+ if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel,
+ &hidl_responder->channel)) {
+ return false;
+ }
+ hidl_responder->preamble =
+ convertLegacyRttPreambleToHidl(legacy_responder.preamble);
+ return true;
+}
+
+bool convertLegacyRttCapabilitiesToHidl(
+ const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+ RttCapabilities* hidl_capabilities) {
+ if (!hidl_capabilities) {
+ return false;
+ }
+ *hidl_capabilities = {};
+ hidl_capabilities->rttOneSidedSupported =
+ legacy_capabilities.rtt_one_sided_supported;
+ hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
+ hidl_capabilities->lciSupported = legacy_capabilities.lci_support;
+ hidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
+ hidl_capabilities->responderSupported =
+ legacy_capabilities.responder_supported;
+ hidl_capabilities->preambleSupport = 0;
+ for (const auto flag :
+ {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY,
+ legacy_hal::WIFI_RTT_PREAMBLE_HT, legacy_hal::WIFI_RTT_PREAMBLE_VHT,
+ legacy_hal::WIFI_RTT_PREAMBLE_HE}) {
+ if (legacy_capabilities.preamble_support & flag) {
+ hidl_capabilities->preambleSupport |=
+ static_cast<std::underlying_type<RttPreamble>::type>(
+ convertLegacyRttPreambleToHidl(flag));
+ }
+ }
+ hidl_capabilities->bwSupport = 0;
+ for (const auto flag :
+ {legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10,
+ legacy_hal::WIFI_RTT_BW_20, legacy_hal::WIFI_RTT_BW_40,
+ legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160}) {
+ if (legacy_capabilities.bw_support & flag) {
+ hidl_capabilities->bwSupport |=
+ static_cast<std::underlying_type<RttBw>::type>(
+ convertLegacyRttBwToHidl(flag));
+ }
+ }
+ hidl_capabilities->mcVersion = legacy_capabilities.mc_version;
+ return true;
+}
+
+bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
+ WifiRateInfo* hidl_rate) {
+ if (!hidl_rate) {
+ return false;
+ }
+ *hidl_rate = {};
+ hidl_rate->preamble =
+ convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
+ hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
+ hidl_rate->bw = convertLegacyWifiChannelWidthToHidl(
+ static_cast<legacy_hal::wifi_channel_width>(legacy_rate.bw));
+ hidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx;
+ hidl_rate->bitRateInKbps = legacy_rate.bitrate;
+ return true;
+}
+
+bool convertLegacyRttResultToHidl(
+ const legacy_hal::wifi_rtt_result& legacy_result, RttResult* hidl_result) {
+ if (!hidl_result) {
+ return false;
+ }
+ *hidl_result = {};
+ CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
+ memcpy(hidl_result->addr.data(), legacy_result.addr,
+ sizeof(legacy_result.addr));
+ hidl_result->burstNum = legacy_result.burst_num;
+ hidl_result->measurementNumber = legacy_result.measurement_number;
+ hidl_result->successNumber = legacy_result.success_number;
+ hidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer;
+ hidl_result->status = convertLegacyRttStatusToHidl(legacy_result.status);
+ hidl_result->retryAfterDuration = legacy_result.retry_after_duration;
+ hidl_result->type = convertLegacyRttTypeToHidl(legacy_result.type);
+ hidl_result->rssi = legacy_result.rssi;
+ hidl_result->rssiSpread = legacy_result.rssi_spread;
+ if (!convertLegacyWifiRateInfoToHidl(legacy_result.tx_rate,
+ &hidl_result->txRate)) {
+ return false;
+ }
+ if (!convertLegacyWifiRateInfoToHidl(legacy_result.rx_rate,
+ &hidl_result->rxRate)) {
+ return false;
+ }
+ hidl_result->rtt = legacy_result.rtt;
+ hidl_result->rttSd = legacy_result.rtt_sd;
+ hidl_result->rttSpread = legacy_result.rtt_spread;
+ hidl_result->distanceInMm = legacy_result.distance_mm;
+ hidl_result->distanceSdInMm = legacy_result.distance_sd_mm;
+ hidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm;
+ hidl_result->timeStampInUs = legacy_result.ts;
+ hidl_result->burstDurationInMs = legacy_result.burst_duration;
+ hidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num;
+ if (legacy_result.LCI &&
+ !convertLegacyIeToHidl(*legacy_result.LCI, &hidl_result->lci)) {
+ return false;
+ }
+ if (legacy_result.LCR &&
+ !convertLegacyIeToHidl(*legacy_result.LCR, &hidl_result->lcr)) {
+ return false;
+ }
+ return true;
+}
+
+bool convertLegacyVectorOfRttResultToHidl(
+ const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+ std::vector<RttResult>* hidl_results) {
+ if (!hidl_results) {
+ return false;
+ }
+ *hidl_results = {};
+ for (const auto legacy_result : legacy_results) {
+ RttResult hidl_result;
+ if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
+ return false;
+ }
+ hidl_results->push_back(hidl_result);
+ }
+ return true;
+}
+} // namespace hidl_struct_util
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h
new file mode 100644
index 0000000..d040c1f
--- /dev/null
+++ b/wifi/1.4/default/hidl_struct_util.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_STRUCT_UTIL_H_
+#define HIDL_STRUCT_UTIL_H_
+
+#include <vector>
+
+#include <android/hardware/wifi/1.0/IWifiChip.h>
+#include <android/hardware/wifi/1.0/types.h>
+#include <android/hardware/wifi/1.2/types.h>
+#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/types.h>
+
+#include "wifi_legacy_hal.h"
+
+/**
+ * This file contains a bunch of functions to convert structs from the legacy
+ * HAL to HIDL and vice versa.
+ * TODO(b/32093047): Add unit tests for these conversion methods in the VTS test
+ * suite.
+ */
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace hidl_struct_util {
+using namespace android::hardware::wifi::V1_0;
+
+// Chip conversion methods.
+bool convertLegacyFeaturesToHidlChipCapabilities(
+ uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+ uint32_t* hidl_caps);
+bool convertLegacyDebugRingBufferStatusToHidl(
+ const legacy_hal::wifi_ring_buffer_status& legacy_status,
+ WifiDebugRingBufferStatus* hidl_status);
+bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
+ const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+ std::vector<WifiDebugRingBufferStatus>* hidl_status_vec);
+bool convertLegacyWakeReasonStatsToHidl(
+ const legacy_hal::WakeReasonStats& legacy_stats,
+ WifiDebugHostWakeReasonStats* hidl_stats);
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
+ V1_1::IWifiChip::TxPowerScenario hidl_scenario);
+legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
+ V1_3::IWifiChip::LatencyMode hidl_latency_mode);
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+ V1_2::IWifiChip::TxPowerScenario hidl_scenario);
+bool convertLegacyWifiMacInfosToHidl(
+ const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+ std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
+
+// STA iface conversion methods.
+bool convertLegacyFeaturesToHidlStaCapabilities(
+ uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+ uint32_t* hidl_caps);
+bool convertLegacyApfCapabilitiesToHidl(
+ const legacy_hal::PacketFilterCapabilities& legacy_caps,
+ StaApfPacketFilterCapabilities* hidl_caps);
+bool convertLegacyGscanCapabilitiesToHidl(
+ const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+ StaBackgroundScanCapabilities* hidl_caps);
+legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band);
+bool convertHidlGscanParamsToLegacy(
+ const StaBackgroundScanParameters& hidl_scan_params,
+ legacy_hal::wifi_scan_cmd_params* legacy_scan_params);
+// |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11
+// Information Elements (IEs)
+bool convertLegacyGscanResultToHidl(
+ const legacy_hal::wifi_scan_result& legacy_scan_result, bool has_ie_data,
+ StaScanResult* hidl_scan_result);
+// |cached_results| is assumed to not include IEs.
+bool convertLegacyVectorOfCachedGscanResultsToHidl(
+ const std::vector<legacy_hal::wifi_cached_scan_results>&
+ legacy_cached_scan_results,
+ std::vector<StaScanData>* hidl_scan_datas);
+bool convertLegacyLinkLayerStatsToHidl(
+ const legacy_hal::LinkLayerStats& legacy_stats,
+ V1_3::StaLinkLayerStats* hidl_stats);
+bool convertLegacyRoamingCapabilitiesToHidl(
+ const legacy_hal::wifi_roaming_capabilities& legacy_caps,
+ StaRoamingCapabilities* hidl_caps);
+bool convertHidlRoamingConfigToLegacy(
+ const StaRoamingConfig& hidl_config,
+ legacy_hal::wifi_roaming_config* legacy_config);
+legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
+ StaRoamingState state);
+bool convertLegacyVectorOfDebugTxPacketFateToHidl(
+ const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+ std::vector<WifiDebugTxPacketFateReport>* hidl_fates);
+bool convertLegacyVectorOfDebugRxPacketFateToHidl(
+ const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+ std::vector<WifiDebugRxPacketFateReport>* hidl_fates);
+
+// NAN iface conversion methods.
+void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
+ size_t max_len, WifiNanStatus* wifiNanStatus);
+bool convertHidlNanEnableRequestToLegacy(
+ const NanEnableRequest& hidl_request,
+ legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequestToLegacy(
+ const NanConfigRequest& hidl_request,
+ legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanEnableRequest_1_4ToLegacy(
+ const NanEnableRequest& hidl_request1,
+ const V1_2::NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequest_1_4ToLegacy(
+ const NanConfigRequest& hidl_request1,
+ const V1_2::NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanPublishRequestToLegacy(
+ const NanPublishRequest& hidl_request,
+ legacy_hal::NanPublishRequest* legacy_request);
+bool convertHidlNanSubscribeRequestToLegacy(
+ const NanSubscribeRequest& hidl_request,
+ legacy_hal::NanSubscribeRequest* legacy_request);
+bool convertHidlNanTransmitFollowupRequestToLegacy(
+ const NanTransmitFollowupRequest& hidl_request,
+ legacy_hal::NanTransmitFollowupRequest* legacy_request);
+bool convertHidlNanDataPathInitiatorRequestToLegacy(
+ const NanInitiateDataPathRequest& hidl_request,
+ legacy_hal::NanDataPathInitiatorRequest* legacy_request);
+bool convertHidlNanDataPathIndicationResponseToLegacy(
+ const NanRespondToDataPathIndicationRequest& hidl_response,
+ legacy_hal::NanDataPathIndicationResponse* legacy_response);
+bool convertLegacyNanResponseHeaderToHidl(
+ const legacy_hal::NanResponseMsg& legacy_response,
+ WifiNanStatus* wifiNanStatus);
+bool convertLegacyNanCapabilitiesResponseToHidl(
+ const legacy_hal::NanCapabilities& legacy_response,
+ NanCapabilities* hidl_response);
+bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
+ NanMatchInd* hidl_ind);
+bool convertLegacyNanFollowupIndToHidl(
+ const legacy_hal::NanFollowupInd& legacy_ind,
+ NanFollowupReceivedInd* hidl_ind);
+bool convertLegacyNanDataPathRequestIndToHidl(
+ const legacy_hal::NanDataPathRequestInd& legacy_ind,
+ NanDataPathRequestInd* hidl_ind);
+bool convertLegacyNanDataPathConfirmIndToHidl(
+ const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+ V1_2::NanDataPathConfirmInd* hidl_ind);
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+ const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+ V1_2::NanDataPathScheduleUpdateInd* hidl_ind);
+
+// RTT controller conversion methods.
+bool convertHidlVectorOfRttConfigToLegacy(
+ const std::vector<RttConfig>& hidl_configs,
+ std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
+bool convertHidlRttLciInformationToLegacy(
+ const RttLciInformation& hidl_info,
+ legacy_hal::wifi_lci_information* legacy_info);
+bool convertHidlRttLcrInformationToLegacy(
+ const RttLcrInformation& hidl_info,
+ legacy_hal::wifi_lcr_information* legacy_info);
+bool convertHidlRttResponderToLegacy(
+ const RttResponder& hidl_responder,
+ legacy_hal::wifi_rtt_responder* legacy_responder);
+bool convertHidlWifiChannelInfoToLegacy(
+ const WifiChannelInfo& hidl_info,
+ legacy_hal::wifi_channel_info* legacy_info);
+bool convertLegacyRttResponderToHidl(
+ const legacy_hal::wifi_rtt_responder& legacy_responder,
+ RttResponder* hidl_responder);
+bool convertLegacyRttCapabilitiesToHidl(
+ const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+ RttCapabilities* hidl_capabilities);
+bool convertLegacyVectorOfRttResultToHidl(
+ const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+ std::vector<RttResult>* hidl_results);
+} // namespace hidl_struct_util
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // HIDL_STRUCT_UTIL_H_
diff --git a/wifi/1.4/default/hidl_sync_util.cpp b/wifi/1.4/default/hidl_sync_util.cpp
new file mode 100644
index 0000000..593a3bc
--- /dev/null
+++ b/wifi/1.4/default/hidl_sync_util.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#include "hidl_sync_util.h"
+
+namespace {
+std::recursive_mutex g_mutex;
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace hidl_sync_util {
+
+std::unique_lock<std::recursive_mutex> acquireGlobalLock() {
+ return std::unique_lock<std::recursive_mutex>{g_mutex};
+}
+
+} // namespace hidl_sync_util
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/hidl_sync_util.h b/wifi/1.4/default/hidl_sync_util.h
new file mode 100644
index 0000000..0244421
--- /dev/null
+++ b/wifi/1.4/default/hidl_sync_util.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_SYNC_UTIL_H_
+#define HIDL_SYNC_UTIL_H_
+
+#include <mutex>
+
+// Utility that provides a global lock to synchronize access between
+// the HIDL thread and the legacy HAL's event loop.
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace hidl_sync_util {
+std::unique_lock<std::recursive_mutex> acquireGlobalLock();
+} // namespace hidl_sync_util
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+#endif // HIDL_SYNC_UTIL_H_
diff --git a/wifi/1.4/default/ringbuffer.cpp b/wifi/1.4/default/ringbuffer.cpp
new file mode 100644
index 0000000..0fe8ef4
--- /dev/null
+++ b/wifi/1.4/default/ringbuffer.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "ringbuffer.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
+
+void Ringbuffer::append(const std::vector<uint8_t>& input) {
+ if (input.size() == 0) {
+ return;
+ }
+ if (input.size() > maxSize_) {
+ LOG(INFO) << "Oversized message of " << input.size()
+ << " bytes is dropped";
+ return;
+ }
+ data_.push_back(input);
+ size_ += input.size() * sizeof(input[0]);
+ while (size_ > maxSize_) {
+ size_ -= data_.front().size() * sizeof(data_.front()[0]);
+ data_.pop_front();
+ }
+}
+
+const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
+ return data_;
+}
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/ringbuffer.h b/wifi/1.4/default/ringbuffer.h
new file mode 100644
index 0000000..ddce648
--- /dev/null
+++ b/wifi/1.4/default/ringbuffer.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RINGBUFFER_H_
+#define RINGBUFFER_H_
+
+#include <list>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+/**
+ * Ringbuffer object used to store debug data.
+ */
+class Ringbuffer {
+ public:
+ explicit Ringbuffer(size_t maxSize);
+
+ // Appends the data buffer and deletes from the front until buffer is
+ // within |maxSize_|.
+ void append(const std::vector<uint8_t>& input);
+ const std::list<std::vector<uint8_t>>& getData() const;
+
+ private:
+ std::list<std::vector<uint8_t>> data_;
+ size_t size_;
+ size_t maxSize_;
+};
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // RINGBUFFER_H_
diff --git a/wifi/1.4/default/service.cpp b/wifi/1.4/default/service.cpp
new file mode 100644
index 0000000..3f7f609
--- /dev/null
+++ b/wifi/1.4/default/service.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <hidl/HidlLazyUtils.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+#include "wifi.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::LazyServiceRegistrar;
+using android::hardware::wifi::V1_4::implementation::feature_flags::
+ WifiFeatureFlags;
+using android::hardware::wifi::V1_4::implementation::iface_util::WifiIfaceUtil;
+using android::hardware::wifi::V1_4::implementation::legacy_hal::WifiLegacyHal;
+using android::hardware::wifi::V1_4::implementation::mode_controller::
+ WifiModeController;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main(int /*argc*/, char** argv) {
+ android::base::InitLogging(
+ argv, android::base::LogdLogger(android::base::SYSTEM));
+ LOG(INFO) << "Wifi Hal is booting up...";
+
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ const auto iface_tool =
+ std::make_shared<android::wifi_system::InterfaceTool>();
+ // Setup hwbinder service
+ android::sp<android::hardware::wifi::V1_4::IWifi> service =
+ new android::hardware::wifi::V1_4::implementation::Wifi(
+ iface_tool, std::make_shared<WifiLegacyHal>(iface_tool),
+ std::make_shared<WifiModeController>(),
+ std::make_shared<WifiIfaceUtil>(iface_tool),
+ std::make_shared<WifiFeatureFlags>());
+ if (kLazyService) {
+ auto registrar = LazyServiceRegistrar::getInstance();
+ CHECK_EQ(registrar.registerService(service), android::NO_ERROR)
+ << "Failed to register wifi HAL";
+ } else {
+ CHECK_EQ(service->registerAsService(), android::NO_ERROR)
+ << "Failed to register wifi HAL";
+ }
+
+ joinRpcThreadpool();
+
+ LOG(INFO) << "Wifi Hal is terminating...";
+ return 0;
+}
diff --git a/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
new file mode 100644
index 0000000..b71d549
--- /dev/null
+++ b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN
+#include "hidl_struct_util.h"
+
+using testing::Test;
+
+namespace {
+constexpr uint32_t kMacId1 = 1;
+constexpr uint32_t kMacId2 = 2;
+constexpr uint32_t kIfaceChannel1 = 3;
+constexpr uint32_t kIfaceChannel2 = 5;
+constexpr char kIfaceName1[] = "wlan0";
+constexpr char kIfaceName2[] = "wlan1";
+} // namespace
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
+
+class HidlStructUtilTest : public Test {};
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) {
+ std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+ legacy_hal::WifiMacInfo legacy_mac_info1 = {
+ .wlan_mac_id = kMacId1,
+ .mac_band =
+ legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
+ legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
+ .channel = kIfaceChannel1};
+ legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
+ .channel = kIfaceChannel2};
+ legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+ legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
+ legacy_mac_infos.push_back(legacy_mac_info1);
+
+ std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+ ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+ legacy_mac_infos, &hidl_radio_mode_infos));
+
+ ASSERT_EQ(1u, hidl_radio_mode_infos.size());
+ auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
+ EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
+ EXPECT_EQ(WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
+ ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
+ auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
+ EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+ EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
+ hidl_iface_info1.channel);
+ auto hidl_iface_info2 = hidl_radio_mode_info1.ifaceInfos[1];
+ EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+ EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
+ hidl_iface_info2.channel);
+}
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) {
+ std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+ legacy_hal::WifiMacInfo legacy_mac_info1 = {
+ .wlan_mac_id = kMacId1, .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
+ legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
+ .channel = kIfaceChannel1};
+ legacy_hal::WifiMacInfo legacy_mac_info2 = {
+ .wlan_mac_id = kMacId2, .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
+ legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
+ .channel = kIfaceChannel2};
+ legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+ legacy_mac_infos.push_back(legacy_mac_info1);
+ legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
+ legacy_mac_infos.push_back(legacy_mac_info2);
+
+ std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+ ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+ legacy_mac_infos, &hidl_radio_mode_infos));
+
+ ASSERT_EQ(2u, hidl_radio_mode_infos.size());
+
+ // Find mac info 1.
+ const auto hidl_radio_mode_info1 = std::find_if(
+ hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+ [&legacy_mac_info1](const IWifiChipEventCallback::RadioModeInfo& x) {
+ return x.radioId == legacy_mac_info1.wlan_mac_id;
+ });
+ ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
+ EXPECT_EQ(WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
+ ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
+ auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
+ EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+ EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
+ hidl_iface_info1.channel);
+
+ // Find mac info 2.
+ const auto hidl_radio_mode_info2 = std::find_if(
+ hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+ [&legacy_mac_info2](const IWifiChipEventCallback::RadioModeInfo& x) {
+ return x.radioId == legacy_mac_info2.wlan_mac_id;
+ });
+ ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
+ EXPECT_EQ(WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
+ ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
+ auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
+ EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+ EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
+ hidl_iface_info2.channel);
+}
+
+TEST_F(HidlStructUtilTest, canConvertLegacyLinkLayerStatsToHidl) {
+ legacy_hal::LinkLayerStats legacy_stats{};
+ legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+ legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+ legacy_stats.iface.beacon_rx = rand();
+ legacy_stats.iface.rssi_mgmt = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries = rand();
+
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries = rand();
+
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries = rand();
+
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand();
+
+ for (auto& radio : legacy_stats.radios) {
+ radio.stats.on_time = rand();
+ radio.stats.tx_time = rand();
+ radio.stats.rx_time = rand();
+ radio.stats.on_time_scan = rand();
+ radio.stats.on_time_nbd = rand();
+ radio.stats.on_time_gscan = rand();
+ radio.stats.on_time_roam_scan = rand();
+ radio.stats.on_time_pno_scan = rand();
+ radio.stats.on_time_hs20 = rand();
+ for (int i = 0; i < 4; i++) {
+ radio.tx_time_per_levels.push_back(rand());
+ }
+
+ legacy_hal::wifi_channel_stat channel_stat1 = {
+ .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
+ .on_time = 0x1111,
+ .cca_busy_time = 0x55,
+ };
+ legacy_hal::wifi_channel_stat channel_stat2 = {
+ .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
+ .on_time = 0x2222,
+ .cca_busy_time = 0x66,
+ };
+ radio.channel_stats.push_back(channel_stat1);
+ radio.channel_stats.push_back(channel_stat2);
+ }
+
+ V1_3::StaLinkLayerStats converted{};
+ hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
+ &converted);
+ EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.beaconRx);
+ EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.avgRssiMgmt);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
+ converted.iface.wmeBePktStats.rxMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
+ converted.iface.wmeBePktStats.txMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
+ converted.iface.wmeBePktStats.lostMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
+ converted.iface.wmeBePktStats.retries);
+
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
+ converted.iface.wmeBkPktStats.rxMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
+ converted.iface.wmeBkPktStats.txMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
+ converted.iface.wmeBkPktStats.lostMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
+ converted.iface.wmeBkPktStats.retries);
+
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
+ converted.iface.wmeViPktStats.rxMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
+ converted.iface.wmeViPktStats.txMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
+ converted.iface.wmeViPktStats.lostMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
+ converted.iface.wmeViPktStats.retries);
+
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
+ converted.iface.wmeVoPktStats.rxMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
+ converted.iface.wmeVoPktStats.txMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
+ converted.iface.wmeVoPktStats.lostMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
+ converted.iface.wmeVoPktStats.retries);
+
+ EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
+ for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time,
+ converted.radios[i].V1_0.onTimeInMs);
+ EXPECT_EQ(legacy_stats.radios[i].stats.tx_time,
+ converted.radios[i].V1_0.txTimeInMs);
+ EXPECT_EQ(legacy_stats.radios[i].stats.rx_time,
+ converted.radios[i].V1_0.rxTimeInMs);
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
+ converted.radios[i].V1_0.onTimeInMsForScan);
+ EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
+ converted.radios[i].V1_0.txTimeInMsPerLevel.size());
+ for (size_t j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size();
+ j++) {
+ EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
+ converted.radios[i].V1_0.txTimeInMsPerLevel[j]);
+ }
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
+ converted.radios[i].onTimeInMsForNanScan);
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
+ converted.radios[i].onTimeInMsForBgScan);
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
+ converted.radios[i].onTimeInMsForRoamScan);
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
+ converted.radios[i].onTimeInMsForPnoScan);
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
+ converted.radios[i].onTimeInMsForHs20Scan);
+ EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(),
+ converted.radios[i].channelStats.size());
+ for (size_t k = 0; k < legacy_stats.radios[i].channel_stats.size();
+ k++) {
+ auto& legacy_channel_st = legacy_stats.radios[i].channel_stats[k];
+ EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
+ converted.radios[i].channelStats[k].channel.width);
+ EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq),
+ converted.radios[i].channelStats[k].channel.centerFreq);
+ EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq0),
+ converted.radios[i].channelStats[k].channel.centerFreq0);
+ EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq1),
+ converted.radios[i].channelStats[k].channel.centerFreq1);
+ EXPECT_EQ(legacy_channel_st.cca_busy_time,
+ converted.radios[i].channelStats[k].ccaBusyTimeInMs);
+ EXPECT_EQ(legacy_channel_st.on_time,
+ converted.radios[i].channelStats[k].onTimeInMs);
+ }
+ }
+}
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyFeaturesToHidl) {
+ using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
+
+ uint32_t hidle_caps;
+
+ uint32_t legacy_feature_set =
+ WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE;
+ uint32_t legacy_logger_feature_set =
+ legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
+
+ ASSERT_TRUE(hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
+ legacy_feature_set, legacy_logger_feature_set, &hidle_caps));
+
+ EXPECT_EQ(HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA |
+ HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS |
+ HidlChipCaps::DEBUG_ERROR_ALERTS | HidlChipCaps::D2D_RTT |
+ HidlChipCaps::SET_LATENCY_MODE |
+ HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP,
+ hidle_caps);
+}
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.3/default/tests/main.cpp b/wifi/1.4/default/tests/main.cpp
similarity index 100%
rename from wifi/1.3/default/tests/main.cpp
rename to wifi/1.4/default/tests/main.cpp
diff --git a/wifi/1.3/default/tests/mock_interface_tool.cpp b/wifi/1.4/default/tests/mock_interface_tool.cpp
similarity index 100%
rename from wifi/1.3/default/tests/mock_interface_tool.cpp
rename to wifi/1.4/default/tests/mock_interface_tool.cpp
diff --git a/wifi/1.3/default/tests/mock_interface_tool.h b/wifi/1.4/default/tests/mock_interface_tool.h
similarity index 100%
rename from wifi/1.3/default/tests/mock_interface_tool.h
rename to wifi/1.4/default/tests/mock_interface_tool.h
diff --git a/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
new file mode 100644
index 0000000..b1fa432
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+
+#include "mock_wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace feature_flags {
+
+MockWifiFeatureFlags::MockWifiFeatureFlags() {}
+
+} // namespace feature_flags
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_feature_flags.h b/wifi/1.4/default/tests/mock_wifi_feature_flags.h
new file mode 100644
index 0000000..72d2304
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_feature_flags.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_FEATURE_FLAGS_H_
+#define MOCK_WIFI_FEATURE_FLAGS_H_
+
+#include <gmock/gmock.h>
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+
+#include "wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace feature_flags {
+
+class MockWifiFeatureFlags : public WifiFeatureFlags {
+ public:
+ MockWifiFeatureFlags();
+
+ MOCK_METHOD0(getChipModes, std::vector<V1_0::IWifiChip::ChipMode>());
+ MOCK_METHOD0(isApMacRandomizationDisabled, bool());
+};
+
+} // namespace feature_flags
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // MOCK_WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.4/default/tests/mock_wifi_iface_util.cpp b/wifi/1.4/default/tests/mock_wifi_iface_util.cpp
new file mode 100644
index 0000000..0968569
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_iface_util.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_iface_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace iface_util {
+
+MockWifiIfaceUtil::MockWifiIfaceUtil(
+ const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+ : WifiIfaceUtil(iface_tool) {}
+} // namespace iface_util
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_iface_util.h b/wifi/1.4/default/tests/mock_wifi_iface_util.h
new file mode 100644
index 0000000..6cc81e4
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_iface_util.h
@@ -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.
+ */
+
+#ifndef MOCK_WIFI_IFACE_UTIL_H_
+#define MOCK_WIFI_IFACE_UTIL_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_iface_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace iface_util {
+
+class MockWifiIfaceUtil : public WifiIfaceUtil {
+ public:
+ MockWifiIfaceUtil(
+ const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+ MOCK_METHOD1(getFactoryMacAddress,
+ std::array<uint8_t, 6>(const std::string&));
+ MOCK_METHOD2(setMacAddress,
+ bool(const std::string&, const std::array<uint8_t, 6>&));
+ MOCK_METHOD0(getOrCreateRandomMacAddress, std::array<uint8_t, 6>());
+ MOCK_METHOD2(registerIfaceEventHandlers,
+ void(const std::string&, IfaceEventHandlers));
+ MOCK_METHOD1(unregisterIfaceEventHandlers, void(const std::string&));
+};
+} // namespace iface_util
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // MOCK_WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp
new file mode 100644
index 0000000..8d65c59
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace legacy_hal {
+
+MockWifiLegacyHal::MockWifiLegacyHal(
+ const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+ : WifiLegacyHal(iface_tool) {}
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_legacy_hal.h b/wifi/1.4/default/tests/mock_wifi_legacy_hal.h
new file mode 100644
index 0000000..6942c1e
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_legacy_hal.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_LEGACY_HAL_H_
+#define MOCK_WIFI_LEGACY_HAL_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace legacy_hal {
+
+class MockWifiLegacyHal : public WifiLegacyHal {
+ public:
+ MockWifiLegacyHal(
+ const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+ MOCK_METHOD0(initialize, wifi_error());
+ MOCK_METHOD0(start, wifi_error());
+ MOCK_METHOD2(stop, wifi_error(std::unique_lock<std::recursive_mutex>*,
+ const std::function<void()>&));
+ MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool));
+ MOCK_METHOD2(registerRadioModeChangeCallbackHandler,
+ wifi_error(const std::string&,
+ const on_radio_mode_change_callback&));
+ MOCK_METHOD1(getFirmwareVersion, std::pair<wifi_error, std::string>(
+ const std::string& iface_name));
+ MOCK_METHOD1(getDriverVersion, std::pair<wifi_error, std::string>(
+ const std::string& iface_name));
+
+ MOCK_METHOD2(selectTxPowerScenario,
+ wifi_error(const std::string& iface_name,
+ wifi_power_scenario scenario));
+ MOCK_METHOD1(resetTxPowerScenario,
+ wifi_error(const std::string& iface_name));
+ MOCK_METHOD2(nanRegisterCallbackHandlers,
+ wifi_error(const std::string&, const NanCallbackHandlers&));
+ MOCK_METHOD2(nanDisableRequest,
+ wifi_error(const std::string&, transaction_id));
+ MOCK_METHOD3(nanDataInterfaceDelete,
+ wifi_error(const std::string&, transaction_id,
+ const std::string&));
+};
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // MOCK_WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp
new file mode 100644
index 0000000..ee09029
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace mode_controller {
+
+MockWifiModeController::MockWifiModeController() : WifiModeController() {}
+} // namespace mode_controller
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_mode_controller.h b/wifi/1.4/default/tests/mock_wifi_mode_controller.h
new file mode 100644
index 0000000..1e1ce69
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_mode_controller.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_MODE_CONTROLLER_H_
+#define MOCK_WIFI_MODE_CONTROLLER_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace mode_controller {
+
+class MockWifiModeController : public WifiModeController {
+ public:
+ MockWifiModeController();
+ MOCK_METHOD0(initialize, bool());
+ MOCK_METHOD1(changeFirmwareMode, bool(IfaceType));
+ MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType));
+ MOCK_METHOD0(deinitialize, bool());
+};
+} // namespace mode_controller
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // MOCK_WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp
new file mode 100644
index 0000000..a65347f
--- /dev/null
+++ b/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+
+#include "ringbuffer.h"
+
+using testing::Return;
+using testing::Test;
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+class RingbufferTest : public Test {
+ public:
+ const uint32_t maxBufferSize_ = 10;
+ Ringbuffer buffer_{maxBufferSize_};
+};
+
+TEST_F(RingbufferTest, CreateEmptyBuffer) {
+ ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, CanUseFullBufferCapacity) {
+ const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+ const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+ buffer_.append(input);
+ buffer_.append(input2);
+ ASSERT_EQ(2u, buffer_.getData().size());
+ EXPECT_EQ(input, buffer_.getData().front());
+ EXPECT_EQ(input2, buffer_.getData().back());
+}
+
+TEST_F(RingbufferTest, OldDataIsRemovedOnOverflow) {
+ const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+ const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+ const std::vector<uint8_t> input3 = {'G'};
+ buffer_.append(input);
+ buffer_.append(input2);
+ buffer_.append(input3);
+ ASSERT_EQ(2u, buffer_.getData().size());
+ EXPECT_EQ(input2, buffer_.getData().front());
+ EXPECT_EQ(input3, buffer_.getData().back());
+}
+
+TEST_F(RingbufferTest, MultipleOldDataIsRemovedOnOverflow) {
+ const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+ const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+ const std::vector<uint8_t> input3(maxBufferSize_, '2');
+ buffer_.append(input);
+ buffer_.append(input2);
+ buffer_.append(input3);
+ ASSERT_EQ(1u, buffer_.getData().size());
+ EXPECT_EQ(input3, buffer_.getData().front());
+}
+
+TEST_F(RingbufferTest, AppendingEmptyBufferDoesNotAddGarbage) {
+ const std::vector<uint8_t> input = {};
+ buffer_.append(input);
+ ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, OversizedAppendIsDropped) {
+ const std::vector<uint8_t> input(maxBufferSize_ + 1, '0');
+ buffer_.append(input);
+ ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) {
+ const std::vector<uint8_t> input(maxBufferSize_, '0');
+ const std::vector<uint8_t> input2(maxBufferSize_ + 1, '1');
+ buffer_.append(input);
+ buffer_.append(input2);
+ ASSERT_EQ(1u, buffer_.getData().size());
+ EXPECT_EQ(input, buffer_.getData().front());
+}
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.3/default/tests/runtests.sh b/wifi/1.4/default/tests/runtests.sh
similarity index 100%
rename from wifi/1.3/default/tests/runtests.sh
rename to wifi/1.4/default/tests/runtests.sh
diff --git a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
new file mode 100644
index 0000000..d35adbc
--- /dev/null
+++ b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
@@ -0,0 +1,875 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "wifi_chip.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_feature_flags.h"
+#include "mock_wifi_iface_util.h"
+#include "mock_wifi_legacy_hal.h"
+#include "mock_wifi_mode_controller.h"
+
+using testing::NiceMock;
+using testing::Return;
+using testing::Test;
+
+namespace {
+using android::hardware::wifi::V1_0::ChipId;
+
+constexpr ChipId kFakeChipId = 5;
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+class WifiChipTest : public Test {
+ protected:
+ void setupV1IfaceCombination() {
+ // clang-format off
+ const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
+ {{{{IfaceType::STA}, 1}, {{IfaceType::P2P}, 1}}}
+ };
+ const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = {
+ {{{{IfaceType::AP}, 1}}}
+ };
+ const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+ {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
+ {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
+ };
+ // clang-format on
+ EXPECT_CALL(*feature_flags_, getChipModes())
+ .WillRepeatedly(testing::Return(modes));
+ }
+
+ void setupV1_AwareIfaceCombination() {
+ // clang-format off
+ const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
+ {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
+ };
+ const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = {
+ {{{{IfaceType::AP}, 1}}}
+ };
+ const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+ {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
+ {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
+ };
+ // clang-format on
+ EXPECT_CALL(*feature_flags_, getChipModes())
+ .WillRepeatedly(testing::Return(modes));
+ }
+
+ void setupV1_AwareDisabledApIfaceCombination() {
+ // clang-format off
+ const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
+ {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
+ };
+ const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+ {feature_flags::chip_mode_ids::kV1Sta, combinationsSta}
+ };
+ // clang-format on
+ EXPECT_CALL(*feature_flags_, getChipModes())
+ .WillRepeatedly(testing::Return(modes));
+ }
+
+ void setupV2_AwareIfaceCombination() {
+ // clang-format off
+ const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
+ {{{{IfaceType::STA}, 1}, {{IfaceType::AP}, 1}}},
+ {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
+ };
+ const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+ {feature_flags::chip_mode_ids::kV3, combinations}
+ };
+ // clang-format on
+ EXPECT_CALL(*feature_flags_, getChipModes())
+ .WillRepeatedly(testing::Return(modes));
+ }
+
+ void setupV2_AwareDisabledApIfaceCombination() {
+ // clang-format off
+ const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
+ {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
+ };
+ const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+ {feature_flags::chip_mode_ids::kV3, combinations}
+ };
+ // clang-format on
+ EXPECT_CALL(*feature_flags_, getChipModes())
+ .WillRepeatedly(testing::Return(modes));
+ }
+
+ void setup_MultiIfaceCombination() {
+ // clang-format off
+ const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
+ {{{{IfaceType::STA}, 3}, {{IfaceType::AP}, 1}}}
+ };
+ const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+ {feature_flags::chip_mode_ids::kV3, combinations}
+ };
+ // clang-format on
+ EXPECT_CALL(*feature_flags_, getChipModes())
+ .WillRepeatedly(testing::Return(modes));
+ }
+
+ void assertNumberOfModes(uint32_t num_modes) {
+ chip_->getAvailableModes(
+ [num_modes](const WifiStatus& status,
+ const std::vector<WifiChip::ChipMode>& modes) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ // V2_Aware has 1 mode of operation.
+ ASSERT_EQ(num_modes, modes.size());
+ });
+ }
+
+ void findModeAndConfigureForIfaceType(const IfaceType& type) {
+ // This should be aligned with kInvalidModeId in wifi_chip.cpp.
+ ChipModeId mode_id = UINT32_MAX;
+ chip_->getAvailableModes(
+ [&mode_id, &type](const WifiStatus& status,
+ const std::vector<WifiChip::ChipMode>& modes) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ for (const auto& mode : modes) {
+ for (const auto& combination : mode.availableCombinations) {
+ for (const auto& limit : combination.limits) {
+ if (limit.types.end() !=
+ std::find(limit.types.begin(),
+ limit.types.end(), type)) {
+ mode_id = mode.id;
+ }
+ }
+ }
+ }
+ });
+ ASSERT_NE(UINT32_MAX, mode_id);
+
+ chip_->configureChip(mode_id, [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+ }
+
+ // Returns an empty string on error.
+ std::string createIface(const IfaceType& type) {
+ std::string iface_name;
+ if (type == IfaceType::AP) {
+ chip_->createApIface([&iface_name](
+ const WifiStatus& status,
+ const sp<V1_0::IWifiApIface>& iface) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(iface.get(), nullptr);
+ iface->getName([&iface_name](const WifiStatus& status,
+ const hidl_string& name) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ iface_name = name.c_str();
+ });
+ }
+ });
+ } else if (type == IfaceType::NAN) {
+ chip_->createNanIface(
+ [&iface_name](
+ const WifiStatus& status,
+ const sp<android::hardware::wifi::V1_0::IWifiNanIface>&
+ iface) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(iface.get(), nullptr);
+ iface->getName([&iface_name](const WifiStatus& status,
+ const hidl_string& name) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ iface_name = name.c_str();
+ });
+ }
+ });
+ } else if (type == IfaceType::P2P) {
+ chip_->createP2pIface(
+ [&iface_name](const WifiStatus& status,
+ const sp<IWifiP2pIface>& iface) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(iface.get(), nullptr);
+ iface->getName([&iface_name](const WifiStatus& status,
+ const hidl_string& name) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ iface_name = name.c_str();
+ });
+ }
+ });
+ } else if (type == IfaceType::STA) {
+ chip_->createStaIface(
+ [&iface_name](const WifiStatus& status,
+ const sp<V1_0::IWifiStaIface>& iface) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(iface.get(), nullptr);
+ iface->getName([&iface_name](const WifiStatus& status,
+ const hidl_string& name) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ iface_name = name.c_str();
+ });
+ }
+ });
+ }
+ return iface_name;
+ }
+
+ void removeIface(const IfaceType& type, const std::string& iface_name) {
+ if (type == IfaceType::AP) {
+ chip_->removeApIface(iface_name, [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+ } else if (type == IfaceType::NAN) {
+ chip_->removeNanIface(iface_name, [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+ } else if (type == IfaceType::P2P) {
+ chip_->removeP2pIface(iface_name, [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+ } else if (type == IfaceType::STA) {
+ chip_->removeStaIface(iface_name, [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+ }
+ }
+
+ bool createRttController() {
+ bool success = false;
+ chip_->createRttController_1_4(
+ NULL, [&success](const WifiStatus& status,
+ const sp<IWifiRttController>& rtt) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(rtt.get(), nullptr);
+ success = true;
+ }
+ });
+ return success;
+ }
+
+ sp<WifiChip> chip_;
+ ChipId chip_id_ = kFakeChipId;
+ std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
+ new NiceMock<wifi_system::MockInterfaceTool>};
+ std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+ new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
+ std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>>
+ mode_controller_{new NiceMock<mode_controller::MockWifiModeController>};
+ std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
+ new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
+ std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
+ feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
+
+ public:
+ void SetUp() override {
+ chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_,
+ iface_util_, feature_flags_);
+
+ EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*legacy_hal_, start())
+ .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
+ }
+
+ void TearDown() override {
+ // Restore default system iface names (This should ideally be using a
+ // mock).
+ property_set("wifi.interface", "wlan0");
+ property_set("wifi.concurrent.interface", "wlan1");
+ }
+};
+
+////////// V1 Iface Combinations ////////////
+// Mode 1 - STA + P2P
+// Mode 2 - AP
+class WifiChipV1IfaceCombinationTest : public WifiChipTest {
+ public:
+ void SetUp() override {
+ setupV1IfaceCombination();
+ WifiChipTest::SetUp();
+ // V1 has 2 modes of operation.
+ assertNumberOfModes(2u);
+ }
+};
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+////////// V1 + Aware Iface Combinations ////////////
+// Mode 1 - STA + P2P/NAN
+// Mode 2 - AP
+class WifiChipV1_AwareIfaceCombinationTest : public WifiChipTest {
+ public:
+ void SetUp() override {
+ setupV1_AwareIfaceCombination();
+ WifiChipTest::SetUp();
+ // V1_Aware has 2 modes of operation.
+ assertNumberOfModes(2u);
+ }
+};
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+ StaMode_CreateStaP2p_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+ StaMode_CreateStaNan_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+ StaMode_CreateStaP2PNan_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+ StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ const auto p2p_iface_name = createIface(IfaceType::P2P);
+ ASSERT_FALSE(p2p_iface_name.empty());
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+ // After removing P2P iface, NAN iface creation should succeed.
+ removeIface(IfaceType::P2P, p2p_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+ StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ const auto nan_iface_name = createIface(IfaceType::NAN);
+ ASSERT_FALSE(nan_iface_name.empty());
+ ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+ // After removing NAN iface, P2P iface creation should succeed.
+ removeIface(IfaceType::NAN, nan_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowApToSta) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ const auto ap_iface_name = createIface(IfaceType::AP);
+ ASSERT_FALSE(ap_iface_name.empty());
+ ASSERT_FALSE(createRttController());
+
+ removeIface(IfaceType::AP, ap_iface_name);
+
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+ .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+ chip_->selectTxPowerScenario_1_2(
+ V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+ [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+ EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+ .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+ chip_->selectTxPowerScenario_1_2(
+ V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+ [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+}
+
+////////// V2 + Aware Iface Combinations ////////////
+// Mode 1 - STA + STA/AP
+// - STA + P2P/NAN
+class WifiChipV2_AwareIfaceCombinationTest : public WifiChipTest {
+ public:
+ void SetUp() override {
+ setupV2_AwareIfaceCombination();
+ WifiChipTest::SetUp();
+ // V2_Aware has 1 mode of operation.
+ assertNumberOfModes(1u);
+ }
+};
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApSta_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+ CreateSta_AfterStaApRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ const auto sta_iface_name = createIface(IfaceType::STA);
+ ASSERT_FALSE(sta_iface_name.empty());
+ const auto ap_iface_name = createIface(IfaceType::AP);
+ ASSERT_FALSE(ap_iface_name.empty());
+
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+
+ // After removing AP & STA iface, STA iface creation should succeed.
+ removeIface(IfaceType::STA, sta_iface_name);
+ removeIface(IfaceType::AP, ap_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+ CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ const auto p2p_iface_name = createIface(IfaceType::P2P);
+ ASSERT_FALSE(p2p_iface_name.empty());
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+ // After removing P2P iface, NAN iface creation should succeed.
+ removeIface(IfaceType::P2P, p2p_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+ CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ const auto nan_iface_name = createIface(IfaceType::NAN);
+ ASSERT_FALSE(nan_iface_name.empty());
+ ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+ // After removing NAN iface, P2P iface creation should succeed.
+ removeIface(IfaceType::NAN, nan_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_FALSE(createIface(IfaceType::AP).empty());
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_FALSE(createIface(IfaceType::AP).empty());
+ ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+ StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ const auto p2p_iface_name = createIface(IfaceType::P2P);
+ ASSERT_FALSE(p2p_iface_name.empty());
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+ // After removing P2P iface, NAN iface creation should succeed.
+ removeIface(IfaceType::P2P, p2p_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+ StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ const auto nan_iface_name = createIface(IfaceType::NAN);
+ ASSERT_FALSE(nan_iface_name.empty());
+ ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+ // After removing NAN iface, P2P iface creation should succeed.
+ removeIface(IfaceType::NAN, nan_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+ CreateStaAp_EnsureDifferentIfaceNames) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ const auto sta_iface_name = createIface(IfaceType::STA);
+ const auto ap_iface_name = createIface(IfaceType::AP);
+ ASSERT_FALSE(sta_iface_name.empty());
+ ASSERT_FALSE(ap_iface_name.empty());
+ ASSERT_NE(sta_iface_name, ap_iface_name);
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlow) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::AP).empty());
+ ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+ .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+ chip_->selectTxPowerScenario_1_2(
+ V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+ [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
+ findModeAndConfigureForIfaceType(IfaceType::AP);
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+ EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan1", testing::_))
+ .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+ chip_->selectTxPowerScenario_1_2(
+ V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+ [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+ InvalidateAndRemoveNanOnStaRemove) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+
+ // Create NAN iface
+ ASSERT_EQ(createIface(IfaceType::NAN), "wlan0");
+
+ // We should have 1 nan iface.
+ chip_->getNanIfaceNames(
+ [](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ ASSERT_EQ(iface_names.size(), 1u);
+ ASSERT_EQ(iface_names[0], "wlan0");
+ });
+ // Retrieve the exact iface object.
+ 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");
+ // We should have 0 nan iface now.
+ chip_->getNanIfaceNames(
+ [](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ ASSERT_EQ(iface_names.size(), 0u);
+ });
+ // Any operation on the nan iface object should return error now.
+ nan_iface->getName(
+ [](const WifiStatus& status, const std::string& /* iface_name */) {
+ ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID, status.code);
+ });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+ InvalidateAndRemoveRttControllerOnStaRemove) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+
+ // Create RTT controller
+ sp<IWifiRttController> rtt_controller;
+ chip_->createRttController_1_4(
+ NULL, [&rtt_controller](const WifiStatus& status,
+ const sp<IWifiRttController>& rtt) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(rtt.get(), nullptr);
+ rtt_controller = rtt;
+ }
+ });
+
+ // Remove the STA iface.
+ removeIface(IfaceType::STA, "wlan0");
+
+ // Any operation on the rtt controller object should return error now.
+ rtt_controller->getBoundIface(
+ [](const WifiStatus& status, const sp<IWifiIface>& /* iface */) {
+ ASSERT_EQ(WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ status.code);
+ });
+}
+
+////////// V1 Iface Combinations when AP creation is disabled //////////
+class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
+ public:
+ void SetUp() override {
+ setupV1_AwareDisabledApIfaceCombination();
+ WifiChipTest::SetUp();
+ }
+};
+
+TEST_F(WifiChipV1_AwareDisabledApIfaceCombinationTest,
+ StaMode_CreateSta_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+////////// V2 Iface Combinations when AP creation is disabled //////////
+class WifiChipV2_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
+ public:
+ void SetUp() override {
+ setupV2_AwareDisabledApIfaceCombination();
+ WifiChipTest::SetUp();
+ }
+};
+
+TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest,
+ CreateSta_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+////////// Hypothetical Iface Combination with multiple ifaces //////////
+class WifiChip_MultiIfaceTest : public WifiChipTest {
+ public:
+ void SetUp() override {
+ setup_MultiIfaceCombination();
+ WifiChipTest::SetUp();
+ }
+};
+
+TEST_F(WifiChip_MultiIfaceTest, Create3Sta) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithDefaultNames) {
+ property_set("wifi.interface.0", "");
+ property_set("wifi.interface.1", "");
+ property_set("wifi.interface.2", "");
+ property_set("wifi.interface", "");
+ property_set("wifi.concurrent.interface", "");
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomNames) {
+ property_set("wifi.interface.0", "test0");
+ property_set("wifi.interface.1", "test1");
+ property_set("wifi.interface.2", "test2");
+ property_set("wifi.interface", "bad0");
+ property_set("wifi.concurrent.interface", "bad1");
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "bad0");
+ ASSERT_EQ(createIface(IfaceType::STA), "bad1");
+ ASSERT_EQ(createIface(IfaceType::STA), "test2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomAltNames) {
+ property_set("wifi.interface.0", "");
+ property_set("wifi.interface.1", "");
+ property_set("wifi.interface.2", "");
+ property_set("wifi.interface", "testA0");
+ property_set("wifi.concurrent.interface", "testA1");
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "testA0");
+ ASSERT_EQ(createIface(IfaceType::STA), "testA1");
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) {
+ findModeAndConfigureForIfaceType(IfaceType::STA);
+ // First AP will be slotted to wlan1.
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+ // First STA will be slotted to wlan0.
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ // All further STA will be slotted to the remaining free indices.
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
+}
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp
new file mode 100644
index 0000000..03394bc
--- /dev/null
+++ b/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN
+#include "wifi_iface_util.h"
+
+#include "mock_interface_tool.h"
+
+using testing::NiceMock;
+using testing::Test;
+
+namespace {
+constexpr uint8_t kValidUnicastLocallyAssignedMacAddressMask = 0x02;
+constexpr uint8_t kMacAddress[] = {0x02, 0x12, 0x45, 0x56, 0xab, 0xcc};
+constexpr char kIfaceName[] = "test-wlan0";
+
+bool isValidUnicastLocallyAssignedMacAddress(
+ const std::array<uint8_t, 6>& mac_address) {
+ uint8_t first_byte = mac_address[0];
+ return (first_byte & 0x3) == kValidUnicastLocallyAssignedMacAddressMask;
+}
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace iface_util {
+class WifiIfaceUtilTest : public Test {
+ protected:
+ std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
+ new NiceMock<wifi_system::MockInterfaceTool>};
+ WifiIfaceUtil* iface_util_ = new WifiIfaceUtil(iface_tool_);
+};
+
+TEST_F(WifiIfaceUtilTest, GetOrCreateRandomMacAddress) {
+ auto mac_address = iface_util_->getOrCreateRandomMacAddress();
+ ASSERT_TRUE(isValidUnicastLocallyAssignedMacAddress(mac_address));
+
+ // All further calls should return the same MAC address.
+ ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
+ ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
+}
+
+TEST_F(WifiIfaceUtilTest, IfaceEventHandlers_SetMacAddress) {
+ std::array<uint8_t, 6> mac_address = {};
+ std::copy(std::begin(kMacAddress), std::end(kMacAddress),
+ std::begin(mac_address));
+ EXPECT_CALL(*iface_tool_, SetMacAddress(testing::_, testing::_))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*iface_tool_, SetUpState(testing::_, testing::_))
+ .WillRepeatedly(testing::Return(true));
+
+ // Register for iface state toggle events.
+ bool callback_invoked = false;
+ iface_util::IfaceEventHandlers event_handlers = {};
+ event_handlers.on_state_toggle_off_on =
+ [&callback_invoked](const std::string& /* iface_name */) {
+ callback_invoked = true;
+ };
+ iface_util_->registerIfaceEventHandlers(kIfaceName, event_handlers);
+ // Invoke setMacAddress and ensure that the cb is invoked.
+ ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
+ ASSERT_TRUE(callback_invoked);
+
+ // Unregister for iface state toggle events.
+ callback_invoked = false;
+ iface_util_->unregisterIfaceEventHandlers(kIfaceName);
+ // Invoke setMacAddress and ensure that the cb is not invoked.
+ ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
+ ASSERT_FALSE(callback_invoked);
+}
+} // namespace iface_util
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
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
new file mode 100644
index 0000000..9022792
--- /dev/null
+++ b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "wifi_nan_iface.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_feature_flags.h"
+#include "mock_wifi_iface_util.h"
+#include "mock_wifi_legacy_hal.h"
+
+using testing::NiceMock;
+using testing::Return;
+using testing::Test;
+
+namespace {
+constexpr char kIfaceName[] = "mockWlan0";
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+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,
+ iface_util::IfaceEventHandlers* out_iface_event_handlers) {
+ *out_iface_event_handlers = in_iface_event_handlers;
+ return true;
+}
+
+class MockNanIfaceEventCallback : public IWifiNanIfaceEventCallback {
+ public:
+ MockNanIfaceEventCallback() = default;
+
+ MOCK_METHOD3(notifyCapabilitiesResponse,
+ Return<void>(uint16_t, const WifiNanStatus&,
+ const NanCapabilities&));
+ MOCK_METHOD2(notifyEnableResponse,
+ Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD2(notifyConfigResponse,
+ Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD2(notifyDisableResponse,
+ Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD3(notifyStartPublishResponse,
+ Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
+ MOCK_METHOD2(notifyStopPublishResponse,
+ Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD3(notifyStartSubscribeResponse,
+ Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
+ MOCK_METHOD2(notifyStopSubscribeResponse,
+ Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD2(notifyTransmitFollowupResponse,
+ Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD2(notifyCreateDataInterfaceResponse,
+ Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD2(notifyDeleteDataInterfaceResponse,
+ Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD3(notifyInitiateDataPathResponse,
+ Return<void>(uint16_t, const WifiNanStatus&, uint32_t));
+ MOCK_METHOD2(notifyRespondToDataPathIndicationResponse,
+ Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD2(notifyTerminateDataPathResponse,
+ Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD1(eventClusterEvent, Return<void>(const NanClusterEventInd&));
+ MOCK_METHOD1(eventDisabled, Return<void>(const WifiNanStatus&));
+ MOCK_METHOD2(eventPublishTerminated,
+ Return<void>(uint8_t, const WifiNanStatus&));
+ MOCK_METHOD2(eventSubscribeTerminated,
+ Return<void>(uint8_t, const WifiNanStatus&));
+ MOCK_METHOD1(eventMatch, Return<void>(const NanMatchInd&));
+ MOCK_METHOD2(eventMatchExpired, Return<void>(uint8_t, uint32_t));
+ MOCK_METHOD1(eventFollowupReceived,
+ Return<void>(const NanFollowupReceivedInd&));
+ MOCK_METHOD2(eventTransmitFollowup,
+ Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD1(eventDataPathRequest,
+ Return<void>(const NanDataPathRequestInd&));
+ 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 {
+ protected:
+ std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
+ new NiceMock<wifi_system::MockInterfaceTool>};
+ std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+ new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
+ std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
+ new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
+};
+
+TEST_F(WifiNanIfaceTest, IfacEventHandlers_OnStateToggleOffOn) {
+ iface_util::IfaceEventHandlers captured_iface_event_handlers = {};
+ EXPECT_CALL(*legacy_hal_,
+ nanRegisterCallbackHandlers(testing::_, testing::_))
+ .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+ EXPECT_CALL(*iface_util_,
+ registerIfaceEventHandlers(testing::_, testing::_))
+ .WillOnce(testing::Invoke(
+ bind(CaptureIfaceEventHandlers, std::placeholders::_1,
+ std::placeholders::_2, &captured_iface_event_handlers)));
+ sp<WifiNanIface> nan_iface =
+ new WifiNanIface(kIfaceName, legacy_hal_, iface_util_);
+
+ // Register a mock nan event callback.
+ sp<NiceMock<MockNanIfaceEventCallback>> mock_event_callback{
+ new NiceMock<MockNanIfaceEventCallback>};
+ nan_iface->registerEventCallback(
+ mock_event_callback, [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+ // Ensure that the eventDisabled() function in mock callback will be
+ // invoked.
+ WifiNanStatus expected_nan_status = {
+ NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
+ EXPECT_CALL(*mock_event_callback, eventDisabled(expected_nan_status))
+ .Times(1);
+
+ // Trigger the iface state toggle callback.
+ captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName);
+}
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi.cpp b/wifi/1.4/default/wifi.cpp
new file mode 100644
index 0000000..4f48d7e
--- /dev/null
+++ b/wifi/1.4/default/wifi.cpp
@@ -0,0 +1,216 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "wifi.h"
+#include "wifi_status_util.h"
+
+namespace {
+// Chip ID to use for the only supported chip.
+static constexpr android::hardware::wifi::V1_0::ChipId kChipId = 0;
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+using hidl_return_util::validateAndCallWithLock;
+
+Wifi::Wifi(
+ const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
+ const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
+ const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
+ const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+ : iface_tool_(iface_tool),
+ legacy_hal_(legacy_hal),
+ mode_controller_(mode_controller),
+ iface_util_(iface_util),
+ feature_flags_(feature_flags),
+ run_state_(RunState::STOPPED) {}
+
+bool Wifi::isValid() {
+ // This object is always valid.
+ return true;
+}
+
+Return<void> Wifi::registerEventCallback(
+ const sp<IWifiEventCallback>& event_callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+ &Wifi::registerEventCallbackInternal, hidl_status_cb,
+ event_callback);
+}
+
+Return<bool> Wifi::isStarted() { return run_state_ != RunState::STOPPED; }
+
+Return<void> Wifi::start(start_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+ &Wifi::startInternal, hidl_status_cb);
+}
+
+Return<void> Wifi::stop(stop_cb hidl_status_cb) {
+ return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN,
+ &Wifi::stopInternal, hidl_status_cb);
+}
+
+Return<void> Wifi::getChipIds(getChipIds_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+ &Wifi::getChipIdsInternal, hidl_status_cb);
+}
+
+Return<void> Wifi::getChip(ChipId chip_id, getChip_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+ &Wifi::getChipInternal, hidl_status_cb, chip_id);
+}
+
+Return<void> Wifi::debug(const hidl_handle& handle,
+ const hidl_vec<hidl_string>&) {
+ LOG(INFO) << "-----------Debug is called----------------";
+ if (!chip_.get()) {
+ return Void();
+ }
+ return chip_->debug(handle, {});
+}
+
+WifiStatus Wifi::registerEventCallbackInternal(
+ const sp<IWifiEventCallback>& event_callback) {
+ if (!event_cb_handler_.addCallback(event_callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus Wifi::startInternal() {
+ if (run_state_ == RunState::STARTED) {
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+ } else if (run_state_ == RunState::STOPPING) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
+ "HAL is stopping");
+ }
+ WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
+ if (wifi_status.code == WifiStatusCode::SUCCESS) {
+ // Create the chip instance once the HAL is started.
+ chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_,
+ iface_util_, feature_flags_);
+ run_state_ = RunState::STARTED;
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onStart().isOk()) {
+ LOG(ERROR) << "Failed to invoke onStart callback";
+ };
+ }
+ LOG(INFO) << "Wifi HAL started";
+ } else {
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onFailure(wifi_status).isOk()) {
+ LOG(ERROR) << "Failed to invoke onFailure callback";
+ }
+ }
+ LOG(ERROR) << "Wifi HAL start failed";
+ }
+ return wifi_status;
+}
+
+WifiStatus Wifi::stopInternal(
+ /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+ if (run_state_ == RunState::STOPPED) {
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+ } else if (run_state_ == RunState::STOPPING) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
+ "HAL is stopping");
+ }
+ // Clear the chip object and its child objects since the HAL is now
+ // stopped.
+ if (chip_.get()) {
+ chip_->invalidate();
+ chip_.clear();
+ }
+ WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
+ if (wifi_status.code == WifiStatusCode::SUCCESS) {
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onStop().isOk()) {
+ LOG(ERROR) << "Failed to invoke onStop callback";
+ };
+ }
+ LOG(INFO) << "Wifi HAL stopped";
+ } else {
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onFailure(wifi_status).isOk()) {
+ LOG(ERROR) << "Failed to invoke onFailure callback";
+ }
+ }
+ LOG(ERROR) << "Wifi HAL stop failed";
+ }
+ return wifi_status;
+}
+
+std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
+ std::vector<ChipId> chip_ids;
+ if (chip_.get()) {
+ chip_ids.emplace_back(kChipId);
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
+}
+
+std::pair<WifiStatus, sp<IWifiChip>> Wifi::getChipInternal(ChipId chip_id) {
+ if (!chip_.get()) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_STARTED), nullptr};
+ }
+ if (chip_id != kChipId) {
+ return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), chip_};
+}
+
+WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
+ if (!mode_controller_->initialize()) {
+ LOG(ERROR) << "Failed to initialize firmware mode controller";
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize legacy HAL: "
+ << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
+ /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+ run_state_ = RunState::STOPPING;
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_->stop(lock, [&]() { run_state_ = RunState::STOPPED; });
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to stop legacy HAL: "
+ << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ if (!mode_controller_->deinitialize()) {
+ LOG(ERROR) << "Failed to deinitialize firmware mode controller";
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi.h b/wifi/1.4/default/wifi.h
new file mode 100644
index 0000000..087d6f7
--- /dev/null
+++ b/wifi/1.4/default/wifi.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_H_
+#define WIFI_H_
+
+#include <functional>
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.4/IWifi.h>
+#include <utils/Looper.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_chip.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+/**
+ * Root HIDL interface object used to control the Wifi HAL.
+ */
+class Wifi : public V1_4::IWifi {
+ public:
+ Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
+ const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::shared_ptr<mode_controller::WifiModeController>
+ mode_controller,
+ const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
+ const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+
+ bool isValid();
+
+ // HIDL methods exposed.
+ Return<void> registerEventCallback(
+ const sp<IWifiEventCallback>& event_callback,
+ registerEventCallback_cb hidl_status_cb) override;
+ Return<bool> isStarted() override;
+ Return<void> start(start_cb hidl_status_cb) override;
+ Return<void> stop(stop_cb hidl_status_cb) override;
+ Return<void> getChipIds(getChipIds_cb hidl_status_cb) override;
+ Return<void> getChip(ChipId chip_id, getChip_cb hidl_status_cb) override;
+ Return<void> debug(const hidl_handle& handle,
+ const hidl_vec<hidl_string>& options) override;
+
+ private:
+ enum class RunState { STOPPED, STARTED, STOPPING };
+
+ // Corresponding worker functions for the HIDL methods.
+ WifiStatus registerEventCallbackInternal(
+ const sp<IWifiEventCallback>& event_callback);
+ WifiStatus startInternal();
+ WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
+ std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
+ std::pair<WifiStatus, sp<IWifiChip>> getChipInternal(ChipId chip_id);
+
+ WifiStatus initializeModeControllerAndLegacyHal();
+ WifiStatus stopLegacyHalAndDeinitializeModeController(
+ std::unique_lock<std::recursive_mutex>* lock);
+
+ // Instance is created in this root level |IWifi| HIDL interface object
+ // and shared with all the child HIDL interface objects.
+ std::shared_ptr<wifi_system::InterfaceTool> iface_tool_;
+ std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
+ std::shared_ptr<iface_util::WifiIfaceUtil> iface_util_;
+ std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
+ RunState run_state_;
+ sp<WifiChip> chip_;
+ hidl_callback_util::HidlCallbackHandler<IWifiEventCallback>
+ event_cb_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(Wifi);
+};
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_H_
diff --git a/wifi/1.4/default/wifi_ap_iface.cpp b/wifi/1.4/default/wifi_ap_iface.cpp
new file mode 100644
index 0000000..8777a4c
--- /dev/null
+++ b/wifi/1.4/default/wifi_ap_iface.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_ap_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiApIface::WifiApIface(
+ const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+ : ifname_(ifname),
+ legacy_hal_(legacy_hal),
+ iface_util_(iface_util),
+ is_valid_(true) {}
+
+void WifiApIface::invalidate() {
+ legacy_hal_.reset();
+ is_valid_ = false;
+}
+
+bool WifiApIface::isValid() { return is_valid_; }
+
+std::string WifiApIface::getName() { return ifname_; }
+
+Return<void> WifiApIface::getName(getName_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiApIface::getType(getType_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiApIface::setCountryCode(const hidl_array<int8_t, 2>& code,
+ setCountryCode_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::setCountryCodeInternal, hidl_status_cb,
+ code);
+}
+
+Return<void> WifiApIface::getValidFrequenciesForBand(
+ V1_0::WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::getValidFrequenciesForBandInternal,
+ hidl_status_cb, band);
+}
+
+Return<void> WifiApIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
+ setMacAddress_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::setMacAddressInternal, hidl_status_cb,
+ mac);
+}
+
+Return<void> WifiApIface::getFactoryMacAddress(
+ getFactoryMacAddress_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::getFactoryMacAddressInternal,
+ hidl_status_cb);
+}
+
+std::pair<WifiStatus, std::string> WifiApIface::getNameInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiApIface::getTypeInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::AP};
+}
+
+WifiStatus WifiApIface::setCountryCodeInternal(
+ const std::array<int8_t, 2>& code) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->setCountryCode(ifname_, code);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+WifiApIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
+ static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
+ "Size mismatch");
+ legacy_hal::wifi_error legacy_status;
+ std::vector<uint32_t> valid_frequencies;
+ std::tie(legacy_status, valid_frequencies) =
+ legacy_hal_.lock()->getValidFrequenciesForBand(
+ ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
+ return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
+}
+
+WifiStatus WifiApIface::setMacAddressInternal(
+ const std::array<uint8_t, 6>& mac) {
+ bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
+ if (!status) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, std::array<uint8_t, 6>>
+WifiApIface::getFactoryMacAddressInternal() {
+ std::array<uint8_t, 6> mac =
+ iface_util_.lock()->getFactoryMacAddress(ifname_);
+ if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 &&
+ mac[4] == 0 && mac[5] == 0) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
+}
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi_ap_iface.h b/wifi/1.4/default/wifi_ap_iface.h
new file mode 100644
index 0000000..bf16d5e
--- /dev/null
+++ b/wifi/1.4/default/wifi_ap_iface.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_AP_IFACE_H_
+#define WIFI_AP_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.4/IWifiApIface.h>
+
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a AP Iface instance.
+ */
+class WifiApIface : public V1_4::IWifiApIface {
+ public:
+ WifiApIface(const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+ // Refer to |WifiChip::invalidate()|.
+ void invalidate();
+ bool isValid();
+ std::string getName();
+
+ // HIDL methods exposed.
+ Return<void> getName(getName_cb hidl_status_cb) override;
+ Return<void> getType(getType_cb hidl_status_cb) override;
+ Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
+ setCountryCode_cb hidl_status_cb) override;
+ Return<void> getValidFrequenciesForBand(
+ V1_0::WifiBand band,
+ getValidFrequenciesForBand_cb hidl_status_cb) override;
+ Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
+ setMacAddress_cb hidl_status_cb) override;
+ Return<void> getFactoryMacAddress(
+ getFactoryMacAddress_cb hidl_status_cb) override;
+
+ private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<WifiStatus, std::string> getNameInternal();
+ std::pair<WifiStatus, IfaceType> getTypeInternal();
+ WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
+ std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+ getValidFrequenciesForBandInternal(V1_0::WifiBand band);
+ WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
+ std::pair<WifiStatus, std::array<uint8_t, 6>>
+ getFactoryMacAddressInternal();
+
+ std::string ifname_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+ bool is_valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiApIface);
+};
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_AP_IFACE_H_
diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp
new file mode 100644
index 0000000..3498510
--- /dev/null
+++ b/wifi/1.4/default/wifi_chip.cpp
@@ -0,0 +1,1579 @@
+/*
+ * 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.
+ */
+
+#include <fcntl.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <cutils/properties.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_chip.h"
+#include "wifi_status_util.h"
+
+namespace {
+using android::sp;
+using android::base::unique_fd;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::wifi::V1_0::ChipModeId;
+using android::hardware::wifi::V1_0::IfaceType;
+using android::hardware::wifi::V1_0::IWifiChip;
+
+constexpr char kCpioMagic[] = "070701";
+constexpr size_t kMaxBufferSizeBytes = 1024 * 1024 * 3;
+constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60 * 10;
+constexpr uint32_t kMaxRingBufferFileNum = 20;
+constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/";
+constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface";
+constexpr char kNoActiveWlanIfaceNamePropertyValue[] = "";
+constexpr unsigned kMaxWlanIfaces = 5;
+
+template <typename Iface>
+void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
+ iface->invalidate();
+ ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface),
+ ifaces.end());
+}
+
+template <typename Iface>
+void invalidateAndClearAll(std::vector<sp<Iface>>& ifaces) {
+ for (const auto& iface : ifaces) {
+ iface->invalidate();
+ }
+ ifaces.clear();
+}
+
+template <typename Iface>
+std::vector<hidl_string> getNames(std::vector<sp<Iface>>& ifaces) {
+ std::vector<hidl_string> names;
+ for (const auto& iface : ifaces) {
+ names.emplace_back(iface->getName());
+ }
+ return names;
+}
+
+template <typename Iface>
+sp<Iface> findUsingName(std::vector<sp<Iface>>& ifaces,
+ const std::string& name) {
+ std::vector<hidl_string> names;
+ for (const auto& iface : ifaces) {
+ if (name == iface->getName()) {
+ return iface;
+ }
+ }
+ return nullptr;
+}
+
+std::string getWlanIfaceName(unsigned idx) {
+ if (idx >= kMaxWlanIfaces) {
+ CHECK(false) << "Requested interface beyond wlan" << kMaxWlanIfaces;
+ return {};
+ }
+
+ std::array<char, PROPERTY_VALUE_MAX> buffer;
+ if (idx == 0 || idx == 1) {
+ const char* altPropName =
+ (idx == 0) ? "wifi.interface" : "wifi.concurrent.interface";
+ auto res = property_get(altPropName, buffer.data(), nullptr);
+ if (res > 0) return buffer.data();
+ }
+ std::string propName = "wifi.interface." + std::to_string(idx);
+ auto res = property_get(propName.c_str(), buffer.data(), nullptr);
+ if (res > 0) return buffer.data();
+
+ return "wlan" + std::to_string(idx);
+}
+
+std::string getP2pIfaceName() {
+ std::array<char, PROPERTY_VALUE_MAX> buffer;
+ property_get("wifi.direct.interface", buffer.data(), "p2p0");
+ return buffer.data();
+}
+
+void setActiveWlanIfaceNameProperty(const std::string& ifname) {
+ auto res = property_set(kActiveWlanIfaceNameProperty, ifname.data());
+ if (res != 0) {
+ PLOG(ERROR) << "Failed to set active wlan iface name property";
+ }
+}
+
+// delete files that meet either conditions:
+// 1. older than a predefined time in the wifi tombstone dir.
+// 2. Files in excess to a predefined amount, starting from the oldest ones
+bool removeOldFilesInternal() {
+ time_t now = time(0);
+ const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
+ std::unique_ptr<DIR, decltype(&closedir)> dir_dump(
+ opendir(kTombstoneFolderPath), closedir);
+ if (!dir_dump) {
+ PLOG(ERROR) << "Failed to open directory";
+ return false;
+ }
+ struct dirent* dp;
+ bool success = true;
+ std::list<std::pair<const time_t, std::string>> valid_files;
+ while ((dp = readdir(dir_dump.get()))) {
+ if (dp->d_type != DT_REG) {
+ continue;
+ }
+ std::string cur_file_name(dp->d_name);
+ struct stat cur_file_stat;
+ std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+ if (stat(cur_file_path.c_str(), &cur_file_stat) == -1) {
+ PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
+ success = false;
+ continue;
+ }
+ const time_t cur_file_time = cur_file_stat.st_mtime;
+ valid_files.push_back(
+ std::pair<const time_t, std::string>(cur_file_time, cur_file_path));
+ }
+ valid_files.sort(); // sort the list of files by last modified time from
+ // small to big.
+ uint32_t cur_file_count = valid_files.size();
+ for (auto cur_file : valid_files) {
+ if (cur_file_count > kMaxRingBufferFileNum ||
+ cur_file.first < delete_files_before) {
+ if (unlink(cur_file.second.c_str()) != 0) {
+ PLOG(ERROR) << "Error deleting file";
+ success = false;
+ }
+ cur_file_count--;
+ } else {
+ break;
+ }
+ }
+ return success;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteHeader(int out_fd, struct stat& st, const char* file_name,
+ size_t file_name_len) {
+ std::array<char, 32 * 1024> read_buf;
+ ssize_t llen =
+ sprintf(read_buf.data(),
+ "%s%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
+ kCpioMagic, static_cast<int>(st.st_ino), st.st_mode, st.st_uid,
+ st.st_gid, static_cast<int>(st.st_nlink),
+ static_cast<int>(st.st_mtime), static_cast<int>(st.st_size),
+ major(st.st_dev), minor(st.st_dev), major(st.st_rdev),
+ minor(st.st_rdev), static_cast<uint32_t>(file_name_len), 0);
+ if (write(out_fd, read_buf.data(), llen) == -1) {
+ PLOG(ERROR) << "Error writing cpio header to file " << file_name;
+ return false;
+ }
+ if (write(out_fd, file_name, file_name_len) == -1) {
+ PLOG(ERROR) << "Error writing filename to file " << file_name;
+ return false;
+ }
+
+ // NUL Pad header up to 4 multiple bytes.
+ llen = (llen + file_name_len) % 4;
+ if (llen != 0) {
+ const uint32_t zero = 0;
+ if (write(out_fd, &zero, 4 - llen) == -1) {
+ PLOG(ERROR) << "Error padding 0s to file " << file_name;
+ return false;
+ }
+ }
+ return true;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+size_t cpioWriteFileContent(int fd_read, int out_fd, struct stat& st) {
+ // writing content of file
+ std::array<char, 32 * 1024> read_buf;
+ ssize_t llen = st.st_size;
+ size_t n_error = 0;
+ while (llen > 0) {
+ ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size());
+ if (bytes_read == -1) {
+ PLOG(ERROR) << "Error reading file";
+ return ++n_error;
+ }
+ llen -= bytes_read;
+ if (write(out_fd, read_buf.data(), bytes_read) == -1) {
+ PLOG(ERROR) << "Error writing data to file";
+ return ++n_error;
+ }
+ if (bytes_read == 0) { // this should never happen, but just in case
+ // to unstuck from while loop
+ PLOG(ERROR) << "Unexpected read result";
+ n_error++;
+ break;
+ }
+ }
+ llen = st.st_size % 4;
+ if (llen != 0) {
+ const uint32_t zero = 0;
+ if (write(out_fd, &zero, 4 - llen) == -1) {
+ PLOG(ERROR) << "Error padding 0s to file";
+ return ++n_error;
+ }
+ }
+ return n_error;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteFileTrailer(int out_fd) {
+ std::array<char, 4096> read_buf;
+ read_buf.fill(0);
+ if (write(out_fd, read_buf.data(),
+ sprintf(read_buf.data(), "070701%040X%056X%08XTRAILER!!!", 1,
+ 0x0b, 0) +
+ 4) == -1) {
+ PLOG(ERROR) << "Error writing trailing bytes";
+ return false;
+ }
+ return true;
+}
+
+// Archives all files in |input_dir| and writes result into |out_fd|
+// Logic obtained from //external/toybox/toys/posix/cpio.c "Output cpio archive"
+// portion
+size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
+ struct dirent* dp;
+ size_t n_error = 0;
+ std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir),
+ closedir);
+ if (!dir_dump) {
+ PLOG(ERROR) << "Failed to open directory";
+ return ++n_error;
+ }
+ while ((dp = readdir(dir_dump.get()))) {
+ if (dp->d_type != DT_REG) {
+ continue;
+ }
+ std::string cur_file_name(dp->d_name);
+ // string.size() does not include the null terminator. The cpio FreeBSD
+ // file header expects the null character to be included in the length.
+ const size_t file_name_len = cur_file_name.size() + 1;
+ struct stat st;
+ const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+ if (stat(cur_file_path.c_str(), &st) == -1) {
+ PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
+ n_error++;
+ continue;
+ }
+ const int fd_read = open(cur_file_path.c_str(), O_RDONLY);
+ if (fd_read == -1) {
+ PLOG(ERROR) << "Failed to open file " << cur_file_path;
+ n_error++;
+ continue;
+ }
+ unique_fd file_auto_closer(fd_read);
+ if (!cpioWriteHeader(out_fd, st, cur_file_name.c_str(),
+ file_name_len)) {
+ return ++n_error;
+ }
+ size_t write_error = cpioWriteFileContent(fd_read, out_fd, st);
+ if (write_error) {
+ return n_error + write_error;
+ }
+ }
+ if (!cpioWriteFileTrailer(out_fd)) {
+ return ++n_error;
+ }
+ return n_error;
+}
+
+// Helper function to create a non-const char*.
+std::vector<char> makeCharVec(const std::string& str) {
+ std::vector<char> vec(str.size() + 1);
+ vec.assign(str.begin(), str.end());
+ vec.push_back('\0');
+ return vec;
+}
+
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+using hidl_return_util::validateAndCallWithLock;
+
+WifiChip::WifiChip(
+ ChipId chip_id, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
+ const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+ : chip_id_(chip_id),
+ legacy_hal_(legacy_hal),
+ mode_controller_(mode_controller),
+ iface_util_(iface_util),
+ is_valid_(true),
+ current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
+ modes_(feature_flags.lock()->getChipModes()),
+ debug_ring_buffer_cb_registered_(false) {
+ setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
+}
+
+void WifiChip::invalidate() {
+ if (!writeRingbufferFilesInternal()) {
+ LOG(ERROR) << "Error writing files to flash";
+ }
+ invalidateAndRemoveAllIfaces();
+ setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
+ legacy_hal_.reset();
+ event_cb_handler_.invalidate();
+ is_valid_ = false;
+}
+
+bool WifiChip::isValid() { return is_valid_; }
+
+std::set<sp<IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
+ return event_cb_handler_.getCallbacks();
+}
+
+Return<void> WifiChip::getId(getId_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getIdInternal, hidl_status_cb);
+}
+
+// Deprecated support for this callback
+Return<void> WifiChip::registerEventCallback(
+ const sp<V1_0::IWifiChipEventCallback>& event_callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::registerEventCallbackInternal,
+ hidl_status_cb, event_callback);
+}
+
+Return<void> WifiChip::getCapabilities(getCapabilities_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getAvailableModes(getAvailableModes_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getAvailableModesInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiChip::configureChip(ChipModeId mode_id,
+ configureChip_cb hidl_status_cb) {
+ return validateAndCallWithLock(
+ this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::configureChipInternal, hidl_status_cb, mode_id);
+}
+
+Return<void> WifiChip::getMode(getMode_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getModeInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::requestChipDebugInfo(
+ requestChipDebugInfo_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::requestChipDebugInfoInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiChip::requestDriverDebugDump(
+ requestDriverDebugDump_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::requestDriverDebugDumpInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiChip::requestFirmwareDebugDump(
+ requestFirmwareDebugDump_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::requestFirmwareDebugDumpInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiChip::createApIface(createApIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createApIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getApIfaceNames(getApIfaceNames_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getApIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getApIface(const hidl_string& ifname,
+ getApIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getApIfaceInternal, hidl_status_cb,
+ ifname);
+}
+
+Return<void> WifiChip::removeApIface(const hidl_string& ifname,
+ removeApIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::removeApIfaceInternal, hidl_status_cb,
+ ifname);
+}
+
+Return<void> WifiChip::createNanIface(createNanIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createNanIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getNanIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getNanIface(const hidl_string& ifname,
+ getNanIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getNanIfaceInternal, hidl_status_cb,
+ ifname);
+}
+
+Return<void> WifiChip::removeNanIface(const hidl_string& ifname,
+ removeNanIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::removeNanIfaceInternal, hidl_status_cb,
+ ifname);
+}
+
+Return<void> WifiChip::createP2pIface(createP2pIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createP2pIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getP2pIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getP2pIface(const hidl_string& ifname,
+ getP2pIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getP2pIfaceInternal, hidl_status_cb,
+ ifname);
+}
+
+Return<void> WifiChip::removeP2pIface(const hidl_string& ifname,
+ removeP2pIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::removeP2pIfaceInternal, hidl_status_cb,
+ ifname);
+}
+
+Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createStaIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getStaIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getStaIface(const hidl_string& ifname,
+ getStaIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getStaIfaceInternal, hidl_status_cb,
+ ifname);
+}
+
+Return<void> WifiChip::removeStaIface(const hidl_string& ifname,
+ removeStaIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::removeStaIfaceInternal, hidl_status_cb,
+ ifname);
+}
+
+Return<void> WifiChip::createRttController(
+ const sp<IWifiIface>& bound_iface, createRttController_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createRttControllerInternal,
+ hidl_status_cb, bound_iface);
+}
+
+Return<void> WifiChip::getDebugRingBuffersStatus(
+ getDebugRingBuffersStatus_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getDebugRingBuffersStatusInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiChip::startLoggingToDebugRingBuffer(
+ const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+ uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
+ startLoggingToDebugRingBuffer_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::startLoggingToDebugRingBufferInternal,
+ hidl_status_cb, ring_name, verbose_level,
+ max_interval_in_sec, min_data_size_in_bytes);
+}
+
+Return<void> WifiChip::forceDumpToDebugRingBuffer(
+ const hidl_string& ring_name,
+ forceDumpToDebugRingBuffer_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::forceDumpToDebugRingBufferInternal,
+ hidl_status_cb, ring_name);
+}
+
+Return<void> WifiChip::flushRingBufferToFile(
+ flushRingBufferToFile_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::flushRingBufferToFileInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiChip::stopLoggingToDebugRingBuffer(
+ stopLoggingToDebugRingBuffer_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::stopLoggingToDebugRingBufferInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiChip::getDebugHostWakeReasonStats(
+ getDebugHostWakeReasonStats_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getDebugHostWakeReasonStatsInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiChip::enableDebugErrorAlerts(
+ bool enable, enableDebugErrorAlerts_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::enableDebugErrorAlertsInternal,
+ hidl_status_cb, enable);
+}
+
+Return<void> WifiChip::selectTxPowerScenario(
+ V1_1::IWifiChip::TxPowerScenario scenario,
+ selectTxPowerScenario_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::selectTxPowerScenarioInternal,
+ hidl_status_cb, scenario);
+}
+
+Return<void> WifiChip::resetTxPowerScenario(
+ resetTxPowerScenario_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::resetTxPowerScenarioInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiChip::setLatencyMode(LatencyMode mode,
+ setLatencyMode_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::setLatencyModeInternal, hidl_status_cb,
+ mode);
+}
+
+Return<void> WifiChip::registerEventCallback_1_2(
+ const sp<V1_2::IWifiChipEventCallback>& event_callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::registerEventCallbackInternal_1_2,
+ hidl_status_cb, event_callback);
+}
+
+Return<void> WifiChip::selectTxPowerScenario_1_2(
+ TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::selectTxPowerScenarioInternal_1_2,
+ hidl_status_cb, scenario);
+}
+
+Return<void> WifiChip::getCapabilities_1_3(getCapabilities_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getCapabilitiesInternal_1_3,
+ hidl_status_cb);
+}
+
+Return<void> WifiChip::debug(const hidl_handle& handle,
+ const hidl_vec<hidl_string>&) {
+ if (handle != nullptr && handle->numFds >= 1) {
+ int fd = handle->data[0];
+ if (!writeRingbufferFilesInternal()) {
+ LOG(ERROR) << "Error writing files to flash";
+ }
+ uint32_t n_error = cpioArchiveFilesInDir(fd, kTombstoneFolderPath);
+ if (n_error != 0) {
+ LOG(ERROR) << n_error << " errors occured in cpio function";
+ }
+ fsync(fd);
+ } else {
+ LOG(ERROR) << "File handle error";
+ }
+ return Void();
+}
+
+Return<void> WifiChip::createRttController_1_4(
+ const sp<IWifiIface>& bound_iface,
+ createRttController_1_4_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createRttControllerInternal_1_4,
+ hidl_status_cb, bound_iface);
+}
+
+Return<void> WifiChip::registerEventCallback_1_4(
+ const sp<IWifiChipEventCallback>& event_callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::registerEventCallbackInternal_1_4,
+ hidl_status_cb, event_callback);
+}
+
+void WifiChip::invalidateAndRemoveAllIfaces() {
+ invalidateAndClearAll(ap_ifaces_);
+ invalidateAndClearAll(nan_ifaces_);
+ invalidateAndClearAll(p2p_ifaces_);
+ invalidateAndClearAll(sta_ifaces_);
+ // Since all the ifaces are invalid now, all RTT controller objects
+ // using those ifaces also need to be invalidated.
+ for (const auto& rtt : rtt_controllers_) {
+ rtt->invalidate();
+ }
+ rtt_controllers_.clear();
+}
+
+void WifiChip::invalidateAndRemoveDependencies(
+ const std::string& removed_iface_name) {
+ for (const auto& nan_iface : nan_ifaces_) {
+ if (nan_iface->getName() == removed_iface_name) {
+ invalidateAndClear(nan_ifaces_, nan_iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback
+ ->onIfaceRemoved(IfaceType::NAN, removed_iface_name)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+ }
+ }
+ }
+ }
+ for (const auto& rtt : rtt_controllers_) {
+ if (rtt->getIfaceName() == removed_iface_name) {
+ invalidateAndClear(rtt_controllers_, rtt);
+ }
+ }
+}
+
+std::pair<WifiStatus, ChipId> WifiChip::getIdInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), chip_id_};
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal(
+ const sp<V1_0::IWifiChipEventCallback>& /* event_callback */) {
+ // Deprecated support for this callback.
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
+ // Deprecated support for this callback.
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
+}
+
+std::pair<WifiStatus, std::vector<IWifiChip::ChipMode>>
+WifiChip::getAvailableModesInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), modes_};
+}
+
+WifiStatus WifiChip::configureChipInternal(
+ /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+ ChipModeId mode_id) {
+ if (!isValidModeId(mode_id)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ if (mode_id == current_mode_id_) {
+ LOG(DEBUG) << "Already in the specified mode " << mode_id;
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+ }
+ WifiStatus status = handleChipConfiguration(lock, mode_id);
+ if (status.code != WifiStatusCode::SUCCESS) {
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onChipReconfigureFailure(status).isOk()) {
+ LOG(ERROR)
+ << "Failed to invoke onChipReconfigureFailure callback";
+ }
+ }
+ return status;
+ }
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onChipReconfigured(mode_id).isOk()) {
+ LOG(ERROR) << "Failed to invoke onChipReconfigured callback";
+ }
+ }
+ current_mode_id_ = mode_id;
+ LOG(INFO) << "Configured chip in mode " << mode_id;
+ setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+ return status;
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
+ if (!isValidModeId(current_mode_id_)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE),
+ current_mode_id_};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
+}
+
+std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
+WifiChip::requestChipDebugInfoInternal() {
+ IWifiChip::ChipDebugInfo result;
+ legacy_hal::wifi_error legacy_status;
+ std::string driver_desc;
+ const auto ifname = getFirstActiveWlanIfaceName();
+ std::tie(legacy_status, driver_desc) =
+ legacy_hal_.lock()->getDriverVersion(ifname);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to get driver version: "
+ << legacyErrorToString(legacy_status);
+ WifiStatus status = createWifiStatusFromLegacyError(
+ legacy_status, "failed to get driver version");
+ return {status, result};
+ }
+ result.driverDescription = driver_desc.c_str();
+
+ std::string firmware_desc;
+ std::tie(legacy_status, firmware_desc) =
+ legacy_hal_.lock()->getFirmwareVersion(ifname);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to get firmware version: "
+ << legacyErrorToString(legacy_status);
+ WifiStatus status = createWifiStatusFromLegacyError(
+ legacy_status, "failed to get firmware version");
+ return {status, result};
+ }
+ result.firmwareDescription = firmware_desc.c_str();
+
+ return {createWifiStatus(WifiStatusCode::SUCCESS), result};
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>>
+WifiChip::requestDriverDebugDumpInternal() {
+ legacy_hal::wifi_error legacy_status;
+ std::vector<uint8_t> driver_dump;
+ std::tie(legacy_status, driver_dump) =
+ legacy_hal_.lock()->requestDriverMemoryDump(
+ getFirstActiveWlanIfaceName());
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to get driver debug dump: "
+ << legacyErrorToString(legacy_status);
+ return {createWifiStatusFromLegacyError(legacy_status),
+ std::vector<uint8_t>()};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), driver_dump};
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>>
+WifiChip::requestFirmwareDebugDumpInternal() {
+ legacy_hal::wifi_error legacy_status;
+ std::vector<uint8_t> firmware_dump;
+ std::tie(legacy_status, firmware_dump) =
+ legacy_hal_.lock()->requestFirmwareMemoryDump(
+ getFirstActiveWlanIfaceName());
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to get firmware debug dump: "
+ << legacyErrorToString(legacy_status);
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), firmware_dump};
+}
+
+std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::createApIfaceInternal() {
+ if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::string ifname = allocateApIfaceName();
+ sp<WifiApIface> iface = new WifiApIface(ifname, legacy_hal_, iface_util_);
+ ap_ifaces_.push_back(iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+ }
+ }
+ setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>>
+WifiChip::getApIfaceNamesInternal() {
+ if (ap_ifaces_.empty()) {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(ap_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::getApIfaceInternal(
+ const std::string& ifname) {
+ const auto iface = findUsingName(ap_ifaces_, ifname);
+ if (!iface.get()) {
+ return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) {
+ const auto iface = findUsingName(ap_ifaces_, ifname);
+ if (!iface.get()) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ // Invalidate & remove any dependent objects first.
+ // Note: This is probably not required because we never create
+ // nan/rtt objects over AP iface. But, there is no harm to do it
+ // here and not make that assumption all over the place.
+ invalidateAndRemoveDependencies(ifname);
+ invalidateAndClear(ap_ifaces_, iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+ }
+ }
+ setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::createNanIfaceInternal() {
+ if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ // These are still assumed to be based on wlan0.
+ std::string ifname = getFirstActiveWlanIfaceName();
+ sp<WifiNanIface> iface = new WifiNanIface(ifname, legacy_hal_, iface_util_);
+ nan_ifaces_.push_back(iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+ }
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>>
+WifiChip::getNanIfaceNamesInternal() {
+ if (nan_ifaces_.empty()) {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::getNanIfaceInternal(
+ const std::string& ifname) {
+ const auto iface = findUsingName(nan_ifaces_, ifname);
+ if (!iface.get()) {
+ return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) {
+ const auto iface = findUsingName(nan_ifaces_, ifname);
+ if (!iface.get()) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ invalidateAndClear(nan_ifaces_, iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceRemoved(IfaceType::NAN, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+ }
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
+ if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::P2P)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::string ifname = getP2pIfaceName();
+ sp<WifiP2pIface> iface = new WifiP2pIface(ifname, legacy_hal_);
+ p2p_ifaces_.push_back(iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+ }
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>>
+WifiChip::getP2pIfaceNamesInternal() {
+ if (p2p_ifaces_.empty()) {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(p2p_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::getP2pIfaceInternal(
+ const std::string& ifname) {
+ const auto iface = findUsingName(p2p_ifaces_, ifname);
+ if (!iface.get()) {
+ return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) {
+ const auto iface = findUsingName(p2p_ifaces_, ifname);
+ if (!iface.get()) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ invalidateAndClear(p2p_ifaces_, iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+ }
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<V1_3::IWifiStaIface>>
+WifiChip::createStaIfaceInternal() {
+ if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::string ifname = allocateStaIfaceName();
+ sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_, iface_util_);
+ sta_ifaces_.push_back(iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+ }
+ }
+ setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>>
+WifiChip::getStaIfaceNamesInternal() {
+ if (sta_ifaces_.empty()) {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<V1_3::IWifiStaIface>> WifiChip::getStaIfaceInternal(
+ const std::string& ifname) {
+ const auto iface = findUsingName(sta_ifaces_, ifname);
+ if (!iface.get()) {
+ return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) {
+ const auto iface = findUsingName(sta_ifaces_, ifname);
+ if (!iface.get()) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ // Invalidate & remove any dependent objects first.
+ invalidateAndRemoveDependencies(ifname);
+ invalidateAndClear(sta_ifaces_, iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+ }
+ }
+ setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+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_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
+WifiChip::getDebugRingBuffersStatusInternal() {
+ legacy_hal::wifi_error legacy_status;
+ std::vector<legacy_hal::wifi_ring_buffer_status>
+ legacy_ring_buffer_status_vec;
+ std::tie(legacy_status, legacy_ring_buffer_status_vec) =
+ legacy_hal_.lock()->getRingBuffersStatus(getFirstActiveWlanIfaceName());
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ std::vector<WifiDebugRingBufferStatus> hidl_ring_buffer_status_vec;
+ if (!hidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToHidl(
+ legacy_ring_buffer_status_vec, &hidl_ring_buffer_status_vec)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS),
+ hidl_ring_buffer_status_vec};
+}
+
+WifiStatus WifiChip::startLoggingToDebugRingBufferInternal(
+ const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+ uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes) {
+ WifiStatus status = registerDebugRingBufferCallback();
+ if (status.code != WifiStatusCode::SUCCESS) {
+ return status;
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->startRingBufferLogging(
+ getFirstActiveWlanIfaceName(), ring_name,
+ static_cast<
+ std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(
+ verbose_level),
+ max_interval_in_sec, min_data_size_in_bytes);
+ ringbuffer_map_.insert(std::pair<std::string, Ringbuffer>(
+ ring_name, Ringbuffer(kMaxBufferSizeBytes)));
+ // if verbose logging enabled, turn up HAL daemon logging as well.
+ if (verbose_level < WifiDebugRingBufferVerboseLevel::VERBOSE) {
+ android::base::SetMinimumLogSeverity(android::base::DEBUG);
+ } else {
+ android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+ }
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::forceDumpToDebugRingBufferInternal(
+ const hidl_string& ring_name) {
+ WifiStatus status = registerDebugRingBufferCallback();
+ if (status.code != WifiStatusCode::SUCCESS) {
+ return status;
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->getRingBufferData(getFirstActiveWlanIfaceName(),
+ ring_name);
+
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::flushRingBufferToFileInternal() {
+ if (!writeRingbufferFilesInternal()) {
+ LOG(ERROR) << "Error writing files to flash";
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::stopLoggingToDebugRingBufferInternal() {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->deregisterRingBufferCallbackHandler(
+ getFirstActiveWlanIfaceName());
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
+WifiChip::getDebugHostWakeReasonStatsInternal() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::WakeReasonStats legacy_stats;
+ std::tie(legacy_status, legacy_stats) =
+ legacy_hal_.lock()->getWakeReasonStats(getFirstActiveWlanIfaceName());
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ WifiDebugHostWakeReasonStats hidl_stats;
+ if (!hidl_struct_util::convertLegacyWakeReasonStatsToHidl(legacy_stats,
+ &hidl_stats)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
+}
+
+WifiStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
+ legacy_hal::wifi_error legacy_status;
+ if (enable) {
+ android::wp<WifiChip> weak_ptr_this(this);
+ const auto& on_alert_callback = [weak_ptr_this](
+ int32_t error_code,
+ std::vector<uint8_t> debug_data) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onDebugErrorAlert(error_code, debug_data)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke onDebugErrorAlert callback";
+ }
+ }
+ };
+ legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
+ getFirstActiveWlanIfaceName(), on_alert_callback);
+ } else {
+ legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler(
+ getFirstActiveWlanIfaceName());
+ }
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::selectTxPowerScenarioInternal(
+ V1_1::IWifiChip::TxPowerScenario scenario) {
+ auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+ getFirstActiveWlanIfaceName(),
+ hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::resetTxPowerScenarioInternal() {
+ auto legacy_status =
+ legacy_hal_.lock()->resetTxPowerScenario(getFirstActiveWlanIfaceName());
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::setLatencyModeInternal(LatencyMode mode) {
+ auto legacy_status = legacy_hal_.lock()->setLatencyMode(
+ getFirstActiveWlanIfaceName(),
+ hidl_struct_util::convertHidlLatencyModeToLegacy(mode));
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal_1_2(
+ const sp<V1_2::IWifiChipEventCallback>& /* event_callback */) {
+ // Deprecated support for this callback.
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(
+ TxPowerScenario scenario) {
+ auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+ getFirstActiveWlanIfaceName(),
+ hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_3() {
+ legacy_hal::wifi_error legacy_status;
+ uint32_t legacy_feature_set;
+ uint32_t legacy_logger_feature_set;
+ const auto ifname = getFirstActiveWlanIfaceName();
+ std::tie(legacy_status, legacy_feature_set) =
+ legacy_hal_.lock()->getSupportedFeatureSet(ifname);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), 0};
+ }
+ 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::convertLegacyFeaturesToHidlChipCapabilities(
+ legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, sp<IWifiRttController>>
+WifiChip::createRttControllerInternal_1_4(const sp<IWifiIface>& bound_iface) {
+ if (sta_ifaces_.size() == 0 &&
+ !canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
+ LOG(ERROR)
+ << "createRttControllerInternal_1_4: Chip cannot support STAs "
+ "(and RTT by extension)";
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ sp<WifiRttController> rtt = new WifiRttController(
+ getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
+ rtt_controllers_.emplace_back(rtt);
+ return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal_1_4(
+ const sp<IWifiChipEventCallback>& event_callback) {
+ if (!event_cb_handler_.addCallback(event_callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::handleChipConfiguration(
+ /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+ ChipModeId mode_id) {
+ // If the chip is already configured in a different mode, stop
+ // the legacy HAL and then start it after firmware mode change.
+ if (isValidModeId(current_mode_id_)) {
+ LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_
+ << " to mode " << mode_id;
+ invalidateAndRemoveAllIfaces();
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->stop(lock, []() {});
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to stop legacy HAL: "
+ << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ }
+ // Firmware mode change not needed for V2 devices.
+ bool success = true;
+ if (mode_id == feature_flags::chip_mode_ids::kV1Sta) {
+ success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
+ } else if (mode_id == feature_flags::chip_mode_ids::kV1Ap) {
+ success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
+ }
+ if (!success) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to start legacy HAL: "
+ << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ // Every time the HAL is restarted, we need to register the
+ // radio mode change callback.
+ WifiStatus status = registerRadioModeChangeCallback();
+ if (status.code != WifiStatusCode::SUCCESS) {
+ // This probably is not a critical failure?
+ LOG(ERROR) << "Failed to register radio mode change callback";
+ }
+ // Extract and save the version information into property.
+ std::pair<WifiStatus, IWifiChip::ChipDebugInfo> version_info;
+ version_info = WifiChip::requestChipDebugInfoInternal();
+ if (WifiStatusCode::SUCCESS == version_info.first.code) {
+ property_set("vendor.wlan.firmware.version",
+ version_info.second.firmwareDescription.c_str());
+ property_set("vendor.wlan.driver.version",
+ version_info.second.driverDescription.c_str());
+ }
+
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::registerDebugRingBufferCallback() {
+ if (debug_ring_buffer_cb_registered_) {
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+ }
+
+ android::wp<WifiChip> weak_ptr_this(this);
+ const auto& on_ring_buffer_data_callback =
+ [weak_ptr_this](const std::string& name,
+ const std::vector<uint8_t>& data,
+ const legacy_hal::wifi_ring_buffer_status& status) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ WifiDebugRingBufferStatus hidl_status;
+ if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(
+ status, &hidl_status)) {
+ LOG(ERROR) << "Error converting ring buffer status";
+ return;
+ }
+ const auto& target = shared_ptr_this->ringbuffer_map_.find(name);
+ if (target != shared_ptr_this->ringbuffer_map_.end()) {
+ Ringbuffer& cur_buffer = target->second;
+ cur_buffer.append(data);
+ } else {
+ LOG(ERROR) << "Ringname " << name << " not found";
+ return;
+ }
+ };
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->registerRingBufferCallbackHandler(
+ getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
+
+ if (legacy_status == legacy_hal::WIFI_SUCCESS) {
+ debug_ring_buffer_cb_registered_ = true;
+ }
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::registerRadioModeChangeCallback() {
+ android::wp<WifiChip> weak_ptr_this(this);
+ const auto& on_radio_mode_change_callback =
+ [weak_ptr_this](const std::vector<legacy_hal::WifiMacInfo>& mac_infos) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ std::vector<IWifiChipEventCallback::RadioModeInfo>
+ hidl_radio_mode_infos;
+ if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+ mac_infos, &hidl_radio_mode_infos)) {
+ LOG(ERROR) << "Error converting wifi mac info";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onRadioModeChange_1_4(hidl_radio_mode_infos)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke onRadioModeChange_1_4"
+ << " callback on: " << toString(callback);
+ }
+ }
+ };
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
+ getFirstActiveWlanIfaceName(), on_radio_mode_change_callback);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::vector<IWifiChip::ChipIfaceCombination>
+WifiChip::getCurrentModeIfaceCombinations() {
+ if (!isValidModeId(current_mode_id_)) {
+ LOG(ERROR) << "Chip not configured in a mode yet";
+ return {};
+ }
+ for (const auto& mode : modes_) {
+ if (mode.id == current_mode_id_) {
+ return mode.availableCombinations;
+ }
+ }
+ CHECK(0) << "Expected to find iface combinations for current mode!";
+ return {};
+}
+
+// Returns a map indexed by IfaceType with the number of ifaces currently
+// created of the corresponding type.
+std::map<IfaceType, size_t> WifiChip::getCurrentIfaceCombination() {
+ std::map<IfaceType, size_t> iface_counts;
+ iface_counts[IfaceType::AP] = ap_ifaces_.size();
+ iface_counts[IfaceType::NAN] = nan_ifaces_.size();
+ iface_counts[IfaceType::P2P] = p2p_ifaces_.size();
+ iface_counts[IfaceType::STA] = sta_ifaces_.size();
+ return iface_counts;
+}
+
+// This expands the provided iface combinations to a more parseable
+// form. Returns a vector of available combinations possible with the number
+// of ifaces of each type in the combination.
+// This method is a port of HalDeviceManager.expandIfaceCombos() from framework.
+std::vector<std::map<IfaceType, size_t>> WifiChip::expandIfaceCombinations(
+ const IWifiChip::ChipIfaceCombination& combination) {
+ uint32_t num_expanded_combos = 1;
+ for (const auto& limit : combination.limits) {
+ for (uint32_t i = 0; i < limit.maxIfaces; i++) {
+ num_expanded_combos *= limit.types.size();
+ }
+ }
+
+ // Allocate the vector of expanded combos and reset all iface counts to 0
+ // in each combo.
+ std::vector<std::map<IfaceType, size_t>> expanded_combos;
+ expanded_combos.resize(num_expanded_combos);
+ for (auto& expanded_combo : expanded_combos) {
+ for (const auto type :
+ {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+ expanded_combo[type] = 0;
+ }
+ }
+ uint32_t span = num_expanded_combos;
+ for (const auto& limit : combination.limits) {
+ for (uint32_t i = 0; i < limit.maxIfaces; i++) {
+ span /= limit.types.size();
+ for (uint32_t k = 0; k < num_expanded_combos; ++k) {
+ const auto iface_type =
+ limit.types[(k / span) % limit.types.size()];
+ expanded_combos[k][iface_type]++;
+ }
+ }
+ }
+ return expanded_combos;
+}
+
+bool WifiChip::canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+ const std::map<IfaceType, size_t>& expanded_combo,
+ IfaceType requested_type) {
+ const auto current_combo = getCurrentIfaceCombination();
+
+ // Check if we have space for 1 more iface of |type| in this combo
+ for (const auto type :
+ {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+ size_t num_ifaces_needed = current_combo.at(type);
+ if (type == requested_type) {
+ num_ifaces_needed++;
+ }
+ size_t num_ifaces_allowed = expanded_combo.at(type);
+ if (num_ifaces_needed > num_ifaces_allowed) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+// ChipIfaceCombination.
+// b) Check if the requested iface type can be added to the current mode
+// with the iface combination that is already active.
+bool WifiChip::canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
+ IfaceType requested_type) {
+ if (!isValidModeId(current_mode_id_)) {
+ LOG(ERROR) << "Chip not configured in a mode yet";
+ return false;
+ }
+ const auto combinations = getCurrentModeIfaceCombinations();
+ for (const auto& combination : combinations) {
+ const auto expanded_combos = expandIfaceCombinations(combination);
+ for (const auto& expanded_combo : expanded_combos) {
+ if (canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+ expanded_combo, requested_type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// Note: This does not consider ifaces already active. It only checks if the
+// provided expanded iface combination can support the requested combo.
+bool WifiChip::canExpandedIfaceComboSupportIfaceCombo(
+ const std::map<IfaceType, size_t>& expanded_combo,
+ const std::map<IfaceType, size_t>& req_combo) {
+ // Check if we have space for 1 more iface of |type| in this combo
+ for (const auto type :
+ {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+ if (req_combo.count(type) == 0) {
+ // Iface of "type" not in the req_combo.
+ continue;
+ }
+ size_t num_ifaces_needed = req_combo.at(type);
+ size_t num_ifaces_allowed = expanded_combo.at(type);
+ if (num_ifaces_needed > num_ifaces_allowed) {
+ return false;
+ }
+ }
+ return true;
+}
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+// ChipIfaceCombination.
+// b) Check if the requested iface combo can be added to the current mode.
+// Note: This does not consider ifaces already active. It only checks if the
+// current mode can support the requested combo.
+bool WifiChip::canCurrentModeSupportIfaceCombo(
+ const std::map<IfaceType, size_t>& req_combo) {
+ if (!isValidModeId(current_mode_id_)) {
+ LOG(ERROR) << "Chip not configured in a mode yet";
+ return false;
+ }
+ const auto combinations = getCurrentModeIfaceCombinations();
+ for (const auto& combination : combinations) {
+ const auto expanded_combos = expandIfaceCombinations(combination);
+ for (const auto& expanded_combo : expanded_combos) {
+ if (canExpandedIfaceComboSupportIfaceCombo(expanded_combo,
+ req_combo)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+// ChipIfaceCombination.
+// b) Check if the requested iface type can be added to the current mode.
+bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType requested_type) {
+ // Check if we can support atleast 1 iface of type.
+ std::map<IfaceType, size_t> req_iface_combo;
+ req_iface_combo[requested_type] = 1;
+ return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
+bool WifiChip::isValidModeId(ChipModeId mode_id) {
+ for (const auto& mode : modes_) {
+ if (mode.id == mode_id) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() {
+ // Check if we can support atleast 1 STA & 1 AP concurrently.
+ std::map<IfaceType, size_t> req_iface_combo;
+ req_iface_combo[IfaceType::AP] = 1;
+ req_iface_combo[IfaceType::STA] = 1;
+ return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
+bool WifiChip::isDualApAllowedInCurrentMode() {
+ // Check if we can support atleast 1 STA & 1 AP concurrently.
+ std::map<IfaceType, size_t> req_iface_combo;
+ req_iface_combo[IfaceType::AP] = 2;
+ return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
+std::string WifiChip::getFirstActiveWlanIfaceName() {
+ if (sta_ifaces_.size() > 0) return sta_ifaces_[0]->getName();
+ if (ap_ifaces_.size() > 0) return ap_ifaces_[0]->getName();
+ // This could happen if the chip call is made before any STA/AP
+ // iface is created. Default to wlan0 for such cases.
+ LOG(WARNING) << "No active wlan interfaces in use! Using default";
+ return getWlanIfaceName(0);
+}
+
+// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
+// not already in use.
+// Note: This doesn't check the actual presence of these interfaces.
+std::string WifiChip::allocateApOrStaIfaceName(uint32_t start_idx) {
+ for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
+ const auto ifname = getWlanIfaceName(idx);
+ if (findUsingName(ap_ifaces_, ifname)) continue;
+ if (findUsingName(sta_ifaces_, ifname)) continue;
+ return ifname;
+ }
+ // This should never happen. We screwed up somewhere if it did.
+ CHECK(false) << "All wlan interfaces in use already!";
+ return {};
+}
+
+// AP iface names start with idx 1 for modes supporting
+// concurrent STA and not dual AP, else start with idx 0.
+std::string WifiChip::allocateApIfaceName() {
+ return allocateApOrStaIfaceName((isStaApConcurrencyAllowedInCurrentMode() &&
+ !isDualApAllowedInCurrentMode())
+ ? 1
+ : 0);
+}
+
+// STA iface names start with idx 0.
+// Primary STA iface will always be 0.
+std::string WifiChip::allocateStaIfaceName() {
+ return allocateApOrStaIfaceName(0);
+}
+
+bool WifiChip::writeRingbufferFilesInternal() {
+ if (!removeOldFilesInternal()) {
+ LOG(ERROR) << "Error occurred while deleting old tombstone files";
+ return false;
+ }
+ // write ringbuffers to file
+ for (const auto& item : ringbuffer_map_) {
+ const Ringbuffer& cur_buffer = item.second;
+ if (cur_buffer.getData().empty()) {
+ continue;
+ }
+ const std::string file_path_raw =
+ kTombstoneFolderPath + item.first + "XXXXXXXXXX";
+ const int dump_fd = mkstemp(makeCharVec(file_path_raw).data());
+ if (dump_fd == -1) {
+ PLOG(ERROR) << "create file failed";
+ return false;
+ }
+ unique_fd file_auto_closer(dump_fd);
+ for (const auto& cur_block : cur_buffer.getData()) {
+ if (write(dump_fd, cur_block.data(),
+ sizeof(cur_block[0]) * cur_block.size()) == -1) {
+ PLOG(ERROR) << "Error writing to file";
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi_chip.h b/wifi/1.4/default/wifi_chip.h
new file mode 100644
index 0000000..3323ade
--- /dev/null
+++ b/wifi/1.4/default/wifi_chip.h
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_CHIP_H_
+#define WIFI_CHIP_H_
+
+#include <list>
+#include <map>
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.4/IWifiChip.h>
+#include <android/hardware/wifi/1.4/IWifiRttController.h>
+
+#include "hidl_callback_util.h"
+#include "ringbuffer.h"
+#include "wifi_ap_iface.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
+#include "wifi_nan_iface.h"
+#include "wifi_p2p_iface.h"
+#include "wifi_rtt_controller.h"
+#include "wifi_sta_iface.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a Wifi HAL chip instance.
+ * Since there is only a single chip instance used today, there is no
+ * identifying handle information stored here.
+ */
+class WifiChip : public V1_4::IWifiChip {
+ public:
+ WifiChip(
+ ChipId chip_id,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<mode_controller::WifiModeController>
+ mode_controller,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
+ const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+ // HIDL does not provide a built-in mechanism to let the server invalidate
+ // a HIDL interface object after creation. If any client process holds onto
+ // a reference to the object in their context, any method calls on that
+ // reference will continue to be directed to the server.
+ //
+ // However Wifi HAL needs to control the lifetime of these objects. So, add
+ // a public |invalidate| method to |WifiChip| and it's child objects. This
+ // will be used to mark an object invalid when either:
+ // a) Wifi HAL is stopped, or
+ // b) Wifi Chip is reconfigured.
+ //
+ // All HIDL method implementations should check if the object is still
+ // marked valid before processing them.
+ void invalidate();
+ bool isValid();
+ std::set<sp<IWifiChipEventCallback>> getEventCallbacks();
+
+ // HIDL methods exposed.
+ Return<void> getId(getId_cb hidl_status_cb) override;
+ // Deprecated support for this callback
+ Return<void> registerEventCallback(
+ const sp<V1_0::IWifiChipEventCallback>& event_callback,
+ registerEventCallback_cb hidl_status_cb) override;
+ Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+ Return<void> getAvailableModes(
+ getAvailableModes_cb hidl_status_cb) override;
+ Return<void> configureChip(ChipModeId mode_id,
+ configureChip_cb hidl_status_cb) override;
+ Return<void> getMode(getMode_cb hidl_status_cb) override;
+ Return<void> requestChipDebugInfo(
+ requestChipDebugInfo_cb hidl_status_cb) override;
+ Return<void> requestDriverDebugDump(
+ requestDriverDebugDump_cb hidl_status_cb) override;
+ Return<void> requestFirmwareDebugDump(
+ requestFirmwareDebugDump_cb hidl_status_cb) override;
+ Return<void> createApIface(createApIface_cb hidl_status_cb) override;
+ Return<void> getApIfaceNames(getApIfaceNames_cb hidl_status_cb) override;
+ Return<void> getApIface(const hidl_string& ifname,
+ getApIface_cb hidl_status_cb) override;
+ Return<void> removeApIface(const hidl_string& ifname,
+ removeApIface_cb hidl_status_cb) override;
+ Return<void> createNanIface(createNanIface_cb hidl_status_cb) override;
+ Return<void> getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) override;
+ Return<void> getNanIface(const hidl_string& ifname,
+ getNanIface_cb hidl_status_cb) override;
+ Return<void> removeNanIface(const hidl_string& ifname,
+ removeNanIface_cb hidl_status_cb) override;
+ Return<void> createP2pIface(createP2pIface_cb hidl_status_cb) override;
+ Return<void> getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) override;
+ Return<void> getP2pIface(const hidl_string& ifname,
+ getP2pIface_cb hidl_status_cb) override;
+ Return<void> removeP2pIface(const hidl_string& ifname,
+ removeP2pIface_cb hidl_status_cb) override;
+ Return<void> createStaIface(createStaIface_cb hidl_status_cb) override;
+ Return<void> getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) override;
+ Return<void> getStaIface(const hidl_string& ifname,
+ getStaIface_cb hidl_status_cb) override;
+ Return<void> removeStaIface(const hidl_string& ifname,
+ removeStaIface_cb hidl_status_cb) override;
+ Return<void> createRttController(
+ const sp<IWifiIface>& bound_iface,
+ createRttController_cb hidl_status_cb) override;
+ Return<void> getDebugRingBuffersStatus(
+ getDebugRingBuffersStatus_cb hidl_status_cb) override;
+ Return<void> startLoggingToDebugRingBuffer(
+ const hidl_string& ring_name,
+ WifiDebugRingBufferVerboseLevel verbose_level,
+ uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
+ startLoggingToDebugRingBuffer_cb hidl_status_cb) override;
+ Return<void> forceDumpToDebugRingBuffer(
+ const hidl_string& ring_name,
+ forceDumpToDebugRingBuffer_cb hidl_status_cb) override;
+ Return<void> flushRingBufferToFile(
+ flushRingBufferToFile_cb hidl_status_cb) override;
+ Return<void> stopLoggingToDebugRingBuffer(
+ stopLoggingToDebugRingBuffer_cb hidl_status_cb) override;
+ Return<void> getDebugHostWakeReasonStats(
+ getDebugHostWakeReasonStats_cb hidl_status_cb) override;
+ Return<void> enableDebugErrorAlerts(
+ bool enable, enableDebugErrorAlerts_cb hidl_status_cb) override;
+ Return<void> selectTxPowerScenario(
+ V1_1::IWifiChip::TxPowerScenario scenario,
+ selectTxPowerScenario_cb hidl_status_cb) override;
+ Return<void> resetTxPowerScenario(
+ resetTxPowerScenario_cb hidl_status_cb) override;
+ Return<void> setLatencyMode(LatencyMode mode,
+ setLatencyMode_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_2(
+ const sp<V1_2::IWifiChipEventCallback>& event_callback,
+ registerEventCallback_1_2_cb hidl_status_cb) override;
+ Return<void> selectTxPowerScenario_1_2(
+ TxPowerScenario scenario,
+ selectTxPowerScenario_cb hidl_status_cb) override;
+ Return<void> getCapabilities_1_3(
+ getCapabilities_cb hidl_status_cb) override;
+ Return<void> debug(const hidl_handle& handle,
+ const hidl_vec<hidl_string>& options) override;
+ Return<void> createRttController_1_4(
+ const sp<IWifiIface>& bound_iface,
+ createRttController_1_4_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_4(
+ const sp<IWifiChipEventCallback>& event_callback,
+ registerEventCallback_1_4_cb hidl_status_cb) override;
+
+ private:
+ void invalidateAndRemoveAllIfaces();
+ // When a STA iface is removed any dependent NAN-ifaces/RTT-controllers are
+ // invalidated & removed.
+ void invalidateAndRemoveDependencies(const std::string& removed_iface_name);
+
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<WifiStatus, ChipId> getIdInternal();
+ // Deprecated support for this callback
+ WifiStatus registerEventCallbackInternal(
+ const sp<V1_0::IWifiChipEventCallback>& event_callback);
+ std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
+ std::pair<WifiStatus, std::vector<ChipMode>> getAvailableModesInternal();
+ WifiStatus configureChipInternal(
+ std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
+ std::pair<WifiStatus, uint32_t> getModeInternal();
+ std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
+ requestChipDebugInfoInternal();
+ std::pair<WifiStatus, std::vector<uint8_t>>
+ requestDriverDebugDumpInternal();
+ std::pair<WifiStatus, std::vector<uint8_t>>
+ requestFirmwareDebugDumpInternal();
+ std::pair<WifiStatus, sp<IWifiApIface>> createApIfaceInternal();
+ std::pair<WifiStatus, std::vector<hidl_string>> getApIfaceNamesInternal();
+ std::pair<WifiStatus, sp<IWifiApIface>> getApIfaceInternal(
+ const std::string& ifname);
+ WifiStatus removeApIfaceInternal(const std::string& ifname);
+ std::pair<WifiStatus, sp<IWifiNanIface>> createNanIfaceInternal();
+ std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
+ std::pair<WifiStatus, sp<IWifiNanIface>> getNanIfaceInternal(
+ const std::string& ifname);
+ WifiStatus removeNanIfaceInternal(const std::string& ifname);
+ std::pair<WifiStatus, sp<IWifiP2pIface>> createP2pIfaceInternal();
+ std::pair<WifiStatus, std::vector<hidl_string>> getP2pIfaceNamesInternal();
+ std::pair<WifiStatus, sp<IWifiP2pIface>> getP2pIfaceInternal(
+ const std::string& ifname);
+ WifiStatus removeP2pIfaceInternal(const std::string& ifname);
+ std::pair<WifiStatus, sp<V1_3::IWifiStaIface>> createStaIfaceInternal();
+ std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
+ 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>>
+ createRttControllerInternal(const sp<IWifiIface>& bound_iface);
+ std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
+ getDebugRingBuffersStatusInternal();
+ WifiStatus startLoggingToDebugRingBufferInternal(
+ const hidl_string& ring_name,
+ WifiDebugRingBufferVerboseLevel verbose_level,
+ uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes);
+ WifiStatus forceDumpToDebugRingBufferInternal(const hidl_string& ring_name);
+ WifiStatus flushRingBufferToFileInternal();
+ WifiStatus stopLoggingToDebugRingBufferInternal();
+ std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
+ getDebugHostWakeReasonStatsInternal();
+ WifiStatus enableDebugErrorAlertsInternal(bool enable);
+ WifiStatus selectTxPowerScenarioInternal(
+ V1_1::IWifiChip::TxPowerScenario scenario);
+ WifiStatus resetTxPowerScenarioInternal();
+ WifiStatus setLatencyModeInternal(LatencyMode mode);
+ WifiStatus registerEventCallbackInternal_1_2(
+ const sp<V1_2::IWifiChipEventCallback>& event_callback);
+ WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
+ std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_3();
+ std::pair<WifiStatus, sp<IWifiRttController>>
+ createRttControllerInternal_1_4(const sp<IWifiIface>& bound_iface);
+ WifiStatus registerEventCallbackInternal_1_4(
+ const sp<IWifiChipEventCallback>& event_callback);
+
+ WifiStatus handleChipConfiguration(
+ std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
+ WifiStatus registerDebugRingBufferCallback();
+ WifiStatus registerRadioModeChangeCallback();
+
+ std::vector<IWifiChip::ChipIfaceCombination>
+ getCurrentModeIfaceCombinations();
+ std::map<IfaceType, size_t> getCurrentIfaceCombination();
+ std::vector<std::map<IfaceType, size_t>> expandIfaceCombinations(
+ const IWifiChip::ChipIfaceCombination& combination);
+ bool canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+ const std::map<IfaceType, size_t>& expanded_combo,
+ IfaceType requested_type);
+ bool canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
+ IfaceType requested_type);
+ bool canExpandedIfaceComboSupportIfaceCombo(
+ const std::map<IfaceType, size_t>& expanded_combo,
+ const std::map<IfaceType, size_t>& req_combo);
+ bool canCurrentModeSupportIfaceCombo(
+ const std::map<IfaceType, size_t>& req_combo);
+ bool canCurrentModeSupportIfaceOfType(IfaceType requested_type);
+ bool isValidModeId(ChipModeId mode_id);
+ bool isStaApConcurrencyAllowedInCurrentMode();
+ bool isDualApAllowedInCurrentMode();
+ std::string getFirstActiveWlanIfaceName();
+ std::string allocateApOrStaIfaceName(uint32_t start_idx);
+ std::string allocateApIfaceName();
+ std::string allocateStaIfaceName();
+ bool writeRingbufferFilesInternal();
+
+ ChipId chip_id_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
+ std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+ std::vector<sp<WifiApIface>> ap_ifaces_;
+ std::vector<sp<WifiNanIface>> nan_ifaces_;
+ std::vector<sp<WifiP2pIface>> p2p_ifaces_;
+ std::vector<sp<WifiStaIface>> sta_ifaces_;
+ std::vector<sp<WifiRttController>> rtt_controllers_;
+ std::map<std::string, Ringbuffer> ringbuffer_map_;
+ bool is_valid_;
+ // Members pertaining to chip configuration.
+ uint32_t current_mode_id_;
+ std::vector<IWifiChip::ChipMode> modes_;
+ // The legacy ring buffer callback API has only a global callback
+ // registration mechanism. Use this to check if we have already
+ // registered a callback.
+ bool debug_ring_buffer_cb_registered_;
+ hidl_callback_util::HidlCallbackHandler<IWifiChipEventCallback>
+ event_cb_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiChip);
+};
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_CHIP_H_
diff --git a/wifi/1.4/default/wifi_feature_flags.cpp b/wifi/1.4/default/wifi_feature_flags.cpp
new file mode 100644
index 0000000..195b460
--- /dev/null
+++ b/wifi/1.4/default/wifi_feature_flags.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#include "wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace feature_flags {
+
+using V1_0::ChipModeId;
+using V1_0::IfaceType;
+using V1_0::IWifiChip;
+
+/* The chip may either have a single mode supporting any number of combinations,
+ * or a fixed dual-mode (so it involves firmware loading to switch between
+ * modes) setting. If there is a need to support more modes, it needs to be
+ * implemented manually in WiFi HAL (see changeFirmwareMode in
+ * WifiChip::handleChipConfiguration).
+ *
+ * Supported combinations are defined in device's makefile, for example:
+ * WIFI_HAL_INTERFACE_COMBINATIONS := {{{STA, AP}, 1}, {{P2P, NAN}, 1}},
+ * WIFI_HAL_INTERFACE_COMBINATIONS += {{{STA}, 1}, {{AP}, 2}}
+ * What means:
+ * Interface combination 1: 1 STA or AP and 1 P2P or NAN concurrent iface
+ * operations.
+ * Interface combination 2: 1 STA and 2 AP concurrent iface operations.
+ *
+ * For backward compatibility, the following makefile flags can be used to
+ * generate combinations list:
+ * - WIFI_HIDL_FEATURE_DUAL_INTERFACE
+ * - WIFI_HIDL_FEATURE_DISABLE_AP
+ * - WIFI_HIDL_FEATURE_AWARE
+ * However, they are ignored if WIFI_HAL_INTERFACE_COMBINATIONS was provided.
+ * With WIFI_HIDL_FEATURE_DUAL_INTERFACE flag set, there is a single mode with
+ * two interface combinations:
+ * Interface Combination 1: Will support 1 STA and 1 P2P or NAN (optional)
+ * concurrent iface operations.
+ * Interface Combination 2: Will support 1 STA and 1 AP concurrent
+ * iface operations.
+ *
+ * The only dual-mode configuration supported is for alternating STA and AP
+ * mode, that may involve firmware reloading. In such case, there are 2 separate
+ * modes of operation with 1 interface combination each:
+ * Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN (optional)
+ * concurrent iface operations.
+ * Mode 2 (AP mode): Will support 1 AP iface operation.
+ *
+ * If Aware is enabled, the iface combination will be modified to support either
+ * P2P or NAN in place of just P2P.
+ */
+// clang-format off
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS
+constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
+#elif defined(WIFI_HIDL_FEATURE_DUAL_INTERFACE)
+// former V2 (fixed dual interface) setup expressed as V3
+constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
+# ifdef WIFI_HIDL_FEATURE_DISABLE_AP
+# ifdef WIFI_HIDL_FEATURE_AWARE
+// 1 STA + 1 of (P2P or NAN)
+# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
+# else
+// 1 STA + 1 P2P
+# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
+# endif
+# else
+# ifdef WIFI_HIDL_FEATURE_AWARE
+// (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
+# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
+ {{{STA}, 1}, {{P2P, NAN}, 1}}
+# else
+// (1 STA + 1 AP) or (1 STA + 1 P2P)
+# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
+ {{{STA}, 1}, {{P2P}, 1}}
+# endif
+# endif
+#else
+// V1 (fixed single interface, dual-mode chip)
+constexpr ChipModeId kMainModeId = chip_mode_ids::kV1Sta;
+# ifdef WIFI_HIDL_FEATURE_AWARE
+// 1 STA + 1 of (P2P or NAN)
+# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
+# else
+// 1 STA + 1 P2P
+# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
+# endif
+
+# ifndef WIFI_HIDL_FEATURE_DISABLE_AP
+# define WIFI_HAL_INTERFACE_COMBINATIONS_AP {{{AP}, 1}}
+# endif
+#endif
+// clang-format on
+
+/**
+ * Helper class to convert a collection of combination limits to a combination.
+ *
+ * The main point here is to simplify the syntax required by
+ * WIFI_HAL_INTERFACE_COMBINATIONS.
+ */
+struct ChipIfaceCombination
+ : public hidl_vec<IWifiChip::ChipIfaceCombinationLimit> {
+ ChipIfaceCombination(
+ const std::initializer_list<IWifiChip::ChipIfaceCombinationLimit> list)
+ : hidl_vec(list) {}
+
+ operator IWifiChip::ChipIfaceCombination() const { return {*this}; }
+
+ static hidl_vec<IWifiChip::ChipIfaceCombination> make_vec(
+ const std::initializer_list<ChipIfaceCombination> list) {
+ return hidl_vec<IWifiChip::ChipIfaceCombination>( //
+ std::begin(list), std::end(list));
+ }
+};
+
+#define STA IfaceType::STA
+#define AP IfaceType::AP
+#define P2P IfaceType::P2P
+#define NAN IfaceType::NAN
+static const std::vector<IWifiChip::ChipMode> kChipModes{
+ {kMainModeId,
+ ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS})},
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP
+ {chip_mode_ids::kV1Ap,
+ ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
+#endif
+};
+#undef STA
+#undef AP
+#undef P2P
+#undef NAN
+
+#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+#pragma message \
+ "WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION is deprecated; override " \
+ "'config_wifi_ap_randomization_supported' in " \
+ "frameworks/base/core/res/res/values/config.xml in the device overlay " \
+ "instead"
+#endif // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+
+WifiFeatureFlags::WifiFeatureFlags() {}
+
+std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes() {
+ return kChipModes;
+}
+
+} // namespace feature_flags
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi_feature_flags.h b/wifi/1.4/default/wifi_feature_flags.h
new file mode 100644
index 0000000..292dedf
--- /dev/null
+++ b/wifi/1.4/default/wifi_feature_flags.h
@@ -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.
+ */
+
+#ifndef WIFI_FEATURE_FLAGS_H_
+#define WIFI_FEATURE_FLAGS_H_
+
+#include <android/hardware/wifi/1.2/IWifiChip.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace feature_flags {
+
+namespace chip_mode_ids {
+// These mode ID's should be unique (even across combo versions). Refer to
+// handleChipConfiguration() for it's usage.
+constexpr V1_0::ChipModeId kInvalid = UINT32_MAX;
+// Mode ID's for V1
+constexpr V1_0::ChipModeId kV1Sta = 0;
+constexpr V1_0::ChipModeId kV1Ap = 1;
+// Mode ID for V3
+constexpr V1_0::ChipModeId kV3 = 3;
+} // namespace chip_mode_ids
+
+class WifiFeatureFlags {
+ public:
+ WifiFeatureFlags();
+ virtual ~WifiFeatureFlags() = default;
+
+ virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes();
+};
+
+} // namespace feature_flags
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.4/default/wifi_iface_util.cpp b/wifi/1.4/default/wifi_iface_util.cpp
new file mode 100644
index 0000000..2883b46
--- /dev/null
+++ b/wifi/1.4/default/wifi_iface_util.cpp
@@ -0,0 +1,118 @@
+/*
+ * 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 <cstddef>
+#include <iostream>
+#include <limits>
+#include <random>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <private/android_filesystem_config.h>
+
+#undef NAN
+#include "wifi_iface_util.h"
+
+namespace {
+// Constants to set the local bit & clear the multicast bit.
+constexpr uint8_t kMacAddressMulticastMask = 0x01;
+constexpr uint8_t kMacAddressLocallyAssignedMask = 0x02;
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace iface_util {
+
+WifiIfaceUtil::WifiIfaceUtil(
+ const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+ : iface_tool_(iface_tool),
+ random_mac_address_(nullptr),
+ event_handlers_map_() {}
+
+std::array<uint8_t, 6> WifiIfaceUtil::getFactoryMacAddress(
+ const std::string& iface_name) {
+ return iface_tool_.lock()->GetFactoryMacAddress(iface_name.c_str());
+}
+
+bool WifiIfaceUtil::setMacAddress(const std::string& iface_name,
+ const std::array<uint8_t, 6>& mac) {
+ if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
+ LOG(ERROR) << "SetUpState(false) failed.";
+ return false;
+ }
+ if (!iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac)) {
+ LOG(ERROR) << "SetMacAddress failed.";
+ return false;
+ }
+ if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
+ LOG(ERROR) << "SetUpState(true) failed.";
+ return false;
+ }
+ IfaceEventHandlers event_handlers = {};
+ const auto it = event_handlers_map_.find(iface_name);
+ if (it != event_handlers_map_.end()) {
+ event_handlers = it->second;
+ }
+ if (event_handlers.on_state_toggle_off_on != nullptr) {
+ event_handlers.on_state_toggle_off_on(iface_name);
+ }
+ LOG(DEBUG) << "Successfully SetMacAddress.";
+ return true;
+}
+
+std::array<uint8_t, 6> WifiIfaceUtil::getOrCreateRandomMacAddress() {
+ if (random_mac_address_) {
+ return *random_mac_address_.get();
+ }
+ random_mac_address_ =
+ std::make_unique<std::array<uint8_t, 6>>(createRandomMacAddress());
+ return *random_mac_address_.get();
+}
+
+void WifiIfaceUtil::registerIfaceEventHandlers(const std::string& iface_name,
+ IfaceEventHandlers handlers) {
+ event_handlers_map_[iface_name] = handlers;
+}
+
+void WifiIfaceUtil::unregisterIfaceEventHandlers(
+ const std::string& iface_name) {
+ event_handlers_map_.erase(iface_name);
+}
+
+std::array<uint8_t, 6> WifiIfaceUtil::createRandomMacAddress() {
+ std::array<uint8_t, 6> address = {};
+ std::random_device rd;
+ std::default_random_engine engine(rd());
+ std::uniform_int_distribution<uint8_t> dist(
+ std::numeric_limits<uint8_t>::min(),
+ std::numeric_limits<uint8_t>::max());
+ for (size_t i = 0; i < address.size(); i++) {
+ address[i] = dist(engine);
+ }
+ // Set the local bit and clear the multicast bit.
+ address[0] |= kMacAddressLocallyAssignedMask;
+ address[0] &= ~kMacAddressMulticastMask;
+ return address;
+}
+} // namespace iface_util
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi_iface_util.h b/wifi/1.4/default/wifi_iface_util.h
new file mode 100644
index 0000000..35edff6
--- /dev/null
+++ b/wifi/1.4/default/wifi_iface_util.h
@@ -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.
+ */
+
+#ifndef WIFI_IFACE_UTIL_H_
+#define WIFI_IFACE_UTIL_H_
+
+#include <wifi_system/interface_tool.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace iface_util {
+
+// Iface event handlers.
+struct IfaceEventHandlers {
+ // Callback to be invoked when the iface is set down & up for MAC address
+ // change.
+ std::function<void(const std::string& iface_name)> on_state_toggle_off_on;
+};
+
+/**
+ * Util class for common iface operations.
+ */
+class WifiIfaceUtil {
+ public:
+ WifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+ virtual ~WifiIfaceUtil() = default;
+
+ virtual std::array<uint8_t, 6> getFactoryMacAddress(
+ const std::string& iface_name);
+ virtual bool setMacAddress(const std::string& iface_name,
+ const std::array<uint8_t, 6>& mac);
+ // Get or create a random MAC address. The MAC address returned from
+ // this method will remain the same throughout the lifetime of the HAL
+ // daemon. (So, changes on every reboot)
+ virtual std::array<uint8_t, 6> getOrCreateRandomMacAddress();
+
+ // Register for any iface event callbacks for the provided interface.
+ virtual void registerIfaceEventHandlers(const std::string& iface_name,
+ IfaceEventHandlers handlers);
+ virtual void unregisterIfaceEventHandlers(const std::string& iface_name);
+
+ private:
+ std::array<uint8_t, 6> createRandomMacAddress();
+
+ std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+ std::unique_ptr<std::array<uint8_t, 6>> random_mac_address_;
+ std::map<std::string, IfaceEventHandlers> event_handlers_map_;
+};
+
+} // namespace iface_util
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp
new file mode 100644
index 0000000..3ca3226
--- /dev/null
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -0,0 +1,1461 @@
+/*
+ * 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.
+ */
+
+#include <array>
+#include <chrono>
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+
+#include "hidl_sync_util.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_stubs.h"
+
+namespace {
+// Constants ported over from the legacy HAL calling code
+// (com_android_server_wifi_WifiNative.cpp). This will all be thrown
+// away when this shim layer is replaced by the real vendor
+// implementation.
+static constexpr uint32_t kMaxVersionStringLength = 256;
+static constexpr uint32_t kMaxCachedGscanResults = 64;
+static constexpr uint32_t kMaxGscanFrequenciesForBand = 64;
+static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
+static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
+static constexpr uint32_t kMaxRingBuffers = 10;
+static constexpr uint32_t kMaxStopCompleteWaitMs = 100;
+static constexpr char kDriverPropName[] = "wlan.driver.status";
+
+// Helper function to create a non-const char* for legacy Hal API's.
+std::vector<char> makeCharVec(const std::string& str) {
+ std::vector<char> vec(str.size() + 1);
+ vec.assign(str.begin(), str.end());
+ vec.push_back('\0');
+ return vec;
+}
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace legacy_hal {
+// Legacy HAL functions accept "C" style function pointers, so use global
+// functions to pass to the legacy HAL function and store the corresponding
+// std::function methods to be invoked.
+//
+// Callback to be invoked once |stop| is complete
+std::function<void(wifi_handle handle)> on_stop_complete_internal_callback;
+void onAsyncStopComplete(wifi_handle handle) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_stop_complete_internal_callback) {
+ on_stop_complete_internal_callback(handle);
+ // Invalidate this callback since we don't want this firing again.
+ on_stop_complete_internal_callback = nullptr;
+ }
+}
+
+// Callback to be invoked for driver dump.
+std::function<void(char*, int)> on_driver_memory_dump_internal_callback;
+void onSyncDriverMemoryDump(char* buffer, int buffer_size) {
+ if (on_driver_memory_dump_internal_callback) {
+ on_driver_memory_dump_internal_callback(buffer, buffer_size);
+ }
+}
+
+// Callback to be invoked for firmware dump.
+std::function<void(char*, int)> on_firmware_memory_dump_internal_callback;
+void onSyncFirmwareMemoryDump(char* buffer, int buffer_size) {
+ if (on_firmware_memory_dump_internal_callback) {
+ on_firmware_memory_dump_internal_callback(buffer, buffer_size);
+ }
+}
+
+// Callback to be invoked for Gscan events.
+std::function<void(wifi_request_id, wifi_scan_event)>
+ on_gscan_event_internal_callback;
+void onAsyncGscanEvent(wifi_request_id id, wifi_scan_event event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_gscan_event_internal_callback) {
+ on_gscan_event_internal_callback(id, event);
+ }
+}
+
+// Callback to be invoked for Gscan full results.
+std::function<void(wifi_request_id, wifi_scan_result*, uint32_t)>
+ on_gscan_full_result_internal_callback;
+void onAsyncGscanFullResult(wifi_request_id id, wifi_scan_result* result,
+ uint32_t buckets_scanned) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_gscan_full_result_internal_callback) {
+ on_gscan_full_result_internal_callback(id, result, buckets_scanned);
+ }
+}
+
+// Callback to be invoked for link layer stats results.
+std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
+ on_link_layer_stats_result_internal_callback;
+void onSyncLinkLayerStatsResult(wifi_request_id id, wifi_iface_stat* iface_stat,
+ int num_radios, wifi_radio_stat* radio_stat) {
+ if (on_link_layer_stats_result_internal_callback) {
+ on_link_layer_stats_result_internal_callback(id, iface_stat, num_radios,
+ radio_stat);
+ }
+}
+
+// Callback to be invoked for rssi threshold breach.
+std::function<void((wifi_request_id, uint8_t*, int8_t))>
+ on_rssi_threshold_breached_internal_callback;
+void onAsyncRssiThresholdBreached(wifi_request_id id, uint8_t* bssid,
+ int8_t rssi) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_rssi_threshold_breached_internal_callback) {
+ on_rssi_threshold_breached_internal_callback(id, bssid, rssi);
+ }
+}
+
+// Callback to be invoked for ring buffer data indication.
+std::function<void(char*, char*, int, wifi_ring_buffer_status*)>
+ on_ring_buffer_data_internal_callback;
+void onAsyncRingBufferData(char* ring_name, char* buffer, int buffer_size,
+ wifi_ring_buffer_status* status) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_ring_buffer_data_internal_callback) {
+ on_ring_buffer_data_internal_callback(ring_name, buffer, buffer_size,
+ status);
+ }
+}
+
+// Callback to be invoked for error alert indication.
+std::function<void(wifi_request_id, char*, int, int)>
+ on_error_alert_internal_callback;
+void onAsyncErrorAlert(wifi_request_id id, char* buffer, int buffer_size,
+ int err_code) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_error_alert_internal_callback) {
+ on_error_alert_internal_callback(id, buffer, buffer_size, err_code);
+ }
+}
+
+// Callback to be invoked for radio mode change indication.
+std::function<void(wifi_request_id, uint32_t, wifi_mac_info*)>
+ on_radio_mode_change_internal_callback;
+void onAsyncRadioModeChange(wifi_request_id id, uint32_t num_macs,
+ wifi_mac_info* mac_infos) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_radio_mode_change_internal_callback) {
+ on_radio_mode_change_internal_callback(id, num_macs, mac_infos);
+ }
+}
+
+// Callback to be invoked for rtt results results.
+std::function<void(wifi_request_id, unsigned num_results,
+ wifi_rtt_result* rtt_results[])>
+ on_rtt_results_internal_callback;
+void onAsyncRttResults(wifi_request_id id, unsigned num_results,
+ wifi_rtt_result* rtt_results[]) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_rtt_results_internal_callback) {
+ on_rtt_results_internal_callback(id, num_results, rtt_results);
+ on_rtt_results_internal_callback = nullptr;
+ }
+}
+
+// Callbacks for the various NAN operations.
+// NOTE: These have very little conversions to perform before invoking the user
+// callbacks.
+// So, handle all of them here directly to avoid adding an unnecessary layer.
+std::function<void(transaction_id, const NanResponseMsg&)>
+ on_nan_notify_response_user_callback;
+void onAysncNanNotifyResponse(transaction_id id, NanResponseMsg* msg) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_notify_response_user_callback && msg) {
+ on_nan_notify_response_user_callback(id, *msg);
+ }
+}
+
+std::function<void(const NanPublishRepliedInd&)>
+ on_nan_event_publish_replied_user_callback;
+void onAysncNanEventPublishReplied(NanPublishRepliedInd* /* event */) {
+ LOG(ERROR) << "onAysncNanEventPublishReplied triggered";
+}
+
+std::function<void(const NanPublishTerminatedInd&)>
+ on_nan_event_publish_terminated_user_callback;
+void onAysncNanEventPublishTerminated(NanPublishTerminatedInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_publish_terminated_user_callback && event) {
+ on_nan_event_publish_terminated_user_callback(*event);
+ }
+}
+
+std::function<void(const NanMatchInd&)> on_nan_event_match_user_callback;
+void onAysncNanEventMatch(NanMatchInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_match_user_callback && event) {
+ on_nan_event_match_user_callback(*event);
+ }
+}
+
+std::function<void(const NanMatchExpiredInd&)>
+ on_nan_event_match_expired_user_callback;
+void onAysncNanEventMatchExpired(NanMatchExpiredInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_match_expired_user_callback && event) {
+ on_nan_event_match_expired_user_callback(*event);
+ }
+}
+
+std::function<void(const NanSubscribeTerminatedInd&)>
+ on_nan_event_subscribe_terminated_user_callback;
+void onAysncNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_subscribe_terminated_user_callback && event) {
+ on_nan_event_subscribe_terminated_user_callback(*event);
+ }
+}
+
+std::function<void(const NanFollowupInd&)> on_nan_event_followup_user_callback;
+void onAysncNanEventFollowup(NanFollowupInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_followup_user_callback && event) {
+ on_nan_event_followup_user_callback(*event);
+ }
+}
+
+std::function<void(const NanDiscEngEventInd&)>
+ on_nan_event_disc_eng_event_user_callback;
+void onAysncNanEventDiscEngEvent(NanDiscEngEventInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_disc_eng_event_user_callback && event) {
+ on_nan_event_disc_eng_event_user_callback(*event);
+ }
+}
+
+std::function<void(const NanDisabledInd&)> on_nan_event_disabled_user_callback;
+void onAysncNanEventDisabled(NanDisabledInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_disabled_user_callback && event) {
+ on_nan_event_disabled_user_callback(*event);
+ }
+}
+
+std::function<void(const NanTCAInd&)> on_nan_event_tca_user_callback;
+void onAysncNanEventTca(NanTCAInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_tca_user_callback && event) {
+ on_nan_event_tca_user_callback(*event);
+ }
+}
+
+std::function<void(const NanBeaconSdfPayloadInd&)>
+ on_nan_event_beacon_sdf_payload_user_callback;
+void onAysncNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_beacon_sdf_payload_user_callback && event) {
+ on_nan_event_beacon_sdf_payload_user_callback(*event);
+ }
+}
+
+std::function<void(const NanDataPathRequestInd&)>
+ on_nan_event_data_path_request_user_callback;
+void onAysncNanEventDataPathRequest(NanDataPathRequestInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_data_path_request_user_callback && event) {
+ on_nan_event_data_path_request_user_callback(*event);
+ }
+}
+std::function<void(const NanDataPathConfirmInd&)>
+ on_nan_event_data_path_confirm_user_callback;
+void onAysncNanEventDataPathConfirm(NanDataPathConfirmInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_data_path_confirm_user_callback && event) {
+ on_nan_event_data_path_confirm_user_callback(*event);
+ }
+}
+
+std::function<void(const NanDataPathEndInd&)>
+ on_nan_event_data_path_end_user_callback;
+void onAysncNanEventDataPathEnd(NanDataPathEndInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_data_path_end_user_callback && event) {
+ on_nan_event_data_path_end_user_callback(*event);
+ }
+}
+
+std::function<void(const NanTransmitFollowupInd&)>
+ on_nan_event_transmit_follow_up_user_callback;
+void onAysncNanEventTransmitFollowUp(NanTransmitFollowupInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_transmit_follow_up_user_callback && event) {
+ on_nan_event_transmit_follow_up_user_callback(*event);
+ }
+}
+
+std::function<void(const NanRangeRequestInd&)>
+ on_nan_event_range_request_user_callback;
+void onAysncNanEventRangeRequest(NanRangeRequestInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_range_request_user_callback && event) {
+ on_nan_event_range_request_user_callback(*event);
+ }
+}
+
+std::function<void(const NanRangeReportInd&)>
+ on_nan_event_range_report_user_callback;
+void onAysncNanEventRangeReport(NanRangeReportInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_range_report_user_callback && event) {
+ on_nan_event_range_report_user_callback(*event);
+ }
+}
+
+std::function<void(const NanDataPathScheduleUpdateInd&)>
+ on_nan_event_schedule_update_user_callback;
+void onAsyncNanEventScheduleUpdate(NanDataPathScheduleUpdateInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_schedule_update_user_callback && event) {
+ on_nan_event_schedule_update_user_callback(*event);
+ }
+}
+// End of the free-standing "C" style callbacks.
+
+WifiLegacyHal::WifiLegacyHal(
+ const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+ : global_handle_(nullptr),
+ awaiting_event_loop_termination_(false),
+ is_started_(false),
+ iface_tool_(iface_tool) {}
+
+wifi_error WifiLegacyHal::initialize() {
+ LOG(DEBUG) << "Initialize legacy HAL";
+ // TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
+ // for now is this function call which we can directly call.
+ if (!initHalFuncTableWithStubs(&global_func_table_)) {
+ LOG(ERROR)
+ << "Failed to initialize legacy hal function table with stubs";
+ return WIFI_ERROR_UNKNOWN;
+ }
+ wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
+ if (status != WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize legacy hal function table";
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::start() {
+ // Ensure that we're starting in a good state.
+ CHECK(global_func_table_.wifi_initialize && !global_handle_ &&
+ iface_name_to_handle_.empty() && !awaiting_event_loop_termination_);
+ if (is_started_) {
+ LOG(DEBUG) << "Legacy HAL already started";
+ return WIFI_SUCCESS;
+ }
+ LOG(DEBUG) << "Waiting for the driver ready";
+ wifi_error status = global_func_table_.wifi_wait_for_driver_ready();
+ if (status == WIFI_ERROR_TIMED_OUT) {
+ LOG(ERROR) << "Timed out awaiting driver ready";
+ return status;
+ }
+ property_set(kDriverPropName, "ok");
+
+ LOG(DEBUG) << "Starting legacy HAL";
+ if (!iface_tool_.lock()->SetWifiUpState(true)) {
+ LOG(ERROR) << "Failed to set WiFi interface up";
+ return WIFI_ERROR_UNKNOWN;
+ }
+ status = global_func_table_.wifi_initialize(&global_handle_);
+ if (status != WIFI_SUCCESS || !global_handle_) {
+ LOG(ERROR) << "Failed to retrieve global handle";
+ return status;
+ }
+ std::thread(&WifiLegacyHal::runEventLoop, this).detach();
+ status = retrieveIfaceHandles();
+ if (status != WIFI_SUCCESS || iface_name_to_handle_.empty()) {
+ LOG(ERROR) << "Failed to retrieve wlan interface handle";
+ return status;
+ }
+ LOG(DEBUG) << "Legacy HAL start complete";
+ is_started_ = true;
+ return WIFI_SUCCESS;
+}
+
+wifi_error WifiLegacyHal::stop(
+ /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+ const std::function<void()>& on_stop_complete_user_callback) {
+ if (!is_started_) {
+ LOG(DEBUG) << "Legacy HAL already stopped";
+ on_stop_complete_user_callback();
+ return WIFI_SUCCESS;
+ }
+ LOG(DEBUG) << "Stopping legacy HAL";
+ on_stop_complete_internal_callback = [on_stop_complete_user_callback,
+ this](wifi_handle handle) {
+ CHECK_EQ(global_handle_, handle) << "Handle mismatch";
+ LOG(INFO) << "Legacy HAL stop complete callback received";
+ // Invalidate all the internal pointers now that the HAL is
+ // stopped.
+ invalidate();
+ iface_tool_.lock()->SetWifiUpState(false);
+ on_stop_complete_user_callback();
+ is_started_ = false;
+ };
+ awaiting_event_loop_termination_ = true;
+ global_func_table_.wifi_cleanup(global_handle_, onAsyncStopComplete);
+ const auto status = stop_wait_cv_.wait_for(
+ *lock, std::chrono::milliseconds(kMaxStopCompleteWaitMs),
+ [this] { return !awaiting_event_loop_termination_; });
+ if (!status) {
+ LOG(ERROR) << "Legacy HAL stop failed or timed out";
+ return WIFI_ERROR_UNKNOWN;
+ }
+ LOG(DEBUG) << "Legacy HAL stop complete";
+ return WIFI_SUCCESS;
+}
+
+bool WifiLegacyHal::isStarted() { return is_started_; }
+
+std::pair<wifi_error, std::string> WifiLegacyHal::getDriverVersion(
+ const std::string& iface_name) {
+ std::array<char, kMaxVersionStringLength> buffer;
+ buffer.fill(0);
+ wifi_error status = global_func_table_.wifi_get_driver_version(
+ getIfaceHandle(iface_name), buffer.data(), buffer.size());
+ return {status, buffer.data()};
+}
+
+std::pair<wifi_error, std::string> WifiLegacyHal::getFirmwareVersion(
+ const std::string& iface_name) {
+ std::array<char, kMaxVersionStringLength> buffer;
+ buffer.fill(0);
+ wifi_error status = global_func_table_.wifi_get_firmware_version(
+ getIfaceHandle(iface_name), buffer.data(), buffer.size());
+ return {status, buffer.data()};
+}
+
+std::pair<wifi_error, std::vector<uint8_t>>
+WifiLegacyHal::requestDriverMemoryDump(const std::string& iface_name) {
+ std::vector<uint8_t> driver_dump;
+ on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer,
+ int buffer_size) {
+ driver_dump.insert(driver_dump.end(),
+ reinterpret_cast<uint8_t*>(buffer),
+ reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+ };
+ wifi_error status = global_func_table_.wifi_get_driver_memory_dump(
+ getIfaceHandle(iface_name), {onSyncDriverMemoryDump});
+ on_driver_memory_dump_internal_callback = nullptr;
+ return {status, std::move(driver_dump)};
+}
+
+std::pair<wifi_error, std::vector<uint8_t>>
+WifiLegacyHal::requestFirmwareMemoryDump(const std::string& iface_name) {
+ std::vector<uint8_t> firmware_dump;
+ on_firmware_memory_dump_internal_callback =
+ [&firmware_dump](char* buffer, int buffer_size) {
+ firmware_dump.insert(
+ firmware_dump.end(), reinterpret_cast<uint8_t*>(buffer),
+ reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+ };
+ wifi_error status = global_func_table_.wifi_get_firmware_memory_dump(
+ getIfaceHandle(iface_name), {onSyncFirmwareMemoryDump});
+ on_firmware_memory_dump_internal_callback = nullptr;
+ return {status, std::move(firmware_dump)};
+}
+
+std::pair<wifi_error, uint32_t> WifiLegacyHal::getSupportedFeatureSet(
+ const std::string& iface_name) {
+ feature_set set;
+ static_assert(sizeof(set) == sizeof(uint64_t),
+ "Some feature_flags can not be represented in output");
+ wifi_error status = global_func_table_.wifi_get_supported_feature_set(
+ getIfaceHandle(iface_name), &set);
+ return {status, static_cast<uint32_t>(set)};
+}
+
+std::pair<wifi_error, PacketFilterCapabilities>
+WifiLegacyHal::getPacketFilterCapabilities(const std::string& iface_name) {
+ PacketFilterCapabilities caps;
+ wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+ getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+ return {status, caps};
+}
+
+wifi_error WifiLegacyHal::setPacketFilter(const std::string& iface_name,
+ const std::vector<uint8_t>& program) {
+ return global_func_table_.wifi_set_packet_filter(
+ getIfaceHandle(iface_name), program.data(), program.size());
+}
+
+std::pair<wifi_error, std::vector<uint8_t>>
+WifiLegacyHal::readApfPacketFilterData(const std::string& iface_name) {
+ PacketFilterCapabilities caps;
+ wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+ getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+ if (status != WIFI_SUCCESS) {
+ return {status, {}};
+ }
+
+ // Size the buffer to read the entire program & work memory.
+ std::vector<uint8_t> buffer(caps.max_len);
+
+ status = global_func_table_.wifi_read_packet_filter(
+ getIfaceHandle(iface_name), /*src_offset=*/0, buffer.data(),
+ buffer.size());
+ return {status, move(buffer)};
+}
+
+std::pair<wifi_error, wifi_gscan_capabilities>
+WifiLegacyHal::getGscanCapabilities(const std::string& iface_name) {
+ wifi_gscan_capabilities caps;
+ wifi_error status = global_func_table_.wifi_get_gscan_capabilities(
+ getIfaceHandle(iface_name), &caps);
+ return {status, caps};
+}
+
+wifi_error WifiLegacyHal::startGscan(
+ const std::string& iface_name, wifi_request_id id,
+ const wifi_scan_cmd_params& params,
+ const std::function<void(wifi_request_id)>& on_failure_user_callback,
+ const on_gscan_results_callback& on_results_user_callback,
+ const on_gscan_full_result_callback& on_full_result_user_callback) {
+ // If there is already an ongoing background scan, reject new scan requests.
+ if (on_gscan_event_internal_callback ||
+ on_gscan_full_result_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+
+ // This callback will be used to either trigger |on_results_user_callback|
+ // or |on_failure_user_callback|.
+ on_gscan_event_internal_callback =
+ [iface_name, on_failure_user_callback, on_results_user_callback, this](
+ wifi_request_id id, wifi_scan_event event) {
+ switch (event) {
+ case WIFI_SCAN_RESULTS_AVAILABLE:
+ case WIFI_SCAN_THRESHOLD_NUM_SCANS:
+ case WIFI_SCAN_THRESHOLD_PERCENT: {
+ wifi_error status;
+ std::vector<wifi_cached_scan_results> cached_scan_results;
+ std::tie(status, cached_scan_results) =
+ getGscanCachedResults(iface_name);
+ if (status == WIFI_SUCCESS) {
+ on_results_user_callback(id, cached_scan_results);
+ return;
+ }
+ FALLTHROUGH_INTENDED;
+ }
+ // Fall through if failed. Failure to retrieve cached scan
+ // results should trigger a background scan failure.
+ case WIFI_SCAN_FAILED:
+ on_failure_user_callback(id);
+ on_gscan_event_internal_callback = nullptr;
+ on_gscan_full_result_internal_callback = nullptr;
+ return;
+ }
+ LOG(FATAL) << "Unexpected gscan event received: " << event;
+ };
+
+ on_gscan_full_result_internal_callback = [on_full_result_user_callback](
+ wifi_request_id id,
+ wifi_scan_result* result,
+ uint32_t buckets_scanned) {
+ if (result) {
+ on_full_result_user_callback(id, result, buckets_scanned);
+ }
+ };
+
+ wifi_scan_result_handler handler = {onAsyncGscanFullResult,
+ onAsyncGscanEvent};
+ wifi_error status = global_func_table_.wifi_start_gscan(
+ id, getIfaceHandle(iface_name), params, handler);
+ if (status != WIFI_SUCCESS) {
+ on_gscan_event_internal_callback = nullptr;
+ on_gscan_full_result_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::stopGscan(const std::string& iface_name,
+ wifi_request_id id) {
+ // If there is no an ongoing background scan, reject stop requests.
+ // TODO(b/32337212): This needs to be handled by the HIDL object because we
+ // need to return the NOT_STARTED error code.
+ if (!on_gscan_event_internal_callback &&
+ !on_gscan_full_result_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ wifi_error status =
+ global_func_table_.wifi_stop_gscan(id, getIfaceHandle(iface_name));
+ // If the request Id is wrong, don't stop the ongoing background scan. Any
+ // other error should be treated as the end of background scan.
+ if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+ on_gscan_event_internal_callback = nullptr;
+ on_gscan_full_result_internal_callback = nullptr;
+ }
+ return status;
+}
+
+std::pair<wifi_error, std::vector<uint32_t>>
+WifiLegacyHal::getValidFrequenciesForBand(const std::string& iface_name,
+ wifi_band band) {
+ static_assert(sizeof(uint32_t) >= sizeof(wifi_channel),
+ "Wifi Channel cannot be represented in output");
+ std::vector<uint32_t> freqs;
+ freqs.resize(kMaxGscanFrequenciesForBand);
+ int32_t num_freqs = 0;
+ wifi_error status = global_func_table_.wifi_get_valid_channels(
+ getIfaceHandle(iface_name), band, freqs.size(),
+ reinterpret_cast<wifi_channel*>(freqs.data()), &num_freqs);
+ CHECK(num_freqs >= 0 &&
+ static_cast<uint32_t>(num_freqs) <= kMaxGscanFrequenciesForBand);
+ freqs.resize(num_freqs);
+ return {status, std::move(freqs)};
+}
+
+wifi_error WifiLegacyHal::setDfsFlag(const std::string& iface_name,
+ bool dfs_on) {
+ return global_func_table_.wifi_set_nodfs_flag(getIfaceHandle(iface_name),
+ dfs_on ? 0 : 1);
+}
+
+wifi_error WifiLegacyHal::enableLinkLayerStats(const std::string& iface_name,
+ bool debug) {
+ wifi_link_layer_params params;
+ params.mpdu_size_threshold = kLinkLayerStatsDataMpduSizeThreshold;
+ params.aggressive_statistics_gathering = debug;
+ return global_func_table_.wifi_set_link_stats(getIfaceHandle(iface_name),
+ params);
+}
+
+wifi_error WifiLegacyHal::disableLinkLayerStats(const std::string& iface_name) {
+ // TODO: Do we care about these responses?
+ uint32_t clear_mask_rsp;
+ uint8_t stop_rsp;
+ return global_func_table_.wifi_clear_link_stats(
+ getIfaceHandle(iface_name), 0xFFFFFFFF, &clear_mask_rsp, 1, &stop_rsp);
+}
+
+std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats(
+ const std::string& iface_name) {
+ LinkLayerStats link_stats{};
+ LinkLayerStats* link_stats_ptr = &link_stats;
+
+ on_link_layer_stats_result_internal_callback =
+ [&link_stats_ptr](wifi_request_id /* id */,
+ wifi_iface_stat* iface_stats_ptr, int num_radios,
+ wifi_radio_stat* radio_stats_ptr) {
+ wifi_radio_stat* l_radio_stats_ptr;
+
+ if (iface_stats_ptr != nullptr) {
+ link_stats_ptr->iface = *iface_stats_ptr;
+ link_stats_ptr->iface.num_peers = 0;
+ } else {
+ LOG(ERROR) << "Invalid iface stats in link layer stats";
+ }
+ if (num_radios <= 0 || radio_stats_ptr == nullptr) {
+ LOG(ERROR) << "Invalid radio stats in link layer stats";
+ return;
+ }
+ l_radio_stats_ptr = radio_stats_ptr;
+ for (int i = 0; i < num_radios; i++) {
+ LinkLayerRadioStats radio;
+
+ radio.stats = *l_radio_stats_ptr;
+ // Copy over the tx level array to the separate vector.
+ if (l_radio_stats_ptr->num_tx_levels > 0 &&
+ l_radio_stats_ptr->tx_time_per_levels != nullptr) {
+ radio.tx_time_per_levels.assign(
+ l_radio_stats_ptr->tx_time_per_levels,
+ l_radio_stats_ptr->tx_time_per_levels +
+ l_radio_stats_ptr->num_tx_levels);
+ }
+ radio.stats.num_tx_levels = 0;
+ radio.stats.tx_time_per_levels = nullptr;
+ /* Copy over the channel stat to separate vector */
+ if (l_radio_stats_ptr->num_channels > 0) {
+ /* Copy the channel stats */
+ radio.channel_stats.assign(
+ l_radio_stats_ptr->channels,
+ l_radio_stats_ptr->channels +
+ l_radio_stats_ptr->num_channels);
+ }
+ link_stats_ptr->radios.push_back(radio);
+ l_radio_stats_ptr =
+ (wifi_radio_stat*)((u8*)l_radio_stats_ptr +
+ sizeof(wifi_radio_stat) +
+ (sizeof(wifi_channel_stat) *
+ l_radio_stats_ptr->num_channels));
+ }
+ };
+
+ wifi_error status = global_func_table_.wifi_get_link_stats(
+ 0, getIfaceHandle(iface_name), {onSyncLinkLayerStatsResult});
+ on_link_layer_stats_result_internal_callback = nullptr;
+ return {status, link_stats};
+}
+
+wifi_error WifiLegacyHal::startRssiMonitoring(
+ const std::string& iface_name, wifi_request_id id, int8_t max_rssi,
+ int8_t min_rssi,
+ const on_rssi_threshold_breached_callback&
+ on_threshold_breached_user_callback) {
+ if (on_rssi_threshold_breached_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_rssi_threshold_breached_internal_callback =
+ [on_threshold_breached_user_callback](wifi_request_id id,
+ uint8_t* bssid_ptr, int8_t rssi) {
+ if (!bssid_ptr) {
+ return;
+ }
+ std::array<uint8_t, 6> bssid_arr;
+ // |bssid_ptr| pointer is assumed to have 6 bytes for the mac
+ // address.
+ std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr));
+ on_threshold_breached_user_callback(id, bssid_arr, rssi);
+ };
+ wifi_error status = global_func_table_.wifi_start_rssi_monitoring(
+ id, getIfaceHandle(iface_name), max_rssi, min_rssi,
+ {onAsyncRssiThresholdBreached});
+ if (status != WIFI_SUCCESS) {
+ on_rssi_threshold_breached_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::stopRssiMonitoring(const std::string& iface_name,
+ wifi_request_id id) {
+ if (!on_rssi_threshold_breached_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ wifi_error status = global_func_table_.wifi_stop_rssi_monitoring(
+ id, getIfaceHandle(iface_name));
+ // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any
+ // other error should be treated as the end of background scan.
+ if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+ on_rssi_threshold_breached_internal_callback = nullptr;
+ }
+ return status;
+}
+
+std::pair<wifi_error, wifi_roaming_capabilities>
+WifiLegacyHal::getRoamingCapabilities(const std::string& iface_name) {
+ wifi_roaming_capabilities caps;
+ wifi_error status = global_func_table_.wifi_get_roaming_capabilities(
+ getIfaceHandle(iface_name), &caps);
+ return {status, caps};
+}
+
+wifi_error WifiLegacyHal::configureRoaming(const std::string& iface_name,
+ const wifi_roaming_config& config) {
+ wifi_roaming_config config_internal = config;
+ return global_func_table_.wifi_configure_roaming(getIfaceHandle(iface_name),
+ &config_internal);
+}
+
+wifi_error WifiLegacyHal::enableFirmwareRoaming(const std::string& iface_name,
+ fw_roaming_state_t state) {
+ return global_func_table_.wifi_enable_firmware_roaming(
+ getIfaceHandle(iface_name), state);
+}
+
+wifi_error WifiLegacyHal::configureNdOffload(const std::string& iface_name,
+ bool enable) {
+ return global_func_table_.wifi_configure_nd_offload(
+ getIfaceHandle(iface_name), enable);
+}
+
+wifi_error WifiLegacyHal::startSendingOffloadedPacket(
+ const std::string& iface_name, uint32_t cmd_id, uint16_t ether_type,
+ const std::vector<uint8_t>& ip_packet_data,
+ const std::array<uint8_t, 6>& src_address,
+ const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
+ std::vector<uint8_t> ip_packet_data_internal(ip_packet_data);
+ std::vector<uint8_t> src_address_internal(
+ src_address.data(), src_address.data() + src_address.size());
+ std::vector<uint8_t> dst_address_internal(
+ dst_address.data(), dst_address.data() + dst_address.size());
+ return global_func_table_.wifi_start_sending_offloaded_packet(
+ cmd_id, getIfaceHandle(iface_name), ether_type,
+ ip_packet_data_internal.data(), ip_packet_data_internal.size(),
+ src_address_internal.data(), dst_address_internal.data(), period_in_ms);
+}
+
+wifi_error WifiLegacyHal::stopSendingOffloadedPacket(
+ const std::string& iface_name, uint32_t cmd_id) {
+ return global_func_table_.wifi_stop_sending_offloaded_packet(
+ cmd_id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setScanningMacOui(const std::string& iface_name,
+ const std::array<uint8_t, 3>& oui) {
+ std::vector<uint8_t> oui_internal(oui.data(), oui.data() + oui.size());
+ return global_func_table_.wifi_set_scanning_mac_oui(
+ getIfaceHandle(iface_name), oui_internal.data());
+}
+
+wifi_error WifiLegacyHal::selectTxPowerScenario(const std::string& iface_name,
+ wifi_power_scenario scenario) {
+ return global_func_table_.wifi_select_tx_power_scenario(
+ getIfaceHandle(iface_name), scenario);
+}
+
+wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) {
+ return global_func_table_.wifi_reset_tx_power_scenario(
+ getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setLatencyMode(const std::string& iface_name,
+ wifi_latency_mode mode) {
+ return global_func_table_.wifi_set_latency_mode(getIfaceHandle(iface_name),
+ mode);
+}
+
+wifi_error WifiLegacyHal::setThermalMitigationMode(wifi_thermal_mode mode,
+ uint32_t completion_window) {
+ return global_func_table_.wifi_set_thermal_mitigation_mode(
+ global_handle_, mode, completion_window);
+}
+
+std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
+ const std::string& iface_name) {
+ uint32_t supported_feature_flags;
+ wifi_error status =
+ global_func_table_.wifi_get_logger_supported_feature_set(
+ getIfaceHandle(iface_name), &supported_feature_flags);
+ return {status, supported_feature_flags};
+}
+
+wifi_error WifiLegacyHal::startPktFateMonitoring(
+ const std::string& iface_name) {
+ return global_func_table_.wifi_start_pkt_fate_monitoring(
+ getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, std::vector<wifi_tx_report>> WifiLegacyHal::getTxPktFates(
+ const std::string& iface_name) {
+ std::vector<wifi_tx_report> tx_pkt_fates;
+ tx_pkt_fates.resize(MAX_FATE_LOG_LEN);
+ size_t num_fates = 0;
+ wifi_error status = global_func_table_.wifi_get_tx_pkt_fates(
+ getIfaceHandle(iface_name), tx_pkt_fates.data(), tx_pkt_fates.size(),
+ &num_fates);
+ CHECK(num_fates <= MAX_FATE_LOG_LEN);
+ tx_pkt_fates.resize(num_fates);
+ return {status, std::move(tx_pkt_fates)};
+}
+
+std::pair<wifi_error, std::vector<wifi_rx_report>> WifiLegacyHal::getRxPktFates(
+ const std::string& iface_name) {
+ std::vector<wifi_rx_report> rx_pkt_fates;
+ rx_pkt_fates.resize(MAX_FATE_LOG_LEN);
+ size_t num_fates = 0;
+ wifi_error status = global_func_table_.wifi_get_rx_pkt_fates(
+ getIfaceHandle(iface_name), rx_pkt_fates.data(), rx_pkt_fates.size(),
+ &num_fates);
+ CHECK(num_fates <= MAX_FATE_LOG_LEN);
+ rx_pkt_fates.resize(num_fates);
+ return {status, std::move(rx_pkt_fates)};
+}
+
+std::pair<wifi_error, WakeReasonStats> WifiLegacyHal::getWakeReasonStats(
+ const std::string& iface_name) {
+ WakeReasonStats stats;
+ stats.cmd_event_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
+ stats.driver_fw_local_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
+
+ // This legacy struct needs separate memory to store the variable sized wake
+ // reason types.
+ stats.wake_reason_cnt.cmd_event_wake_cnt =
+ reinterpret_cast<int32_t*>(stats.cmd_event_wake_cnt.data());
+ stats.wake_reason_cnt.cmd_event_wake_cnt_sz =
+ stats.cmd_event_wake_cnt.size();
+ stats.wake_reason_cnt.cmd_event_wake_cnt_used = 0;
+ stats.wake_reason_cnt.driver_fw_local_wake_cnt =
+ reinterpret_cast<int32_t*>(stats.driver_fw_local_wake_cnt.data());
+ stats.wake_reason_cnt.driver_fw_local_wake_cnt_sz =
+ stats.driver_fw_local_wake_cnt.size();
+ stats.wake_reason_cnt.driver_fw_local_wake_cnt_used = 0;
+
+ wifi_error status = global_func_table_.wifi_get_wake_reason_stats(
+ getIfaceHandle(iface_name), &stats.wake_reason_cnt);
+
+ CHECK(
+ stats.wake_reason_cnt.cmd_event_wake_cnt_used >= 0 &&
+ static_cast<uint32_t>(stats.wake_reason_cnt.cmd_event_wake_cnt_used) <=
+ kMaxWakeReasonStatsArraySize);
+ stats.cmd_event_wake_cnt.resize(
+ stats.wake_reason_cnt.cmd_event_wake_cnt_used);
+ stats.wake_reason_cnt.cmd_event_wake_cnt = nullptr;
+
+ CHECK(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used >= 0 &&
+ static_cast<uint32_t>(
+ stats.wake_reason_cnt.driver_fw_local_wake_cnt_used) <=
+ kMaxWakeReasonStatsArraySize);
+ stats.driver_fw_local_wake_cnt.resize(
+ stats.wake_reason_cnt.driver_fw_local_wake_cnt_used);
+ stats.wake_reason_cnt.driver_fw_local_wake_cnt = nullptr;
+
+ return {status, stats};
+}
+
+wifi_error WifiLegacyHal::registerRingBufferCallbackHandler(
+ const std::string& iface_name,
+ const on_ring_buffer_data_callback& on_user_data_callback) {
+ if (on_ring_buffer_data_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_ring_buffer_data_internal_callback =
+ [on_user_data_callback](char* ring_name, char* buffer, int buffer_size,
+ wifi_ring_buffer_status* status) {
+ if (status && buffer) {
+ std::vector<uint8_t> buffer_vector(
+ reinterpret_cast<uint8_t*>(buffer),
+ reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+ on_user_data_callback(ring_name, buffer_vector, *status);
+ }
+ };
+ wifi_error status = global_func_table_.wifi_set_log_handler(
+ 0, getIfaceHandle(iface_name), {onAsyncRingBufferData});
+ if (status != WIFI_SUCCESS) {
+ on_ring_buffer_data_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::deregisterRingBufferCallbackHandler(
+ const std::string& iface_name) {
+ if (!on_ring_buffer_data_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_ring_buffer_data_internal_callback = nullptr;
+ return global_func_table_.wifi_reset_log_handler(
+ 0, getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
+WifiLegacyHal::getRingBuffersStatus(const std::string& iface_name) {
+ std::vector<wifi_ring_buffer_status> ring_buffers_status;
+ ring_buffers_status.resize(kMaxRingBuffers);
+ uint32_t num_rings = kMaxRingBuffers;
+ wifi_error status = global_func_table_.wifi_get_ring_buffers_status(
+ getIfaceHandle(iface_name), &num_rings, ring_buffers_status.data());
+ CHECK(num_rings <= kMaxRingBuffers);
+ ring_buffers_status.resize(num_rings);
+ return {status, std::move(ring_buffers_status)};
+}
+
+wifi_error WifiLegacyHal::startRingBufferLogging(const std::string& iface_name,
+ const std::string& ring_name,
+ uint32_t verbose_level,
+ uint32_t max_interval_sec,
+ uint32_t min_data_size) {
+ return global_func_table_.wifi_start_logging(
+ getIfaceHandle(iface_name), verbose_level, 0, max_interval_sec,
+ min_data_size, makeCharVec(ring_name).data());
+}
+
+wifi_error WifiLegacyHal::getRingBufferData(const std::string& iface_name,
+ const std::string& ring_name) {
+ return global_func_table_.wifi_get_ring_data(getIfaceHandle(iface_name),
+ makeCharVec(ring_name).data());
+}
+
+wifi_error WifiLegacyHal::registerErrorAlertCallbackHandler(
+ const std::string& iface_name,
+ const on_error_alert_callback& on_user_alert_callback) {
+ if (on_error_alert_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_error_alert_internal_callback = [on_user_alert_callback](
+ wifi_request_id id, char* buffer,
+ int buffer_size, int err_code) {
+ if (buffer) {
+ CHECK(id == 0);
+ on_user_alert_callback(
+ err_code,
+ std::vector<uint8_t>(
+ reinterpret_cast<uint8_t*>(buffer),
+ reinterpret_cast<uint8_t*>(buffer) + buffer_size));
+ }
+ };
+ wifi_error status = global_func_table_.wifi_set_alert_handler(
+ 0, getIfaceHandle(iface_name), {onAsyncErrorAlert});
+ if (status != WIFI_SUCCESS) {
+ on_error_alert_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::deregisterErrorAlertCallbackHandler(
+ const std::string& iface_name) {
+ if (!on_error_alert_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_error_alert_internal_callback = nullptr;
+ return global_func_table_.wifi_reset_alert_handler(
+ 0, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::registerRadioModeChangeCallbackHandler(
+ const std::string& iface_name,
+ const on_radio_mode_change_callback& on_user_change_callback) {
+ if (on_radio_mode_change_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_radio_mode_change_internal_callback = [on_user_change_callback](
+ wifi_request_id /* id */,
+ uint32_t num_macs,
+ wifi_mac_info* mac_infos_arr) {
+ if (num_macs > 0 && mac_infos_arr) {
+ std::vector<WifiMacInfo> mac_infos_vec;
+ for (uint32_t i = 0; i < num_macs; i++) {
+ WifiMacInfo mac_info;
+ mac_info.wlan_mac_id = mac_infos_arr[i].wlan_mac_id;
+ mac_info.mac_band = mac_infos_arr[i].mac_band;
+ for (int32_t j = 0; j < mac_infos_arr[i].num_iface; j++) {
+ WifiIfaceInfo iface_info;
+ iface_info.name = mac_infos_arr[i].iface_info[j].iface_name;
+ iface_info.channel = mac_infos_arr[i].iface_info[j].channel;
+ mac_info.iface_infos.push_back(iface_info);
+ }
+ mac_infos_vec.push_back(mac_info);
+ }
+ on_user_change_callback(mac_infos_vec);
+ }
+ };
+ wifi_error status = global_func_table_.wifi_set_radio_mode_change_handler(
+ 0, getIfaceHandle(iface_name), {onAsyncRadioModeChange});
+ if (status != WIFI_SUCCESS) {
+ on_radio_mode_change_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::startRttRangeRequest(
+ const std::string& iface_name, wifi_request_id id,
+ const std::vector<wifi_rtt_config>& rtt_configs,
+ const on_rtt_results_callback& on_results_user_callback) {
+ if (on_rtt_results_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+
+ on_rtt_results_internal_callback =
+ [on_results_user_callback](wifi_request_id id, unsigned num_results,
+ wifi_rtt_result* rtt_results[]) {
+ if (num_results > 0 && !rtt_results) {
+ LOG(ERROR) << "Unexpected nullptr in RTT results";
+ return;
+ }
+ std::vector<const wifi_rtt_result*> rtt_results_vec;
+ std::copy_if(rtt_results, rtt_results + num_results,
+ back_inserter(rtt_results_vec),
+ [](wifi_rtt_result* rtt_result) {
+ return rtt_result != nullptr;
+ });
+ on_results_user_callback(id, rtt_results_vec);
+ };
+
+ std::vector<wifi_rtt_config> rtt_configs_internal(rtt_configs);
+ wifi_error status = global_func_table_.wifi_rtt_range_request(
+ id, getIfaceHandle(iface_name), rtt_configs.size(),
+ rtt_configs_internal.data(), {onAsyncRttResults});
+ if (status != WIFI_SUCCESS) {
+ on_rtt_results_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::cancelRttRangeRequest(
+ const std::string& iface_name, wifi_request_id id,
+ const std::vector<std::array<uint8_t, 6>>& mac_addrs) {
+ if (!on_rtt_results_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ static_assert(sizeof(mac_addr) == sizeof(std::array<uint8_t, 6>),
+ "MAC address size mismatch");
+ // TODO: How do we handle partial cancels (i.e only a subset of enabled mac
+ // addressed are cancelled).
+ std::vector<std::array<uint8_t, 6>> mac_addrs_internal(mac_addrs);
+ wifi_error status = global_func_table_.wifi_rtt_range_cancel(
+ id, getIfaceHandle(iface_name), mac_addrs.size(),
+ reinterpret_cast<mac_addr*>(mac_addrs_internal.data()));
+ // If the request Id is wrong, don't stop the ongoing range request. Any
+ // other error should be treated as the end of rtt ranging.
+ if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+ on_rtt_results_internal_callback = nullptr;
+ }
+ return status;
+}
+
+std::pair<wifi_error, wifi_rtt_capabilities> WifiLegacyHal::getRttCapabilities(
+ const std::string& iface_name) {
+ wifi_rtt_capabilities rtt_caps;
+ wifi_error status = global_func_table_.wifi_get_rtt_capabilities(
+ getIfaceHandle(iface_name), &rtt_caps);
+ return {status, rtt_caps};
+}
+
+std::pair<wifi_error, wifi_rtt_responder> WifiLegacyHal::getRttResponderInfo(
+ const std::string& iface_name) {
+ wifi_rtt_responder rtt_responder;
+ wifi_error status = global_func_table_.wifi_rtt_get_responder_info(
+ getIfaceHandle(iface_name), &rtt_responder);
+ return {status, rtt_responder};
+}
+
+wifi_error WifiLegacyHal::enableRttResponder(
+ const std::string& iface_name, wifi_request_id id,
+ const wifi_channel_info& channel_hint, uint32_t max_duration_secs,
+ const wifi_rtt_responder& info) {
+ wifi_rtt_responder info_internal(info);
+ return global_func_table_.wifi_enable_responder(
+ id, getIfaceHandle(iface_name), channel_hint, max_duration_secs,
+ &info_internal);
+}
+
+wifi_error WifiLegacyHal::disableRttResponder(const std::string& iface_name,
+ wifi_request_id id) {
+ return global_func_table_.wifi_disable_responder(
+ id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setRttLci(const std::string& iface_name,
+ wifi_request_id id,
+ const wifi_lci_information& info) {
+ wifi_lci_information info_internal(info);
+ return global_func_table_.wifi_set_lci(id, getIfaceHandle(iface_name),
+ &info_internal);
+}
+
+wifi_error WifiLegacyHal::setRttLcr(const std::string& iface_name,
+ wifi_request_id id,
+ const wifi_lcr_information& info) {
+ wifi_lcr_information info_internal(info);
+ return global_func_table_.wifi_set_lcr(id, getIfaceHandle(iface_name),
+ &info_internal);
+}
+
+wifi_error WifiLegacyHal::nanRegisterCallbackHandlers(
+ const std::string& iface_name, const NanCallbackHandlers& user_callbacks) {
+ on_nan_notify_response_user_callback = user_callbacks.on_notify_response;
+ on_nan_event_publish_terminated_user_callback =
+ user_callbacks.on_event_publish_terminated;
+ on_nan_event_match_user_callback = user_callbacks.on_event_match;
+ on_nan_event_match_expired_user_callback =
+ user_callbacks.on_event_match_expired;
+ on_nan_event_subscribe_terminated_user_callback =
+ user_callbacks.on_event_subscribe_terminated;
+ on_nan_event_followup_user_callback = user_callbacks.on_event_followup;
+ on_nan_event_disc_eng_event_user_callback =
+ user_callbacks.on_event_disc_eng_event;
+ on_nan_event_disabled_user_callback = user_callbacks.on_event_disabled;
+ on_nan_event_tca_user_callback = user_callbacks.on_event_tca;
+ on_nan_event_beacon_sdf_payload_user_callback =
+ user_callbacks.on_event_beacon_sdf_payload;
+ on_nan_event_data_path_request_user_callback =
+ user_callbacks.on_event_data_path_request;
+ on_nan_event_data_path_confirm_user_callback =
+ user_callbacks.on_event_data_path_confirm;
+ on_nan_event_data_path_end_user_callback =
+ user_callbacks.on_event_data_path_end;
+ on_nan_event_transmit_follow_up_user_callback =
+ user_callbacks.on_event_transmit_follow_up;
+ on_nan_event_range_request_user_callback =
+ user_callbacks.on_event_range_request;
+ on_nan_event_range_report_user_callback =
+ user_callbacks.on_event_range_report;
+ on_nan_event_schedule_update_user_callback =
+ user_callbacks.on_event_schedule_update;
+
+ return global_func_table_.wifi_nan_register_handler(
+ getIfaceHandle(iface_name),
+ {onAysncNanNotifyResponse, onAysncNanEventPublishReplied,
+ onAysncNanEventPublishTerminated, onAysncNanEventMatch,
+ onAysncNanEventMatchExpired, onAysncNanEventSubscribeTerminated,
+ onAysncNanEventFollowup, onAysncNanEventDiscEngEvent,
+ onAysncNanEventDisabled, onAysncNanEventTca,
+ onAysncNanEventBeaconSdfPayload, onAysncNanEventDataPathRequest,
+ onAysncNanEventDataPathConfirm, onAysncNanEventDataPathEnd,
+ onAysncNanEventTransmitFollowUp, onAysncNanEventRangeRequest,
+ onAysncNanEventRangeReport, onAsyncNanEventScheduleUpdate});
+}
+
+wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanEnableRequest& msg) {
+ NanEnableRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_enable_request(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanDisableRequest(const std::string& iface_name,
+ transaction_id id) {
+ return global_func_table_.wifi_nan_disable_request(
+ id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::nanPublishRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanPublishRequest& msg) {
+ NanPublishRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_publish_request(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanPublishCancelRequest(
+ const std::string& iface_name, transaction_id id,
+ const NanPublishCancelRequest& msg) {
+ NanPublishCancelRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_publish_cancel_request(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanSubscribeRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanSubscribeRequest& msg) {
+ NanSubscribeRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_subscribe_request(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanSubscribeCancelRequest(
+ const std::string& iface_name, transaction_id id,
+ const NanSubscribeCancelRequest& msg) {
+ NanSubscribeCancelRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_subscribe_cancel_request(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanTransmitFollowupRequest(
+ const std::string& iface_name, transaction_id id,
+ const NanTransmitFollowupRequest& msg) {
+ NanTransmitFollowupRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_transmit_followup_request(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanStatsRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanStatsRequest& msg) {
+ NanStatsRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_stats_request(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanConfigRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanConfigRequest& msg) {
+ NanConfigRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_config_request(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanTcaRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanTCARequest& msg) {
+ NanTCARequest msg_internal(msg);
+ return global_func_table_.wifi_nan_tca_request(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanBeaconSdfPayloadRequest(
+ const std::string& iface_name, transaction_id id,
+ const NanBeaconSdfPayloadRequest& msg) {
+ NanBeaconSdfPayloadRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_beacon_sdf_payload_request(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+std::pair<wifi_error, NanVersion> WifiLegacyHal::nanGetVersion() {
+ NanVersion version;
+ wifi_error status =
+ global_func_table_.wifi_nan_get_version(global_handle_, &version);
+ return {status, version};
+}
+
+wifi_error WifiLegacyHal::nanGetCapabilities(const std::string& iface_name,
+ transaction_id id) {
+ return global_func_table_.wifi_nan_get_capabilities(
+ id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::nanDataInterfaceCreate(
+ const std::string& iface_name, transaction_id id,
+ const std::string& data_iface_name) {
+ return global_func_table_.wifi_nan_data_interface_create(
+ id, getIfaceHandle(iface_name), makeCharVec(data_iface_name).data());
+}
+
+wifi_error WifiLegacyHal::nanDataInterfaceDelete(
+ const std::string& iface_name, transaction_id id,
+ const std::string& data_iface_name) {
+ return global_func_table_.wifi_nan_data_interface_delete(
+ id, getIfaceHandle(iface_name), makeCharVec(data_iface_name).data());
+}
+
+wifi_error WifiLegacyHal::nanDataRequestInitiator(
+ const std::string& iface_name, transaction_id id,
+ const NanDataPathInitiatorRequest& msg) {
+ NanDataPathInitiatorRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_data_request_initiator(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanDataIndicationResponse(
+ const std::string& iface_name, transaction_id id,
+ const NanDataPathIndicationResponse& msg) {
+ NanDataPathIndicationResponse msg_internal(msg);
+ return global_func_table_.wifi_nan_data_indication_response(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+typedef struct {
+ u8 num_ndp_instances;
+ NanDataPathId ndp_instance_id;
+} NanDataPathEndSingleNdpIdRequest;
+
+wifi_error WifiLegacyHal::nanDataEnd(const std::string& iface_name,
+ transaction_id id,
+ uint32_t ndpInstanceId) {
+ NanDataPathEndSingleNdpIdRequest msg;
+ msg.num_ndp_instances = 1;
+ msg.ndp_instance_id = ndpInstanceId;
+ wifi_error status = global_func_table_.wifi_nan_data_end(
+ id, getIfaceHandle(iface_name), (NanDataPathEndRequest*)&msg);
+ return status;
+}
+
+wifi_error WifiLegacyHal::setCountryCode(const std::string& iface_name,
+ std::array<int8_t, 2> code) {
+ std::string code_str(code.data(), code.data() + code.size());
+ return global_func_table_.wifi_set_country_code(getIfaceHandle(iface_name),
+ code_str.c_str());
+}
+
+wifi_error WifiLegacyHal::retrieveIfaceHandles() {
+ wifi_interface_handle* iface_handles = nullptr;
+ int num_iface_handles = 0;
+ wifi_error status = global_func_table_.wifi_get_ifaces(
+ global_handle_, &num_iface_handles, &iface_handles);
+ if (status != WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to enumerate interface handles";
+ return status;
+ }
+ for (int i = 0; i < num_iface_handles; ++i) {
+ std::array<char, IFNAMSIZ> iface_name_arr = {};
+ status = global_func_table_.wifi_get_iface_name(
+ iface_handles[i], iface_name_arr.data(), iface_name_arr.size());
+ if (status != WIFI_SUCCESS) {
+ LOG(WARNING) << "Failed to get interface handle name";
+ continue;
+ }
+ // Assuming the interface name is null terminated since the legacy HAL
+ // API does not return a size.
+ std::string iface_name(iface_name_arr.data());
+ LOG(INFO) << "Adding interface handle for " << iface_name;
+ iface_name_to_handle_[iface_name] = iface_handles[i];
+ }
+ return WIFI_SUCCESS;
+}
+
+wifi_interface_handle WifiLegacyHal::getIfaceHandle(
+ const std::string& iface_name) {
+ const auto iface_handle_iter = iface_name_to_handle_.find(iface_name);
+ if (iface_handle_iter == iface_name_to_handle_.end()) {
+ LOG(ERROR) << "Unknown iface name: " << iface_name;
+ return nullptr;
+ }
+ return iface_handle_iter->second;
+}
+
+void WifiLegacyHal::runEventLoop() {
+ LOG(DEBUG) << "Starting legacy HAL event loop";
+ global_func_table_.wifi_event_loop(global_handle_);
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (!awaiting_event_loop_termination_) {
+ LOG(FATAL)
+ << "Legacy HAL event loop terminated, but HAL was not stopping";
+ }
+ LOG(DEBUG) << "Legacy HAL event loop terminated";
+ awaiting_event_loop_termination_ = false;
+ stop_wait_cv_.notify_one();
+}
+
+std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
+WifiLegacyHal::getGscanCachedResults(const std::string& iface_name) {
+ std::vector<wifi_cached_scan_results> cached_scan_results;
+ cached_scan_results.resize(kMaxCachedGscanResults);
+ int32_t num_results = 0;
+ wifi_error status = global_func_table_.wifi_get_cached_gscan_results(
+ getIfaceHandle(iface_name), true /* always flush */,
+ cached_scan_results.size(), cached_scan_results.data(), &num_results);
+ CHECK(num_results >= 0 &&
+ static_cast<uint32_t>(num_results) <= kMaxCachedGscanResults);
+ cached_scan_results.resize(num_results);
+ // Check for invalid IE lengths in these cached scan results and correct it.
+ for (auto& cached_scan_result : cached_scan_results) {
+ int num_scan_results = cached_scan_result.num_results;
+ for (int i = 0; i < num_scan_results; i++) {
+ auto& scan_result = cached_scan_result.results[i];
+ if (scan_result.ie_length > 0) {
+ LOG(DEBUG) << "Cached scan result has non-zero IE length "
+ << scan_result.ie_length;
+ scan_result.ie_length = 0;
+ }
+ }
+ }
+ return {status, std::move(cached_scan_results)};
+}
+
+void WifiLegacyHal::invalidate() {
+ global_handle_ = nullptr;
+ iface_name_to_handle_.clear();
+ on_driver_memory_dump_internal_callback = nullptr;
+ on_firmware_memory_dump_internal_callback = nullptr;
+ on_gscan_event_internal_callback = nullptr;
+ on_gscan_full_result_internal_callback = nullptr;
+ on_link_layer_stats_result_internal_callback = nullptr;
+ on_rssi_threshold_breached_internal_callback = nullptr;
+ on_ring_buffer_data_internal_callback = nullptr;
+ on_error_alert_internal_callback = nullptr;
+ on_radio_mode_change_internal_callback = nullptr;
+ on_rtt_results_internal_callback = nullptr;
+ on_nan_notify_response_user_callback = nullptr;
+ on_nan_event_publish_terminated_user_callback = nullptr;
+ on_nan_event_match_user_callback = nullptr;
+ on_nan_event_match_expired_user_callback = nullptr;
+ on_nan_event_subscribe_terminated_user_callback = nullptr;
+ on_nan_event_followup_user_callback = nullptr;
+ on_nan_event_disc_eng_event_user_callback = nullptr;
+ on_nan_event_disabled_user_callback = nullptr;
+ on_nan_event_tca_user_callback = nullptr;
+ on_nan_event_beacon_sdf_payload_user_callback = nullptr;
+ on_nan_event_data_path_request_user_callback = nullptr;
+ on_nan_event_data_path_confirm_user_callback = nullptr;
+ on_nan_event_data_path_end_user_callback = nullptr;
+ on_nan_event_transmit_follow_up_user_callback = nullptr;
+ on_nan_event_range_request_user_callback = nullptr;
+ on_nan_event_range_report_user_callback = nullptr;
+ on_nan_event_schedule_update_user_callback = nullptr;
+}
+
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h
new file mode 100644
index 0000000..a7b40a0
--- /dev/null
+++ b/wifi/1.4/default/wifi_legacy_hal.h
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_H_
+#define WIFI_LEGACY_HAL_H_
+
+#include <condition_variable>
+#include <functional>
+#include <map>
+#include <thread>
+#include <vector>
+
+#include <wifi_system/interface_tool.h>
+
+// HACK: The include inside the namespace below also transitively includes a
+// bunch of libc headers into the namespace, which leads to functions like
+// socketpair being defined in
+// android::hardware::wifi::V1_1::implementation::legacy_hal. Include this one
+// particular header as a hacky workaround until that's fixed.
+#include <sys/socket.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+// This is in a separate namespace to prevent typename conflicts between
+// the legacy HAL types and the HIDL interface types.
+namespace legacy_hal {
+// Wrap all the types defined inside the legacy HAL header files inside this
+// namespace.
+#include <hardware_legacy/wifi_hal.h>
+
+// APF capabilities supported by the iface.
+struct PacketFilterCapabilities {
+ uint32_t version;
+ uint32_t max_len;
+};
+
+// WARNING: We don't care about the variable sized members of either
+// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma
+// to escape the compiler warnings regarding this.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
+// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
+// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
+// into a separate return element to avoid passing pointers around.
+struct LinkLayerRadioStats {
+ wifi_radio_stat stats;
+ std::vector<uint32_t> tx_time_per_levels;
+ std::vector<wifi_channel_stat> channel_stats;
+};
+
+struct LinkLayerStats {
+ wifi_iface_stat iface;
+ std::vector<LinkLayerRadioStats> radios;
+};
+#pragma GCC diagnostic pop
+
+// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
+// |WLAN_DRIVER_WAKE_REASON_CNT.driver_fw_local_wake_cnt| stats is provided
+// as a pointer in |WLAN_DRIVER_WAKE_REASON_CNT| structure in the legacy HAL
+// API. Separate that out into a separate return elements to avoid passing
+// pointers around.
+struct WakeReasonStats {
+ WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt;
+ std::vector<uint32_t> cmd_event_wake_cnt;
+ std::vector<uint32_t> driver_fw_local_wake_cnt;
+};
+
+// NAN response and event callbacks struct.
+struct NanCallbackHandlers {
+ // NotifyResponse invoked to notify the status of the Request.
+ std::function<void(transaction_id, const NanResponseMsg&)>
+ on_notify_response;
+ // Various event callbacks.
+ std::function<void(const NanPublishTerminatedInd&)>
+ on_event_publish_terminated;
+ std::function<void(const NanMatchInd&)> on_event_match;
+ std::function<void(const NanMatchExpiredInd&)> on_event_match_expired;
+ std::function<void(const NanSubscribeTerminatedInd&)>
+ on_event_subscribe_terminated;
+ std::function<void(const NanFollowupInd&)> on_event_followup;
+ std::function<void(const NanDiscEngEventInd&)> on_event_disc_eng_event;
+ std::function<void(const NanDisabledInd&)> on_event_disabled;
+ std::function<void(const NanTCAInd&)> on_event_tca;
+ std::function<void(const NanBeaconSdfPayloadInd&)>
+ on_event_beacon_sdf_payload;
+ std::function<void(const NanDataPathRequestInd&)>
+ on_event_data_path_request;
+ std::function<void(const NanDataPathConfirmInd&)>
+ on_event_data_path_confirm;
+ std::function<void(const NanDataPathEndInd&)> on_event_data_path_end;
+ std::function<void(const NanTransmitFollowupInd&)>
+ on_event_transmit_follow_up;
+ std::function<void(const NanRangeRequestInd&)> on_event_range_request;
+ std::function<void(const NanRangeReportInd&)> on_event_range_report;
+ std::function<void(const NanDataPathScheduleUpdateInd&)>
+ on_event_schedule_update;
+};
+
+// Full scan results contain IE info and are hence passed by reference, to
+// preserve the variable length array member |ie_data|. Callee must not retain
+// the pointer.
+using on_gscan_full_result_callback =
+ std::function<void(wifi_request_id, const wifi_scan_result*, uint32_t)>;
+// These scan results don't contain any IE info, so no need to pass by
+// reference.
+using on_gscan_results_callback = std::function<void(
+ wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
+
+// Invoked when the rssi value breaches the thresholds set.
+using on_rssi_threshold_breached_callback =
+ std::function<void(wifi_request_id, std::array<uint8_t, 6>, int8_t)>;
+
+// Callback for RTT range request results.
+// Rtt results contain IE info and are hence passed by reference, to
+// preserve the |LCI| and |LCR| pointers. Callee must not retain
+// the pointer.
+using on_rtt_results_callback = std::function<void(
+ wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
+
+// Callback for ring buffer data.
+using on_ring_buffer_data_callback =
+ std::function<void(const std::string&, const std::vector<uint8_t>&,
+ const wifi_ring_buffer_status&)>;
+
+// Callback for alerts.
+using on_error_alert_callback =
+ std::function<void(int32_t, const std::vector<uint8_t>&)>;
+
+// Struct for the mac info from the legacy HAL. This is a cleaner version
+// of the |wifi_mac_info| & |wifi_iface_info|.
+typedef struct {
+ std::string name;
+ wifi_channel channel;
+} WifiIfaceInfo;
+
+typedef struct {
+ uint32_t wlan_mac_id;
+ /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
+ uint32_t mac_band;
+ /* Represents the connected Wi-Fi interfaces associated with each MAC */
+ std::vector<WifiIfaceInfo> iface_infos;
+} WifiMacInfo;
+
+// Callback for radio mode change
+using on_radio_mode_change_callback =
+ std::function<void(const std::vector<WifiMacInfo>&)>;
+
+/**
+ * Class that encapsulates all legacy HAL interactions.
+ * This class manages the lifetime of the event loop thread used by legacy HAL.
+ *
+ * Note: There will only be a single instance of this class created in the Wifi
+ * object and will be valid for the lifetime of the process.
+ */
+class WifiLegacyHal {
+ public:
+ WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+ virtual ~WifiLegacyHal() = default;
+
+ // Initialize the legacy HAL function table.
+ virtual wifi_error initialize();
+ // Start the legacy HAL and the event looper thread.
+ virtual wifi_error start();
+ // Deinitialize the legacy HAL and wait for the event loop thread to exit
+ // using a predefined timeout.
+ virtual wifi_error stop(std::unique_lock<std::recursive_mutex>* lock,
+ const std::function<void()>& on_complete_callback);
+ // Checks if legacy HAL has successfully started
+ bool isStarted();
+ // Wrappers for all the functions in the legacy HAL function table.
+ virtual std::pair<wifi_error, std::string> getDriverVersion(
+ const std::string& iface_name);
+ virtual std::pair<wifi_error, std::string> getFirmwareVersion(
+ const std::string& iface_name);
+ std::pair<wifi_error, std::vector<uint8_t>> requestDriverMemoryDump(
+ const std::string& iface_name);
+ std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
+ const std::string& iface_name);
+ std::pair<wifi_error, uint32_t> getSupportedFeatureSet(
+ const std::string& iface_name);
+ // APF functions.
+ std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
+ const std::string& iface_name);
+ wifi_error setPacketFilter(const std::string& iface_name,
+ const std::vector<uint8_t>& program);
+ std::pair<wifi_error, std::vector<uint8_t>> readApfPacketFilterData(
+ const std::string& iface_name);
+ // Gscan functions.
+ std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities(
+ const std::string& iface_name);
+ // These API's provides a simplified interface over the legacy Gscan API's:
+ // a) All scan events from the legacy HAL API other than the
+ // |WIFI_SCAN_FAILED| are treated as notification of results.
+ // This method then retrieves the cached scan results from the legacy
+ // HAL API and triggers the externally provided
+ // |on_results_user_callback| on success.
+ // b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan
+ // results
+ // triggers the externally provided |on_failure_user_callback|.
+ // c) Full scan result event triggers the externally provided
+ // |on_full_result_user_callback|.
+ wifi_error startGscan(
+ const std::string& iface_name, wifi_request_id id,
+ const wifi_scan_cmd_params& params,
+ const std::function<void(wifi_request_id)>& on_failure_callback,
+ const on_gscan_results_callback& on_results_callback,
+ const on_gscan_full_result_callback& on_full_result_callback);
+ wifi_error stopGscan(const std::string& iface_name, wifi_request_id id);
+ std::pair<wifi_error, std::vector<uint32_t>> getValidFrequenciesForBand(
+ const std::string& iface_name, wifi_band band);
+ virtual wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on);
+ // Link layer stats functions.
+ wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug);
+ wifi_error disableLinkLayerStats(const std::string& iface_name);
+ std::pair<wifi_error, LinkLayerStats> getLinkLayerStats(
+ const std::string& iface_name);
+ // RSSI monitor functions.
+ wifi_error startRssiMonitoring(const std::string& iface_name,
+ wifi_request_id id, int8_t max_rssi,
+ int8_t min_rssi,
+ const on_rssi_threshold_breached_callback&
+ on_threshold_breached_callback);
+ wifi_error stopRssiMonitoring(const std::string& iface_name,
+ wifi_request_id id);
+ std::pair<wifi_error, wifi_roaming_capabilities> getRoamingCapabilities(
+ const std::string& iface_name);
+ wifi_error configureRoaming(const std::string& iface_name,
+ const wifi_roaming_config& config);
+ wifi_error enableFirmwareRoaming(const std::string& iface_name,
+ fw_roaming_state_t state);
+ wifi_error configureNdOffload(const std::string& iface_name, bool enable);
+ wifi_error startSendingOffloadedPacket(
+ const std::string& iface_name, uint32_t cmd_id, uint16_t ether_type,
+ const std::vector<uint8_t>& ip_packet_data,
+ const std::array<uint8_t, 6>& src_address,
+ const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
+ wifi_error stopSendingOffloadedPacket(const std::string& iface_name,
+ uint32_t cmd_id);
+ wifi_error setScanningMacOui(const std::string& iface_name,
+ const std::array<uint8_t, 3>& oui);
+ virtual wifi_error selectTxPowerScenario(const std::string& iface_name,
+ wifi_power_scenario scenario);
+ virtual wifi_error resetTxPowerScenario(const std::string& iface_name);
+ wifi_error setLatencyMode(const std::string& iface_name,
+ wifi_latency_mode mode);
+ wifi_error setThermalMitigationMode(wifi_thermal_mode mode,
+ uint32_t completion_window);
+ // Logger/debug functions.
+ std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(
+ const std::string& iface_name);
+ wifi_error startPktFateMonitoring(const std::string& iface_name);
+ std::pair<wifi_error, std::vector<wifi_tx_report>> getTxPktFates(
+ const std::string& iface_name);
+ std::pair<wifi_error, std::vector<wifi_rx_report>> getRxPktFates(
+ const std::string& iface_name);
+ std::pair<wifi_error, WakeReasonStats> getWakeReasonStats(
+ const std::string& iface_name);
+ wifi_error registerRingBufferCallbackHandler(
+ const std::string& iface_name,
+ const on_ring_buffer_data_callback& on_data_callback);
+ wifi_error deregisterRingBufferCallbackHandler(
+ const std::string& iface_name);
+ std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
+ getRingBuffersStatus(const std::string& iface_name);
+ wifi_error startRingBufferLogging(const std::string& iface_name,
+ const std::string& ring_name,
+ uint32_t verbose_level,
+ uint32_t max_interval_sec,
+ uint32_t min_data_size);
+ wifi_error getRingBufferData(const std::string& iface_name,
+ const std::string& ring_name);
+ wifi_error registerErrorAlertCallbackHandler(
+ const std::string& iface_name,
+ const on_error_alert_callback& on_alert_callback);
+ wifi_error deregisterErrorAlertCallbackHandler(
+ const std::string& iface_name);
+ // Radio mode functions.
+ virtual wifi_error registerRadioModeChangeCallbackHandler(
+ const std::string& iface_name,
+ const on_radio_mode_change_callback& on_user_change_callback);
+ // RTT functions.
+ wifi_error startRttRangeRequest(
+ const std::string& iface_name, wifi_request_id id,
+ const std::vector<wifi_rtt_config>& rtt_configs,
+ const on_rtt_results_callback& on_results_callback);
+ wifi_error cancelRttRangeRequest(
+ const std::string& iface_name, wifi_request_id id,
+ const std::vector<std::array<uint8_t, 6>>& mac_addrs);
+ std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities(
+ const std::string& iface_name);
+ std::pair<wifi_error, wifi_rtt_responder> getRttResponderInfo(
+ const std::string& iface_name);
+ wifi_error enableRttResponder(const std::string& iface_name,
+ wifi_request_id id,
+ const wifi_channel_info& channel_hint,
+ uint32_t max_duration_secs,
+ const wifi_rtt_responder& info);
+ wifi_error disableRttResponder(const std::string& iface_name,
+ wifi_request_id id);
+ wifi_error setRttLci(const std::string& iface_name, wifi_request_id id,
+ const wifi_lci_information& info);
+ wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id,
+ const wifi_lcr_information& info);
+ // NAN functions.
+ virtual wifi_error nanRegisterCallbackHandlers(
+ const std::string& iface_name, const NanCallbackHandlers& callbacks);
+ wifi_error nanEnableRequest(const std::string& iface_name,
+ transaction_id id, const NanEnableRequest& msg);
+ virtual wifi_error nanDisableRequest(const std::string& iface_name,
+ transaction_id id);
+ wifi_error nanPublishRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanPublishRequest& msg);
+ wifi_error nanPublishCancelRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanPublishCancelRequest& msg);
+ wifi_error nanSubscribeRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanSubscribeRequest& msg);
+ wifi_error nanSubscribeCancelRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanSubscribeCancelRequest& msg);
+ wifi_error nanTransmitFollowupRequest(
+ const std::string& iface_name, transaction_id id,
+ const NanTransmitFollowupRequest& msg);
+ wifi_error nanStatsRequest(const std::string& iface_name, transaction_id id,
+ const NanStatsRequest& msg);
+ wifi_error nanConfigRequest(const std::string& iface_name,
+ transaction_id id, const NanConfigRequest& msg);
+ wifi_error nanTcaRequest(const std::string& iface_name, transaction_id id,
+ const NanTCARequest& msg);
+ wifi_error nanBeaconSdfPayloadRequest(
+ const std::string& iface_name, transaction_id id,
+ const NanBeaconSdfPayloadRequest& msg);
+ std::pair<wifi_error, NanVersion> nanGetVersion();
+ wifi_error nanGetCapabilities(const std::string& iface_name,
+ transaction_id id);
+ wifi_error nanDataInterfaceCreate(const std::string& iface_name,
+ transaction_id id,
+ const std::string& data_iface_name);
+ virtual wifi_error nanDataInterfaceDelete(
+ const std::string& iface_name, transaction_id id,
+ const std::string& data_iface_name);
+ wifi_error nanDataRequestInitiator(const std::string& iface_name,
+ transaction_id id,
+ const NanDataPathInitiatorRequest& msg);
+ wifi_error nanDataIndicationResponse(
+ const std::string& iface_name, transaction_id id,
+ const NanDataPathIndicationResponse& msg);
+ wifi_error nanDataEnd(const std::string& iface_name, transaction_id id,
+ uint32_t ndpInstanceId);
+ // AP functions.
+ wifi_error setCountryCode(const std::string& iface_name,
+ std::array<int8_t, 2> code);
+
+ private:
+ // Retrieve interface handles for all the available interfaces.
+ wifi_error retrieveIfaceHandles();
+ wifi_interface_handle getIfaceHandle(const std::string& iface_name);
+ // Run the legacy HAL event loop thread.
+ void runEventLoop();
+ // Retrieve the cached gscan results to pass the results back to the
+ // external callbacks.
+ std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
+ getGscanCachedResults(const std::string& iface_name);
+ void invalidate();
+
+ // Global function table of legacy HAL.
+ wifi_hal_fn global_func_table_;
+ // Opaque handle to be used for all global operations.
+ wifi_handle global_handle_;
+ // Map of interface name to handle that is to be used for all interface
+ // specific operations.
+ std::map<std::string, wifi_interface_handle> iface_name_to_handle_;
+ // Flag to indicate if we have initiated the cleanup of legacy HAL.
+ std::atomic<bool> awaiting_event_loop_termination_;
+ std::condition_variable_any stop_wait_cv_;
+ // Flag to indicate if the legacy HAL has been started.
+ bool is_started_;
+ std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+};
+
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
new file mode 100644
index 0000000..bbe470e
--- /dev/null
+++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+#include "wifi_legacy_hal_stubs.h"
+
+// TODO: Remove these stubs from HalTool in libwifi-system.
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace legacy_hal {
+template <typename>
+struct stubFunction;
+
+template <typename R, typename... Args>
+struct stubFunction<R (*)(Args...)> {
+ static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; }
+};
+template <typename... Args>
+struct stubFunction<void (*)(Args...)> {
+ static constexpr void invoke(Args...) {}
+};
+
+template <typename T>
+void populateStubFor(T* val) {
+ *val = &stubFunction<T>::invoke;
+}
+
+bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) {
+ if (hal_fn == nullptr) {
+ return false;
+ }
+ populateStubFor(&hal_fn->wifi_initialize);
+ populateStubFor(&hal_fn->wifi_wait_for_driver_ready);
+ populateStubFor(&hal_fn->wifi_cleanup);
+ populateStubFor(&hal_fn->wifi_event_loop);
+ populateStubFor(&hal_fn->wifi_get_error_info);
+ populateStubFor(&hal_fn->wifi_get_supported_feature_set);
+ populateStubFor(&hal_fn->wifi_get_concurrency_matrix);
+ populateStubFor(&hal_fn->wifi_set_scanning_mac_oui);
+ populateStubFor(&hal_fn->wifi_get_supported_channels);
+ populateStubFor(&hal_fn->wifi_is_epr_supported);
+ populateStubFor(&hal_fn->wifi_get_ifaces);
+ populateStubFor(&hal_fn->wifi_get_iface_name);
+ populateStubFor(&hal_fn->wifi_set_iface_event_handler);
+ populateStubFor(&hal_fn->wifi_reset_iface_event_handler);
+ populateStubFor(&hal_fn->wifi_start_gscan);
+ populateStubFor(&hal_fn->wifi_stop_gscan);
+ populateStubFor(&hal_fn->wifi_get_cached_gscan_results);
+ populateStubFor(&hal_fn->wifi_set_bssid_hotlist);
+ populateStubFor(&hal_fn->wifi_reset_bssid_hotlist);
+ populateStubFor(&hal_fn->wifi_set_significant_change_handler);
+ populateStubFor(&hal_fn->wifi_reset_significant_change_handler);
+ populateStubFor(&hal_fn->wifi_get_gscan_capabilities);
+ populateStubFor(&hal_fn->wifi_set_link_stats);
+ populateStubFor(&hal_fn->wifi_get_link_stats);
+ populateStubFor(&hal_fn->wifi_clear_link_stats);
+ populateStubFor(&hal_fn->wifi_get_valid_channels);
+ populateStubFor(&hal_fn->wifi_rtt_range_request);
+ populateStubFor(&hal_fn->wifi_rtt_range_cancel);
+ populateStubFor(&hal_fn->wifi_get_rtt_capabilities);
+ populateStubFor(&hal_fn->wifi_rtt_get_responder_info);
+ populateStubFor(&hal_fn->wifi_enable_responder);
+ populateStubFor(&hal_fn->wifi_disable_responder);
+ populateStubFor(&hal_fn->wifi_set_nodfs_flag);
+ populateStubFor(&hal_fn->wifi_start_logging);
+ populateStubFor(&hal_fn->wifi_set_epno_list);
+ populateStubFor(&hal_fn->wifi_reset_epno_list);
+ populateStubFor(&hal_fn->wifi_set_country_code);
+ populateStubFor(&hal_fn->wifi_get_firmware_memory_dump);
+ populateStubFor(&hal_fn->wifi_set_log_handler);
+ populateStubFor(&hal_fn->wifi_reset_log_handler);
+ populateStubFor(&hal_fn->wifi_set_alert_handler);
+ populateStubFor(&hal_fn->wifi_reset_alert_handler);
+ populateStubFor(&hal_fn->wifi_get_firmware_version);
+ populateStubFor(&hal_fn->wifi_get_ring_buffers_status);
+ populateStubFor(&hal_fn->wifi_get_logger_supported_feature_set);
+ populateStubFor(&hal_fn->wifi_get_ring_data);
+ populateStubFor(&hal_fn->wifi_enable_tdls);
+ populateStubFor(&hal_fn->wifi_disable_tdls);
+ populateStubFor(&hal_fn->wifi_get_tdls_status);
+ populateStubFor(&hal_fn->wifi_get_tdls_capabilities);
+ populateStubFor(&hal_fn->wifi_get_driver_version);
+ populateStubFor(&hal_fn->wifi_set_passpoint_list);
+ populateStubFor(&hal_fn->wifi_reset_passpoint_list);
+ populateStubFor(&hal_fn->wifi_set_lci);
+ populateStubFor(&hal_fn->wifi_set_lcr);
+ populateStubFor(&hal_fn->wifi_start_sending_offloaded_packet);
+ populateStubFor(&hal_fn->wifi_stop_sending_offloaded_packet);
+ populateStubFor(&hal_fn->wifi_start_rssi_monitoring);
+ populateStubFor(&hal_fn->wifi_stop_rssi_monitoring);
+ populateStubFor(&hal_fn->wifi_get_wake_reason_stats);
+ populateStubFor(&hal_fn->wifi_configure_nd_offload);
+ populateStubFor(&hal_fn->wifi_get_driver_memory_dump);
+ populateStubFor(&hal_fn->wifi_start_pkt_fate_monitoring);
+ populateStubFor(&hal_fn->wifi_get_tx_pkt_fates);
+ populateStubFor(&hal_fn->wifi_get_rx_pkt_fates);
+ populateStubFor(&hal_fn->wifi_nan_enable_request);
+ populateStubFor(&hal_fn->wifi_nan_disable_request);
+ populateStubFor(&hal_fn->wifi_nan_publish_request);
+ populateStubFor(&hal_fn->wifi_nan_publish_cancel_request);
+ populateStubFor(&hal_fn->wifi_nan_subscribe_request);
+ populateStubFor(&hal_fn->wifi_nan_subscribe_cancel_request);
+ populateStubFor(&hal_fn->wifi_nan_transmit_followup_request);
+ populateStubFor(&hal_fn->wifi_nan_stats_request);
+ populateStubFor(&hal_fn->wifi_nan_config_request);
+ populateStubFor(&hal_fn->wifi_nan_tca_request);
+ populateStubFor(&hal_fn->wifi_nan_beacon_sdf_payload_request);
+ populateStubFor(&hal_fn->wifi_nan_register_handler);
+ populateStubFor(&hal_fn->wifi_nan_get_version);
+ populateStubFor(&hal_fn->wifi_nan_get_capabilities);
+ populateStubFor(&hal_fn->wifi_nan_data_interface_create);
+ populateStubFor(&hal_fn->wifi_nan_data_interface_delete);
+ populateStubFor(&hal_fn->wifi_nan_data_request_initiator);
+ populateStubFor(&hal_fn->wifi_nan_data_indication_response);
+ populateStubFor(&hal_fn->wifi_nan_data_end);
+ populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities);
+ populateStubFor(&hal_fn->wifi_set_packet_filter);
+ populateStubFor(&hal_fn->wifi_read_packet_filter);
+ populateStubFor(&hal_fn->wifi_get_roaming_capabilities);
+ populateStubFor(&hal_fn->wifi_enable_firmware_roaming);
+ populateStubFor(&hal_fn->wifi_configure_roaming);
+ populateStubFor(&hal_fn->wifi_select_tx_power_scenario);
+ populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
+ populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
+ populateStubFor(&hal_fn->wifi_set_latency_mode);
+ populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
+ return true;
+}
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.h b/wifi/1.4/default/wifi_legacy_hal_stubs.h
new file mode 100644
index 0000000..577a545
--- /dev/null
+++ b/wifi/1.4/default/wifi_legacy_hal_stubs.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_STUBS_H_
+#define WIFI_LEGACY_HAL_STUBS_H_
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace legacy_hal {
+#include <hardware_legacy/wifi_hal.h>
+
+bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/wifi/1.4/default/wifi_mode_controller.cpp b/wifi/1.4/default/wifi_mode_controller.cpp
new file mode 100644
index 0000000..252121a
--- /dev/null
+++ b/wifi/1.4/default/wifi_mode_controller.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <private/android_filesystem_config.h>
+
+#include "wifi_mode_controller.h"
+
+using android::hardware::wifi::V1_0::IfaceType;
+using android::wifi_hal::DriverTool;
+
+namespace {
+int convertIfaceTypeToFirmwareMode(IfaceType type) {
+ int mode;
+ switch (type) {
+ case IfaceType::AP:
+ mode = DriverTool::kFirmwareModeAp;
+ break;
+ case IfaceType::P2P:
+ mode = DriverTool::kFirmwareModeP2p;
+ break;
+ case IfaceType::NAN:
+ // NAN is exposed in STA mode currently.
+ mode = DriverTool::kFirmwareModeSta;
+ break;
+ case IfaceType::STA:
+ mode = DriverTool::kFirmwareModeSta;
+ break;
+ }
+ return mode;
+}
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace mode_controller {
+
+WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
+
+bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
+ return driver_tool_->IsFirmwareModeChangeNeeded(
+ convertIfaceTypeToFirmwareMode(type));
+}
+
+bool WifiModeController::initialize() {
+ if (!driver_tool_->LoadDriver()) {
+ LOG(ERROR) << "Failed to load WiFi driver";
+ return false;
+ }
+ return true;
+}
+
+bool WifiModeController::changeFirmwareMode(IfaceType type) {
+ if (!driver_tool_->ChangeFirmwareMode(
+ convertIfaceTypeToFirmwareMode(type))) {
+ LOG(ERROR) << "Failed to change firmware mode";
+ return false;
+ }
+ return true;
+}
+
+bool WifiModeController::deinitialize() {
+ if (!driver_tool_->UnloadDriver()) {
+ LOG(ERROR) << "Failed to unload WiFi driver";
+ return false;
+ }
+ return true;
+}
+} // namespace mode_controller
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi_mode_controller.h b/wifi/1.4/default/wifi_mode_controller.h
new file mode 100644
index 0000000..45fa999
--- /dev/null
+++ b/wifi/1.4/default/wifi_mode_controller.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_MODE_CONTROLLER_H_
+#define WIFI_MODE_CONTROLLER_H_
+
+#include <wifi_hal/driver_tool.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace mode_controller {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * Class that encapsulates all firmware mode configuration.
+ * This class will perform the necessary firmware reloads to put the chip in the
+ * required state (essentially a wrapper over DriverTool).
+ */
+class WifiModeController {
+ public:
+ WifiModeController();
+ virtual ~WifiModeController() = default;
+
+ // Checks if a firmware mode change is necessary to support the specified
+ // iface type operations.
+ virtual bool isFirmwareModeChangeNeeded(IfaceType type);
+ virtual bool initialize();
+ // Change the firmware mode to support the specified iface type operations.
+ virtual bool changeFirmwareMode(IfaceType type);
+ // Unload the driver. This should be invoked whenever |IWifi.stop()| is
+ // invoked.
+ virtual bool deinitialize();
+
+ private:
+ std::unique_ptr<wifi_hal::DriverTool> driver_tool_;
+};
+
+} // namespace mode_controller
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.4/default/wifi_nan_iface.cpp b/wifi/1.4/default/wifi_nan_iface.cpp
new file mode 100644
index 0000000..073101c
--- /dev/null
+++ b/wifi/1.4/default/wifi_nan_iface.cpp
@@ -0,0 +1,917 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_nan_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiNanIface::WifiNanIface(
+ const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+ : ifname_(ifname),
+ legacy_hal_(legacy_hal),
+ iface_util_(iface_util),
+ is_valid_(true) {
+ // Register all the callbacks here. these should be valid for the lifetime
+ // of the object. Whenever the mode changes legacy HAL will remove
+ // all of these callbacks.
+ legacy_hal::NanCallbackHandlers callback_handlers;
+ android::wp<WifiNanIface> weak_ptr_this(this);
+
+ // Callback for response.
+ callback_handlers
+ .on_notify_response = [weak_ptr_this](
+ legacy_hal::transaction_id id,
+ const legacy_hal::NanResponseMsg& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ WifiNanStatus wifiNanStatus;
+ if (!hidl_struct_util::convertLegacyNanResponseHeaderToHidl(
+ msg, &wifiNanStatus)) {
+ LOG(ERROR) << "Failed to convert nan response header";
+ return;
+ }
+
+ switch (msg.response_type) {
+ case legacy_hal::NAN_RESPONSE_ENABLED: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyEnableResponse(id, wifiNanStatus)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_DISABLED: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyDisableResponse(id, wifiNanStatus)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_PUBLISH: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->notifyStartPublishResponse(
+ id, wifiNanStatus,
+ msg.body.publish_response.publish_id)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyStopPublishResponse(id, wifiNanStatus)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->notifyTransmitFollowupResponse(id, wifiNanStatus)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_SUBSCRIBE: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->notifyStartSubscribeResponse(
+ id, wifiNanStatus,
+ msg.body.subscribe_response.subscribe_id)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->notifyStopSubscribeResponse(id, wifiNanStatus)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_CONFIG: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyConfigResponse(id, wifiNanStatus)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_GET_CAPABILITIES: {
+ NanCapabilities hidl_struct;
+ if (!hidl_struct_util::
+ convertLegacyNanCapabilitiesResponseToHidl(
+ msg.body.nan_capabilities, &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->notifyCapabilitiesResponse(id, wifiNanStatus,
+ hidl_struct)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_DP_INTERFACE_CREATE: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->notifyCreateDataInterfaceResponse(id,
+ wifiNanStatus)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_DP_INTERFACE_DELETE: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->notifyDeleteDataInterfaceResponse(id,
+ wifiNanStatus)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_DP_INITIATOR_RESPONSE: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->notifyInitiateDataPathResponse(
+ id, wifiNanStatus,
+ msg.body.data_request_response.ndp_instance_id)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_DP_RESPONDER_RESPONSE: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->notifyRespondToDataPathIndicationResponse(
+ id, wifiNanStatus)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_DP_END: {
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->notifyTerminateDataPathResponse(id,
+ wifiNanStatus)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
+ /* fall through */
+ case legacy_hal::NAN_RESPONSE_TCA:
+ /* fall through */
+ case legacy_hal::NAN_RESPONSE_STATS:
+ /* fall through */
+ case legacy_hal::NAN_RESPONSE_ERROR:
+ /* fall through */
+ default:
+ LOG(ERROR) << "Unknown or unhandled response type: "
+ << msg.response_type;
+ return;
+ }
+ };
+
+ callback_handlers.on_event_disc_eng_event =
+ [weak_ptr_this](const legacy_hal::NanDiscEngEventInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ NanClusterEventInd hidl_struct;
+ // event types defined identically - hence can be cast
+ hidl_struct.eventType = (NanClusterEventType)msg.event_type;
+ hidl_struct.addr = msg.data.mac_addr.addr;
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventClusterEvent(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_disabled =
+ [weak_ptr_this](const legacy_hal::NanDisabledInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ WifiNanStatus status;
+ hidl_struct_util::convertToWifiNanStatus(
+ msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventDisabled(status).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_publish_terminated =
+ [weak_ptr_this](const legacy_hal::NanPublishTerminatedInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ WifiNanStatus status;
+ hidl_struct_util::convertToWifiNanStatus(
+ msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventPublishTerminated(msg.publish_id, status)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_subscribe_terminated =
+ [weak_ptr_this](const legacy_hal::NanSubscribeTerminatedInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ WifiNanStatus status;
+ hidl_struct_util::convertToWifiNanStatus(
+ msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->eventSubscribeTerminated(msg.subscribe_id, status)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_match =
+ [weak_ptr_this](const legacy_hal::NanMatchInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ NanMatchInd hidl_struct;
+ if (!hidl_struct_util::convertLegacyNanMatchIndToHidl(
+ msg, &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventMatch(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_match_expired =
+ [weak_ptr_this](const legacy_hal::NanMatchExpiredInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->eventMatchExpired(msg.publish_subscribe_id,
+ msg.requestor_instance_id)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_followup =
+ [weak_ptr_this](const legacy_hal::NanFollowupInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ NanFollowupReceivedInd hidl_struct;
+ if (!hidl_struct_util::convertLegacyNanFollowupIndToHidl(
+ msg, &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventFollowupReceived(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_transmit_follow_up =
+ [weak_ptr_this](const legacy_hal::NanTransmitFollowupInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ WifiNanStatus status;
+ hidl_struct_util::convertToWifiNanStatus(
+ msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventTransmitFollowup(msg.id, status).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_data_path_request =
+ [weak_ptr_this](const legacy_hal::NanDataPathRequestInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ NanDataPathRequestInd hidl_struct;
+ if (!hidl_struct_util::convertLegacyNanDataPathRequestIndToHidl(
+ msg, &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventDataPathRequest(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_data_path_confirm =
+ [weak_ptr_this](const legacy_hal::NanDataPathConfirmInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ V1_2::NanDataPathConfirmInd hidl_struct;
+ if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl(
+ msg, &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback :
+ shared_ptr_this->getEventCallbacks_1_2()) {
+ if (!callback->eventDataPathConfirm_1_2(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_data_path_end =
+ [weak_ptr_this](const legacy_hal::NanDataPathEndInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ for (int i = 0; i < msg.num_ndp_instances; ++i) {
+ if (!callback
+ ->eventDataPathTerminated(msg.ndp_instance_id[i])
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ }
+ };
+
+ callback_handlers.on_event_beacon_sdf_payload =
+ [weak_ptr_this](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
+ LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
+ };
+
+ callback_handlers.on_event_range_request =
+ [weak_ptr_this](const legacy_hal::NanRangeRequestInd& /* msg */) {
+ LOG(ERROR) << "on_event_range_request - should not be called";
+ };
+
+ callback_handlers.on_event_range_report =
+ [weak_ptr_this](const legacy_hal::NanRangeReportInd& /* msg */) {
+ LOG(ERROR) << "on_event_range_report - should not be called";
+ };
+
+ callback_handlers
+ .on_event_schedule_update = [weak_ptr_this](
+ const legacy_hal::
+ NanDataPathScheduleUpdateInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ V1_2::NanDataPathScheduleUpdateInd hidl_struct;
+ if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
+ msg, &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks_1_2()) {
+ if (!callback->eventDataPathScheduleUpdate(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_,
+ callback_handlers);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to register nan callbacks. Invalidating object";
+ invalidate();
+ }
+
+ // Register for iface state toggle events.
+ iface_util::IfaceEventHandlers event_handlers = {};
+ event_handlers.on_state_toggle_off_on =
+ [weak_ptr_this](const std::string& /* iface_name */) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ // Tell framework that NAN has been disabled.
+ WifiNanStatus status = {
+ NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventDisabled(status).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+ iface_util_.lock()->registerIfaceEventHandlers(ifname_, event_handlers);
+}
+
+void WifiNanIface::invalidate() {
+ // send commands to HAL to actually disable and destroy interfaces
+ legacy_hal_.lock()->nanDisableRequest(ifname_, 0xFFFF);
+ legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFE, "aware_data0");
+ legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFD, "aware_data1");
+ iface_util_.lock()->unregisterIfaceEventHandlers(ifname_);
+ legacy_hal_.reset();
+ event_cb_handler_.invalidate();
+ event_cb_handler_1_2_.invalidate();
+ is_valid_ = false;
+}
+
+bool WifiNanIface::isValid() { return is_valid_; }
+
+std::string WifiNanIface::getName() { return ifname_; }
+
+std::set<sp<V1_0::IWifiNanIfaceEventCallback>>
+WifiNanIface::getEventCallbacks() {
+ return event_cb_handler_.getCallbacks();
+}
+
+std::set<sp<V1_2::IWifiNanIfaceEventCallback>>
+WifiNanIface::getEventCallbacks_1_2() {
+ return event_cb_handler_1_2_.getCallbacks();
+}
+
+Return<void> WifiNanIface::getName(getName_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiNanIface::getType(getType_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiNanIface::registerEventCallback(
+ const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::registerEventCallbackInternal,
+ hidl_status_cb, callback);
+}
+
+Return<void> WifiNanIface::getCapabilitiesRequest(
+ uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::getCapabilitiesRequestInternal,
+ hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiNanIface::enableRequest(uint16_t cmd_id,
+ const V1_0::NanEnableRequest& msg,
+ enableRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::enableRequestInternal, hidl_status_cb,
+ cmd_id, msg);
+}
+
+Return<void> WifiNanIface::configRequest(uint16_t cmd_id,
+ const V1_0::NanConfigRequest& msg,
+ configRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::configRequestInternal, hidl_status_cb,
+ cmd_id, msg);
+}
+
+Return<void> WifiNanIface::disableRequest(uint16_t cmd_id,
+ disableRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::disableRequestInternal,
+ hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiNanIface::startPublishRequest(
+ uint16_t cmd_id, const NanPublishRequest& msg,
+ startPublishRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::startPublishRequestInternal,
+ hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::stopPublishRequest(
+ uint16_t cmd_id, uint8_t sessionId, stopPublishRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::stopPublishRequestInternal,
+ hidl_status_cb, cmd_id, sessionId);
+}
+
+Return<void> WifiNanIface::startSubscribeRequest(
+ uint16_t cmd_id, const NanSubscribeRequest& msg,
+ startSubscribeRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::startSubscribeRequestInternal,
+ hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::stopSubscribeRequest(
+ uint16_t cmd_id, uint8_t sessionId,
+ stopSubscribeRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::stopSubscribeRequestInternal,
+ hidl_status_cb, cmd_id, sessionId);
+}
+
+Return<void> WifiNanIface::transmitFollowupRequest(
+ uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
+ transmitFollowupRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::transmitFollowupRequestInternal,
+ hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::createDataInterfaceRequest(
+ uint16_t cmd_id, const hidl_string& iface_name,
+ createDataInterfaceRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::createDataInterfaceRequestInternal,
+ hidl_status_cb, cmd_id, iface_name);
+}
+
+Return<void> WifiNanIface::deleteDataInterfaceRequest(
+ uint16_t cmd_id, const hidl_string& iface_name,
+ deleteDataInterfaceRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::deleteDataInterfaceRequestInternal,
+ hidl_status_cb, cmd_id, iface_name);
+}
+
+Return<void> WifiNanIface::initiateDataPathRequest(
+ uint16_t cmd_id, const NanInitiateDataPathRequest& msg,
+ initiateDataPathRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::initiateDataPathRequestInternal,
+ hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::respondToDataPathIndicationRequest(
+ uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg,
+ respondToDataPathIndicationRequest_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::respondToDataPathIndicationRequestInternal,
+ hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::terminateDataPathRequest(
+ uint16_t cmd_id, uint32_t ndpInstanceId,
+ terminateDataPathRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::terminateDataPathRequestInternal,
+ hidl_status_cb, cmd_id, ndpInstanceId);
+}
+
+Return<void> WifiNanIface::registerEventCallback_1_2(
+ const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_2_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::registerEventCallback_1_2Internal,
+ hidl_status_cb, callback);
+}
+
+Return<void> WifiNanIface::enableRequest_1_2(
+ 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,
+ &WifiNanIface::enableRequest_1_2Internal,
+ hidl_status_cb, cmd_id, msg1, msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_2(
+ 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,
+ &WifiNanIface::configRequest_1_2Internal,
+ 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_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiNanIface::getTypeInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::NAN};
+}
+
+WifiStatus WifiNanIface::registerEventCallbackInternal(
+ const sp<V1_0::IWifiNanIfaceEventCallback>& callback) {
+ if (!event_cb_handler_.addCallback(callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t cmd_id) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::enableRequestInternal(
+ uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequestInternal(
+ uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::disableRequestInternal(uint16_t cmd_id) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDisableRequest(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::startPublishRequestInternal(
+ uint16_t cmd_id, const NanPublishRequest& msg) {
+ legacy_hal::NanPublishRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanPublishRequestToLegacy(msg,
+ &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanPublishRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::stopPublishRequestInternal(uint16_t cmd_id,
+ uint8_t sessionId) {
+ legacy_hal::NanPublishCancelRequest legacy_msg;
+ legacy_msg.publish_id = sessionId;
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanPublishCancelRequest(ifname_, cmd_id,
+ legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::startSubscribeRequestInternal(
+ uint16_t cmd_id, const NanSubscribeRequest& msg) {
+ legacy_hal::NanSubscribeRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanSubscribeRequestToLegacy(
+ msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanSubscribeRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::stopSubscribeRequestInternal(uint16_t cmd_id,
+ uint8_t sessionId) {
+ legacy_hal::NanSubscribeCancelRequest legacy_msg;
+ legacy_msg.subscribe_id = sessionId;
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanSubscribeCancelRequest(ifname_, cmd_id,
+ legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::transmitFollowupRequestInternal(
+ uint16_t cmd_id, const NanTransmitFollowupRequest& msg) {
+ legacy_hal::NanTransmitFollowupRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanTransmitFollowupRequestToLegacy(
+ msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanTransmitFollowupRequest(ifname_, cmd_id,
+ legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::createDataInterfaceRequestInternal(
+ uint16_t cmd_id, const std::string& iface_name) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDataInterfaceCreate(ifname_, cmd_id, iface_name);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::deleteDataInterfaceRequestInternal(
+ uint16_t cmd_id, const std::string& iface_name) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, cmd_id, iface_name);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::initiateDataPathRequestInternal(
+ uint16_t cmd_id, const NanInitiateDataPathRequest& msg) {
+ legacy_hal::NanDataPathInitiatorRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequestToLegacy(
+ msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id,
+ legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::respondToDataPathIndicationRequestInternal(
+ uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg) {
+ legacy_hal::NanDataPathIndicationResponse legacy_msg;
+ if (!hidl_struct_util::convertHidlNanDataPathIndicationResponseToLegacy(
+ msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id,
+ legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::terminateDataPathRequestInternal(
+ uint16_t cmd_id, uint32_t ndpInstanceId) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::registerEventCallback_1_2Internal(
+ const sp<V1_2::IWifiNanIfaceEventCallback>& callback) {
+ sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
+ if (!event_cb_handler_.addCallback(callback_1_0)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ if (!event_cb_handler_1_2_.addCallback(callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+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_4ToLegacy(
+ msg1, msg2, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+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_4ToLegacy(
+ msg1, msg2, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi_nan_iface.h b/wifi/1.4/default/wifi_nan_iface.h
new file mode 100644
index 0000000..c16628b
--- /dev/null
+++ b/wifi/1.4/default/wifi_nan_iface.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_NAN_IFACE_H_
+#define WIFI_NAN_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
+#include <android/hardware/wifi/1.4/IWifiNanIface.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+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_4::IWifiNanIface {
+ public:
+ WifiNanIface(const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+ // Refer to |WifiChip::invalidate()|.
+ void invalidate();
+ bool isValid();
+ std::string getName();
+
+ // HIDL methods exposed.
+ Return<void> getName(getName_cb hidl_status_cb) override;
+ Return<void> getType(getType_cb hidl_status_cb) override;
+ Return<void> registerEventCallback(
+ const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
+ 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 V1_0::NanEnableRequest& msg,
+ enableRequest_cb hidl_status_cb) override;
+ 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;
+ Return<void> startPublishRequest(
+ uint16_t cmd_id, const NanPublishRequest& msg,
+ startPublishRequest_cb hidl_status_cb) override;
+ Return<void> stopPublishRequest(
+ uint16_t cmd_id, uint8_t sessionId,
+ stopPublishRequest_cb hidl_status_cb) override;
+ Return<void> startSubscribeRequest(
+ uint16_t cmd_id, const NanSubscribeRequest& msg,
+ startSubscribeRequest_cb hidl_status_cb) override;
+ Return<void> stopSubscribeRequest(
+ uint16_t cmd_id, uint8_t sessionId,
+ stopSubscribeRequest_cb hidl_status_cb) override;
+ Return<void> transmitFollowupRequest(
+ uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
+ transmitFollowupRequest_cb hidl_status_cb) override;
+ Return<void> createDataInterfaceRequest(
+ uint16_t cmd_id, const hidl_string& iface_name,
+ createDataInterfaceRequest_cb hidl_status_cb) override;
+ Return<void> deleteDataInterfaceRequest(
+ uint16_t cmd_id, const hidl_string& iface_name,
+ deleteDataInterfaceRequest_cb hidl_status_cb) override;
+ Return<void> initiateDataPathRequest(
+ uint16_t cmd_id, const NanInitiateDataPathRequest& msg,
+ initiateDataPathRequest_cb hidl_status_cb) override;
+ Return<void> respondToDataPathIndicationRequest(
+ uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg,
+ respondToDataPathIndicationRequest_cb hidl_status_cb) override;
+ Return<void> terminateDataPathRequest(
+ uint16_t cmd_id, uint32_t ndpInstanceId,
+ terminateDataPathRequest_cb hidl_status_cb) override;
+
+ Return<void> registerEventCallback_1_2(
+ const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_2_cb hidl_status_cb) override;
+ Return<void> enableRequest_1_2(
+ 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;
+
+ private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<WifiStatus, std::string> getNameInternal();
+ std::pair<WifiStatus, IfaceType> getTypeInternal();
+ WifiStatus registerEventCallbackInternal(
+ const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
+ WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
+ WifiStatus enableRequestInternal(uint16_t cmd_id,
+ const V1_0::NanEnableRequest& msg);
+ WifiStatus configRequestInternal(uint16_t cmd_id,
+ const V1_0::NanConfigRequest& msg);
+ WifiStatus disableRequestInternal(uint16_t cmd_id);
+ WifiStatus startPublishRequestInternal(uint16_t cmd_id,
+ const NanPublishRequest& msg);
+ WifiStatus stopPublishRequestInternal(uint16_t cmd_id, uint8_t sessionId);
+ WifiStatus startSubscribeRequestInternal(uint16_t cmd_id,
+ const NanSubscribeRequest& msg);
+ WifiStatus stopSubscribeRequestInternal(uint16_t cmd_id, uint8_t sessionId);
+ WifiStatus transmitFollowupRequestInternal(
+ uint16_t cmd_id, const NanTransmitFollowupRequest& msg);
+ WifiStatus createDataInterfaceRequestInternal(
+ uint16_t cmd_id, const std::string& iface_name);
+ WifiStatus deleteDataInterfaceRequestInternal(
+ uint16_t cmd_id, const std::string& iface_name);
+ WifiStatus initiateDataPathRequestInternal(
+ uint16_t cmd_id, const NanInitiateDataPathRequest& msg);
+ WifiStatus respondToDataPathIndicationRequestInternal(
+ uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg);
+ WifiStatus terminateDataPathRequestInternal(uint16_t cmd_id,
+ uint32_t ndpInstanceId);
+
+ WifiStatus registerEventCallback_1_2Internal(
+ const sp<V1_2::IWifiNanIfaceEventCallback>& callback);
+ WifiStatus enableRequest_1_2Internal(
+ 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);
+
+ // all 1_0 and descendant callbacks
+ std::set<sp<V1_0::IWifiNanIfaceEventCallback>> getEventCallbacks();
+ // all 1_2 and descendant callbacks
+ std::set<sp<V1_2::IWifiNanIfaceEventCallback>> getEventCallbacks_1_2();
+
+ std::string ifname_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+ bool is_valid_;
+ hidl_callback_util::HidlCallbackHandler<V1_0::IWifiNanIfaceEventCallback>
+ event_cb_handler_;
+ hidl_callback_util::HidlCallbackHandler<V1_2::IWifiNanIfaceEventCallback>
+ event_cb_handler_1_2_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
+};
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_NAN_IFACE_H_
diff --git a/wifi/1.4/default/wifi_p2p_iface.cpp b/wifi/1.4/default/wifi_p2p_iface.cpp
new file mode 100644
index 0000000..9e7341f
--- /dev/null
+++ b/wifi/1.4/default/wifi_p2p_iface.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "wifi_p2p_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiP2pIface::WifiP2pIface(
+ const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+ : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
+
+void WifiP2pIface::invalidate() {
+ legacy_hal_.reset();
+ is_valid_ = false;
+}
+
+bool WifiP2pIface::isValid() { return is_valid_; }
+
+std::string WifiP2pIface::getName() { return ifname_; }
+
+Return<void> WifiP2pIface::getName(getName_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiP2pIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiP2pIface::getType(getType_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiP2pIface::getTypeInternal, hidl_status_cb);
+}
+
+std::pair<WifiStatus, std::string> WifiP2pIface::getNameInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiP2pIface::getTypeInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::P2P};
+}
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi_p2p_iface.h b/wifi/1.4/default/wifi_p2p_iface.h
new file mode 100644
index 0000000..a6fc59d
--- /dev/null
+++ b/wifi/1.4/default/wifi_p2p_iface.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_P2P_IFACE_H_
+#define WIFI_P2P_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiP2pIface.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a P2P Iface instance.
+ */
+class WifiP2pIface : public V1_0::IWifiP2pIface {
+ public:
+ WifiP2pIface(const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+ // Refer to |WifiChip::invalidate()|.
+ void invalidate();
+ bool isValid();
+ std::string getName();
+
+ // HIDL methods exposed.
+ Return<void> getName(getName_cb hidl_status_cb) override;
+ Return<void> getType(getType_cb hidl_status_cb) override;
+
+ private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<WifiStatus, std::string> getNameInternal();
+ std::pair<WifiStatus, IfaceType> getTypeInternal();
+
+ std::string ifname_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ bool is_valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiP2pIface);
+};
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_P2P_IFACE_H_
diff --git a/wifi/1.4/default/wifi_rtt_controller.cpp b/wifi/1.4/default/wifi_rtt_controller.cpp
new file mode 100644
index 0000000..594a116
--- /dev/null
+++ b/wifi/1.4/default/wifi_rtt_controller.cpp
@@ -0,0 +1,351 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_rtt_controller.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiRttController::WifiRttController(
+ const std::string& iface_name, const sp<IWifiIface>& bound_iface,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+ : ifname_(iface_name),
+ bound_iface_(bound_iface),
+ legacy_hal_(legacy_hal),
+ is_valid_(true) {}
+
+void WifiRttController::invalidate() {
+ legacy_hal_.reset();
+ event_callbacks_.clear();
+ is_valid_ = false;
+}
+
+bool WifiRttController::isValid() { return is_valid_; }
+
+std::vector<sp<IWifiRttControllerEventCallback>>
+WifiRttController::getEventCallbacks() {
+ return event_callbacks_;
+}
+
+std::string WifiRttController::getIfaceName() { return ifname_; }
+
+Return<void> WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getBoundIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::registerEventCallback(
+ const sp<V1_0::IWifiRttControllerEventCallback>& callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this,
+ WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::registerEventCallbackInternal,
+ hidl_status_cb, callback);
+}
+
+Return<void> WifiRttController::rangeRequest(
+ uint32_t cmd_id, const hidl_vec<V1_0::RttConfig>& rtt_configs,
+ rangeRequest_cb hidl_status_cb) {
+ return validateAndCall(this,
+ WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::rangeRequestInternal,
+ hidl_status_cb, cmd_id, rtt_configs);
+}
+
+Return<void> WifiRttController::rangeCancel(
+ uint32_t cmd_id, const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
+ rangeCancel_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::rangeCancelInternal, hidl_status_cb, cmd_id, addrs);
+}
+
+Return<void> WifiRttController::getCapabilities(
+ getCapabilities_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::setLci(uint32_t cmd_id,
+ const RttLciInformation& lci,
+ setLci_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::setLciInternal, hidl_status_cb, cmd_id, lci);
+}
+
+Return<void> WifiRttController::setLcr(uint32_t cmd_id,
+ const RttLcrInformation& lcr,
+ setLcr_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::setLcrInternal, hidl_status_cb, cmd_id, lcr);
+}
+
+Return<void> WifiRttController::getResponderInfo(
+ getResponderInfo_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getResponderInfoInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::enableResponder(
+ uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds, const V1_0::RttResponder& info,
+ enableResponder_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::enableResponderInternal, hidl_status_cb, cmd_id,
+ channel_hint, max_duration_seconds, info);
+}
+
+Return<void> WifiRttController::disableResponder(
+ uint32_t cmd_id, disableResponder_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::disableResponderInternal, hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiRttController::registerEventCallback_1_4(
+ const sp<IWifiRttControllerEventCallback>& callback,
+ registerEventCallback_1_4_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::registerEventCallbackInternal_1_4, hidl_status_cb,
+ callback);
+}
+
+Return<void> WifiRttController::rangeRequest_1_4(
+ uint32_t cmd_id, const hidl_vec<RttConfig>& rtt_configs,
+ rangeRequest_1_4_cb hidl_status_cb) {
+ return validateAndCall(this,
+ WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::rangeRequestInternal_1_4,
+ hidl_status_cb, cmd_id, rtt_configs);
+}
+
+Return<void> WifiRttController::getCapabilities_1_4(
+ getCapabilities_1_4_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getCapabilitiesInternal_1_4, hidl_status_cb);
+}
+
+Return<void> WifiRttController::getResponderInfo_1_4(
+ getResponderInfo_1_4_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getResponderInfoInternal_1_4, hidl_status_cb);
+}
+
+Return<void> WifiRttController::enableResponder_1_4(
+ uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds, const RttResponder& info,
+ enableResponder_1_4_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::enableResponderInternal_1_4, hidl_status_cb, cmd_id,
+ channel_hint, max_duration_seconds, info);
+}
+
+std::pair<WifiStatus, sp<IWifiIface>>
+WifiRttController::getBoundIfaceInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_};
+}
+
+WifiStatus WifiRttController::registerEventCallbackInternal(
+ const sp<V1_0::IWifiRttControllerEventCallback>& /* callback */) {
+ // Deprecated support for this api
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiRttController::rangeRequestInternal(
+ uint32_t /* cmd_id */,
+ const std::vector<V1_0::RttConfig>& /* rtt_configs */) {
+ // Deprecated support for this api
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiRttController::rangeCancelInternal(
+ uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs) {
+ std::vector<std::array<uint8_t, 6>> legacy_addrs;
+ for (const auto& addr : addrs) {
+ legacy_addrs.push_back(addr);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id,
+ legacy_addrs);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_0::RttCapabilities>
+WifiRttController::getCapabilitiesInternal() {
+ // Deprecated support for this api
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id,
+ const RttLciInformation& lci) {
+ legacy_hal::wifi_lci_information legacy_lci;
+ if (!hidl_struct_util::convertHidlRttLciInformationToLegacy(lci,
+ &legacy_lci)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->setRttLci(ifname_, cmd_id, legacy_lci);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id,
+ const RttLcrInformation& lcr) {
+ legacy_hal::wifi_lcr_information legacy_lcr;
+ if (!hidl_struct_util::convertHidlRttLcrInformationToLegacy(lcr,
+ &legacy_lcr)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->setRttLcr(ifname_, cmd_id, legacy_lcr);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_0::RttResponder>
+WifiRttController::getResponderInfoInternal() {
+ // Deprecated support for this api
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiRttController::enableResponderInternal(
+ uint32_t /* cmd_id */, const WifiChannelInfo& /* channel_hint */,
+ uint32_t /* max_duration_seconds */, const V1_0::RttResponder& /* info */) {
+ // Deprecated support for this api
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
+}
+
+WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiRttController::registerEventCallbackInternal_1_4(
+ const sp<IWifiRttControllerEventCallback>& callback) {
+ // TODO(b/31632518): remove the callback when the client is destroyed
+ event_callbacks_.emplace_back(callback);
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiRttController::rangeRequestInternal_1_4(
+ uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs) {
+ std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
+ if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(
+ rtt_configs, &legacy_configs)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ android::wp<WifiRttController> weak_ptr_this(this);
+ const auto& on_results_callback =
+ [weak_ptr_this](
+ legacy_hal::wifi_request_id id,
+ const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ std::vector<RttResult> hidl_results;
+ if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(
+ results, &hidl_results)) {
+ LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ callback->onResults_1_4(id, hidl_results);
+ }
+ };
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->startRttRangeRequest(
+ ifname_, cmd_id, legacy_configs, on_results_callback);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, RttCapabilities>
+WifiRttController::getCapabilitiesInternal_1_4() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::wifi_rtt_capabilities legacy_caps;
+ std::tie(legacy_status, legacy_caps) =
+ legacy_hal_.lock()->getRttCapabilities(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ RttCapabilities hidl_caps;
+ if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps,
+ &hidl_caps)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, RttResponder>
+WifiRttController::getResponderInfoInternal_1_4() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::wifi_rtt_responder legacy_responder;
+ std::tie(legacy_status, legacy_responder) =
+ legacy_hal_.lock()->getRttResponderInfo(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ RttResponder hidl_responder;
+ if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder,
+ &hidl_responder)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
+}
+
+WifiStatus WifiRttController::enableResponderInternal_1_4(
+ uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds, const RttResponder& info) {
+ legacy_hal::wifi_channel_info legacy_channel_info;
+ if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(
+ channel_hint, &legacy_channel_info)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_rtt_responder legacy_responder;
+ if (!hidl_struct_util::convertHidlRttResponderToLegacy(info,
+ &legacy_responder)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->enableRttResponder(
+ ifname_, cmd_id, legacy_channel_info, max_duration_seconds,
+ legacy_responder);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi_rtt_controller.h b/wifi/1.4/default/wifi_rtt_controller.h
new file mode 100644
index 0000000..1f12555
--- /dev/null
+++ b/wifi/1.4/default/wifi_rtt_controller.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_RTT_CONTROLLER_H_
+#define WIFI_RTT_CONTROLLER_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiIface.h>
+#include <android/hardware/wifi/1.4/IWifiRttController.h>
+#include <android/hardware/wifi/1.4/IWifiRttControllerEventCallback.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+/**
+ * HIDL interface object used to control all RTT operations.
+ */
+class WifiRttController : public V1_4::IWifiRttController {
+ public:
+ WifiRttController(
+ const std::string& iface_name, const sp<IWifiIface>& bound_iface,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+ // Refer to |WifiChip::invalidate()|.
+ void invalidate();
+ bool isValid();
+ std::vector<sp<IWifiRttControllerEventCallback>> getEventCallbacks();
+ std::string getIfaceName();
+
+ // HIDL methods exposed.
+ Return<void> getBoundIface(getBoundIface_cb hidl_status_cb) override;
+ Return<void> registerEventCallback(
+ const sp<V1_0::IWifiRttControllerEventCallback>& callback,
+ registerEventCallback_cb hidl_status_cb) override;
+ Return<void> rangeRequest(uint32_t cmd_id,
+ const hidl_vec<V1_0::RttConfig>& rtt_configs,
+ rangeRequest_cb hidl_status_cb) override;
+ Return<void> rangeCancel(uint32_t cmd_id,
+ const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
+ rangeCancel_cb hidl_status_cb) override;
+ Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+ Return<void> setLci(uint32_t cmd_id, const RttLciInformation& lci,
+ setLci_cb hidl_status_cb) override;
+ Return<void> setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
+ setLcr_cb hidl_status_cb) override;
+ Return<void> getResponderInfo(getResponderInfo_cb hidl_status_cb) override;
+ Return<void> enableResponder(uint32_t cmd_id,
+ const WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds,
+ const V1_0::RttResponder& info,
+ enableResponder_cb hidl_status_cb) override;
+ Return<void> disableResponder(uint32_t cmd_id,
+ disableResponder_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_4(
+ const sp<IWifiRttControllerEventCallback>& callback,
+ registerEventCallback_1_4_cb hidl_status_cb) override;
+ Return<void> rangeRequest_1_4(uint32_t cmd_id,
+ const hidl_vec<RttConfig>& rtt_configs,
+ rangeRequest_1_4_cb hidl_status_cb) override;
+ Return<void> getCapabilities_1_4(
+ getCapabilities_1_4_cb hidl_status_cb) override;
+ Return<void> getResponderInfo_1_4(
+ getResponderInfo_1_4_cb hidl_status_cb) override;
+ Return<void> enableResponder_1_4(
+ uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds, const RttResponder& info,
+ enableResponder_1_4_cb hidl_status_cb) override;
+
+ private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<WifiStatus, sp<IWifiIface>> getBoundIfaceInternal();
+ WifiStatus registerEventCallbackInternal(
+ const sp<V1_0::IWifiRttControllerEventCallback>& callback);
+ WifiStatus rangeRequestInternal(
+ uint32_t cmd_id, const std::vector<V1_0::RttConfig>& rtt_configs);
+ WifiStatus rangeCancelInternal(
+ uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs);
+ std::pair<WifiStatus, V1_0::RttCapabilities> getCapabilitiesInternal();
+ WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci);
+ WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr);
+ std::pair<WifiStatus, V1_0::RttResponder> getResponderInfoInternal();
+ WifiStatus enableResponderInternal(uint32_t cmd_id,
+ const WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds,
+ const V1_0::RttResponder& info);
+ WifiStatus disableResponderInternal(uint32_t cmd_id);
+ WifiStatus registerEventCallbackInternal_1_4(
+ const sp<IWifiRttControllerEventCallback>& callback);
+ WifiStatus rangeRequestInternal_1_4(
+ uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs);
+ std::pair<WifiStatus, RttCapabilities> getCapabilitiesInternal_1_4();
+ std::pair<WifiStatus, RttResponder> getResponderInfoInternal_1_4();
+ WifiStatus enableResponderInternal_1_4(uint32_t cmd_id,
+ const WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds,
+ const RttResponder& info);
+
+ std::string ifname_;
+ sp<IWifiIface> bound_iface_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::vector<sp<IWifiRttControllerEventCallback>> event_callbacks_;
+ bool is_valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiRttController);
+};
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_RTT_CONTROLLER_H_
diff --git a/wifi/1.4/default/wifi_sta_iface.cpp b/wifi/1.4/default/wifi_sta_iface.cpp
new file mode 100644
index 0000000..e2ea6e4
--- /dev/null
+++ b/wifi/1.4/default/wifi_sta_iface.cpp
@@ -0,0 +1,647 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_sta_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiStaIface::WifiStaIface(
+ const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+ : ifname_(ifname),
+ legacy_hal_(legacy_hal),
+ iface_util_(iface_util),
+ is_valid_(true) {
+ // Turn on DFS channel usage for STA iface.
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->setDfsFlag(ifname_, true);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR)
+ << "Failed to set DFS flag; DFS channels may be unavailable.";
+ }
+}
+
+void WifiStaIface::invalidate() {
+ legacy_hal_.reset();
+ event_cb_handler_.invalidate();
+ is_valid_ = false;
+}
+
+bool WifiStaIface::isValid() { return is_valid_; }
+
+std::string WifiStaIface::getName() { return ifname_; }
+
+std::set<sp<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
+ return event_cb_handler_.getCallbacks();
+}
+
+Return<void> WifiStaIface::getName(getName_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getType(getType_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::registerEventCallback(
+ const sp<IWifiStaIfaceEventCallback>& callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::registerEventCallbackInternal,
+ hidl_status_cb, callback);
+}
+
+Return<void> WifiStaIface::getCapabilities(getCapabilities_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getCapabilitiesInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getApfPacketFilterCapabilities(
+ getApfPacketFilterCapabilities_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getApfPacketFilterCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::installApfPacketFilter(
+ uint32_t cmd_id, const hidl_vec<uint8_t>& program,
+ installApfPacketFilter_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::installApfPacketFilterInternal,
+ hidl_status_cb, cmd_id, program);
+}
+
+Return<void> WifiStaIface::readApfPacketFilterData(
+ readApfPacketFilterData_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::readApfPacketFilterDataInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getBackgroundScanCapabilities(
+ getBackgroundScanCapabilities_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getBackgroundScanCapabilitiesInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getValidFrequenciesForBand(
+ V1_0::WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getValidFrequenciesForBandInternal,
+ hidl_status_cb, band);
+}
+
+Return<void> WifiStaIface::startBackgroundScan(
+ uint32_t cmd_id, const StaBackgroundScanParameters& params,
+ startBackgroundScan_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::startBackgroundScanInternal,
+ hidl_status_cb, cmd_id, params);
+}
+
+Return<void> WifiStaIface::stopBackgroundScan(
+ uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::stopBackgroundScanInternal,
+ hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::enableLinkLayerStatsCollection(
+ bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::enableLinkLayerStatsCollectionInternal, hidl_status_cb,
+ debug);
+}
+
+Return<void> WifiStaIface::disableLinkLayerStatsCollection(
+ disableLinkLayerStatsCollection_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::disableLinkLayerStatsCollectionInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats(
+ getLinkLayerStats_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getLinkLayerStatsInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats_1_3(
+ getLinkLayerStats_1_3_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getLinkLayerStatsInternal_1_3,
+ hidl_status_cb);
+}
+
+Return<void> WifiStaIface::startRssiMonitoring(
+ uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
+ startRssiMonitoring_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::startRssiMonitoringInternal,
+ hidl_status_cb, cmd_id, max_rssi, min_rssi);
+}
+
+Return<void> WifiStaIface::stopRssiMonitoring(
+ uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::stopRssiMonitoringInternal,
+ hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::getRoamingCapabilities(
+ getRoamingCapabilities_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getRoamingCapabilitiesInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiStaIface::configureRoaming(
+ const StaRoamingConfig& config, configureRoaming_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::configureRoamingInternal,
+ hidl_status_cb, config);
+}
+
+Return<void> WifiStaIface::setRoamingState(StaRoamingState state,
+ setRoamingState_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::setRoamingStateInternal,
+ hidl_status_cb, state);
+}
+
+Return<void> WifiStaIface::enableNdOffload(bool enable,
+ enableNdOffload_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::enableNdOffloadInternal,
+ hidl_status_cb, enable);
+}
+
+Return<void> WifiStaIface::startSendingKeepAlivePackets(
+ uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data,
+ uint16_t ether_type, const hidl_array<uint8_t, 6>& src_address,
+ const hidl_array<uint8_t, 6>& dst_address, uint32_t period_in_ms,
+ startSendingKeepAlivePackets_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::startSendingKeepAlivePacketsInternal,
+ hidl_status_cb, cmd_id, ip_packet_data, ether_type,
+ src_address, dst_address, period_in_ms);
+}
+
+Return<void> WifiStaIface::stopSendingKeepAlivePackets(
+ uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::stopSendingKeepAlivePacketsInternal,
+ hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::setScanningMacOui(
+ const hidl_array<uint8_t, 3>& oui, setScanningMacOui_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::setScanningMacOuiInternal,
+ hidl_status_cb, oui);
+}
+
+Return<void> WifiStaIface::startDebugPacketFateMonitoring(
+ startDebugPacketFateMonitoring_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::startDebugPacketFateMonitoringInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getDebugTxPacketFates(
+ getDebugTxPacketFates_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getDebugTxPacketFatesInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getDebugRxPacketFates(
+ getDebugRxPacketFates_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getDebugRxPacketFatesInternal,
+ hidl_status_cb);
+}
+
+Return<void> WifiStaIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
+ setMacAddress_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::setMacAddressInternal, hidl_status_cb,
+ mac);
+}
+
+Return<void> WifiStaIface::getFactoryMacAddress(
+ getFactoryMacAddress_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getFactoryMacAddressInternal,
+ hidl_status_cb);
+}
+
+std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiStaIface::getTypeInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::STA};
+}
+
+WifiStatus WifiStaIface::registerEventCallbackInternal(
+ const sp<IWifiStaIfaceEventCallback>& callback) {
+ if (!event_cb_handler_.addCallback(callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
+ 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>
+WifiStaIface::getApfPacketFilterCapabilitiesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::PacketFilterCapabilities legacy_caps;
+ std::tie(legacy_status, legacy_caps) =
+ legacy_hal_.lock()->getPacketFilterCapabilities(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ StaApfPacketFilterCapabilities hidl_caps;
+ if (!hidl_struct_util::convertLegacyApfCapabilitiesToHidl(legacy_caps,
+ &hidl_caps)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+WifiStatus WifiStaIface::installApfPacketFilterInternal(
+ uint32_t /* cmd_id */, const std::vector<uint8_t>& program) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->setPacketFilter(ifname_, program);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>>
+WifiStaIface::readApfPacketFilterDataInternal() {
+ const std::pair<legacy_hal::wifi_error, std::vector<uint8_t>>
+ legacy_status_and_data =
+ legacy_hal_.lock()->readApfPacketFilterData(ifname_);
+ return {createWifiStatusFromLegacyError(legacy_status_and_data.first),
+ std::move(legacy_status_and_data.second)};
+}
+
+std::pair<WifiStatus, StaBackgroundScanCapabilities>
+WifiStaIface::getBackgroundScanCapabilitiesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::wifi_gscan_capabilities legacy_caps;
+ std::tie(legacy_status, legacy_caps) =
+ legacy_hal_.lock()->getGscanCapabilities(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ StaBackgroundScanCapabilities hidl_caps;
+ if (!hidl_struct_util::convertLegacyGscanCapabilitiesToHidl(legacy_caps,
+ &hidl_caps)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+WifiStaIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
+ static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
+ "Size mismatch");
+ legacy_hal::wifi_error legacy_status;
+ std::vector<uint32_t> valid_frequencies;
+ std::tie(legacy_status, valid_frequencies) =
+ legacy_hal_.lock()->getValidFrequenciesForBand(
+ ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
+ return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
+}
+
+WifiStatus WifiStaIface::startBackgroundScanInternal(
+ uint32_t cmd_id, const StaBackgroundScanParameters& params) {
+ legacy_hal::wifi_scan_cmd_params legacy_params;
+ if (!hidl_struct_util::convertHidlGscanParamsToLegacy(params,
+ &legacy_params)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ android::wp<WifiStaIface> weak_ptr_this(this);
+ const auto& on_failure_callback =
+ [weak_ptr_this](legacy_hal::wifi_request_id id) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onBackgroundScanFailure(id).isOk()) {
+ LOG(ERROR)
+ << "Failed to invoke onBackgroundScanFailure callback";
+ }
+ }
+ };
+ const auto& on_results_callback =
+ [weak_ptr_this](
+ legacy_hal::wifi_request_id id,
+ const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ std::vector<StaScanData> hidl_scan_datas;
+ if (!hidl_struct_util::
+ convertLegacyVectorOfCachedGscanResultsToHidl(
+ results, &hidl_scan_datas)) {
+ LOG(ERROR) << "Failed to convert scan results to HIDL structs";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onBackgroundScanResults(id, hidl_scan_datas)
+ .isOk()) {
+ LOG(ERROR)
+ << "Failed to invoke onBackgroundScanResults callback";
+ }
+ }
+ };
+ const auto& on_full_result_callback = [weak_ptr_this](
+ legacy_hal::wifi_request_id id,
+ const legacy_hal::
+ wifi_scan_result* result,
+ uint32_t buckets_scanned) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ StaScanResult hidl_scan_result;
+ if (!hidl_struct_util::convertLegacyGscanResultToHidl(
+ *result, true, &hidl_scan_result)) {
+ LOG(ERROR) << "Failed to convert full scan results to HIDL structs";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback
+ ->onBackgroundFullScanResult(id, buckets_scanned,
+ hidl_scan_result)
+ .isOk()) {
+ LOG(ERROR)
+ << "Failed to invoke onBackgroundFullScanResult callback";
+ }
+ }
+ };
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startGscan(
+ ifname_, cmd_id, legacy_params, on_failure_callback,
+ on_results_callback, on_full_result_callback);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopBackgroundScanInternal(uint32_t cmd_id) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->stopGscan(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->enableLinkLayerStats(ifname_, debug);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->disableLinkLayerStats(ifname_);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_0::StaLinkLayerStats>
+WifiStaIface::getLinkLayerStatsInternal() {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_3::StaLinkLayerStats>
+WifiStaIface::getLinkLayerStatsInternal_1_3() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::LinkLayerStats legacy_stats;
+ std::tie(legacy_status, legacy_stats) =
+ legacy_hal_.lock()->getLinkLayerStats(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ V1_3::StaLinkLayerStats hidl_stats;
+ if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
+ &hidl_stats)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
+}
+
+WifiStatus WifiStaIface::startRssiMonitoringInternal(uint32_t cmd_id,
+ int32_t max_rssi,
+ int32_t min_rssi) {
+ android::wp<WifiStaIface> weak_ptr_this(this);
+ const auto& on_threshold_breached_callback =
+ [weak_ptr_this](legacy_hal::wifi_request_id id,
+ std::array<uint8_t, 6> bssid, int8_t rssi) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onRssiThresholdBreached(id, bssid, rssi)
+ .isOk()) {
+ LOG(ERROR)
+ << "Failed to invoke onRssiThresholdBreached callback";
+ }
+ }
+ };
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->startRssiMonitoring(ifname_, cmd_id, max_rssi,
+ min_rssi,
+ on_threshold_breached_callback);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopRssiMonitoringInternal(uint32_t cmd_id) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->stopRssiMonitoring(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, StaRoamingCapabilities>
+WifiStaIface::getRoamingCapabilitiesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::wifi_roaming_capabilities legacy_caps;
+ std::tie(legacy_status, legacy_caps) =
+ legacy_hal_.lock()->getRoamingCapabilities(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ StaRoamingCapabilities hidl_caps;
+ if (!hidl_struct_util::convertLegacyRoamingCapabilitiesToHidl(legacy_caps,
+ &hidl_caps)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+WifiStatus WifiStaIface::configureRoamingInternal(
+ const StaRoamingConfig& config) {
+ legacy_hal::wifi_roaming_config legacy_config;
+ if (!hidl_struct_util::convertHidlRoamingConfigToLegacy(config,
+ &legacy_config)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->configureRoaming(ifname_, legacy_config);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->enableFirmwareRoaming(
+ ifname_, hidl_struct_util::convertHidlRoamingStateToLegacy(state));
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::enableNdOffloadInternal(bool enable) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->configureNdOffload(ifname_, enable);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
+ uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
+ uint16_t ether_type, const std::array<uint8_t, 6>& src_address,
+ const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->startSendingOffloadedPacket(
+ ifname_, cmd_id, ether_type, ip_packet_data, src_address,
+ dst_address, period_in_ms);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(uint32_t cmd_id) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->stopSendingOffloadedPacket(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::setScanningMacOuiInternal(
+ const std::array<uint8_t, 3>& oui) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->setScanningMacOui(ifname_, oui);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->startPktFateMonitoring(ifname_);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
+WifiStaIface::getDebugTxPacketFatesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ std::vector<legacy_hal::wifi_tx_report> legacy_fates;
+ std::tie(legacy_status, legacy_fates) =
+ legacy_hal_.lock()->getTxPktFates(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ std::vector<WifiDebugTxPacketFateReport> hidl_fates;
+ if (!hidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToHidl(
+ legacy_fates, &hidl_fates)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
+WifiStaIface::getDebugRxPacketFatesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ std::vector<legacy_hal::wifi_rx_report> legacy_fates;
+ std::tie(legacy_status, legacy_fates) =
+ legacy_hal_.lock()->getRxPktFates(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ std::vector<WifiDebugRxPacketFateReport> hidl_fates;
+ if (!hidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToHidl(
+ legacy_fates, &hidl_fates)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
+}
+
+WifiStatus WifiStaIface::setMacAddressInternal(
+ const std::array<uint8_t, 6>& mac) {
+ bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
+ if (!status) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, std::array<uint8_t, 6>>
+WifiStaIface::getFactoryMacAddressInternal() {
+ std::array<uint8_t, 6> mac =
+ iface_util_.lock()->getFactoryMacAddress(ifname_);
+ return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
+}
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi_sta_iface.h b/wifi/1.4/default/wifi_sta_iface.h
new file mode 100644
index 0000000..dee04f2
--- /dev/null
+++ b/wifi/1.4/default/wifi_sta_iface.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_STA_IFACE_H_
+#define WIFI_STA_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
+#include <android/hardware/wifi/1.3/IWifiStaIface.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a STA Iface instance.
+ */
+class WifiStaIface : public V1_3::IWifiStaIface {
+ public:
+ WifiStaIface(const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+ // Refer to |WifiChip::invalidate()|.
+ void invalidate();
+ bool isValid();
+ std::set<sp<IWifiStaIfaceEventCallback>> getEventCallbacks();
+ std::string getName();
+
+ // HIDL methods exposed.
+ Return<void> getName(getName_cb hidl_status_cb) override;
+ Return<void> getType(getType_cb hidl_status_cb) override;
+ Return<void> registerEventCallback(
+ const sp<IWifiStaIfaceEventCallback>& callback,
+ registerEventCallback_cb hidl_status_cb) override;
+ Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+ Return<void> getApfPacketFilterCapabilities(
+ getApfPacketFilterCapabilities_cb hidl_status_cb) override;
+ Return<void> installApfPacketFilter(
+ uint32_t cmd_id, const hidl_vec<uint8_t>& program,
+ installApfPacketFilter_cb hidl_status_cb) override;
+ Return<void> readApfPacketFilterData(
+ readApfPacketFilterData_cb hidl_status_cb) override;
+ Return<void> getBackgroundScanCapabilities(
+ getBackgroundScanCapabilities_cb hidl_status_cb) override;
+ Return<void> getValidFrequenciesForBand(
+ V1_0::WifiBand band,
+ getValidFrequenciesForBand_cb hidl_status_cb) override;
+ Return<void> startBackgroundScan(
+ uint32_t cmd_id, const StaBackgroundScanParameters& params,
+ startBackgroundScan_cb hidl_status_cb) override;
+ Return<void> stopBackgroundScan(
+ uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) override;
+ Return<void> enableLinkLayerStatsCollection(
+ bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) override;
+ Return<void> disableLinkLayerStatsCollection(
+ disableLinkLayerStatsCollection_cb hidl_status_cb) override;
+ Return<void> getLinkLayerStats(
+ getLinkLayerStats_cb hidl_status_cb) override;
+ Return<void> getLinkLayerStats_1_3(
+ getLinkLayerStats_1_3_cb hidl_status_cb) override;
+ Return<void> startRssiMonitoring(
+ uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
+ startRssiMonitoring_cb hidl_status_cb) override;
+ Return<void> stopRssiMonitoring(
+ uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
+ Return<void> getRoamingCapabilities(
+ getRoamingCapabilities_cb hidl_status_cb) override;
+ Return<void> configureRoaming(const StaRoamingConfig& config,
+ configureRoaming_cb hidl_status_cb) override;
+ Return<void> setRoamingState(StaRoamingState state,
+ setRoamingState_cb hidl_status_cb) override;
+ Return<void> enableNdOffload(bool enable,
+ enableNdOffload_cb hidl_status_cb) override;
+ Return<void> startSendingKeepAlivePackets(
+ uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data,
+ uint16_t ether_type, const hidl_array<uint8_t, 6>& src_address,
+ const hidl_array<uint8_t, 6>& dst_address, uint32_t period_in_ms,
+ startSendingKeepAlivePackets_cb hidl_status_cb) override;
+ Return<void> stopSendingKeepAlivePackets(
+ uint32_t cmd_id,
+ stopSendingKeepAlivePackets_cb hidl_status_cb) override;
+ Return<void> setScanningMacOui(
+ const hidl_array<uint8_t, 3>& oui,
+ setScanningMacOui_cb hidl_status_cb) override;
+ Return<void> startDebugPacketFateMonitoring(
+ startDebugPacketFateMonitoring_cb hidl_status_cb) override;
+ Return<void> getDebugTxPacketFates(
+ getDebugTxPacketFates_cb hidl_status_cb) override;
+ Return<void> getDebugRxPacketFates(
+ getDebugRxPacketFates_cb hidl_status_cb) override;
+ Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
+ setMacAddress_cb hidl_status_cb) override;
+ Return<void> getFactoryMacAddress(
+ getFactoryMacAddress_cb hidl_status_cb) override;
+
+ private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<WifiStatus, std::string> getNameInternal();
+ std::pair<WifiStatus, IfaceType> getTypeInternal();
+ WifiStatus registerEventCallbackInternal(
+ const sp<IWifiStaIfaceEventCallback>& callback);
+ std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
+ std::pair<WifiStatus, StaApfPacketFilterCapabilities>
+ getApfPacketFilterCapabilitiesInternal();
+ WifiStatus installApfPacketFilterInternal(
+ uint32_t cmd_id, const std::vector<uint8_t>& program);
+ std::pair<WifiStatus, std::vector<uint8_t>>
+ readApfPacketFilterDataInternal();
+ std::pair<WifiStatus, StaBackgroundScanCapabilities>
+ getBackgroundScanCapabilitiesInternal();
+ std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+ getValidFrequenciesForBandInternal(V1_0::WifiBand band);
+ WifiStatus startBackgroundScanInternal(
+ uint32_t cmd_id, const StaBackgroundScanParameters& params);
+ WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
+ WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
+ WifiStatus disableLinkLayerStatsCollectionInternal();
+ std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal();
+ std::pair<WifiStatus, V1_3::StaLinkLayerStats>
+ getLinkLayerStatsInternal_1_3();
+ WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi,
+ int32_t min_rssi);
+ WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
+ std::pair<WifiStatus, StaRoamingCapabilities>
+ getRoamingCapabilitiesInternal();
+ WifiStatus configureRoamingInternal(const StaRoamingConfig& config);
+ WifiStatus setRoamingStateInternal(StaRoamingState state);
+ WifiStatus enableNdOffloadInternal(bool enable);
+ WifiStatus startSendingKeepAlivePacketsInternal(
+ uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
+ uint16_t ether_type, const std::array<uint8_t, 6>& src_address,
+ const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
+ WifiStatus stopSendingKeepAlivePacketsInternal(uint32_t cmd_id);
+ WifiStatus setScanningMacOuiInternal(const std::array<uint8_t, 3>& oui);
+ WifiStatus startDebugPacketFateMonitoringInternal();
+ std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
+ getDebugTxPacketFatesInternal();
+ std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
+ getDebugRxPacketFatesInternal();
+ WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
+ std::pair<WifiStatus, std::array<uint8_t, 6>>
+ getFactoryMacAddressInternal();
+
+ std::string ifname_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+ bool is_valid_;
+ hidl_callback_util::HidlCallbackHandler<IWifiStaIfaceEventCallback>
+ event_cb_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
+};
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_STA_IFACE_H_
diff --git a/wifi/1.4/default/wifi_status_util.cpp b/wifi/1.4/default/wifi_status_util.cpp
new file mode 100644
index 0000000..8ceb926
--- /dev/null
+++ b/wifi/1.4/default/wifi_status_util.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+std::string legacyErrorToString(legacy_hal::wifi_error error) {
+ switch (error) {
+ case legacy_hal::WIFI_SUCCESS:
+ return "SUCCESS";
+ case legacy_hal::WIFI_ERROR_UNINITIALIZED:
+ return "UNINITIALIZED";
+ case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
+ return "NOT_AVAILABLE";
+ case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
+ return "NOT_SUPPORTED";
+ case legacy_hal::WIFI_ERROR_INVALID_ARGS:
+ return "INVALID_ARGS";
+ case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
+ return "INVALID_REQUEST_ID";
+ case legacy_hal::WIFI_ERROR_TIMED_OUT:
+ return "TIMED_OUT";
+ case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
+ return "TOO_MANY_REQUESTS";
+ case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
+ return "OUT_OF_MEMORY";
+ case legacy_hal::WIFI_ERROR_BUSY:
+ return "BUSY";
+ case legacy_hal::WIFI_ERROR_UNKNOWN:
+ return "UNKNOWN";
+ default:
+ return "UNKNOWN ERROR";
+ }
+}
+
+WifiStatus createWifiStatus(WifiStatusCode code,
+ const std::string& description) {
+ return {code, description};
+}
+
+WifiStatus createWifiStatus(WifiStatusCode code) {
+ return createWifiStatus(code, "");
+}
+
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
+ const std::string& desc) {
+ switch (error) {
+ case legacy_hal::WIFI_ERROR_UNINITIALIZED:
+ case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, desc);
+
+ case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED, desc);
+
+ case legacy_hal::WIFI_ERROR_INVALID_ARGS:
+ case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS, desc);
+
+ case legacy_hal::WIFI_ERROR_TIMED_OUT:
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+ desc + ", timed out");
+
+ case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+ desc + ", too many requests");
+
+ case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+ desc + ", out of memory");
+
+ case legacy_hal::WIFI_ERROR_BUSY:
+ return createWifiStatus(WifiStatusCode::ERROR_BUSY);
+
+ case legacy_hal::WIFI_ERROR_NONE:
+ return createWifiStatus(WifiStatusCode::SUCCESS, desc);
+
+ case legacy_hal::WIFI_ERROR_UNKNOWN:
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
+
+ default:
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+ "unknown error");
+ }
+}
+
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) {
+ return createWifiStatusFromLegacyError(error, "");
+}
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.4/default/wifi_status_util.h b/wifi/1.4/default/wifi_status_util.h
new file mode 100644
index 0000000..3ff58f0
--- /dev/null
+++ b/wifi/1.4/default/wifi_status_util.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_STATUS_UTIL_H_
+#define WIFI_STATUS_UTIL_H_
+
+#include <android/hardware/wifi/1.4/IWifi.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+std::string legacyErrorToString(legacy_hal::wifi_error error);
+WifiStatus createWifiStatus(WifiStatusCode code,
+ const std::string& description);
+WifiStatus createWifiStatus(WifiStatusCode code);
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
+ const std::string& description);
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
+
+} // namespace implementation
+} // namespace V1_4
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_STATUS_UTIL_H_
diff --git a/wifi/1.4/types.hal b/wifi/1.4/types.hal
new file mode 100644
index 0000000..4f1d22e
--- /dev/null
+++ b/wifi/1.4/types.hal
@@ -0,0 +1,593 @@
+/*
+ * 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::MacAddress;
+import @1.0::NanBandIndex;
+import @1.0::NanBandSpecificConfig;
+import @1.0::Rssi;
+import @1.0::RttBw;
+import @1.0::RttConfig;
+import @1.0::RttPeerType;
+import @1.0::RttPreamble;
+import @1.0::RttStatus;
+import @1.0::RttType;
+import @1.0::TimeSpanInPs;
+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;
+import @1.0::WifiRatePreamble;
+
+/**
+ * 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,
+};
+
+/**
+ * The discovery bands supported by NAN.
+ */
+enum NanBandIndex : @1.0::NanBandIndex {
+ /**
+ * Index for 6 GHz band.
+ */
+ NAN_BAND_6GHZ = 2,
+};
+
+/**
+ * Wifi Rate Preamble
+ */
+enum WifiRatePreamble : @1.0::WifiRatePreamble {
+ /**
+ * Preamble type for 11ax
+ */
+ HE = 5,
+};
+
+/**
+ * RTT Measurement Preamble.
+ */
+enum RttPreamble : @1.0::RttPreamble {
+ /**
+ * Preamble type for 11ax
+ */
+ HE = 0x8,
+};
+
+/**
+ * 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 {
+ /**
+ * Peer device mac address.
+ */
+ MacAddress addr;
+
+ /**
+ * 1-sided or 2-sided RTT.
+ */
+ RttType type;
+
+ /**
+ * Optional - peer device hint (STA, P2P, AP).
+ */
+ RttPeerType peer;
+
+ /**
+ * Required for STA-AP mode, optional for P2P, NBD etc.
+ */
+ WifiChannelInfo channel;
+
+ /**
+ * Time interval between bursts (units: 100 ms).
+ * Applies to 1-sided and 2-sided RTT multi-burst requests.
+ * Range: 0-31, 0: no preference by initiator (2-sided RTT).
+ */
+ uint32_t burstPeriod;
+
+ /**
+ * Total number of RTT bursts to be executed. It will be
+ * specified in the same way as the parameter "Number of
+ * Burst Exponent" found in the FTM frame format. It
+ * applies to both: 1-sided RTT and 2-sided RTT. Valid
+ * values are 0 to 15 as defined in 802.11mc std.
+ * 0 means single shot
+ * The implication of this parameter on the maximum
+ * number of RTT results is the following:
+ * for 1-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst)
+ * for 2-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst - 1)
+ */
+ uint32_t numBurst;
+
+ /**
+ * Num of frames per burst.
+ * Minimum value = 1, Maximum value = 31
+ * For 2-sided this equals the number of FTM frames
+ * to be attempted in a single burst. This also
+ * equals the number of FTM frames that the
+ * initiator will request that the responder send
+ * in a single frame.
+ */
+ uint32_t numFramesPerBurst;
+
+ /**
+ * Number of retries for a failed RTT frame.
+ * Applies to 1-sided RTT only. Minimum value = 0, Maximum value = 3
+ */
+ uint32_t numRetriesPerRttFrame;
+
+ /**
+ * Following fields are only valid for 2-side RTT.
+ *
+ *
+ * Maximum number of retries that the initiator can
+ * retry an FTMR frame.
+ * Minimum value = 0, Maximum value = 3
+ */
+ uint32_t numRetriesPerFtmr;
+
+ /**
+ * Whether to request location civic info or not.
+ */
+ bool mustRequestLci;
+
+ /**
+ * Whether to request location civic records or not.
+ */
+ bool mustRequestLcr;
+
+ /**
+ * Applies to 1-sided and 2-sided RTT. Valid values will
+ * be 2-11 and 15 as specified by the 802.11mc std for
+ * the FTM parameter burst duration. In a multi-burst
+ * request, if responder overrides with larger value,
+ * the initiator will return failure. In a single-burst
+ * request if responder overrides with larger value,
+ * the initiator will sent TMR_STOP to terminate RTT
+ * at the end of the burst_duration it requested.
+ */
+ uint32_t burstDuration;
+
+ /**
+ * RTT preamble to be used in the RTT frames.
+ */
+ RttPreamble preamble;
+
+ /**
+ * RTT BW to be used in the RTT frames.
+ */
+ RttBw bw;
+};
+
+/**
+ * RTT Capabilities.
+ */
+struct RttCapabilities {
+ /**
+ * if 1-sided rtt data collection is supported.
+ */
+ bool rttOneSidedSupported;
+
+ /**
+ * if ftm rtt data collection is supported.
+ */
+ bool rttFtmSupported;
+
+ /**
+ * if initiator supports LCI request. Applies to 2-sided RTT.
+ */
+ bool lciSupported;
+
+ /**
+ * if initiator supports LCR request. Applies to 2-sided RTT.
+ */
+ bool lcrSupported;
+
+ /**
+ * if 11mc responder mode is supported.
+ */
+ bool responderSupported;
+
+ /**
+ * Bit mask indicates what preamble is supported by initiator.
+ * Combination of |RttPreamble| values.
+ */
+ bitfield<RttPreamble> preambleSupport;
+
+ /**
+ * Bit mask indicates what BW is supported by initiator.
+ * Combination of |RttBw| values.
+ */
+ bitfield<RttBw> bwSupport;
+
+ /**
+ * Draft 11mc spec version supported by chip.
+ * For instance, version 4.0 must be 40 and version 4.3 must be 43 etc.
+ */
+ uint8_t mcVersion;
+};
+
+/**
+ * RTT Responder information
+ */
+struct RttResponder {
+ WifiChannelInfo channel;
+
+ RttPreamble preamble;
+};
+
+/**
+ * Wifi rate info.
+ */
+struct WifiRateInfo {
+ /**
+ * Preamble used for RTT measurements.
+ */
+ WifiRatePreamble preamble;
+
+ /**
+ * Number of spatial streams.
+ */
+ WifiRateNss nss;
+
+ /**
+ * Bandwidth of channel.
+ */
+ WifiChannelWidthInMhz bw;
+
+ /**
+ * OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps.
+ * HT/VHT/HE it would be mcs index.
+ */
+ uint8_t rateMcsIdx;
+
+ /**
+ * Bitrate in units of 100 Kbps.
+ */
+ uint32_t bitRateInKbps;
+};
+
+/**
+ * RTT results.
+ */
+struct RttResult {
+ /**
+ * Peer device mac address.
+ */
+ MacAddress addr;
+
+ /**
+ * Burst number in a multi-burst request.
+ */
+ uint32_t burstNum;
+
+ /**
+ * Total RTT measurement frames attempted.
+ */
+ uint32_t measurementNumber;
+
+ /**
+ * Total successful RTT measurement frames.
+ */
+ uint32_t successNumber;
+
+ /**
+ * Maximum number of "FTM frames per burst" supported by
+ * the responder STA. Applies to 2-sided RTT only.
+ * If reponder overrides with larger value:
+ * - for single-burst request initiator will truncate the
+ * larger value and send a TMR_STOP after receiving as
+ * many frames as originally requested.
+ * - for multi-burst request, initiator will return
+ * failure right away.
+ */
+ uint8_t numberPerBurstPeer;
+
+ /**
+ * Ranging status.
+ */
+ RttStatus status;
+
+ /**
+ * When status == RTT_STATUS_FAIL_BUSY_TRY_LATER,
+ * this will be the time provided by the responder as to
+ * when the request can be tried again. Applies to 2-sided
+ * RTT only. In sec, 1-31sec.
+ */
+ uint8_t retryAfterDuration;
+
+ /**
+ * RTT type.
+ */
+ RttType type;
+
+ /**
+ * Average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB.
+ */
+ Rssi rssi;
+
+ /**
+ * Rssi spread in 0.5 dB steps e.g. 5 implies 2.5 dB spread (optional).
+ */
+ Rssi rssiSpread;
+
+ /**
+ * 1-sided RTT: TX rate of RTT frame.
+ * 2-sided RTT: TX rate of initiator's Ack in response to FTM frame.
+ */
+ WifiRateInfo txRate;
+
+ /**
+ * 1-sided RTT: TX rate of Ack from other side.
+ * 2-sided RTT: TX rate of FTM frame coming from responder.
+ */
+ WifiRateInfo rxRate;
+
+ /**
+ * Round trip time in picoseconds
+ */
+ TimeSpanInPs rtt;
+
+ /**
+ * Rtt standard deviation in picoseconds.
+ */
+ TimeSpanInPs rttSd;
+
+ /**
+ * Difference between max and min rtt times recorded in picoseconds.
+ */
+ TimeSpanInPs rttSpread;
+
+ /**
+ * Distance in mm (optional).
+ */
+ int32_t distanceInMm;
+
+ /**
+ * Standard deviation in mm (optional).
+ */
+ int32_t distanceSdInMm;
+
+ /**
+ * Difference between max and min distance recorded in mm (optional).
+ */
+ int32_t distanceSpreadInMm;
+
+ /**
+ * Time of the measurement (in microseconds since boot).
+ */
+ TimeStampInUs timeStampInUs;
+
+ /**
+ * in ms, actual time taken by the FW to finish one burst
+ * measurement. Applies to 1-sided and 2-sided RTT.
+ */
+ uint32_t burstDurationInMs;
+
+ /**
+ * Number of bursts allowed by the responder. Applies
+ * to 2-sided RTT only.
+ */
+ uint32_t negotiatedBurstNum;
+
+ /**
+ * for 11mc only.
+ */
+ WifiInformationElement lci;
+
+ /**
+ * for 11mc only.
+ */
+ WifiInformationElement lcr;
+};
diff --git a/wifi/1.3/default/OWNERS b/wifi/1.4/vts/OWNERS
similarity index 100%
copy from wifi/1.3/default/OWNERS
copy to wifi/1.4/vts/OWNERS
diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp
new file mode 100644
index 0000000..46ac3ee
--- /dev/null
+++ b/wifi/1.4/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.
+//
+
+// SoftAP-specific tests, similar to VtsHalWifiApV1_0TargetTest.
+cc_test {
+ name: "VtsHalWifiApV1_4TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "VtsHalWifiV1_4TargetTest.cpp",
+ "wifi_ap_iface_hidl_test.cpp",
+ "wifi_chip_hidl_test.cpp",
+ "wifi_nan_iface_hidl_test.cpp"
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "libwifi-system-iface"
+ ],
+ test_suites: ["general-tests", "vts-core"],
+}
diff --git a/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp
new file mode 100644
index 0000000..7e0f3cd
--- /dev/null
+++ b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.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/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
new file mode 100644
index 0000000..3507d30
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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/hardware/wifi/1.4/IWifi.h>
+#include <android/hardware/wifi/1.4/IWifiApIface.h>
+#include <gtest/gtest.h>
+#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::hidl_array;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_4::IWifi;
+using ::android::hardware::wifi::V1_4::IWifiApIface;
+
+extern WifiHidlEnvironment* gEnv;
+
+/**
+ * Fixture to use for all STA Iface HIDL interface tests.
+ */
+class WifiApIfaceHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ // Make sure to start with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_ap_iface_ =
+ IWifiApIface::castFrom(getWifiApIface(GetInstanceName()));
+ ASSERT_NE(nullptr, wifi_ap_iface_.get());
+ }
+
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+ protected:
+ sp<IWifiApIface> wifi_ap_iface_;
+
+ private:
+ std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * SetMacAddress:
+ * Ensures that calls to set MAC address will return a success status
+ * code.
+ */
+TEST_P(WifiApIfaceHidlTest, SetMacAddress) {
+ const hidl_array<uint8_t, 6> kMac{{0x12, 0x22, 0x33, 0x52, 0x10, 0x41}};
+ EXPECT_EQ(WifiStatusCode::SUCCESS,
+ HIDL_INVOKE(wifi_ap_iface_, setMacAddress, kMac).code);
+}
+
+/*
+ * GetFactoryMacAddress:
+ * Ensures that calls to get factory MAC address will retrieve a non-zero MAC
+ * and return a success status code.
+ */
+TEST_P(WifiApIfaceHidlTest, GetFactoryMacAddress) {
+ std::pair<WifiStatus, hidl_array<uint8_t, 6> > status_and_mac =
+ HIDL_INVOKE(wifi_ap_iface_, getFactoryMacAddress);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code);
+ hidl_array<uint8_t, 6> all_zero{};
+ EXPECT_NE(all_zero, status_and_mac.second);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiApIfaceHidlTest,
+ testing::ValuesIn(
+ android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
new file mode 100644
index 0000000..7896067
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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 <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+
+#undef NAN // NAN is defined in bionic/libc/include/math.h:38
+
+#include <android/hardware/wifi/1.4/IWifi.h>
+#include <android/hardware/wifi/1.4/IWifiChip.h>
+#include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
+#include <gtest/gtest.h>
+#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::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_4::IWifiChip;
+using ::android::hardware::wifi::V1_4::IWifiChipEventCallback;
+
+/**
+ * Fixture to use for all Wifi chip HIDL interface tests.
+ */
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ // Make sure to start with a clean state
+ stopWifi(GetInstanceName());
+
+ wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
+ ASSERT_NE(nullptr, wifi_chip_.get());
+ }
+
+ virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+ // A simple test implementation of WifiChipEventCallback.
+ class WifiChipEventCallback
+ : public ::testing::VtsHalHidlTargetCallbackBase<WifiChipHidlTest>,
+ public IWifiChipEventCallback {
+ public:
+ WifiChipEventCallback(){};
+
+ virtual ~WifiChipEventCallback() = default;
+
+ Return<void> onChipReconfigured(uint32_t modeId __unused) {
+ return Void();
+ };
+
+ Return<void> onChipReconfigureFailure(
+ const WifiStatus& status __unused) {
+ return Void();
+ };
+
+ Return<void> onIfaceAdded(IfaceType type __unused,
+ const hidl_string& name __unused) {
+ return Void();
+ };
+
+ Return<void> onIfaceRemoved(IfaceType type __unused,
+ const hidl_string& name __unused) {
+ return Void();
+ };
+
+ Return<void> onDebugRingBufferDataAvailable(
+ const WifiDebugRingBufferStatus& status __unused,
+ const hidl_vec<uint8_t>& data __unused) {
+ return Void();
+ };
+
+ Return<void> onDebugErrorAlert(int32_t errorCode __unused,
+ const hidl_vec<uint8_t>& debugData
+ __unused) {
+ return Void();
+ };
+
+ Return<void> onRadioModeChange(
+ const hidl_vec<::android::hardware::wifi::V1_2::
+ IWifiChipEventCallback::RadioModeInfo>&
+ radioModeInfos __unused) {
+ return Void();
+ };
+
+ Return<void> onRadioModeChange_1_4(
+ const hidl_vec<RadioModeInfo>& radioModeInfos __unused) {
+ return Void();
+ };
+ };
+
+ protected:
+ sp<IWifiChip> wifi_chip_;
+
+ private:
+ std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * registerEventCallback_1_4
+ * This test case tests the registerEventCallback_1_4() API which registers
+ * a call back function with the hal implementation
+ *
+ * Note: it is not feasible to test the invocation of the call back function
+ * since event is triggered internally in the HAL implementation, and can not be
+ * triggered from the test case
+ */
+TEST_P(WifiChipHidlTest, registerEventCallback_1_4) {
+ sp<WifiChipEventCallback> wifiChipEventCallback =
+ new WifiChipEventCallback();
+ const auto& status = HIDL_INVOKE(wifi_chip_, registerEventCallback_1_4,
+ wifiChipEventCallback);
+
+ if (status.code != WifiStatusCode::SUCCESS) {
+ EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code);
+ return;
+ }
+}
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..688faf1
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -0,0 +1,547 @@
+/*
+ * 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 {
+ // Make sure to start with a clean state
+ stopWifi(GetInstanceName());
+
+ 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/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..0869da0
--- /dev/null
+++ b/wifi/hostapd/1.2/IHostapd.hal
@@ -0,0 +1,217 @@
+/*
+ * 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.EncryptionType;
+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 {
+ /** Possible Security types. */
+ enum EncryptionType : @1.0::IHostapd.EncryptionType {
+ WPA3_SAE_TRANSITION,
+ WPA3_SAE,
+ };
+
+ /**
+ * 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;
+
+ /**
+ * 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 specify the channel frequency range for ACS.
+ */
+ struct AcsFrequencyRange {
+ /**
+ * Channel Frequency (in MHz) at the start of the range.
+ */
+ uint32_t start;
+
+ /**
+ * Channel Frequency (in MHz) at the end of the range.
+ */
+ uint32_t end;
+ };
+
+ /**
+ * Parameters to control the channel selection for the interface.
+ */
+ struct ChannelParams {
+ /**
+ * Band to use for the SoftAp operations.
+ */
+ bitfield<BandMask> bandMask;
+
+ /**
+ * This option can be used to specify the channel frequencies (in MHz) selected by ACS.
+ * If this is an empty list, all channels allowed in selected HW mode
+ * are specified implicitly.
+ * Note: channels may be overridden by firmware.
+ * Note: this option is ignored if ACS is disabled.
+ */
+ vec<AcsFrequencyRange> acsChannelFreqRangesMhz;
+ };
+
+ /**
+ * 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;
+ };
+
+ /**
+ * Parameters to use for setting up the access point network.
+ */
+ struct NetworkParams {
+ /**
+ * Baseline information as defined in HAL 1.0.
+ */
+ @1.0::IHostapd.NetworkParams V1_0;
+ /** Key management mask for the replace V1_0.encryptionType. */
+ EncryptionType encryptionType;
+ /**
+ * Passphrase for WPA3_SAE network, WPA3_SAE_TRANSITION and
+ * WPA2_PSK. Replaces @1.0::IHostapd.NetworkParams.pskPassphrase.
+ */
+ string passphrase;
+ };
+
+
+ /**
+ * 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/1.3/default/OWNERS b/wifi/hostapd/1.2/vts/OWNERS
similarity index 100%
copy from wifi/1.3/default/OWNERS
copy to wifi/hostapd/1.2/vts/OWNERS
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..9f57934
--- /dev/null
+++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
@@ -0,0 +1,411 @@
+/*
+ * 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 char kInvalidMaxPskNwPassphrase[] =
+ "0123456789012345678901234567890123456789012345678901234567890123456789";
+constexpr char kInvalidMinPskNwPassphrase[] = "test";
+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(hostapd_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 getIfaceParamsWithAcsAndFreqRange() {
+ IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithAcs();
+ ::android::hardware::wifi::hostapd::V1_2::IHostapd::AcsFrequencyRange
+ acsFrequencyRange;
+ acsFrequencyRange.start = 2412;
+ acsFrequencyRange.end = 2462;
+ std::vector<::android::hardware::wifi::hostapd::V1_2::IHostapd::
+ AcsFrequencyRange>
+ vec_acsFrequencyRange;
+ vec_acsFrequencyRange.push_back(acsFrequencyRange);
+ iface_params_1_2.channelParams.acsChannelFreqRangesMhz =
+ vec_acsFrequencyRange;
+ return iface_params_1_2;
+ }
+
+ IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidFreqRange() {
+ IHostapd::IfaceParams iface_params_1_2 =
+ getIfaceParamsWithAcsAndFreqRange();
+ iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].start = 222;
+ iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].end = 999;
+ return iface_params_1_2;
+ }
+
+ IHostapd::NetworkParams getOpenNwParams() {
+ IHostapd::NetworkParams nw_params_1_2;
+ ::android::hardware::wifi::hostapd::V1_0::IHostapd::NetworkParams
+ nw_params_1_0;
+ nw_params_1_0.ssid =
+ std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+ nw_params_1_0.isHidden = false;
+ nw_params_1_2.V1_0 = nw_params_1_0;
+ nw_params_1_2.encryptionType = IHostapd::EncryptionType::NONE;
+ return nw_params_1_2;
+ }
+
+ IHostapd::NetworkParams getPskNwParams() {
+ IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams();
+ nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA2;
+ nw_params_1_2.passphrase = kNwPassphrase;
+ return nw_params_1_2;
+ }
+
+ IHostapd::NetworkParams getInvalidPskNwParams() {
+ IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams();
+ nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA2;
+ nw_params_1_2.passphrase = kInvalidMaxPskNwPassphrase;
+
+ return nw_params_1_2;
+ }
+
+ IHostapd::NetworkParams getSaeTransitionNwParams() {
+ IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams();
+ nw_params_1_2.encryptionType =
+ IHostapd::EncryptionType::WPA3_SAE_TRANSITION;
+ nw_params_1_2.passphrase = kNwPassphrase;
+ return nw_params_1_2;
+ }
+
+ IHostapd::NetworkParams getInvalidSaeTransitionNwParams() {
+ IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams();
+ nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA2;
+ nw_params_1_2.passphrase = kInvalidMinPskNwPassphrase;
+ return nw_params_1_2;
+ }
+
+ IHostapd::NetworkParams getSaeNwParams() {
+ IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams();
+ nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA3_SAE;
+ nw_params_1_2.passphrase = kNwPassphrase;
+ return nw_params_1_2;
+ }
+
+ IHostapd::NetworkParams getInvalidSaeNwParams() {
+ IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams();
+ nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA3_SAE;
+ nw_params_1_2.passphrase = "";
+ return nw_params_1_2;
+ }
+
+ 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 & frequency Range.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndFreqRange) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcsAndFreqRange(), 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, AddPskAccessPointWithAcsAndInvalidFreqRange) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcsAndInvalidFreqRange(),
+ 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 an access point with SAE Transition network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddSaeTransitionAccessPointWithoutAcs) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+ getSaeTransitionNwParams());
+ EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with SAE network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddSAEAccessPointWithoutAcs) {
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(), getSaeNwParams());
+ 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_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcs(), getPskNwParams());
+ // TODO: b/140172237, fix this in R
+ /*
+ 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 & 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);
+}
+
+/**
+ * Adds an access point with invalid SAE transition network config.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddInvalidSaeTransitionAccessPointWithoutAcs) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+ getInvalidSaeTransitionNwParams());
+ EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid SAE network config.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddInvalidSaeAccessPointWithoutAcs) {
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+ getInvalidSaeNwParams());
+ 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/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index d47e42f..d0df4a4 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -57,6 +57,11 @@
// Helper function to initialize the driver and firmware to STA mode
// using the vendor HAL HIDL interface.
void initilializeDriverAndFirmware(const std::string& wifi_instance_name) {
+ // Skip if wifi instance is not set.
+ if (wifi_instance_name == "") {
+ return;
+ }
+
sp<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name);
ChipModeId mode_id;
EXPECT_TRUE(configureChipToSupportIfaceType(
@@ -66,6 +71,11 @@
// Helper function to deinitialize the driver and firmware
// using the vendor HAL HIDL interface.
void deInitilializeDriverAndFirmware(const std::string& wifi_instance_name) {
+ // Skip if wifi instance is not set.
+ if (wifi_instance_name == "") {
+ return;
+ }
+
stopWifi(wifi_instance_name);
}
diff --git a/wifi/supplicant/1.1/vts/functional/Android.bp b/wifi/supplicant/1.1/vts/functional/Android.bp
index 8457532..6bcfa8a 100644
--- a/wifi/supplicant/1.1/vts/functional/Android.bp
+++ b/wifi/supplicant/1.1/vts/functional/Android.bp
@@ -19,7 +19,7 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["supplicant_hidl_test_utils_1_1.cpp"],
export_include_dirs: [
- "."
+ ".",
],
static_libs: [
"VtsHalWifiV1_0TargetTestUtil",
@@ -54,5 +54,8 @@
"libwifi-system",
"libwifi-system-iface",
],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
index 9063a3b..f582cc1 100644
--- a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
+++ b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
@@ -14,45 +14,8 @@
* limitations under the License.
*/
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.1/IWifi.h>
-#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
-
#include "supplicant_hidl_test_utils.h"
-#include "wifi_hidl_test_utils.h"
-class WifiSupplicantHidlEnvironment_1_1 : public WifiSupplicantHidlEnvironment {
- public:
- // get the test environment singleton
- static WifiSupplicantHidlEnvironment_1_1* Instance() {
- static WifiSupplicantHidlEnvironment_1_1* instance =
- new WifiSupplicantHidlEnvironment_1_1;
- return instance;
- }
- virtual void registerTestServices() override {
- registerTestService<::android::hardware::wifi::V1_0::IWifi>();
- registerTestService<::android::hardware::wifi::V1_1::IWifi>();
- registerTestService<
- ::android::hardware::wifi::supplicant::V1_0::ISupplicant>();
- registerTestService<
- ::android::hardware::wifi::supplicant::V1_1::ISupplicant>();
- }
-
- private:
- WifiSupplicantHidlEnvironment_1_1() {}
-};
-
-WifiSupplicantHidlEnvironment* gEnv =
- WifiSupplicantHidlEnvironment_1_1::Instance();
-
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(gEnv);
- ::testing::InitGoogleTest(&argc, argv);
- gEnv->init(&argc, argv);
- int status = gEnv->initFromOptions(argc, argv);
- if (status == 0) {
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- }
- return status;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
index 28f980c..24a7ec3 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
@@ -17,10 +17,12 @@
#include <android-base/logging.h>
#include <cutils/properties.h>
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/supplicant/1.0/types.h>
#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "supplicant_hidl_test_utils.h"
#include "supplicant_hidl_test_utils_1_1.h"
@@ -33,22 +35,11 @@
using ::android::hardware::wifi::supplicant::V1_1::ISupplicant;
using ::android::sp;
-extern WifiSupplicantHidlEnvironment* gEnv;
-
-class SupplicantHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantHidlTest : public SupplicantHidlTestBase {
public:
- virtual void SetUp() override {
- startSupplicantAndWaitForHidlService();
- supplicant_ = getSupplicant_1_1();
- ASSERT_NE(supplicant_.get(), nullptr);
- }
-
- virtual void TearDown() override { stopSupplicant(); }
+ virtual void SetUp() override { SupplicantHidlTestBase::SetUp(); }
protected:
- // ISupplicant object used for all tests in this fixture.
- sp<ISupplicant> supplicant_;
-
std::string getWlan0IfaceName() {
std::array<char, PROPERTY_VALUE_MAX> buffer;
property_get("wifi.interface", buffer.data(), "wlan0");
@@ -65,7 +56,7 @@
/*
* AddStaInterface
*/
-TEST_F(SupplicantHidlTest, AddStaInterface) {
+TEST_P(SupplicantHidlTest, AddStaInterface) {
ISupplicant::IfaceInfo iface_info;
iface_info.name = getWlan0IfaceName();
iface_info.type = IfaceType::STA;
@@ -82,8 +73,8 @@
/*
* AddP2pInterface
*/
-TEST_F(SupplicantHidlTest, AddP2pInterface) {
- if (!gEnv->isP2pOn) return;
+TEST_P(SupplicantHidlTest, AddP2pInterface) {
+ if (isP2pOn_) return;
ISupplicant::IfaceInfo iface_info;
iface_info.name = getP2pIfaceName();
iface_info.type = IfaceType::P2P;
@@ -100,7 +91,7 @@
/*
* RemoveStaInterface
*/
-TEST_F(SupplicantHidlTest, RemoveStaInterface) {
+TEST_P(SupplicantHidlTest, RemoveStaInterface) {
ISupplicant::IfaceInfo iface_info;
iface_info.name = getWlan0IfaceName();
iface_info.type = IfaceType::STA;
@@ -122,8 +113,8 @@
/*
* RemoveP2pInterface
*/
-TEST_F(SupplicantHidlTest, RemoveP2pInterface) {
- if (!gEnv->isP2pOn) return;
+TEST_P(SupplicantHidlTest, RemoveP2pInterface) {
+ if (isP2pOn_) return;
ISupplicant::IfaceInfo iface_info;
iface_info.name = getP2pIfaceName();
iface_info.type = IfaceType::P2P;
@@ -146,6 +137,23 @@
* Terminate
* This terminates the service.
*/
-TEST_F(SupplicantHidlTest, Terminate) {
- supplicant_->terminate();
+TEST_P(SupplicantHidlTest, Terminate) { supplicant_->terminate(); }
+
+static std::vector<std::string> get_wifi_instances() {
+ std::vector<std::string> instances =
+ android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::V1_0::IWifi::descriptor);
+ // Also test when wifi instance is not set.
+ instances.push_back("");
+
+ return instances;
}
+
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, SupplicantHidlTest,
+ testing::Combine(
+ testing::ValuesIn(get_wifi_instances()),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::supplicant::V1_1::ISupplicant::
+ descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp
index 04a5ed9..b75a2fb 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
#include "supplicant_hidl_test_utils.h"
@@ -25,14 +24,19 @@
using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaNetwork;
using ::android::sp;
-sp<ISupplicant> getSupplicant_1_1() {
- return ISupplicant::castFrom(getSupplicant());
+sp<ISupplicant> getSupplicant_1_1(const std::string& supplicant_instance_name,
+ bool isP2pOn) {
+ return ISupplicant::castFrom(
+ getSupplicant(supplicant_instance_name, isP2pOn));
}
-sp<ISupplicantStaIface> getSupplicantStaIface_1_1() {
- return ISupplicantStaIface::castFrom(getSupplicantStaIface());
+sp<ISupplicantStaIface> getSupplicantStaIface_1_1(
+ const sp<ISupplicant>& supplicant) {
+ return ISupplicantStaIface::castFrom(getSupplicantStaIface(supplicant));
}
-sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_1() {
- return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork());
+sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_1(
+ const sp<ISupplicant>& supplicant) {
+ return ISupplicantStaNetwork::castFrom(
+ createSupplicantStaNetwork(supplicant));
}
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
index 1c13325..3629882 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
@@ -14,20 +14,52 @@
* limitations under the License.
*/
-#ifndef SUPPLICANT_HIDL_TEST_UTILS_1_1_H
-#define SUPPLICANT_HIDL_TEST_UTILS_1_1_H
+#pragma once
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#include <VtsCoreUtil.h>
#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIface.h>
#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaNetwork.h>
+#include <gtest/gtest.h>
android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicant>
- getSupplicant_1_1();
+getSupplicant_1_1(const std::string& supplicant_instance_name, bool isP2pOn);
android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface>
- getSupplicantStaIface_1_1();
+getSupplicantStaIface_1_1(
+ const android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicant>&
+ supplicant);
android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicantStaNetwork>
- createSupplicantStaNetwork_1_1();
+createSupplicantStaNetwork_1_1(
+ const android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicant>&
+ supplicant);
-#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_1_H */
+class SupplicantHidlTestBase
+ : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+ public:
+ virtual void SetUp() override {
+ wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+ supplicant_v1_1_instance_name_ = std::get<1>(GetParam());
+ isP2pOn_ =
+ testing::deviceSupportsFeature("android.hardware.wifi.direct");
+ stopSupplicant(wifi_v1_0_instance_name_);
+ startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
+ supplicant_v1_1_instance_name_);
+ supplicant_ =
+ getSupplicant_1_1(supplicant_v1_1_instance_name_, isP2pOn_);
+ ASSERT_NE(supplicant_.get(), nullptr);
+ }
+
+ virtual void TearDown() override {
+ stopSupplicant(wifi_v1_0_instance_name_);
+ }
+
+ protected:
+ android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicant>
+ supplicant_;
+ bool isP2pOn_ = false;
+ std::string wifi_v1_0_instance_name_;
+ std::string supplicant_v1_1_instance_name_;
+};
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp
index c5e6319..8a1aecc 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -16,9 +16,13 @@
#include <android-base/logging.h>
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIface.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "supplicant_hidl_test_utils.h"
#include "supplicant_hidl_test_utils_1_1.h"
@@ -29,26 +33,24 @@
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface;
-using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIfaceCallback;
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_1::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface;
+using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIfaceCallback;
-class SupplicantStaIfaceHidlTest
- : public ::testing::VtsHalHidlTargetTestBase {
- public:
- virtual void SetUp() override {
- startSupplicantAndWaitForHidlService();
- EXPECT_TRUE(turnOnExcessiveLogging());
- sta_iface_ = getSupplicantStaIface_1_1();
- ASSERT_NE(sta_iface_.get(), nullptr);
- }
+class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBase {
+ public:
+ virtual void SetUp() override {
+ SupplicantHidlTestBase::SetUp();
+ EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ sta_iface_ = getSupplicantStaIface_1_1(supplicant_);
+ ASSERT_NE(sta_iface_.get(), nullptr);
+ }
- virtual void TearDown() override { stopSupplicant(); }
-
- protected:
- // ISupplicantStaIface object used for all tests in this fixture.
- sp<ISupplicantStaIface> sta_iface_;
+ protected:
+ // ISupplicantStaIface object used for all tests in this fixture.
+ sp<ISupplicantStaIface> sta_iface_;
};
class IfaceCallback : public ISupplicantStaIfaceCallback {
@@ -131,9 +133,19 @@
/*
* RegisterCallback_1_1
*/
-TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_1) {
- sta_iface_->registerCallback_1_1(
- new IfaceCallback(), [](const SupplicantStatus& status) {
- EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
- });
+TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback_1_1) {
+ sta_iface_->registerCallback_1_1(
+ new IfaceCallback(), [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
}
+
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, SupplicantStaIfaceHidlTest,
+ testing::Combine(
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::V1_0::IWifi::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::supplicant::V1_1::ISupplicant::
+ descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp
index fa52556..a4b7d40 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -16,8 +16,11 @@
#include <android-base/logging.h>
-#include <VtsHalHidlTargetTestBase.h>
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaNetwork.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "supplicant_hidl_test_utils.h"
#include "supplicant_hidl_test_utils_1_1.h"
@@ -26,27 +29,26 @@
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_1::ISupplicant;
using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaNetwork;
+
namespace {
constexpr uint8_t kTestIdentity[] = {0x45, 0x67, 0x98, 0x67, 0x56};
constexpr uint8_t kTestEncryptedIdentity[] = {0x35, 0x37, 0x58, 0x57, 0x26};
} // namespace
-class SupplicantStaNetworkHidlTest
- : public ::testing::VtsHalHidlTargetTestBase {
- public:
- virtual void SetUp() override {
- startSupplicantAndWaitForHidlService();
- EXPECT_TRUE(turnOnExcessiveLogging());
- sta_network_ = createSupplicantStaNetwork_1_1();
- ASSERT_NE(sta_network_.get(), nullptr);
- }
+class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBase {
+ public:
+ virtual void SetUp() override {
+ SupplicantHidlTestBase::SetUp();
+ EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ sta_network_ = createSupplicantStaNetwork_1_1(supplicant_);
+ ASSERT_NE(sta_network_.get(), nullptr);
+ }
- virtual void TearDown() override { stopSupplicant(); }
-
- protected:
- // ISupplicantStaNetwork object used for all tests in this fixture.
- sp<ISupplicantStaNetwork> sta_network_;
+ protected:
+ // ISupplicantStaNetwork object used for all tests in this fixture.
+ sp<ISupplicantStaNetwork> sta_network_;
};
/*
@@ -54,36 +56,49 @@
* Ensures that an instance of the ISupplicantStaNetwork proxy object is
* successfully created.
*/
-TEST(SupplicantStaNetworkHidlTestNoFixture, Create) {
- startSupplicantAndWaitForHidlService();
- EXPECT_NE(nullptr, createSupplicantStaNetwork_1_1().get());
- stopSupplicant();
+TEST_P(SupplicantStaNetworkHidlTest, Create) {
+ stopSupplicant(wifi_v1_0_instance_name_);
+ startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
+ supplicant_v1_1_instance_name_);
+ sp<ISupplicant> supplicant =
+ getSupplicant_1_1(supplicant_v1_1_instance_name_, isP2pOn_);
+ EXPECT_NE(nullptr, createSupplicantStaNetwork_1_1(supplicant).get());
}
/*
* Ensure that the encrypted imsi identity is set successfully.
*/
-TEST_F(SupplicantStaNetworkHidlTest, setEapEncryptedImsiIdentity) {
- std::vector<uint8_t> encrypted_identity(
- kTestEncryptedIdentity,
- kTestEncryptedIdentity + sizeof(kTestEncryptedIdentity));
- sta_network_->setEapEncryptedImsiIdentity(
- encrypted_identity, [](const SupplicantStatus &status) {
- EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
- });
+TEST_P(SupplicantStaNetworkHidlTest, setEapEncryptedImsiIdentity) {
+ std::vector<uint8_t> encrypted_identity(
+ kTestEncryptedIdentity,
+ kTestEncryptedIdentity + sizeof(kTestEncryptedIdentity));
+ sta_network_->setEapEncryptedImsiIdentity(
+ encrypted_identity, [](const SupplicantStatus &status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
}
/*
* Ensure that the identity and the encrypted imsi identity are sent
* successfully.
*/
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapIdentityResponse_1_1) {
- sta_network_->sendNetworkEapIdentityResponse_1_1(
- std::vector<uint8_t>(kTestIdentity,
- kTestIdentity + sizeof(kTestIdentity)),
- std::vector<uint8_t>(kTestEncryptedIdentity,
- kTestIdentity + sizeof(kTestEncryptedIdentity)),
- [](const SupplicantStatus &status) {
- EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
- });
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapIdentityResponse_1_1) {
+ sta_network_->sendNetworkEapIdentityResponse_1_1(
+ std::vector<uint8_t>(kTestIdentity,
+ kTestIdentity + sizeof(kTestIdentity)),
+ std::vector<uint8_t>(kTestEncryptedIdentity,
+ kTestIdentity + sizeof(kTestEncryptedIdentity)),
+ [](const SupplicantStatus &status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
}
+
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, SupplicantStaNetworkHidlTest,
+ testing::Combine(
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::V1_0::IWifi::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::supplicant::V1_1::ISupplicant::
+ descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp
index b7949d1..9781074 100644
--- a/wifi/supplicant/1.2/vts/functional/Android.bp
+++ b/wifi/supplicant/1.2/vts/functional/Android.bp
@@ -19,7 +19,7 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["supplicant_hidl_test_utils_1_2.cpp"],
export_include_dirs: [
- "."
+ ".",
],
static_libs: [
"VtsHalWifiV1_0TargetTestUtil",
@@ -51,13 +51,17 @@
"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",
"libwifi-system",
"libwifi-system-iface",
],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
cc_test {
@@ -81,5 +85,8 @@
"libwifi-system",
"libwifi-system-iface",
],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
-
diff --git a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp
index 267fa67..9dbeee1 100644
--- a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp
+++ b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp
@@ -14,47 +14,8 @@
* limitations under the License.
*/
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.1/IWifi.h>
-#include <android/hardware/wifi/supplicant/1.2/ISupplicant.h>
-
#include "supplicant_hidl_test_utils.h"
-#include "wifi_hidl_test_utils.h"
-class WifiSupplicantHidlEnvironment_1_2 : public WifiSupplicantHidlEnvironment {
- public:
- // get the test environment singleton
- static WifiSupplicantHidlEnvironment_1_2* Instance() {
- static WifiSupplicantHidlEnvironment_1_2* instance =
- new WifiSupplicantHidlEnvironment_1_2;
- return instance;
- }
- virtual void registerTestServices() override {
- registerTestService<::android::hardware::wifi::V1_0::IWifi>();
- registerTestService<::android::hardware::wifi::V1_1::IWifi>();
- registerTestService<
- ::android::hardware::wifi::supplicant::V1_0::ISupplicant>();
- registerTestService<
- ::android::hardware::wifi::supplicant::V1_1::ISupplicant>();
- registerTestService<
- ::android::hardware::wifi::supplicant::V1_2::ISupplicant>();
- }
-
- private:
- WifiSupplicantHidlEnvironment_1_2() {}
-};
-
-WifiSupplicantHidlEnvironment* gEnv =
- WifiSupplicantHidlEnvironment_1_2::Instance();
-
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(gEnv);
- ::testing::InitGoogleTest(&argc, argv);
- gEnv->init(&argc, argv);
- int status = gEnv->initFromOptions(argc, argv);
- if (status == 0) {
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- }
- return status;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp
index f270bff..480929a 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp
@@ -26,18 +26,24 @@
using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface;
using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
-sp<ISupplicant> getSupplicant_1_2() {
- return ISupplicant::castFrom(getSupplicant());
+sp<ISupplicant> getSupplicant_1_2(const std::string& supplicant_instance_name,
+ bool isP2pOn) {
+ return ISupplicant::castFrom(
+ getSupplicant(supplicant_instance_name, isP2pOn));
}
-sp<ISupplicantStaIface> getSupplicantStaIface_1_2() {
- return ISupplicantStaIface::castFrom(getSupplicantStaIface());
+sp<ISupplicantStaIface> getSupplicantStaIface_1_2(
+ const sp<ISupplicant>& supplicant) {
+ return ISupplicantStaIface::castFrom(getSupplicantStaIface(supplicant));
}
-sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_2() {
- return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork());
+sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_2(
+ const sp<ISupplicant>& supplicant) {
+ return ISupplicantStaNetwork::castFrom(
+ createSupplicantStaNetwork(supplicant));
}
-sp<ISupplicantP2pIface> getSupplicantP2pIface_1_2() {
- return ISupplicantP2pIface::castFrom(getSupplicantP2pIface());
+sp<ISupplicantP2pIface> getSupplicantP2pIface_1_2(
+ const sp<ISupplicant>& supplicant) {
+ return ISupplicantP2pIface::castFrom(getSupplicantP2pIface(supplicant));
}
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h
index 8a7ccc5..5ecfdd4 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h
@@ -14,24 +14,59 @@
* limitations under the License.
*/
-#ifndef SUPPLICANT_HIDL_TEST_UTILS_1_2_H
-#define SUPPLICANT_HIDL_TEST_UTILS_1_2_H
+#pragma once
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#include <VtsCoreUtil.h>
#include <android/hardware/wifi/supplicant/1.2/ISupplicant.h>
#include <android/hardware/wifi/supplicant/1.2/ISupplicantP2pIface.h>
#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIface.h>
#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
+#include <gtest/gtest.h>
android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant>
-getSupplicant_1_2();
+getSupplicant_1_2(const std::string& supplicant_instance_name, bool isP2pOn);
android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface>
-getSupplicantStaIface_1_2();
+getSupplicantStaIface_1_2(
+ const android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant>&
+ supplicant);
android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork>
-createSupplicantStaNetwork_1_2();
+createSupplicantStaNetwork_1_2(
+ const android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant>&
+ supplicant);
android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicantP2pIface>
-getSupplicantP2pIface_1_2();
+getSupplicantP2pIface_1_2(
+ const android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant>&
+ supplicant);
-#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_2_H */
+class SupplicantHidlTestBase
+ : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+ public:
+ virtual void SetUp() override {
+ wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+ supplicant_v1_2_instance_name_ = std::get<1>(GetParam());
+ isP2pOn_ =
+ testing::deviceSupportsFeature("android.hardware.wifi.direct");
+ stopSupplicant(wifi_v1_0_instance_name_);
+ startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
+ supplicant_v1_2_instance_name_);
+ supplicant_ =
+ getSupplicant_1_2(supplicant_v1_2_instance_name_, isP2pOn_);
+ ASSERT_NE(supplicant_.get(), nullptr);
+ EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ }
+
+ virtual void TearDown() override {
+ stopSupplicant(wifi_v1_0_instance_name_);
+ }
+
+ protected:
+ android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant>
+ supplicant_;
+ bool isP2pOn_ = false;
+ std::string wifi_v1_0_instance_name_;
+ std::string supplicant_v1_2_instance_name_;
+};
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp
index 1b78ac3..2b63ad0 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp
@@ -18,7 +18,11 @@
#include <VtsHalHidlTargetTestBase.h>
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/supplicant/1.2/ISupplicantP2pIface.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "supplicant_hidl_test_utils.h"
#include "supplicant_hidl_test_utils_1_2.h"
@@ -26,6 +30,7 @@
using ::android::sp;
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_2::ISupplicant;
using ::android::hardware::wifi::supplicant::V1_2::ISupplicantP2pIface;
namespace {
@@ -35,17 +40,15 @@
constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0};
} // namespace
-class SupplicantP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantP2pIfaceHidlTest : public SupplicantHidlTestBase {
public:
virtual void SetUp() override {
- startSupplicantAndWaitForHidlService();
- EXPECT_TRUE(turnOnExcessiveLogging());
- p2p_iface_ = getSupplicantP2pIface_1_2();
+ SupplicantHidlTestBase::SetUp();
+ EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ p2p_iface_ = getSupplicantP2pIface_1_2(supplicant_);
ASSERT_NE(p2p_iface_.get(), nullptr);
}
- virtual void TearDown() override { stopSupplicant(); }
-
protected:
// ISupplicantP2pIface object used for all tests in this fixture.
sp<ISupplicantP2pIface> p2p_iface_;
@@ -54,7 +57,7 @@
/*
* Verify that AddGroup_1_2 could create a group successfully.
*/
-TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_Success) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddGroup_1_2_Success) {
std::vector<uint8_t> ssid(kTestSsid, kTestSsid + sizeof(kTestSsid));
std::string passphrase = kTestPassphrase;
int freq = 0;
@@ -73,7 +76,7 @@
/*
* Verify that AddGroup_1_2 fails due to invalid SSID.
*/
-TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidSsid) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidSsid) {
std::vector<uint8_t> ssid;
std::string passphrase = kTestPassphrase;
int freq = 0;
@@ -92,7 +95,7 @@
/*
* Verify that AddGroup_1_2 fails due to invalid passphrase.
*/
-TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidPassphrase) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidPassphrase) {
std::vector<uint8_t> ssid(kTestSsid, kTestSsid + sizeof(kTestSsid));
std::string passphrase = "1234";
int freq = 0;
@@ -111,7 +114,7 @@
/*
* Verify that AddGroup_1_2 fails due to invalid frequency.
*/
-TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidFrequency) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidFrequency) {
std::vector<uint8_t> ssid(kTestSsid, kTestSsid + sizeof(kTestSsid));
std::string passphrase = kTestPassphrase;
int freq = 9999;
@@ -134,7 +137,7 @@
/*
* Verify that setMacRandomization successes.
*/
-TEST_F(SupplicantP2pIfaceHidlTest, EnableMacRandomization) {
+TEST_P(SupplicantP2pIfaceHidlTest, EnableMacRandomization) {
p2p_iface_->setMacRandomization(true, [](const SupplicantStatus& status) {
if (!isMacRandomizationSupported(status)) return;
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -157,3 +160,13 @@
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
});
}
+
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, SupplicantP2pIfaceHidlTest,
+ testing::Combine(
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::V1_0::IWifi::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::supplicant::V1_2::ISupplicant::
+ descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
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..8116c3f 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
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#include <VtsHalHidlTargetTestBase.h>
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.h>
#include <android/hardware/wifi/supplicant/1.0/types.h>
#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIfaceCallback.h>
@@ -22,7 +23,11 @@
#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/GtestPrinter.h>
#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
#include <hidl/Status.h>
#include "supplicant_hidl_test_utils.h"
@@ -40,6 +45,7 @@
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_2::ISupplicant;
using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface;
using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIfaceCallback;
using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
@@ -47,18 +53,16 @@
#define TIMEOUT_PERIOD 60
class IfaceDppCallback;
-class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBase {
public:
virtual void SetUp() override {
- startSupplicantAndWaitForHidlService();
- EXPECT_TRUE(turnOnExcessiveLogging());
- sta_iface_ = getSupplicantStaIface_1_2();
+ SupplicantHidlTestBase::SetUp();
+ EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ sta_iface_ = getSupplicantStaIface_1_2(supplicant_);
ASSERT_NE(sta_iface_.get(), nullptr);
count_ = 0;
}
- virtual void TearDown() override { stopSupplicant(); }
-
enum DppCallbackType {
ANY_CALLBACK = -2,
INVALID = -1,
@@ -99,6 +103,7 @@
protected:
// ISupplicantStaIface object used for all tests in this fixture.
sp<ISupplicantStaIface> sta_iface_;
+
bool isDppSupported() {
uint32_t keyMgmtMask = 0;
@@ -252,7 +257,7 @@
/*
* RegisterCallback_1_2
*/
-TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_2) {
+TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback_1_2) {
sta_iface_->registerCallback_1_2(
new IfaceCallback(), [](const SupplicantStatus& status) {
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -262,7 +267,7 @@
/*
* GetKeyMgmtCapabilities
*/
-TEST_F(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities) {
+TEST_P(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities) {
sta_iface_->getKeyMgmtCapabilities(
[&](const SupplicantStatus& status, uint32_t keyMgmtMask) {
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -278,7 +283,7 @@
/*
* AddDppPeerUriAndRomveUri
*/
-TEST_F(SupplicantStaIfaceHidlTest, AddDppPeerUriAndRomveUri) {
+TEST_P(SupplicantStaIfaceHidlTest, AddDppPeerUriAndRomveUri) {
// We need to first get the key management capabilities from the device.
// If DPP is not supported, we just pass the test.
if (!isDppSupported()) {
@@ -310,7 +315,7 @@
/*
* StartDppEnrolleeInitiator
*/
-TEST_F(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) {
+TEST_P(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()) {
@@ -318,6 +323,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=;;";
@@ -361,7 +379,7 @@
/*
* StartDppConfiguratorInitiator
*/
-TEST_F(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) {
+TEST_P(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()) {
@@ -369,6 +387,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=;;";
@@ -413,3 +446,13 @@
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
});
}
+
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, SupplicantStaIfaceHidlTest,
+ testing::Combine(
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::V1_0::IWifi::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::supplicant::V1_2::ISupplicant::
+ descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
index ed421d7..4c3d808 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -16,8 +16,12 @@
#include <android-base/logging.h>
-#include <VtsHalHidlTargetTestBase.h>
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaNetwork.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include "supplicant_hidl_test_utils.h"
#include "supplicant_hidl_test_utils_1_2.h"
@@ -26,24 +30,21 @@
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_2::ISupplicant;
using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
// namespace {
// constexpr uint8_t kTestIdentity[] = {0x45, 0x67, 0x98, 0x67, 0x56};
// constexpr uint8_t kTestEncryptedIdentity[] = {0x35, 0x37, 0x58, 0x57, 0x26};
//} // namespace
-class SupplicantStaNetworkHidlTest
- : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBase {
public:
virtual void SetUp() override {
- startSupplicantAndWaitForHidlService();
- EXPECT_TRUE(turnOnExcessiveLogging());
- sta_network_ = createSupplicantStaNetwork_1_2();
+ SupplicantHidlTestBase::SetUp();
+ sta_network_ = createSupplicantStaNetwork_1_2(supplicant_);
ASSERT_NE(sta_network_.get(), nullptr);
}
- virtual void TearDown() override { stopSupplicant(); }
-
protected:
// ISupplicantStaNetwork object used for all tests in this fixture.
sp<ISupplicantStaNetwork> sta_network_;
@@ -52,7 +53,7 @@
/*
* SetGetSaePassword
*/
-TEST_F(SupplicantStaNetworkHidlTest, SetGetSaePassword) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetSaePassword) {
std::string password = "topsecret";
sta_network_->setSaePassword(password, [](const SupplicantStatus &status) {
@@ -69,7 +70,7 @@
/*
* SetGetSaePasswordId
*/
-TEST_F(SupplicantStaNetworkHidlTest, SetGetSaePasswordId) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetSaePasswordId) {
std::string passwordId = "id1";
sta_network_->setSaePasswordId(
@@ -87,7 +88,7 @@
/*
* SetGetGroupMgmtCipher
*/
-TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupMgmtCipher) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupMgmtCipher) {
uint32_t groupMgmtCipher =
(uint32_t)ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_GMAC_256;
@@ -107,7 +108,7 @@
/*
* SetGetKeyMgmt_1_2
*/
-TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_2) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_2) {
uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::SAE;
sta_network_->setKeyMgmt_1_2(keyMgmt, [](const SupplicantStatus &status) {
@@ -124,7 +125,7 @@
/*
* SetGetGroupCipher_1_2
*/
-TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_2) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_2) {
uint32_t groupCipher =
(uint32_t)ISupplicantStaNetwork::GroupCipherMask::GCMP_256;
@@ -144,7 +145,7 @@
/*
* SetGetPairwiseCipher_1_2
*/
-TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_2) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_2) {
uint32_t pairwiseCipher =
(uint32_t)ISupplicantStaNetwork::PairwiseCipherMask::GCMP_256;
@@ -164,7 +165,7 @@
/*
* EnableSuiteBEapOpenSslCiphers
*/
-TEST_F(SupplicantStaNetworkHidlTest, EnableSuiteBEapOpenSslCiphers) {
+TEST_P(SupplicantStaNetworkHidlTest, EnableSuiteBEapOpenSslCiphers) {
sta_network_->enableSuiteBEapOpenSslCiphers(
[](const SupplicantStatus &status) {
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -179,7 +180,7 @@
/*
* EnableTlsSuiteBEapPhase1Param
*/
-TEST_F(SupplicantStaNetworkHidlTest, EnableTlsSuiteBEapPhase1Param) {
+TEST_P(SupplicantStaNetworkHidlTest, EnableTlsSuiteBEapPhase1Param) {
sta_network_->enableTlsSuiteBEapPhase1Param(
true, [](const SupplicantStatus &status) {
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -190,3 +191,13 @@
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
});
}
+
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, SupplicantStaNetworkHidlTest,
+ testing::Combine(
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::V1_0::IWifi::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::supplicant::V1_2::ISupplicant::
+ descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.3/Android.bp b/wifi/supplicant/1.3/Android.bp
new file mode 100644
index 0000000..15c72fe
--- /dev/null
+++ b/wifi/supplicant/1.3/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.wifi.supplicant@1.3",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "ISupplicant.hal",
+ "ISupplicantStaIface.hal",
+ "ISupplicantStaIfaceCallback.hal",
+ "ISupplicantStaNetwork.hal",
+ ],
+ interfaces: [
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hardware.wifi.supplicant@1.1",
+ "android.hardware.wifi.supplicant@1.2",
+ "android.hardware.wifi@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/wifi/supplicant/1.3/ISupplicant.hal b/wifi/supplicant/1.3/ISupplicant.hal
new file mode 100644
index 0000000..246ce1f
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicant.hal
@@ -0,0 +1,29 @@
+/*
+ * 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.supplicant@1.3;
+
+import @1.2::ISupplicant;
+
+/**
+ * Interface exposed by the supplicant HIDL service registered
+ * with the hardware service manager.
+ * This is the root level object for any the supplicant interactions.
+ * To use 1.3 features you must cast specific interfaces returned from the
+ * 1.2 HAL. For example V1_2::ISupplicant::addIface() adds V1_2::ISupplicantIface,
+ * which can be cast to V1_3::ISupplicantStaIface.
+ */
+interface ISupplicant extends @1.2::ISupplicant {};
diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal
new file mode 100644
index 0000000..b501a95
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal
@@ -0,0 +1,122 @@
+/*
+ * 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.supplicant@1.3;
+
+import @1.0::SupplicantStatus;
+import @1.2::ISupplicantStaIface;
+import ISupplicantStaNetwork;
+import ISupplicantStaIfaceCallback;
+import @1.0::MacAddress;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * interface (e.g wlan0) it controls.
+ */
+interface ISupplicantStaIface extends @1.2::ISupplicantStaIface {
+ /**
+ * Register for callbacks from this interface.
+ *
+ * These callbacks are invoked for events that are specific to this interface.
+ * Registration of multiple callback objects is supported. These objects must
+ * be automatically deleted when the corresponding client process is dead or
+ * if this interface is removed.
+ *
+ * @param callback An instance of the |ISupplicantStaIfaceCallback| HIDL
+ * interface object.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+ */
+ registerCallback_1_3(ISupplicantStaIfaceCallback callback)
+ generates (SupplicantStatus status);
+
+ /**
+ * Get Connection capabilities
+ *
+ * @return status Status of the operation, and connection capabilities.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ */
+ getConnectionCapabilities()
+ generates (SupplicantStatus status, ConnectionCapabilities capabilities);
+
+ /**
+ * Get wpa driver capabilities.
+ *
+ * @return status Status of the operation, and a bitmap of wpa driver features.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ */
+ getWpaDriverCapabilities() generates (SupplicantStatus status,
+ bitfield<WpaDriverCapabilitiesMask> driverCapabilitiesMask);
+
+ /**
+ * Set MBO cellular data status.
+ *
+ * @param available true means cellular data available, false otherwise.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |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);
+
+ /**
+ * Flush FILS HLP IEs
+ * Use this to flush all the HLP IEs in wpa_supplicant
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+ * |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+ */
+ filsHlpFlushRequest() generates (SupplicantStatus status);
+
+ /**
+ * Add FILS HLP IEs
+ * Use this to add a HLP IE to wpa_supplicant
+ *
+ * @param dst_mac MAC address of the destination
+ * @param pkt The contents of the HLP IE starting from ethertype
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+ * |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+ */
+ filsHlpAddRequest(MacAddress dst_mac, vec<uint8_t> pkt) generates (SupplicantStatus status);
+};
diff --git a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
new file mode 100644
index 0000000..6828dcd
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
@@ -0,0 +1,219 @@
+/*
+ * 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.supplicant@1.3;
+
+import @1.2::ISupplicantStaIfaceCallback;
+import @1.0::ISupplicantStaIfaceCallback.State;
+import @1.0::Bssid;
+import @1.0::SupplicantNetworkId;
+import @1.0::Ssid;
+
+/**
+ * Callback Interface exposed by the supplicant service
+ * for each station mode interface (ISupplicantStaIface).
+ *
+ * Clients need to host an instance of this HIDL interface object and
+ * pass a reference of the object to the supplicant via the
+ * corresponding |ISupplicantStaIface.registerCallback_1_3| method.
+ */
+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
+ * @param serializedEntry is serialized PMK cache entry, the content is
+ * 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);
+
+ /**
+ * Indicates an EAP authentication failure.
+ */
+ oneway onEapFailure_1_3(uint32_t errorCode);
+
+ /**
+ * Used to indicate a state change event on this particular iface. If this
+ * event is triggered by a particular network, the |SupplicantNetworkId|,
+ * |ssid|, |bssid| parameters must indicate the parameters of the network/AP
+ * which caused this state transition.
+ *
+ * @param newState New State of the interface. This must be one of the |State|
+ * values above.
+ * @param bssid BSSID of the corresponding AP which caused this state
+ * change event. This must be zero'ed if this event is not
+ * specific to a particular network.
+ * @param id ID of the corresponding network which caused this
+ * state change event. This must be invalid (UINT32_MAX) if this
+ * event is not specific to a particular network.
+ * @param ssid SSID of the corresponding network which caused this state
+ * change event. This must be empty if this event is not specific
+ * to a particular network.
+ * @param filsHlpSent If FILS HLP IEs were included in this association.
+ */
+ oneway onStateChanged_1_3(State newState, Bssid bssid, SupplicantNetworkId id, Ssid ssid,
+ bool filsHlpSent);
+};
diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
new file mode 100644
index 0000000..0566a21
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
@@ -0,0 +1,291 @@
+/*
+ * 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.supplicant@1.3;
+
+import @1.0::ISupplicantStaNetwork;
+import @1.0::SupplicantStatus;
+import @1.2::ISupplicantStaNetwork;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * configuration it controls.
+ */
+interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork {
+ /**
+ * Possible mask of values for Proto param.
+ */
+ enum ProtoMask : @1.0::ISupplicantStaNetwork.ProtoMask {
+ WAPI = 1 << 2,
+ };
+
+ /**
+ * Possible mask of values for KeyMgmt param.
+ */
+ enum KeyMgmtMask : @1.2::ISupplicantStaNetwork.KeyMgmtMask {
+ /*
+ * WAPI Psk
+ */
+ WAPI_PSK = 1 << 12,
+ /**
+ * WAPI Cert
+ */
+ WAPI_CERT = 1 << 13,
+ /**
+ * FILS shared key authentication with sha-256
+ */
+ FILS_SHA256 = 1 << 18,
+ /**
+ * FILS shared key authentication with sha-384
+ */
+ FILS_SHA384 = 1 << 19,
+ };
+
+ /**
+ * Possible mask of values for PairwiseCipher param.
+ */
+ enum PairwiseCipherMask : @1.2::ISupplicantStaNetwork.PairwiseCipherMask {
+ /**
+ * SMS4 Pairwise Cipher
+ */
+ SMS4 = 1 << 7,
+ };
+
+ /**
+ * Possible mask of values for GroupCipher param.
+ */
+ enum GroupCipherMask : @1.2::ISupplicantStaNetwork.GroupCipherMask {
+ /**
+ * SMS4 Group Cipher
+ */
+ SMS4 = 1 << 7,
+ };
+
+ /**
+ * Possible mask of values for AuthAlg param.
+ */
+ enum AuthAlgMask : @1.0::ISupplicantStaNetwork.AuthAlgMask {
+ SAE = 1 << 4,
+ };
+
+ /**
+ * Set OCSP (Online Certificate Status Protocol) type for this network.
+ *
+ * @param ocspType value to set.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setOcsp(OcspType ocspType) generates (SupplicantStatus status);
+
+ /**
+ * Get OCSP (Online Certificate Status Protocol) type for this network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ * @return ocspType ocsp type.
+ */
+ 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
+ * opaque for the framework and depends on the native implementation.
+ * @return status Status of the operation
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setPmkCache(vec<uint8_t> serializedEntry) generates (SupplicantStatus status);
+
+ /**
+ * Set auth alg mask for the network.
+ *
+ * @param authAlgMask value to set.
+ * Combination of |ProtoMask| values.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setAuthAlg_1_3(bitfield<AuthAlgMask> authAlgMask) generates (SupplicantStatus status);
+
+ /**
+ * Get the auth alg mask set for the network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ * @return authAlgMask Combination of |AuthAlgMask| values.
+ */
+ getAuthAlg_1_3() generates (SupplicantStatus status, bitfield<AuthAlgMask> authAlgMask);
+
+ /**
+ * Enable EAP ERP for this network.
+ *
+ * @param enable true to set, false otherwise.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setEapErp(bool enable) generates (SupplicantStatus status);
+};
diff --git a/wifi/supplicant/1.3/types.hal b/wifi/supplicant/1.3/types.hal
new file mode 100644
index 0000000..a4b2ff7
--- /dev/null
+++ b/wifi/supplicant/1.3/types.hal
@@ -0,0 +1,119 @@
+/*
+ * 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.supplicant@1.3;
+
+import @1.2::DppProgressCode;
+import @1.2::DppFailureCode;
+
+import android.hardware.wifi@1.0::WifiChannelWidthInMhz;
+
+/**
+ * OcspType: The type of OCSP request.
+ */
+enum OcspType : uint32_t {
+ NONE,
+ REQUEST_CERT_STATUS,
+ REQUIRE_CERT_STATUS,
+ REQUIRE_ALL_CERTS_STATUS,
+};
+
+/**
+ * Wifi Technologies
+ */
+enum WifiTechnology : uint32_t {
+ UNKNOWN = 0,
+ /**
+ * For 802.11a/b/g
+ */
+ LEGACY = 1,
+ /**
+ * For 802.11n
+ */
+ HT = 2,
+ /**
+ * For 802.11ac
+ */
+ VHT = 3,
+ /**
+ * For 802.11ax
+ */
+ HE = 4,
+};
+
+/**
+ * Connection Capabilities supported by current network and device
+ */
+struct ConnectionCapabilities {
+ /**
+ * Wifi Technology
+ */
+ WifiTechnology technology;
+ /**
+ * channel bandwidth
+ */
+ WifiChannelWidthInMhz channelBandwidth;
+ /**
+ * max number of Tx spatial streams
+ */
+ uint32_t maxNumberTxSpatialStreams;
+ /**
+ * max number of Rx spatial streams
+ */
+ uint32_t maxNumberRxSpatialStreams;
+};
+
+/**
+ * WPA Driver capability.
+ */
+enum WpaDriverCapabilitiesMask : uint32_t {
+ /**
+ * Multi Band Operation.
+ */
+ MBO = 1 << 0,
+ /**
+ * Optimized Connectivity Experience.
+ */
+ 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/1.3/default/OWNERS b/wifi/supplicant/1.3/vts/OWNERS
similarity index 100%
copy from wifi/1.3/default/OWNERS
copy to wifi/supplicant/1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.3/vts/functional/Android.bp b/wifi/supplicant/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..3dabe7c
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/Android.bp
@@ -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.
+//
+
+cc_library_static {
+ name: "VtsHalWifiSupplicantV1_3TargetTestUtil",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["supplicant_hidl_test_utils_1_3.cpp"],
+ export_include_dirs: [
+ ".",
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_1TargetTestUtil",
+ "VtsHalWifiSupplicantV1_2TargetTestUtil",
+ "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",
+ "libgmock",
+ "libwifi-system",
+ "libwifi-system-iface",
+ ],
+}
+
+cc_test {
+ name: "VtsHalWifiSupplicantV1_3TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "VtsHalWifiSupplicantV1_3TargetTest.cpp",
+ "supplicant_sta_iface_hidl_test.cpp",
+ "supplicant_sta_network_hidl_test.cpp",
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_1TargetTestUtil",
+ "VtsHalWifiSupplicantV1_2TargetTestUtil",
+ "VtsHalWifiSupplicantV1_3TargetTestUtil",
+ "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",
+ "libwifi-system",
+ "libwifi-system-iface",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp b/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp
new file mode 100644
index 0000000..9dbeee1
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.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 "supplicant_hidl_test_utils.h"
+
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp
new file mode 100644
index 0000000..7ea5462
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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 <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_3.h"
+
+using ::android::sp;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
+
+sp<ISupplicantStaIface> getSupplicantStaIface_1_3(
+ const android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicant>&
+ supplicant) {
+ return ISupplicantStaIface::castFrom(getSupplicantStaIface(supplicant));
+}
+
+sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_3(
+ const android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicant>&
+ supplicant) {
+ return ISupplicantStaNetwork::castFrom(
+ createSupplicantStaNetwork(supplicant));
+}
+
+sp<ISupplicant> getSupplicant_1_3(const std::string& supplicant_instance_name,
+ bool isP2pOn) {
+ return ISupplicant::castFrom(
+ getSupplicant(supplicant_instance_name, isP2pOn));
+}
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h
new file mode 100644
index 0000000..f8dca13
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h
@@ -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.
+ */
+
+#ifndef SUPPLICANT_HIDL_TEST_UTILS_1_3_H
+#define SUPPLICANT_HIDL_TEST_UTILS_1_3_H
+
+#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
+
+android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface>
+getSupplicantStaIface_1_3(
+ const android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicant>&
+ supplicant);
+android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork>
+createSupplicantStaNetwork_1_3(
+ const android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicant>&
+ supplicant);
+android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicant>
+getSupplicant_1_3(const std::string& supplicant_instance_name, bool isP2pOn);
+#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_3_H */
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
new file mode 100644
index 0000000..f7019d2
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -0,0 +1,600 @@
+/*
+ * 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 <android/hardware/wifi/1.1/IWifi.h>
+#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.2/types.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.3/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <hidl/Status.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_3.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+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::ISupplicant;
+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::TestWithParam<std::tuple<std::string, std::string>> {
+ public:
+ virtual void SetUp() override {
+ wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+ supplicant_v1_3_instance_name_ = std::get<1>(GetParam());
+ isP2pOn_ =
+ testing::deviceSupportsFeature("android.hardware.wifi.direct");
+
+ startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
+ supplicant_v1_3_instance_name_);
+ supplicant_ =
+ getSupplicant_1_3(supplicant_v1_3_instance_name_, isP2pOn_);
+ EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ sta_iface_ = getSupplicantStaIface_1_3(supplicant_);
+ ASSERT_NE(sta_iface_.get(), nullptr);
+ }
+
+ virtual void TearDown() override {
+ stopSupplicant(wifi_v1_0_instance_name_);
+ }
+
+ 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_;
+ sp<ISupplicant> supplicant_;
+ bool isP2pOn_ = false;
+ std::string wifi_v1_0_instance_name_;
+ std::string supplicant_v1_3_instance_name_;
+
+ 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 {
+ Return<void> onNetworkAdded(uint32_t /* id */) override { return Void(); }
+ Return<void> onNetworkRemoved(uint32_t /* id */) override { return Void(); }
+ Return<void> onStateChanged(
+ ISupplicantStaIfaceCallback::State /* newState */,
+ const hidl_array<uint8_t, 6>& /*bssid */, uint32_t /* id */,
+ const hidl_vec<uint8_t>& /* ssid */) override {
+ return Void();
+ }
+ Return<void> onAnqpQueryDone(
+ const hidl_array<uint8_t, 6>& /* bssid */,
+ const ISupplicantStaIfaceCallback::AnqpData& /* data */,
+ const ISupplicantStaIfaceCallback::Hs20AnqpData& /* hs20Data */)
+ override {
+ return Void();
+ }
+ virtual Return<void> onHs20IconQueryDone(
+ const hidl_array<uint8_t, 6>& /* bssid */,
+ const hidl_string& /* fileName */,
+ const hidl_vec<uint8_t>& /* data */) override {
+ return Void();
+ }
+ virtual Return<void> onHs20SubscriptionRemediation(
+ const hidl_array<uint8_t, 6>& /* bssid */,
+ ISupplicantStaIfaceCallback::OsuMethod /* osuMethod */,
+ const hidl_string& /* url*/) override {
+ return Void();
+ }
+ Return<void> onHs20DeauthImminentNotice(
+ const hidl_array<uint8_t, 6>& /* bssid */, uint32_t /* reasonCode */,
+ uint32_t /* reAuthDelayInSec */,
+ const hidl_string& /* url */) override {
+ return Void();
+ }
+ Return<void> onDisconnected(const hidl_array<uint8_t, 6>& /* bssid */,
+ bool /* locallyGenerated */,
+ ISupplicantStaIfaceCallback::ReasonCode
+ /* reasonCode */) override {
+ return Void();
+ }
+ Return<void> onAssociationRejected(
+ const hidl_array<uint8_t, 6>& /* bssid */,
+ ISupplicantStaIfaceCallback::StatusCode /* statusCode */,
+ bool /*timedOut */) override {
+ return Void();
+ }
+ Return<void> onAuthenticationTimeout(
+ const hidl_array<uint8_t, 6>& /* bssid */) override {
+ return Void();
+ }
+ Return<void> onBssidChanged(
+ ISupplicantStaIfaceCallback::BssidChangeReason /* reason */,
+ const hidl_array<uint8_t, 6>& /* bssid */) override {
+ return Void();
+ }
+ Return<void> onEapFailure() override { return Void(); }
+ Return<void> onEapFailure_1_1(
+ ISupplicantStaIfaceCallback::EapErrorCode /* eapErrorCode */) override {
+ return Void();
+ }
+ Return<void> onEapFailure_1_3(uint32_t /* eapErrorCode */) override {
+ return Void();
+ }
+ Return<void> onWpsEventSuccess() override { return Void(); }
+ Return<void> onWpsEventFail(
+ const hidl_array<uint8_t, 6>& /* bssid */,
+ ISupplicantStaIfaceCallback::WpsConfigError /* configError */,
+ ISupplicantStaIfaceCallback::WpsErrorIndication /* errorInd */)
+ override {
+ return Void();
+ }
+ Return<void> onWpsEventPbcOverlap() override { return Void(); }
+ Return<void> onExtRadioWorkStart(uint32_t /* id */) override {
+ return Void();
+ }
+ Return<void> onExtRadioWorkTimeout(uint32_t /* id*/) override {
+ return Void();
+ }
+ Return<void> onDppSuccessConfigReceived(
+ const hidl_vec<uint8_t>& /* ssid */, const hidl_string& /* password */,
+ const hidl_array<uint8_t, 32>& /* psk */,
+ DppAkm /* securityAkm */) override {
+ return Void();
+ }
+ Return<void> onDppSuccessConfigSent() override { return Void(); }
+ Return<void> onDppProgress(DppProgressCode /* code */) override {
+ return Void();
+ }
+ 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();
+ }
+ Return<void> onStateChanged_1_3(
+ ISupplicantStaIfaceCallback::State /* newState */,
+ const hidl_array<uint8_t, 6>& /*bssid */, uint32_t /* id */,
+ const hidl_vec<uint8_t>& /* ssid */, bool /* filsHlpSent */) override {
+ return Void();
+ }
+};
+
+class IfacePmkCacheCallback : public IfaceCallback {
+ SupplicantStaIfaceHidlTest& parent_;
+ Return<void> onPmkCacheAdded(
+ int64_t expirationTimeInSec,
+ const hidl_vec<uint8_t>& serializedEntry) override {
+ parent_.pmkCacheExpirationTimeInSec = expirationTimeInSec;
+ parent_.serializedPmkCacheEntry = serializedEntry;
+ return Void();
+ }
+
+ public:
+ IfacePmkCacheCallback(SupplicantStaIfaceHidlTest& parent)
+ : 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
+ */
+TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback_1_3) {
+ sta_iface_->registerCallback_1_3(
+ new IfaceCallback(), [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * getConnectionCapabilities
+ */
+TEST_P(SupplicantStaIfaceHidlTest, GetConnectionCapabilities) {
+ sta_iface_->getConnectionCapabilities(
+ [&](const SupplicantStatus& status,
+ ConnectionCapabilities /* capabilities */) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * GetWpaDriverCapabilities
+ */
+TEST_P(SupplicantStaIfaceHidlTest, GetWpaDriverCapabilities) {
+ sta_iface_->getWpaDriverCapabilities(
+ [&](const SupplicantStatus& status, uint32_t) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * SetMboCellularDataStatus
+ */
+TEST_P(SupplicantStaIfaceHidlTest, SetMboCellularDataStatus) {
+ uint32_t driverCapMask = 0;
+
+ // Get MBO support from the device.
+ sta_iface_->getWpaDriverCapabilities(
+ [&](const SupplicantStatus& status, uint32_t driverCapMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+
+ driverCapMask = driverCapMaskInternal;
+ });
+
+ SupplicantStatusCode expectedStatusCode =
+ (driverCapMask & WpaDriverCapabilitiesMask::MBO)
+ ? SupplicantStatusCode::SUCCESS
+ : SupplicantStatusCode::FAILURE_UNKNOWN;
+
+ sta_iface_->setMboCellularDataStatus(
+ true, [expectedStatusCode](const SupplicantStatus& status) {
+ EXPECT_EQ(expectedStatusCode, status.code);
+ });
+}
+
+/*
+ * GetKeyMgmtCapabilities_1_3
+ */
+TEST_P(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_P(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_P(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);
+ });
+}
+
+/*
+ * FilsHlpAddRequest
+ */
+TEST_P(SupplicantStaIfaceHidlTest, FilsHlpAddRequest) {
+ uint32_t keyMgmtMask = 0;
+ uint8_t destMacAddr[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
+ std::vector<uint8_t> pktBuffer = {
+ 0x08, 0x00, 0x45, 0x10, 0x01, 0x3a, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11,
+ 0x39, 0xa4, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x44,
+ 0x00, 0x43, 0x01, 0x26, 0x77, 0x1e, 0x01, 0x01, 0x06, 0x00, 0x81, 0xf9,
+ 0xf7, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0xc3,
+ 0x65, 0xca, 0x34, 0x63, 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,
+ 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, 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, 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,
+ 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x01, 0x3d,
+ 0x07, 0x01, 0x86, 0xc3, 0x65, 0xca, 0x34, 0x63, 0x39, 0x02, 0x05, 0xdc,
+ 0x3c, 0x0e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2d, 0x64, 0x68,
+ 0x63, 0x70, 0x2d, 0x52, 0x37, 0x0a, 0x01, 0x03, 0x06, 0x0f, 0x1a, 0x1c,
+ 0x33, 0x3a, 0x3b, 0x2b, 0xff, 0x00};
+
+ sta_iface_->getKeyMgmtCapabilities_1_3(
+ [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ keyMgmtMask = keyMgmtMaskInternal;
+ });
+
+ SupplicantStatusCode expectedStatusCode =
+ (keyMgmtMask & (ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256 |
+ ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384))
+ ? SupplicantStatusCode::SUCCESS
+ : SupplicantStatusCode::FAILURE_UNKNOWN;
+
+ sta_iface_->filsHlpAddRequest(
+ destMacAddr, pktBuffer,
+ [expectedStatusCode](const SupplicantStatus& status) {
+ EXPECT_EQ(expectedStatusCode, status.code);
+ });
+}
+
+/*
+ * FilsHlpFlushRequest
+ */
+TEST_P(SupplicantStaIfaceHidlTest, FilsHlpFlushRequest) {
+ uint32_t keyMgmtMask = 0;
+ sta_iface_->getKeyMgmtCapabilities_1_3(
+ [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ keyMgmtMask = keyMgmtMaskInternal;
+ });
+
+ SupplicantStatusCode expectedStatusCode =
+ (keyMgmtMask & (ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256 |
+ ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384))
+ ? SupplicantStatusCode::SUCCESS
+ : SupplicantStatusCode::FAILURE_UNKNOWN;
+
+ sta_iface_->filsHlpFlushRequest(
+ [expectedStatusCode](const SupplicantStatus& status) {
+ EXPECT_EQ(expectedStatusCode, status.code);
+ });
+}
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, SupplicantStaIfaceHidlTest,
+ testing::Combine(
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::V1_0::IWifi::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::supplicant::V1_3::ISupplicant::
+ descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);
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
new file mode 100644
index 0000000..13f3366
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -0,0 +1,318 @@
+/*
+ * 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 <VtsCoreUtil.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.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::ISupplicant;
+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 {
+constexpr OcspType kTestOcspType = OcspType::REQUEST_CERT_STATUS;
+constexpr OcspType kTestInvalidOcspType = (OcspType)-1;
+} // namespace
+
+class SupplicantStaNetworkHidlTest
+ : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+ public:
+ virtual void SetUp() override {
+ wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+ supplicant_v1_3_instance_name_ = std::get<1>(GetParam());
+ isP2pOn_ =
+ testing::deviceSupportsFeature("android.hardware.wifi.direct");
+ startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
+ supplicant_v1_3_instance_name_);
+ supplicant_ =
+ getSupplicant_1_3(supplicant_v1_3_instance_name_, isP2pOn_);
+ EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+ sta_network_ = createSupplicantStaNetwork_1_3(supplicant_);
+ ASSERT_NE(sta_network_.get(), nullptr);
+ }
+
+ virtual void TearDown() override {
+ stopSupplicant(wifi_v1_0_instance_name_);
+ }
+
+ protected:
+ sp<ISupplicantStaIface> sta_iface_;
+ // ISupplicantStaNetwork object used for all tests in this fixture.
+ sp<ISupplicantStaNetwork> sta_network_;
+ sp<ISupplicant> supplicant_;
+ bool isP2pOn_ = false;
+ std::string wifi_v1_0_instance_name_;
+ std::string supplicant_v1_3_instance_name_;
+
+ 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;
+ }
+};
+
+/*
+ * SetGetOcsp
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetGetOcsp) {
+ OcspType testOcspType = kTestOcspType;
+
+ sta_network_->setOcsp(testOcspType, [](const SupplicantStatus &status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ sta_network_->setOcsp(
+ kTestInvalidOcspType, [](const SupplicantStatus &status) {
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_ARGS_INVALID, status.code);
+ });
+
+ sta_network_->getOcsp(
+ [testOcspType](const SupplicantStatus &status, OcspType ocspType) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(testOcspType, ocspType);
+ });
+}
+
+/*
+ * SetPmkCacheEntry
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetPmkCache) {
+ uint8_t bytes[128] = {0};
+ std::vector<uint8_t> serializedEntry(bytes, bytes + sizeof(bytes));
+
+ sta_network_->setPmkCache(
+ serializedEntry, [](const SupplicantStatus &status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * SetGetKeyMgmt_1_3, check new WAPI proto support
+ */
+TEST_P(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_P(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_P(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_P(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_P(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);
+ });
+ }
+}
+/*
+ * SetEapErp
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetEapErp) {
+ uint32_t keyMgmtMask = 0;
+ sta_iface_->getKeyMgmtCapabilities_1_3(
+ [&](const SupplicantStatus &status, uint32_t keyMgmtMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ keyMgmtMask = keyMgmtMaskInternal;
+ });
+
+ SupplicantStatusCode expectedStatusCode =
+ (keyMgmtMask & (ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256 |
+ ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384))
+ ? SupplicantStatusCode::SUCCESS
+ : SupplicantStatusCode::FAILURE_UNKNOWN;
+
+ sta_network_->setEapErp(
+ true, [expectedStatusCode](const SupplicantStatus &status) {
+ EXPECT_EQ(expectedStatusCode, status.code);
+ });
+}
+INSTANTIATE_TEST_CASE_P(
+ PerInstance, SupplicantStaNetworkHidlTest,
+ testing::Combine(
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::V1_0::IWifi::descriptor)),
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ android::hardware::wifi::supplicant::V1_3::ISupplicant::
+ descriptor))),
+ android::hardware::PrintInstanceTupleNameToString<>);