Merge "VTS - avoid same MAC for AP and STA"
diff --git a/automotive/audiocontrol/aidl/Android.bp b/automotive/audiocontrol/aidl/Android.bp
new file mode 100644
index 0000000..f8240b1
--- /dev/null
+++ b/automotive/audiocontrol/aidl/Android.bp
@@ -0,0 +1,13 @@
+// This is the expected build file, but it may not be right in all cases
+
+aidl_interface {
+ name: "android.hardware.automotive.audiocontrol",
+ vendor_available: true,
+ srcs: ["android/hardware/automotive/audiocontrol/*.aidl"],
+ stability: "vintf",
+ backend: {
+ java: {
+ sdk_version: "module_current",
+ },
+ },
+}
diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl
new file mode 100644
index 0000000..3dc393a
--- /dev/null
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl
@@ -0,0 +1,29 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.audiocontrol;
+@Backing(type="int") @VintfStability
+enum AudioFocusChange {
+ NONE = 0,
+ GAIN = 1,
+ GAIN_TRANSIENT = 2,
+ GAIN_TRANSIENT_MAY_DUCK = 3,
+ GAIN_TRANSIENT_EXCLUSIVE = 4,
+ LOSS = -1,
+ LOSS_TRANSIENT = -2,
+ LOSS_TRANSIENT_CAN_DUCK = -3,
+}
diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IAudioControl.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IAudioControl.aidl
new file mode 100644
index 0000000..6916846
--- /dev/null
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IAudioControl.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.audiocontrol;
+@VintfStability
+interface IAudioControl {
+ oneway void onAudioFocusChange(in String usage, in int zoneId, in android.hardware.automotive.audiocontrol.AudioFocusChange focusChange);
+ oneway void registerFocusListener(in android.hardware.automotive.audiocontrol.IFocusListener listener);
+ oneway void setBalanceTowardRight(in float value);
+ oneway void setFadeTowardFront(in float value);
+}
diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IFocusListener.aidl b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IFocusListener.aidl
new file mode 100644
index 0000000..f00f042
--- /dev/null
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/current/android/hardware/automotive/audiocontrol/IFocusListener.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.audiocontrol;
+@VintfStability
+interface IFocusListener {
+ oneway void abandonAudioFocus(in String usage, in int zoneId);
+ oneway void requestAudioFocus(in String usage, in int zoneId, in android.hardware.automotive.audiocontrol.AudioFocusChange focusGain);
+}
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl
new file mode 100644
index 0000000..fc35fa9
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+/**
+ * Changes in audio focus that can be experienced
+ */
+@VintfStability
+@Backing(type="int")
+enum AudioFocusChange {
+ NONE = 0,
+ GAIN = 1,
+ GAIN_TRANSIENT = 2,
+ GAIN_TRANSIENT_MAY_DUCK = 3,
+ GAIN_TRANSIENT_EXCLUSIVE = 4,
+ LOSS = -1, // -1 * GAIN,
+ LOSS_TRANSIENT = -2, // -1 * GAIN_TRANSIENT,
+ LOSS_TRANSIENT_CAN_DUCK = -3, // -1 * GAIN_TRANSIENT_MAY_DUCK,
+}
\ No newline at end of file
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl
new file mode 100644
index 0000000..0641691
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.audiocontrol;
+
+import android.hardware.automotive.audiocontrol.AudioFocusChange;
+import android.hardware.automotive.audiocontrol.IFocusListener;
+
+/**
+ * Interacts with the car's audio subsystem to manage audio sources and volumes
+ */
+@VintfStability
+interface IAudioControl {
+ /**
+ * 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}. See
+ * {@code audioUsage} in audio_policy_configuration.xsd for the list of allowed values.
+ * @param zoneId The identifier for the audio zone that the HAL is playing the stream in
+ * @param focusChange the AudioFocusChange that has occurred.
+ */
+ oneway void onAudioFocusChange(in String usage, in int zoneId, in AudioFocusChange focusChange);
+
+ /**
+ * 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.
+ */
+ oneway void registerFocusListener(in IFocusListener listener);
+
+ /**
+ * 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 void setBalanceTowardRight(in 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 void setFadeTowardFront(in float value);
+}
\ No newline at end of file
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IFocusListener.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IFocusListener.aidl
new file mode 100644
index 0000000..b79295a
--- /dev/null
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IFocusListener.aidl
@@ -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.automotive.audiocontrol;
+
+import android.hardware.automotive.audiocontrol.AudioFocusChange;
+
+/**
+ * Callback interface for audio focus listener.
+ *
+ * For typical configuration, the listener the car audio service.
+ */
+@VintfStability
+interface IFocusListener {
+ /**
+ * 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}.
+ * See {@code audioUsage} in audio_policy_configuration.xsd for the list of allowed values.
+ * @param zoneId The identifier for the audio zone that the HAL abandoning focus
+ */
+ oneway void abandonAudioFocus(in String usage, in int zoneId);
+
+ /**
+ * 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}. See
+ * {@code audioUsage} in audio_policy_configuration.xsd for the list of allowed values.
+ * @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 void requestAudioFocus(in String usage, in int zoneId, in AudioFocusChange focusGain);
+}
\ No newline at end of file
diff --git a/automotive/audiocontrol/aidl/default/Android.bp b/automotive/audiocontrol/aidl/default/Android.bp
new file mode 100644
index 0000000..faf7ad2
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/Android.bp
@@ -0,0 +1,36 @@
+// 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-service.example",
+ relative_install_path: "hw",
+ init_rc: ["audiocontrol-default.rc"],
+ vintf_fragments: ["audiocontrol-default.xml"],
+ vendor: true,
+ generated_headers: ["audio_policy_configuration_V7_0"],
+ generated_sources: ["audio_policy_configuration_V7_0"],
+ header_libs: ["libxsdc-utils"],
+ shared_libs: [
+ "android.hardware.automotive.audiocontrol-ndk_platform",
+ "libbase",
+ "libbinder_ndk",
+ "liblog",
+ "libcutils",
+ "libxml2",
+ ],
+ srcs: [
+ "AudioControl.cpp",
+ "main.cpp",
+ ],
+}
diff --git a/automotive/audiocontrol/aidl/default/AudioControl.cpp b/automotive/audiocontrol/aidl/default/AudioControl.cpp
new file mode 100644
index 0000000..b637310
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/AudioControl.cpp
@@ -0,0 +1,224 @@
+/*
+ * 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 "AudioControl.h"
+
+#include <aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.h>
+#include <aidl/android/hardware/automotive/audiocontrol/IFocusListener.h>
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+#include <audio_policy_configuration_V7_0.h>
+#include <private/android_filesystem_config.h>
+
+#include <stdio.h>
+
+namespace aidl::android::hardware::automotive::audiocontrol {
+
+using ::android::base::EqualsIgnoreCase;
+using ::android::base::ParseInt;
+using ::std::string;
+
+namespace xsd {
+using namespace audio::policy::configuration::V7_0;
+}
+
+namespace {
+const float kLowerBound = -1.0f;
+const float kUpperBound = 1.0f;
+bool checkCallerHasWritePermissions(int fd) {
+ // Double check that's only called by root - it should be be blocked at debug() level,
+ // but it doesn't hurt to make sure...
+ if (AIBinder_getCallingUid() != AID_ROOT) {
+ dprintf(fd, "Must be root\n");
+ return false;
+ }
+ return true;
+}
+
+bool isValidValue(float value) {
+ return (value >= kLowerBound) && (value <= kUpperBound);
+}
+
+bool safelyParseInt(string s, int* out) {
+ if (!ParseInt(s, out)) {
+ return false;
+ }
+ return true;
+}
+} // namespace
+
+ndk::ScopedAStatus AudioControl::registerFocusListener(
+ const shared_ptr<IFocusListener>& in_listener) {
+ LOG(DEBUG) << "registering focus listener";
+
+ if (in_listener.get()) {
+ std::atomic_store(&mFocusListener, in_listener);
+ } else {
+ LOG(ERROR) << "Unexpected nullptr for listener resulting in no-op.";
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AudioControl::setBalanceTowardRight(float value) {
+ if (isValidValue(value)) {
+ // Just log in this default mock implementation
+ LOG(INFO) << "Balance set to " << value;
+ } else {
+ LOG(ERROR) << "Balance value out of range -1 to 1 at " << value;
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AudioControl::setFadeTowardFront(float value) {
+ if (isValidValue(value)) {
+ // Just log in this default mock implementation
+ LOG(INFO) << "Fader set to " << value;
+ } else {
+ LOG(ERROR) << "Fader value out of range -1 to 1 at " << value;
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AudioControl::onAudioFocusChange(const string& in_usage, int32_t in_zoneId,
+ AudioFocusChange in_focusChange) {
+ LOG(INFO) << "Focus changed: " << toString(in_focusChange).c_str() << " for usage "
+ << in_usage.c_str() << " in zone " << in_zoneId;
+ return ndk::ScopedAStatus::ok();
+}
+
+binder_status_t AudioControl::dump(int fd, const char** args, uint32_t numArgs) {
+ if (numArgs == 0) {
+ return dumpsys(fd);
+ }
+
+ string option = string(args[0]);
+ if (EqualsIgnoreCase(option, "--help")) {
+ return cmdHelp(fd);
+ } else if (EqualsIgnoreCase(option, "--request")) {
+ return cmdRequestFocus(fd, args, numArgs);
+ } else if (EqualsIgnoreCase(option, "--abandon")) {
+ return cmdAbandonFocus(fd, args, numArgs);
+ } else {
+ dprintf(fd, "Invalid option: %s\n", option.c_str());
+ return STATUS_BAD_VALUE;
+ }
+}
+
+binder_status_t AudioControl::dumpsys(int fd) {
+ if (mFocusListener == nullptr) {
+ dprintf(fd, "No focus listener registered\n");
+ } else {
+ dprintf(fd, "Focus listener registered\n");
+ }
+ return STATUS_OK;
+}
+
+binder_status_t AudioControl::cmdHelp(int fd) const {
+ dprintf(fd, "Usage: \n\n");
+ dprintf(fd, "[no args]: dumps focus listener status\n");
+ dprintf(fd, "--help: shows this help\n");
+ dprintf(fd,
+ "--request <USAGE> <ZONE_ID> <FOCUS_GAIN>: requests audio focus for specified "
+ "usage (string), audio zone ID (int), and focus gain type (int)\n");
+ dprintf(fd,
+ "--abandon <USAGE> <ZONE_ID>: abandons audio focus for specified usage (string) and "
+ "audio zone ID (int)\n");
+ dprintf(fd, "See audio_policy_configuration.xsd for valid AudioUsage values.\n");
+ return STATUS_OK;
+}
+
+binder_status_t AudioControl::cmdRequestFocus(int fd, const char** args, uint32_t numArgs) {
+ if (!checkCallerHasWritePermissions(fd)) {
+ return STATUS_PERMISSION_DENIED;
+ }
+ if (numArgs != 4) {
+ dprintf(fd,
+ "Invalid number of arguments: please provide --request <USAGE> <ZONE_ID> "
+ "<FOCUS_GAIN>\n");
+ return STATUS_BAD_VALUE;
+ }
+
+ string usage = string(args[1]);
+ if (xsd::stringToAudioUsage(usage) == xsd::AudioUsage::UNKNOWN) {
+ dprintf(fd,
+ "Unknown usage provided: %s. Please see audio_policy_configuration.xsd V7_0 "
+ "for supported values\n",
+ usage.c_str());
+ return STATUS_BAD_VALUE;
+ }
+
+ int zoneId;
+ if (!safelyParseInt(string(args[2]), &zoneId)) {
+ dprintf(fd, "Non-integer zoneId provided with request: %s\n", string(args[2]).c_str());
+ return STATUS_BAD_VALUE;
+ }
+
+ int focusGainValue;
+ if (!safelyParseInt(string(args[3]), &focusGainValue)) {
+ dprintf(fd, "Non-integer focusGain provided with request: %s\n", string(args[3]).c_str());
+ return STATUS_BAD_VALUE;
+ }
+ AudioFocusChange focusGain = AudioFocusChange(focusGainValue);
+
+ if (mFocusListener == nullptr) {
+ dprintf(fd, "Unable to request focus - no focus listener registered\n");
+ return STATUS_BAD_VALUE;
+ }
+
+ mFocusListener->requestAudioFocus(usage, zoneId, focusGain);
+ dprintf(fd, "Requested focus for usage %s, zoneId %d, and focusGain %d\n", usage.c_str(),
+ zoneId, focusGain);
+ return STATUS_OK;
+}
+
+binder_status_t AudioControl::cmdAbandonFocus(int fd, const char** args, uint32_t numArgs) {
+ if (!checkCallerHasWritePermissions(fd)) {
+ return STATUS_PERMISSION_DENIED;
+ }
+ if (numArgs != 3) {
+ dprintf(fd, "Invalid number of arguments: please provide --abandon <USAGE> <ZONE_ID>\n");
+ return STATUS_BAD_VALUE;
+ }
+
+ string usage = string(args[1]);
+ if (xsd::stringToAudioUsage(usage) == xsd::AudioUsage::UNKNOWN) {
+ dprintf(fd,
+ "Unknown usage provided: %s. Please see audio_policy_configuration.xsd V7_0 "
+ "for supported values\n",
+ usage.c_str());
+ return STATUS_BAD_VALUE;
+ }
+
+ int zoneId;
+ if (!safelyParseInt(string(args[2]), &zoneId)) {
+ dprintf(fd, "Non-integer zoneId provided with abandon: %s\n", string(args[2]).c_str());
+ return STATUS_BAD_VALUE;
+ }
+
+ if (mFocusListener == nullptr) {
+ dprintf(fd, "Unable to abandon focus - no focus listener registered\n");
+ return STATUS_BAD_VALUE;
+ }
+
+ mFocusListener->abandonAudioFocus(usage, zoneId);
+ dprintf(fd, "Abandoned focus for usage %s and zoneId %d\n", usage.c_str(), zoneId);
+ return STATUS_OK;
+}
+
+} // namespace aidl::android::hardware::automotive::audiocontrol
diff --git a/automotive/audiocontrol/aidl/default/AudioControl.h b/automotive/audiocontrol/aidl/default/AudioControl.h
new file mode 100644
index 0000000..a77da3e
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/AudioControl.h
@@ -0,0 +1,51 @@
+/*
+ * 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_AUDIOCONTROL_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_AUDIOCONTROL_H
+
+#include <aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.h>
+#include <aidl/android/hardware/automotive/audiocontrol/BnAudioControl.h>
+
+namespace aidl::android::hardware::automotive::audiocontrol {
+
+using ::std::shared_ptr;
+
+class AudioControl : public BnAudioControl {
+ public:
+ ndk::ScopedAStatus onAudioFocusChange(const std::string& in_usage, int32_t in_zoneId,
+ AudioFocusChange in_focusChange) override;
+ ndk::ScopedAStatus registerFocusListener(
+ const shared_ptr<IFocusListener>& in_listener) override;
+ ndk::ScopedAStatus setBalanceTowardRight(float in_value) override;
+ ndk::ScopedAStatus setFadeTowardFront(float in_value) override;
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+ private:
+ // This focus listener will only be used by this HAL instance to communicate with
+ // a single instance of CarAudioService. As such, it doesn't have explicit serialization.
+ // If a different AudioControl implementation were to have multiple threads leveraging this
+ // listener, then it should also include mutexes or make the listener atomic.
+ shared_ptr<IFocusListener> mFocusListener;
+
+ binder_status_t cmdHelp(int fd) const;
+ binder_status_t cmdRequestFocus(int fd, const char** args, uint32_t numArgs);
+ binder_status_t cmdAbandonFocus(int fd, const char** args, uint32_t numArgs);
+ binder_status_t dumpsys(int fd);
+};
+
+} // namespace aidl::android::hardware::automotive::audiocontrol
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_AUDIOCONTROL_H
diff --git a/automotive/audiocontrol/aidl/default/audiocontrol-default.rc b/automotive/audiocontrol/aidl/default/audiocontrol-default.rc
new file mode 100644
index 0000000..88d180d
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.rc
@@ -0,0 +1,4 @@
+service vendor.audiocontrol-default /vendor/bin/hw/android.hardware.automotive.audiocontrol-service.example
+ class hal
+ user audioserver
+ group system
diff --git a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
new file mode 100644
index 0000000..f95d05f
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.automotive.audiocontrol</name>
+ <fqname>IAudioControl/default</fqname>
+ </hal>
+</manifest>
diff --git a/automotive/audiocontrol/aidl/default/main.cpp b/automotive/audiocontrol/aidl/default/main.cpp
new file mode 100644
index 0000000..996665f
--- /dev/null
+++ b/automotive/audiocontrol/aidl/default/main.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "AudioControl.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::automotive::audiocontrol::AudioControl;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<AudioControl> audioControl = ndk::SharedRefBase::make<AudioControl>();
+
+ const std::string instance = std::string() + AudioControl::descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(audioControl->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/automotive/audiocontrol/aidl/vts/Android.bp b/automotive/audiocontrol/aidl/vts/Android.bp
new file mode 100644
index 0000000..3d81e00
--- /dev/null
+++ b/automotive/audiocontrol/aidl/vts/Android.bp
@@ -0,0 +1,38 @@
+// 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: "VtsAidlHalAudioControlTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ generated_headers: ["audio_policy_configuration_V7_0"],
+ generated_sources: ["audio_policy_configuration_V7_0"],
+ header_libs: ["libxsdc-utils"],
+ srcs: ["VtsHalAudioControlTargetTest.cpp"],
+ shared_libs: [
+ "libbinder",
+ "libbase",
+ "libxml2",
+ ],
+ static_libs: [
+ "android.hardware.automotive.audiocontrol-cpp",
+ "libgmock",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp b/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp
new file mode 100644
index 0000000..c734e29
--- /dev/null
+++ b/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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 "VtsAidlHalAudioControlTest"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <gmock/gmock.h>
+
+#include <android/hardware/automotive/audiocontrol/BnFocusListener.h>
+#include <android/hardware/automotive/audiocontrol/IAudioControl.h>
+#include <android/log.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+using android::ProcessState;
+using android::sp;
+using android::String16;
+using android::binder::Status;
+using android::hardware::automotive::audiocontrol::AudioFocusChange;
+using android::hardware::automotive::audiocontrol::BnFocusListener;
+using android::hardware::automotive::audiocontrol::IAudioControl;
+
+#include "audio_policy_configuration_V7_0.h"
+
+namespace xsd {
+using namespace audio::policy::configuration::V7_0;
+}
+
+class AudioControlAidl : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ audioControl = android::waitForDeclaredService<IAudioControl>(String16(GetParam().c_str()));
+ ASSERT_NE(audioControl, nullptr);
+ }
+
+ sp<IAudioControl> audioControl;
+ int32_t capabilities;
+};
+
+TEST_P(AudioControlAidl, OnSetFadeTowardsFront) {
+ ALOGI("Fader exercise test (silent)");
+
+ // Set the fader all the way to the back
+ ASSERT_TRUE(audioControl->setFadeTowardFront(-1.0f).isOk());
+
+ // Set the fader all the way to the front
+ ASSERT_TRUE(audioControl->setFadeTowardFront(1.0f).isOk());
+
+ // Set the fader part way toward the back
+ ASSERT_TRUE(audioControl->setFadeTowardFront(-0.333f).isOk());
+
+ // Set the fader to a out of bounds value (driver should clamp)
+ ASSERT_TRUE(audioControl->setFadeTowardFront(99999.9f).isOk());
+
+ // Set the fader to a negative out of bounds value (driver should clamp)
+ ASSERT_TRUE(audioControl->setFadeTowardFront(-99999.9f).isOk());
+
+ // Set the fader back to the middle
+ ASSERT_TRUE(audioControl->setFadeTowardFront(0.0f).isOk());
+}
+
+TEST_P(AudioControlAidl, OnSetBalanceTowardsRight) {
+ ALOGI("Balance exercise test (silent)");
+
+ // Set the balance all the way to the left
+ ASSERT_TRUE(audioControl->setBalanceTowardRight(-1.0f).isOk());
+
+ // Set the balance all the way to the right
+ ASSERT_TRUE(audioControl->setBalanceTowardRight(1.0f).isOk());
+
+ // Set the balance part way toward the left
+ ASSERT_TRUE(audioControl->setBalanceTowardRight(-0.333f).isOk());
+
+ // Set the balance to a out of bounds value (driver should clamp)
+ ASSERT_TRUE(audioControl->setBalanceTowardRight(99999.9f).isOk());
+
+ // Set the balance to a negative out of bounds value (driver should clamp)
+ ASSERT_TRUE(audioControl->setBalanceTowardRight(-99999.9f).isOk());
+
+ // Set the balance back to the middle
+ ASSERT_TRUE(audioControl->setBalanceTowardRight(0.0f).isOk());
+
+ // Set the balance back to the middle
+ audioControl->setBalanceTowardRight(0.0f).isOk();
+}
+
+struct FocusListenerMock : BnFocusListener {
+ MOCK_METHOD(Status, requestAudioFocus,
+ (const String16& usage, int32_t zoneId, AudioFocusChange focusGain));
+ MOCK_METHOD(Status, abandonAudioFocus, (const String16& usage, int32_t 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(AudioControlAidl, FocusListenerRegistration) {
+ ALOGI("Focus listener test");
+
+ sp<FocusListenerMock> listener = new FocusListenerMock();
+ ASSERT_TRUE(audioControl->registerFocusListener(listener).isOk());
+
+ sp<FocusListenerMock> listener2 = new FocusListenerMock();
+ ASSERT_TRUE(audioControl->registerFocusListener(listener2).isOk());
+};
+
+TEST_P(AudioControlAidl, FocusChangeExercise) {
+ ALOGI("Focus Change test");
+
+ String16 usage = String16(xsd::toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA).c_str());
+ ASSERT_TRUE(
+ audioControl->onAudioFocusChange(usage, 0, AudioFocusChange::GAIN_TRANSIENT).isOk());
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlAidl);
+INSTANTIATE_TEST_SUITE_P(
+ Audiocontrol, AudioControlAidl,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::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/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index d1d254b..57f390c 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -35,10 +35,8 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
+ <hal format="aidl" optional="true">
<name>android.hardware.automotive.audiocontrol</name>
- <version>1.0</version>
- <version>2.0</version>
<interface>
<name>IAudioControl</name>
<instance>default</instance>
diff --git a/radio/1.6/IRadioIndication.hal b/radio/1.6/IRadioIndication.hal
index d9aaa38..c135090 100644
--- a/radio/1.6/IRadioIndication.hal
+++ b/radio/1.6/IRadioIndication.hal
@@ -40,4 +40,17 @@
* 3. Unsolicited disconnect from either modem or network side.
*/
oneway dataCallListChanged_1_6(RadioIndicationType type, vec<SetupDataCallResult> dcList);
+
+ /**
+ * The modem can explicitly set SetupDataCallResult::suggestedRetryTime after a failure in
+ * IRadio@1.6::SetupDataCall. During that time, no new calls are allowed to
+ * IRadio@1.6::SetupDataCall that use the same APN.
+ *
+ * When IRadioIndication@1.6::unthrottleApn is sent, AOSP will no longer throttle calls
+ * to IRadio@1.6::SetupDataCall for the given APN.
+ *
+ * @param type Type of radio indication
+ * @param apn Apn to unthrottle
+ */
+ oneway unthrottleApn(RadioIndicationType type, string apn);
};
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
index f0550af..989ba6d 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
+++ b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
@@ -808,6 +808,9 @@
RadioIndicationType type,
const hidl_vec<::android::hardware::radio::V1_6::SetupDataCallResult>& dcList);
+ Return<void> unthrottleApn(RadioIndicationType type,
+ const ::android::hardware::hidl_string& apn);
+
/* 1.5 Api */
Return<void> uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled);
diff --git a/radio/1.6/vts/functional/radio_indication.cpp b/radio/1.6/vts/functional/radio_indication.cpp
index 57ee873..b353c82 100644
--- a/radio/1.6/vts/functional/radio_indication.cpp
+++ b/radio/1.6/vts/functional/radio_indication.cpp
@@ -25,6 +25,11 @@
return Void();
}
+Return<void> RadioIndication_v1_6::unthrottleApn(RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_string& /*apn*/) {
+ return Void();
+}
+
/* 1.5 Apis */
Return<void> RadioIndication_v1_6::uiccApplicationsEnablementChanged(RadioIndicationType /*type*/,
bool /*enabled*/) {
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 22efe08..78e6239 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
@@ -21,6 +21,7 @@
#include <android/hardware/wifi/1.3/IWifi.h>
#include <android/hardware/wifi/1.3/IWifiStaIface.h>
+#include <android/hardware/wifi/1.5/IWifiStaIface.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
@@ -88,7 +89,6 @@
// No-op if link layer stats is not supported.
return;
}
-
// Enable link layer stats collection.
EXPECT_EQ(WifiStatusCode::SUCCESS,
HIDL_INVOKE(wifi_sta_iface_, enableLinkLayerStatsCollection, true)
@@ -96,8 +96,17 @@
// Retrieve link layer stats.
const auto& status_and_stats =
HIDL_INVOKE(wifi_sta_iface_, getLinkLayerStats_1_3);
- EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_stats.first.code);
- EXPECT_GT(status_and_stats.second.timeStampInMs, 0u);
+ sp<android::hardware::wifi::V1_5::IWifiStaIface> staIface1_5 =
+ android::hardware::wifi::V1_5::IWifiStaIface::castFrom(wifi_sta_iface_);
+ if (staIface1_5.get() == nullptr) {
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_stats.first.code);
+ EXPECT_GT(status_and_stats.second.timeStampInMs, 0u);
+ } else {
+ // not supported on 1.5 HAL.
+ EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED,
+ status_and_stats.first.code);
+ }
+
// Disable link layer stats collection.
EXPECT_EQ(
WifiStatusCode::SUCCESS,
diff --git a/wifi/1.5/Android.bp b/wifi/1.5/Android.bp
index ecb0a35..5a62a3a 100644
--- a/wifi/1.5/Android.bp
+++ b/wifi/1.5/Android.bp
@@ -9,6 +9,7 @@
"IWifiChip.hal",
"IWifiNanIface.hal",
"IWifiNanIfaceEventCallback.hal",
+ "IWifiStaIface.hal",
],
interfaces: [
"android.hardware.wifi@1.0",
diff --git a/wifi/1.5/IWifiChip.hal b/wifi/1.5/IWifiChip.hal
index 5243baf..dcc9279 100644
--- a/wifi/1.5/IWifiChip.hal
+++ b/wifi/1.5/IWifiChip.hal
@@ -36,6 +36,53 @@
};
/**
+ * When there are 2 or more simultaneous STA connections, this use case hint indicates what
+ * use-case is being enabled by the framework. This use case hint can be used by the firmware
+ * to modify various firmware configurations like:
+ * - Allowed BSSIDs the firmware can choose for the initial connection/roaming attempts.
+ * - Duty cycle to choose for the 2 STA connections if the radio is in MCC mode.
+ * - Whether roaming, APF and other offloads needs to be enabled or not.
+ * Note:
+ * - This will be invoked before an active wifi connection is established on the second
+ * interface.
+ * - This use-case hint is implicitly void when the second STA interface is brought down.
+ */
+ enum MultiStaUseCase : uint8_t {
+ /**
+ * Usage:
+ * - This will be sent down for make before break use-case.
+ * - Platform is trying to speculatively connect to a second network and evaluate it without
+ * disrupting the primary connection.
+ * Requirements for Firmware:
+ * - Do not reduce the number of tx/rx chains of primary connection.
+ * - If using MCC, should set the MCC duty cycle of the primary connection to be higher than
+ * the secondary connection (maybe 70/30 split).
+ * - Should pick the best BSSID for the secondary STA (disregard the chip mode) independent
+ * of the primary STA:
+ * - Don’t optimize for DBS vs MCC/SCC
+ * - Should not impact the primary connection’s bssid selection:
+ * - Don’t downgrade chains of the existing primary connection.
+ * - Don’t optimize for DBS vs MCC/SCC.
+ */
+ DUAL_STA_TRANSIENT_PREFER_PRIMARY = 0,
+ /**
+ * Usage:
+ * - This will be sent down for any app requested peer to peer connections.
+ * - In this case, both the connections needs to be allocated equal resources.
+ * - For the peer to peer use case, BSSID for the secondary connection will be chosen by the
+ * framework.
+ *
+ * Requirements for Firmware:
+ * - Can choose MCC or DBS mode depending on the MCC efficiency and HW capability.
+ * - If using MCC, set the MCC duty cycle of the primary connection to be equal to the
+ * secondary connection.
+ * - Prefer BSSID candidates which will help provide the best "overall" performance for both
+ * the connections.
+ */
+ DUAL_STA_NON_TRANSIENT_UNBIASED = 1,
+ };
+
+ /**
* Get the capabilities supported by this chip.
*
* @return status WifiStatus of the operation.
@@ -48,4 +95,36 @@
*/
getCapabilities_1_5()
generates (WifiStatus status, bitfield<ChipCapabilityMask> capabilities);
+
+ /**
+ * Invoked to indicate that the provided iface is the primary STA iface when there are more
+ * than 1 STA iface concurrently active.
+ * Note: If the wifi firmware/chip cannot support multiple instances of any offload
+ * (like roaming, APF, rssi threshold, etc), the firmware should ensure that these
+ * offloads are at least enabled for the primary interface. If the new primary interface is
+ * already connected to a network, the firmware must switch all the offloads on
+ * this new interface without disconnecting.
+ *
+ * @param ifname Name of the STA iface.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|
+ */
+ setMultiStaPrimaryConnection(string ifName) generates (WifiStatus status);
+
+ /**
+ * Invoked to indicate the STA + STA use-case that is active.
+ *
+ * Refer to documentation of |MultiStaUseCase| for details.
+ *
+ * @param useCase Use case that is active.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|
+ */
+ setMultiStaUseCase(MultiStaUseCase useCase) generates (WifiStatus status);
};
diff --git a/wifi/1.5/IWifiNanIface.hal b/wifi/1.5/IWifiNanIface.hal
index 93257b5..d7c15de 100644
--- a/wifi/1.5/IWifiNanIface.hal
+++ b/wifi/1.5/IWifiNanIface.hal
@@ -92,13 +92,12 @@
* |WifiStatusCode.SUCCESS|,
* |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
*/
- registerEventCallback_1_5(IWifiNanIfaceEventCallback callback)
- generates (WifiStatus status);
+ registerEventCallback_1_5(IWifiNanIfaceEventCallback callback) generates (WifiStatus status);
/**
* Get NAN capabilities. Asynchronous response is with
* |IWifiNanIfaceEventCallback.notifyCapabilitiesResponse|.
-
+ *
* Note: supersedes the @1.0::IWifiNanIface.getCapabilitiesRequest() method which is deprecated
* as of HAL version 1.5.
*
@@ -109,5 +108,5 @@
* |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
* |WifiStatusCode.ERROR_UNKNOWN|
*/
- getCapabilitiesRequest_1_5(CommandIdShort cmdId) generates (WifiStatus status);
-};
\ No newline at end of file
+ getCapabilitiesRequest_1_5(CommandIdShort cmdId) generates (WifiStatus status);
+};
diff --git a/wifi/1.5/IWifiNanIfaceEventCallback.hal b/wifi/1.5/IWifiNanIfaceEventCallback.hal
index 867c03c..046b702 100644
--- a/wifi/1.5/IWifiNanIfaceEventCallback.hal
+++ b/wifi/1.5/IWifiNanIfaceEventCallback.hal
@@ -40,5 +40,5 @@
* @param capabilities Capability data.
*/
oneway notifyCapabilitiesResponse_1_5(CommandIdShort id, WifiNanStatus status,
- NanCapabilities capabilities);
-};
\ No newline at end of file
+ NanCapabilities capabilities);
+};
diff --git a/wifi/1.5/IWifiStaIface.hal b/wifi/1.5/IWifiStaIface.hal
new file mode 100644
index 0000000..e9d411e
--- /dev/null
+++ b/wifi/1.5/IWifiStaIface.hal
@@ -0,0 +1,44 @@
+/*
+ * 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.wifi@1.5;
+
+import @1.0::WifiStatus;
+import @1.3::IWifiStaIface;
+
+/**
+ * Interface used to represent a single STA iface.
+ *
+ * IWifiChip.createStaIface() must return a @1.5::IWifiStaIface when supported.
+ */
+interface IWifiStaIface extends @1.3::IWifiStaIface {
+ /**
+ * Retrieve the latest link layer stats.
+ * Must fail if |StaIfaceCapabilityMask.LINK_LAYER_STATS| is not set or if
+ * link layer stats collection hasn't been explicitly enabled.
+ *
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_STARTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ * @return stats Instance of |LinkLayerStats|.
+ */
+ getLinkLayerStats_1_5() generates (WifiStatus status, StaLinkLayerStats stats);
+};
diff --git a/wifi/1.5/default/hidl_struct_util.cpp b/wifi/1.5/default/hidl_struct_util.cpp
index 578f3e2..83d06fe 100644
--- a/wifi/1.5/default/hidl_struct_util.cpp
+++ b/wifi/1.5/default/hidl_struct_util.cpp
@@ -866,46 +866,48 @@
bool convertLegacyLinkLayerStatsToHidl(
const legacy_hal::LinkLayerStats& legacy_stats,
- V1_3::StaLinkLayerStats* hidl_stats) {
+ 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 =
+ hidl_stats->iface.V1_0.beaconRx = legacy_stats.iface.beacon_rx;
+ hidl_stats->iface.V1_0.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
+ hidl_stats->iface.V1_0.wmeBePktStats.rxMpdu =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
- hidl_stats->iface.wmeBePktStats.txMpdu =
+ hidl_stats->iface.V1_0.wmeBePktStats.txMpdu =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
- hidl_stats->iface.wmeBePktStats.lostMpdu =
+ hidl_stats->iface.V1_0.wmeBePktStats.lostMpdu =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
- hidl_stats->iface.wmeBePktStats.retries =
+ hidl_stats->iface.V1_0.wmeBePktStats.retries =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
- hidl_stats->iface.wmeBkPktStats.rxMpdu =
+ hidl_stats->iface.V1_0.wmeBkPktStats.rxMpdu =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
- hidl_stats->iface.wmeBkPktStats.txMpdu =
+ hidl_stats->iface.V1_0.wmeBkPktStats.txMpdu =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
- hidl_stats->iface.wmeBkPktStats.lostMpdu =
+ hidl_stats->iface.V1_0.wmeBkPktStats.lostMpdu =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
- hidl_stats->iface.wmeBkPktStats.retries =
+ hidl_stats->iface.V1_0.wmeBkPktStats.retries =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
- hidl_stats->iface.wmeViPktStats.rxMpdu =
+ hidl_stats->iface.V1_0.wmeViPktStats.rxMpdu =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
- hidl_stats->iface.wmeViPktStats.txMpdu =
+ hidl_stats->iface.V1_0.wmeViPktStats.txMpdu =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
- hidl_stats->iface.wmeViPktStats.lostMpdu =
+ hidl_stats->iface.V1_0.wmeViPktStats.lostMpdu =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
- hidl_stats->iface.wmeViPktStats.retries =
+ hidl_stats->iface.V1_0.wmeViPktStats.retries =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
- hidl_stats->iface.wmeVoPktStats.rxMpdu =
+ hidl_stats->iface.V1_0.wmeVoPktStats.rxMpdu =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
- hidl_stats->iface.wmeVoPktStats.txMpdu =
+ hidl_stats->iface.V1_0.wmeVoPktStats.txMpdu =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
- hidl_stats->iface.wmeVoPktStats.lostMpdu =
+ hidl_stats->iface.V1_0.wmeVoPktStats.lostMpdu =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
- hidl_stats->iface.wmeVoPktStats.retries =
+ hidl_stats->iface.V1_0.wmeVoPktStats.retries =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
+ hidl_stats->iface.timeSliceDutyCycleInPercent =
+ legacy_stats.iface.info.time_slicing_duty_cycle_percent;
// radio legacy_stats conversion.
std::vector<V1_3::StaLinkLayerRadioStats> hidl_radios_stats;
for (const auto& legacy_radio_stats : legacy_stats.radios) {
@@ -2787,6 +2789,17 @@
}
CHECK(false);
}
+
+legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy(
+ IWifiChip::MultiStaUseCase use_case) {
+ switch (use_case) {
+ case IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY:
+ return legacy_hal::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
+ case IWifiChip::MultiStaUseCase::DUAL_STA_NON_TRANSIENT_UNBIASED:
+ return legacy_hal::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
+ }
+ CHECK(false);
+}
} // namespace hidl_struct_util
} // namespace implementation
} // namespace V1_5
diff --git a/wifi/1.5/default/hidl_struct_util.h b/wifi/1.5/default/hidl_struct_util.h
index b0b1d22..49d8a12 100644
--- a/wifi/1.5/default/hidl_struct_util.h
+++ b/wifi/1.5/default/hidl_struct_util.h
@@ -69,6 +69,8 @@
hidl_radio_mode_infos);
legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
IfaceType hidl_interface_type);
+legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy(
+ IWifiChip::MultiStaUseCase use_case);
// STA iface conversion methods.
bool convertLegacyFeaturesToHidlStaCapabilities(
@@ -96,7 +98,7 @@
std::vector<StaScanData>* hidl_scan_datas);
bool convertLegacyLinkLayerStatsToHidl(
const legacy_hal::LinkLayerStats& legacy_stats,
- V1_3::StaLinkLayerStats* hidl_stats);
+ StaLinkLayerStats* hidl_stats);
bool convertLegacyRoamingCapabilitiesToHidl(
const legacy_hal::wifi_roaming_capabilities& legacy_caps,
StaRoamingCapabilities* hidl_caps);
diff --git a/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
index 81eb14e..ea84c61 100644
--- a/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
+++ b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
@@ -154,6 +154,8 @@
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand();
+ legacy_stats.iface.info.time_slicing_duty_cycle_percent = rand();
+
for (auto& radio : legacy_stats.radios) {
radio.stats.on_time = rand();
radio.stats.tx_time = rand();
@@ -182,46 +184,49 @@
radio.channel_stats.push_back(channel_stat2);
}
- V1_3::StaLinkLayerStats converted{};
+ V1_5::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.beacon_rx, converted.iface.V1_0.beaconRx);
+ EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.V1_0.avgRssiMgmt);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
- converted.iface.wmeBePktStats.rxMpdu);
+ converted.iface.V1_0.wmeBePktStats.rxMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
- converted.iface.wmeBePktStats.txMpdu);
+ converted.iface.V1_0.wmeBePktStats.txMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
- converted.iface.wmeBePktStats.lostMpdu);
+ converted.iface.V1_0.wmeBePktStats.lostMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
- converted.iface.wmeBePktStats.retries);
+ converted.iface.V1_0.wmeBePktStats.retries);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
- converted.iface.wmeBkPktStats.rxMpdu);
+ converted.iface.V1_0.wmeBkPktStats.rxMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
- converted.iface.wmeBkPktStats.txMpdu);
+ converted.iface.V1_0.wmeBkPktStats.txMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
- converted.iface.wmeBkPktStats.lostMpdu);
+ converted.iface.V1_0.wmeBkPktStats.lostMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
- converted.iface.wmeBkPktStats.retries);
+ converted.iface.V1_0.wmeBkPktStats.retries);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
- converted.iface.wmeViPktStats.rxMpdu);
+ converted.iface.V1_0.wmeViPktStats.rxMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
- converted.iface.wmeViPktStats.txMpdu);
+ converted.iface.V1_0.wmeViPktStats.txMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
- converted.iface.wmeViPktStats.lostMpdu);
+ converted.iface.V1_0.wmeViPktStats.lostMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
- converted.iface.wmeViPktStats.retries);
+ converted.iface.V1_0.wmeViPktStats.retries);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
- converted.iface.wmeVoPktStats.rxMpdu);
+ converted.iface.V1_0.wmeVoPktStats.rxMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
- converted.iface.wmeVoPktStats.txMpdu);
+ converted.iface.V1_0.wmeVoPktStats.txMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
- converted.iface.wmeVoPktStats.lostMpdu);
+ converted.iface.V1_0.wmeVoPktStats.lostMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
- converted.iface.wmeVoPktStats.retries);
+ converted.iface.V1_0.wmeVoPktStats.retries);
+
+ EXPECT_EQ(legacy_stats.iface.info.time_slicing_duty_cycle_percent,
+ converted.iface.timeSliceDutyCycleInPercent);
EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
diff --git a/wifi/1.5/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
index ebff722..1c238c8 100644
--- a/wifi/1.5/default/wifi_chip.cpp
+++ b/wifi/1.5/default/wifi_chip.cpp
@@ -678,6 +678,20 @@
hidl_status_cb, event_callback);
}
+Return<void> WifiChip::setMultiStaPrimaryConnection(
+ const hidl_string& ifname, setMultiStaPrimaryConnection_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::setMultiStaPrimaryConnectionInternal,
+ hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::setMultiStaUseCase(
+ MultiStaUseCase use_case, setMultiStaUseCase_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::setMultiStaUseCaseInternal,
+ hidl_status_cb, use_case);
+}
+
void WifiChip::invalidateAndRemoveAllIfaces() {
invalidateAndClearAll(ap_ifaces_);
invalidateAndClearAll(nan_ifaces_);
@@ -1016,7 +1030,7 @@
return createWifiStatus(WifiStatusCode::SUCCESS);
}
-std::pair<WifiStatus, sp<V1_3::IWifiStaIface>>
+std::pair<WifiStatus, sp<V1_5::IWifiStaIface>>
WifiChip::createStaIfaceInternal() {
if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) {
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
@@ -1050,7 +1064,7 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
}
-std::pair<WifiStatus, sp<V1_3::IWifiStaIface>> WifiChip::getStaIfaceInternal(
+std::pair<WifiStatus, sp<V1_5::IWifiStaIface>> WifiChip::getStaIfaceInternal(
const std::string& ifname) {
const auto iface = findUsingName(sta_ifaces_, ifname);
if (!iface.get()) {
@@ -1295,6 +1309,19 @@
return createWifiStatus(WifiStatusCode::SUCCESS);
}
+WifiStatus WifiChip::setMultiStaPrimaryConnectionInternal(
+ const std::string& ifname) {
+ auto legacy_status =
+ legacy_hal_.lock()->multiStaSetPrimaryConnection(ifname);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::setMultiStaUseCaseInternal(MultiStaUseCase use_case) {
+ auto legacy_status = legacy_hal_.lock()->multiStaSetUseCase(
+ hidl_struct_util::convertHidlMultiStaUseCaseToLegacy(use_case));
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
WifiStatus WifiChip::handleChipConfiguration(
/* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
ChipModeId mode_id) {
diff --git a/wifi/1.5/default/wifi_chip.h b/wifi/1.5/default/wifi_chip.h
index 8cc0452..693d480 100644
--- a/wifi/1.5/default/wifi_chip.h
+++ b/wifi/1.5/default/wifi_chip.h
@@ -163,6 +163,12 @@
Return<void> registerEventCallback_1_4(
const sp<V1_4::IWifiChipEventCallback>& event_callback,
registerEventCallback_1_4_cb hidl_status_cb) override;
+ Return<void> setMultiStaPrimaryConnection(
+ const hidl_string& ifname,
+ setMultiStaPrimaryConnection_cb hidl_status_cb) override;
+ Return<void> setMultiStaUseCase(
+ MultiStaUseCase use_case,
+ setMultiStaUseCase_cb hidl_status_cb) override;
private:
void invalidateAndRemoveAllIfaces();
@@ -201,9 +207,9 @@
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, sp<V1_5::IWifiStaIface>> createStaIfaceInternal();
std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
- std::pair<WifiStatus, sp<V1_3::IWifiStaIface>> getStaIfaceInternal(
+ std::pair<WifiStatus, sp<V1_5::IWifiStaIface>> getStaIfaceInternal(
const std::string& ifname);
WifiStatus removeStaIfaceInternal(const std::string& ifname);
std::pair<WifiStatus, sp<V1_0::IWifiRttController>>
@@ -233,6 +239,8 @@
createRttControllerInternal_1_4(const sp<IWifiIface>& bound_iface);
WifiStatus registerEventCallbackInternal_1_4(
const sp<V1_4::IWifiChipEventCallback>& event_callback);
+ WifiStatus setMultiStaPrimaryConnectionInternal(const std::string& ifname);
+ WifiStatus setMultiStaUseCaseInternal(MultiStaUseCase use_case);
WifiStatus handleChipConfiguration(
std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
diff --git a/wifi/1.5/default/wifi_legacy_hal.cpp b/wifi/1.5/default/wifi_legacy_hal.cpp
index 398bfac..76e718b 100644
--- a/wifi/1.5/default/wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal.cpp
@@ -1510,6 +1510,17 @@
return res;
}
+wifi_error WifiLegacyHal::multiStaSetPrimaryConnection(
+ const std::string& ifname) {
+ return global_func_table_.wifi_multi_sta_set_primary_connection(
+ global_handle_, getIfaceHandle(ifname));
+}
+
+wifi_error WifiLegacyHal::multiStaSetUseCase(wifi_multi_sta_use_case use_case) {
+ return global_func_table_.wifi_multi_sta_set_use_case(global_handle_,
+ use_case);
+}
+
void WifiLegacyHal::invalidate() {
global_handle_ = nullptr;
iface_name_to_handle_.clear();
diff --git a/wifi/1.5/default/wifi_legacy_hal.h b/wifi/1.5/default/wifi_legacy_hal.h
index 9a06efd..555c540 100644
--- a/wifi/1.5/default/wifi_legacy_hal.h
+++ b/wifi/1.5/default/wifi_legacy_hal.h
@@ -382,6 +382,10 @@
virtual wifi_error deleteVirtualInterface(const std::string& ifname);
wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname);
+ // STA + STA functions
+ virtual wifi_error multiStaSetPrimaryConnection(const std::string& ifname);
+ virtual wifi_error multiStaSetUseCase(wifi_multi_sta_use_case use_case);
+
private:
// Retrieve interface handles for all the available interfaces.
wifi_error retrieveIfaceHandles();
diff --git a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
index a1122e9..71d2ddf 100644
--- a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
@@ -147,6 +147,8 @@
populateStubFor(&hal_fn->wifi_get_supported_iface_name);
populateStubFor(&hal_fn->wifi_early_initialize);
populateStubFor(&hal_fn->wifi_get_chip_feature_set);
+ populateStubFor(&hal_fn->wifi_multi_sta_set_primary_connection);
+ populateStubFor(&hal_fn->wifi_multi_sta_set_use_case);
return true;
}
diff --git a/wifi/1.5/default/wifi_sta_iface.cpp b/wifi/1.5/default/wifi_sta_iface.cpp
index 04087fd..f3dcfc5 100644
--- a/wifi/1.5/default/wifi_sta_iface.cpp
+++ b/wifi/1.5/default/wifi_sta_iface.cpp
@@ -163,6 +163,13 @@
hidl_status_cb);
}
+Return<void> WifiStaIface::getLinkLayerStats_1_5(
+ getLinkLayerStats_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getLinkLayerStatsInternal_1_5,
+ hidl_status_cb);
+}
+
Return<void> WifiStaIface::startRssiMonitoring(
uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
startRssiMonitoring_cb hidl_status_cb) {
@@ -470,6 +477,11 @@
std::pair<WifiStatus, V1_3::StaLinkLayerStats>
WifiStaIface::getLinkLayerStatsInternal_1_3() {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_5::StaLinkLayerStats>
+WifiStaIface::getLinkLayerStatsInternal_1_5() {
legacy_hal::wifi_error legacy_status;
legacy_hal::LinkLayerStats legacy_stats;
std::tie(legacy_status, legacy_stats) =
@@ -477,7 +489,7 @@
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {createWifiStatusFromLegacyError(legacy_status), {}};
}
- V1_3::StaLinkLayerStats hidl_stats;
+ V1_5::StaLinkLayerStats hidl_stats;
if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
&hidl_stats)) {
return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
diff --git a/wifi/1.5/default/wifi_sta_iface.h b/wifi/1.5/default/wifi_sta_iface.h
index 7695f3c..94873c9 100644
--- a/wifi/1.5/default/wifi_sta_iface.h
+++ b/wifi/1.5/default/wifi_sta_iface.h
@@ -19,7 +19,7 @@
#include <android-base/macros.h>
#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
-#include <android/hardware/wifi/1.3/IWifiStaIface.h>
+#include <android/hardware/wifi/1.5/IWifiStaIface.h>
#include "hidl_callback_util.h"
#include "wifi_iface_util.h"
@@ -35,7 +35,7 @@
/**
* HIDL interface object used to control a STA Iface instance.
*/
-class WifiStaIface : public V1_3::IWifiStaIface {
+class WifiStaIface : public V1_5::IWifiStaIface {
public:
WifiStaIface(const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
@@ -78,6 +78,8 @@
getLinkLayerStats_cb hidl_status_cb) override;
Return<void> getLinkLayerStats_1_3(
getLinkLayerStats_1_3_cb hidl_status_cb) override;
+ Return<void> getLinkLayerStats_1_5(
+ getLinkLayerStats_1_5_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;
@@ -138,6 +140,8 @@
std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal();
std::pair<WifiStatus, V1_3::StaLinkLayerStats>
getLinkLayerStatsInternal_1_3();
+ std::pair<WifiStatus, V1_5::StaLinkLayerStats>
+ getLinkLayerStatsInternal_1_5();
WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi,
int32_t min_rssi);
WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
diff --git a/wifi/1.5/types.hal b/wifi/1.5/types.hal
index 5873f79..3fbec82 100644
--- a/wifi/1.5/types.hal
+++ b/wifi/1.5/types.hal
@@ -16,10 +16,14 @@
package android.hardware.wifi@1.5;
+import @1.0::StaLinkLayerIfaceStats;
+import @1.0::StaLinkLayerIfacePacketStats;
+import @1.0::TimeStampInMs;
import @1.0::WifiBand;
import @1.0::NanCipherSuiteType;
import @1.0::NanCapabilities;
import @1.2::NanConfigRequestSupplemental;
+import @1.3::StaLinkLayerRadioStats;
/**
* Wifi bands defined in 80211 spec.
@@ -48,6 +52,7 @@
* Baseline information as defined in HAL 1.2.
*/
@1.2::NanConfigRequestSupplemental V1_2;
+
/**
* Controls whether NAN instant communication mode is enabled.
*/
@@ -62,8 +67,43 @@
* Baseline information as defined in HAL 1.0.
*/
@1.0::NanCapabilities V1_0;
+
/**
* Flag to indicate id instant communication mode is supported.
*/
bool instantCommunicationModeSupportFlag;
-};
\ No newline at end of file
+};
+
+/**
+ * Iface statistics for the current connection.
+ */
+struct StaLinkLayerIfaceStats {
+ /**
+ * Baseline information as defined in HAL 1.0.
+ */
+ @1.0::StaLinkLayerIfaceStats V1_0;
+
+ /**
+ * Duty cycle for the iface.
+ * if this iface is being served using time slicing on a radio with one or more ifaces
+ * (i.e MCC), then the duty cycle assigned to this iface in %.
+ * If not using time slicing (i.e SCC or DBS), set to 100.
+ */
+ uint8_t timeSliceDutyCycleInPercent;
+};
+
+/**
+ * Link layer stats retrieved via |getLinkLayerStats|.
+ */
+struct StaLinkLayerStats {
+ StaLinkLayerIfaceStats iface;
+
+ vec<StaLinkLayerRadioStats> radios;
+
+ /**
+ * TimeStamp for each stats sample.
+ * This is the absolute milliseconds from boot when these stats were
+ * sampled.
+ */
+ TimeStampInMs timeStampInMs;
+};
diff --git a/wifi/1.5/vts/functional/Android.bp b/wifi/1.5/vts/functional/Android.bp
index a7ba498..eb595c9 100644
--- a/wifi/1.5/vts/functional/Android.bp
+++ b/wifi/1.5/vts/functional/Android.bp
@@ -14,6 +14,29 @@
// limitations under the License.
//
+cc_test {
+ name: "VtsHalWifiV1_5TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "wifi_chip_hidl_test.cpp",
+ "wifi_sta_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",
+ "android.hardware.wifi@1.5",
+ "libwifi-system-iface",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
+
// These tests are split out so that they can be conditioned on presence of the
// "android.hardware.wifi.aware" feature.
cc_test {
diff --git a/wifi/1.5/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.5/vts/functional/wifi_chip_hidl_test.cpp
new file mode 100644
index 0000000..eeaa7e0
--- /dev/null
+++ b/wifi/1.5/vts/functional/wifi_chip_hidl_test.cpp
@@ -0,0 +1,149 @@
+/*
+ * 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 <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/IWifiChipEventCallback.h>
+#include <android/hardware/wifi/1.5/IWifi.h>
+#include <android/hardware/wifi/1.5/IWifiChip.h>
+#include <android/hardware/wifi/1.5/IWifiStaIface.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::ChipModeId;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifiIface;
+using ::android::hardware::wifi::V1_0::IWifiStaIface;
+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::IWifiChipEventCallback;
+using ::android::hardware::wifi::V1_5::IWifiChip;
+
+/**
+ * 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()); }
+
+ 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;
+ }
+
+ WifiStatusCode createStaIface(sp<IWifiStaIface>* sta_iface) {
+ const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createStaIface);
+ *sta_iface = status_and_iface.second;
+ return status_and_iface.first.code;
+ }
+
+ 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;
+ }
+
+ std::vector<sp<IWifiStaIface>> create2StaIfacesIfPossible() {
+ configureChipForIfaceType(IfaceType::STA, true);
+ sp<IWifiStaIface> iface1, iface2;
+ EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&iface1));
+ EXPECT_NE(nullptr, iface1.get());
+
+ // Try to create 2nd iface
+ auto status = createStaIface(&iface2);
+ if (status != WifiStatusCode::SUCCESS) {
+ return {iface1};
+ }
+ EXPECT_NE(nullptr, iface2.get());
+ return {iface1, iface2};
+ }
+
+ sp<IWifiChip> wifi_chip_;
+
+ private:
+ std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * setMultiStaPrimaryConnection
+ *
+ * Only run if device supports 2 STA ifaces.
+ */
+TEST_P(WifiChipHidlTest, setMultiStaPrimaryConnection) {
+ auto ifaces = create2StaIfacesIfPossible();
+ if (ifaces.size() < 2) {
+ GTEST_SKIP() << "Device does not support more than 1 STA concurrently";
+ }
+
+ const auto& status = HIDL_INVOKE(wifi_chip_, setMultiStaPrimaryConnection,
+ getIfaceName(ifaces.front()));
+ if (status.code != WifiStatusCode::SUCCESS) {
+ EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code);
+ }
+}
+
+/*
+ * setMultiStaUseCase
+ *
+ * Only run if device supports 2 STA ifaces.
+ */
+TEST_P(WifiChipHidlTest, setMultiStaUseCase) {
+ auto ifaces = create2StaIfacesIfPossible();
+ if (ifaces.size() < 2) {
+ GTEST_SKIP() << "Device does not support more than 1 STA concurrently";
+ }
+
+ const auto& status = HIDL_INVOKE(
+ wifi_chip_, setMultiStaUseCase,
+ IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY);
+ if (status.code != WifiStatusCode::SUCCESS) {
+ EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code);
+ }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiChipHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ ::android::hardware::wifi::V1_5::IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.5/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.5/vts/functional/wifi_sta_iface_hidl_test.cpp
new file mode 100644
index 0000000..8cc3300
--- /dev/null
+++ b/wifi/1.5/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 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 <numeric>
+#include <vector>
+
+#include <android-base/logging.h>
+
+#include <android/hardware/wifi/1.5/IWifi.h>
+#include <android/hardware/wifi/1.5/IWifiChip.h>
+#include <android/hardware/wifi/1.5/IWifiStaIface.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_5::IWifiChip;
+using ::android::hardware::wifi::V1_5::IWifiStaIface;
+
+/**
+ * Fixture to use for all STA Iface HIDL interface tests.
+ */
+class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ // 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(GetInstanceName()); }
+
+ protected:
+ bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) {
+ const auto& status_and_caps =
+ HIDL_INVOKE(wifi_sta_iface_, getCapabilities);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+ return (status_and_caps.second & cap_mask) != 0;
+ }
+
+ WifiStatusCode createStaIface(sp<IWifiStaIface>* sta_iface) {
+ sp<IWifiChip> wifi_chip =
+ IWifiChip::castFrom(getWifiChip(GetInstanceName()));
+ EXPECT_NE(nullptr, wifi_chip.get());
+ const auto& status_and_iface = HIDL_INVOKE(wifi_chip, createStaIface);
+ *sta_iface = IWifiStaIface::castFrom(status_and_iface.second);
+ return status_and_iface.first.code;
+ }
+
+ sp<IWifiStaIface> wifi_sta_iface_;
+
+ private:
+ std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * GetLinkLayerStats_1_5
+ * Ensures that calls to get link layer stats V1_5 will retrieve a non-empty
+ * StaLinkLayerStats after link layer stats collection is enabled.
+ */
+TEST_P(WifiStaIfaceHidlTest, GetLinkLayerStats_1_5) {
+ if (!isCapabilitySupported(
+ IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) {
+ // No-op if link layer stats is not supported.
+ return;
+ }
+
+ // Enable link layer stats collection.
+ EXPECT_EQ(WifiStatusCode::SUCCESS,
+ HIDL_INVOKE(wifi_sta_iface_, enableLinkLayerStatsCollection, true)
+ .code);
+ // Retrieve link layer stats.
+ const auto& status_and_stats =
+ HIDL_INVOKE(wifi_sta_iface_, getLinkLayerStats_1_5);
+ EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_stats.first.code);
+ EXPECT_GT(status_and_stats.second.timeStampInMs, 0u);
+ // Try to create 2nd iface. If yes, it should fill in the duty cycle field.
+ sp<IWifiStaIface> iface;
+ auto status = createStaIface(&iface);
+ if (status == WifiStatusCode::SUCCESS) {
+ EXPECT_GT(status_and_stats.second.iface.timeSliceDutyCycleInPercent,
+ 0u);
+ }
+ // Disable link layer stats collection.
+ EXPECT_EQ(
+ WifiStatusCode::SUCCESS,
+ HIDL_INVOKE(wifi_sta_iface_, disableLinkLayerStatsCollection).code);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceHidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, WifiStaIfaceHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ ::android::hardware::wifi::V1_5::IWifi::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/wifi/supplicant/1.3/vts/functional/Android.bp b/wifi/supplicant/1.3/vts/functional/Android.bp
index 68c2929..1784fad 100644
--- a/wifi/supplicant/1.3/vts/functional/Android.bp
+++ b/wifi/supplicant/1.3/vts/functional/Android.bp
@@ -54,6 +54,7 @@
"android.hardware.wifi.supplicant@1.1",
"android.hardware.wifi.supplicant@1.2",
"android.hardware.wifi.supplicant@1.3",
+ "android.hardware.wifi.supplicant@1.4",
"android.hardware.wifi@1.0",
"android.hardware.wifi@1.1",
"libgmock",
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 6dc267c..189e2b9 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -23,6 +23,8 @@
#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 <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.4/types.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/HidlSupport.h>
@@ -61,6 +63,10 @@
SupplicantHidlTestBaseV1_3::SetUp();
sta_iface_ = getSupplicantStaIface_1_3(supplicant_);
ASSERT_NE(sta_iface_.get(), nullptr);
+
+ /* Variable used to check the underlying HAL version. */
+ sta_iface_v1_4_ = ::android::hardware::wifi::supplicant::V1_4::
+ ISupplicantStaIface::castFrom(sta_iface_);
}
int64_t pmkCacheExpirationTimeInSec;
@@ -108,6 +114,8 @@
protected:
// ISupplicantStaIface object used for all tests in this fixture.
sp<ISupplicantStaIface> sta_iface_;
+ sp<::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface>
+ sta_iface_v1_4_ = nullptr;
bool isDppSupported() {
uint32_t keyMgmtMask = 0;
@@ -342,9 +350,12 @@
* GetWpaDriverCapabilities
*/
TEST_P(SupplicantStaIfaceHidlTest, GetWpaDriverCapabilities) {
+ SupplicantStatusCode expectedCode =
+ (nullptr != sta_iface_v1_4_) ? SupplicantStatusCode::FAILURE_UNKNOWN
+ : SupplicantStatusCode::SUCCESS;
sta_iface_->getWpaDriverCapabilities(
[&](const SupplicantStatus& status, uint32_t) {
- EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(expectedCode, status.code);
});
}
@@ -355,12 +366,26 @@
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);
+ if (nullptr != sta_iface_v1_4_) {
+ sta_iface_v1_4_->getWpaDriverCapabilities_1_4(
+ [&](const ::android::hardware::wifi::supplicant::V1_4::
+ SupplicantStatus& status,
+ uint32_t driverCapMaskInternal) {
+ EXPECT_EQ(::android::hardware::wifi::supplicant::V1_4::
+ SupplicantStatusCode::SUCCESS,
+ status.code);
- driverCapMask = driverCapMaskInternal;
- });
+ driverCapMask = driverCapMaskInternal;
+ });
+ } else {
+ sta_iface_->getWpaDriverCapabilities(
+ [&](const SupplicantStatus& status,
+ uint32_t driverCapMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+
+ driverCapMask = driverCapMaskInternal;
+ });
+ }
SupplicantStatusCode expectedStatusCode =
(driverCapMask & WpaDriverCapabilitiesMask::MBO)
diff --git a/wifi/supplicant/1.4/ISupplicantStaIface.hal b/wifi/supplicant/1.4/ISupplicantStaIface.hal
index 096d8d5..f9e4c9b 100644
--- a/wifi/supplicant/1.4/ISupplicantStaIface.hal
+++ b/wifi/supplicant/1.4/ISupplicantStaIface.hal
@@ -16,6 +16,9 @@
package android.hardware.wifi.supplicant@1.4;
+import @1.0::SupplicantStatus;
+import @1.0::ISupplicantStaIface;
+import @1.0::MacAddress;
import ISupplicantStaIfaceCallback;
import @1.3::ISupplicantStaIface;
@@ -24,7 +27,6 @@
* interface (e.g wlan0) it controls.
*/
interface ISupplicantStaIface extends @1.3::ISupplicantStaIface {
-
/**
* Get Connection capabilities
*
@@ -54,4 +56,32 @@
*/
registerCallback_1_4(ISupplicantStaIfaceCallback callback)
generates (SupplicantStatus status);
+
+ /**
+ * Initiate Venue URL ANQP (for IEEE 802.11u Interworking/Hotspot 2.0) query with the
+ * specified access point. This specific query can be used only post connection, once security
+ * is established and PMF is enabled, to avoid spoofing preassociation ANQP responses.
+ * The ANQP data fetched must be returned in the
+ * |ISupplicantStaIfaceCallback.onAnqpQueryDone| callback.
+ *
+ * @param macAddress MAC address of the access point.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+ */
+ initiateVenueUrlAnqpQuery(MacAddress macAddress)
+ generates (SupplicantStatus status);
+
+ /**
+ * 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_1_4() generates (SupplicantStatus status,
+ bitfield<WpaDriverCapabilitiesMask> driverCapabilitiesMask);
};
diff --git a/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.hal
index 20bce34..852696d 100644
--- a/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.hal
+++ b/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.hal
@@ -16,6 +16,8 @@
package android.hardware.wifi.supplicant@1.4;
+import @1.0::ISupplicantStaIfaceCallback.AnqpData;
+import @1.0::ISupplicantStaIfaceCallback.Hs20AnqpData;
import @1.3::ISupplicantStaIfaceCallback;
import @1.0::ISupplicantStaIfaceCallback.State;
import @1.0::Bssid;
@@ -30,6 +32,19 @@
*/
interface ISupplicantStaIfaceCallback extends @1.3::ISupplicantStaIfaceCallback {
/**
+ * ANQP data for IEEE Std 802.11-2016.
+ * The format of the data within these elements follows the IEEE
+ * Std 802.11-2016 standard, section 9.4.5.
+ */
+ struct AnqpData {
+ /**
+ * Baseline information as defined in HAL 1.0.
+ */
+ @1.0::ISupplicantStaIfaceCallback.AnqpData V1_0; /* Container for v1.0 of this struct */
+ vec<uint8_t> venueUrl; /* Venue URL ANQP-element */
+ };
+
+ /**
* Used to indicate a Hotspot 2.0 terms and conditions acceptance is requested from the user
* before allowing the device to get internet access.
*
@@ -37,4 +52,16 @@
* @param url URL of the T&C server.
*/
oneway onHs20TermsAndConditionsAcceptanceRequestedNotification(Bssid bssid, string url);
+
+ /**
+ * Used to indicate the result of ANQP (either for IEEE 802.11u Interworking
+ * or Hotspot 2.0) query.
+ *
+ * @param bssid BSSID of the access point.
+ * @param data ANQP data fetched from the access point.
+ * All the fields in this struct must be empty if the query failed.
+ * @param hs20Data ANQP data fetched from the Hotspot 2.0 access point.
+ * All the fields in this struct must be empty if the query failed.
+ */
+ oneway onAnqpQueryDone_1_4(Bssid bssid, AnqpData data, Hs20AnqpData hs20Data);
};
diff --git a/wifi/supplicant/1.4/ISupplicantStaNetwork.hal b/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
index 4295879..80beedf 100644
--- a/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
@@ -25,6 +25,16 @@
*/
interface ISupplicantStaNetwork extends @1.3::ISupplicantStaNetwork {
/**
+ * Possible mask of values for KeyMgmt param.
+ */
+ enum KeyMgmtMask : @1.3::ISupplicantStaNetwork.KeyMgmtMask {
+ /**
+ * SAE PK mode
+ */
+ SAE_PK,
+ };
+
+ /**
* Possible mask of values for PairwiseCipher param.
*/
enum PairwiseCipherMask : @1.3::ISupplicantStaNetwork.PairwiseCipherMask {
@@ -160,4 +170,22 @@
* |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
*/
enableSaeH2eOnlyMode(bool enable) generates (SupplicantStatus status);
+
+ /**
+ * Set whether to enable SAE PK (Public Key) only mode to enable public AP validation.
+ * When enabled, only SAE PK network is allowed; otherwise PK is optional.
+ * If this API is not called before connecting to an SAE
+ * network, SAE PK mode depends on SAE PK config in wpa_supplicant configuration.
+ * If SAE PK config of wpa_supplicant configuration is not set,
+ * the default mode is optional (support for both PK and standard mode).
+ *
+ * @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|,
+ * |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+ */
+ enableSaePkOnlyMode(bool enable) generates (SupplicantStatus status);
};
diff --git a/wifi/supplicant/1.4/types.hal b/wifi/supplicant/1.4/types.hal
index b4b6a36..18af8fe 100644
--- a/wifi/supplicant/1.4/types.hal
+++ b/wifi/supplicant/1.4/types.hal
@@ -18,6 +18,7 @@
import @1.0::SupplicantStatusCode;
import @1.3::ConnectionCapabilities;
+import @1.3::WpaDriverCapabilitiesMask;
/**
* Detailed network mode for legacy network
@@ -71,3 +72,13 @@
*/
string debugMessage;
};
+
+/**
+ * WPA Driver capability.
+ */
+enum WpaDriverCapabilitiesMask : @1.3::WpaDriverCapabilitiesMask {
+ /**
+ *
+ */
+ SAE_PK = 1 << 2,
+};
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 88396b6..c0b5a70 100644
--- a/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -50,6 +50,10 @@
using ::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface;
using ::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIfaceCallback;
+namespace {
+constexpr uint8_t kTestMacAddr[] = {0x56, 0x67, 0x67, 0xf4, 0x56, 0x92};
+} // namespace
+
using SupplicantStatusV1_4 =
::android::hardware::wifi::supplicant::V1_4::SupplicantStatus;
using SupplicantStatusCodeV1_4 =
@@ -61,11 +65,15 @@
SupplicantHidlTestBaseV1_4::SetUp();
sta_iface_ = getSupplicantStaIface_1_4(supplicant_);
ASSERT_NE(sta_iface_.get(), nullptr);
+
+ memcpy(mac_addr_.data(), kTestMacAddr, mac_addr_.size());
}
protected:
// ISupplicantStaIface object used for all tests in this fixture.
sp<ISupplicantStaIface> sta_iface_;
+ // MAC address to use for various tests.
+ std::array<uint8_t, 6> mac_addr_;
};
class IfaceCallback : public ISupplicantStaIfaceCallback {
@@ -79,7 +87,8 @@
}
Return<void> onAnqpQueryDone(
const hidl_array<uint8_t, 6>& /* bssid */,
- const ISupplicantStaIfaceCallback::AnqpData& /* data */,
+ const ::android::hardware::wifi::supplicant::V1_0::
+ ISupplicantStaIfaceCallback::AnqpData& /* data */,
const ISupplicantStaIfaceCallback::Hs20AnqpData& /* hs20Data */)
override {
return Void();
@@ -193,6 +202,14 @@
const hidl_vec<uint8_t>& /* ssid */, bool /* filsHlpSent */) override {
return Void();
}
+ Return<void> onAnqpQueryDone_1_4(
+ const hidl_array<uint8_t, 6>& /* bssid */,
+ const ::android::hardware::wifi::supplicant::V1_4::
+ ISupplicantStaIfaceCallback::AnqpData& /* data */,
+ const ISupplicantStaIfaceCallback::Hs20AnqpData& /* hs20Data */)
+ override {
+ return Void();
+ }
};
/*
@@ -216,6 +233,28 @@
});
}
+/*
+ * InitiateVenueUrlAnqpQuery.
+ */
+TEST_P(SupplicantStaIfaceHidlTest, InitiateVenueUrlAnqpQuery) {
+ sta_iface_->initiateVenueUrlAnqpQuery(
+ mac_addr_, [](const SupplicantStatusV1_4& status) {
+ // These requests will fail unless the BSSID mentioned is actually
+ // present in scan results.
+ EXPECT_EQ(SupplicantStatusCodeV1_4::FAILURE_UNKNOWN, status.code);
+ });
+}
+
+/*
+ * GetWpaDriverCapabilities
+ */
+TEST_P(SupplicantStaIfaceHidlTest, GetWpaDriverCapabilities) {
+ sta_iface_->getWpaDriverCapabilities_1_4(
+ [&](const SupplicantStatusV1_4& status, uint32_t) {
+ EXPECT_EQ(SupplicantStatusCodeV1_4::SUCCESS, status.code);
+ });
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaIfaceHidlTest);
INSTANTIATE_TEST_CASE_P(
PerInstance, SupplicantStaIfaceHidlTest,
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.4/vts/functional/supplicant_sta_network_hidl_test.cpp
index 86314e2..0e38c4b 100644
--- a/wifi/supplicant/1.4/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -46,11 +46,15 @@
::android::hardware::wifi::supplicant::V1_4::SupplicantStatus;
using SupplicantStatusCodeV1_4 =
::android::hardware::wifi::supplicant::V1_4::SupplicantStatusCode;
+using WpaDriverCapabilitiesMaskV1_4 =
+ ::android::hardware::wifi::supplicant::V1_4::WpaDriverCapabilitiesMask;
class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBaseV1_4 {
public:
virtual void SetUp() override {
SupplicantHidlTestBaseV1_4::SetUp();
+ sta_iface_ = getSupplicantStaIface_1_4(supplicant_);
+ ASSERT_NE(nullptr, sta_iface_.get());
sta_network_ = createSupplicantStaNetwork(supplicant_);
ASSERT_NE(sta_network_.get(), nullptr);
/* variable used to check if the underlying HAL version is 1.4 or
@@ -61,10 +65,21 @@
}
protected:
+ sp<::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface>
+ sta_iface_;
sp<::android::hardware::wifi::supplicant::V1_4::ISupplicantStaNetwork>
v1_4 = nullptr;
// ISupplicantStaNetwork object used for all tests in this fixture.
sp<ISupplicantStaNetwork> sta_network_;
+ bool isSaePkSupported() {
+ uint32_t caps;
+ sta_iface_->getWpaDriverCapabilities_1_4(
+ [&](const SupplicantStatusV1_4& status, uint32_t capsInternal) {
+ EXPECT_EQ(SupplicantStatusCodeV1_4::SUCCESS, status.code);
+ caps = capsInternal;
+ });
+ return !!(caps & WpaDriverCapabilitiesMaskV1_4::SAE_PK);
+ }
};
class NetworkCallback : public ISupplicantStaNetworkCallback {
@@ -106,6 +121,22 @@
});
}
+/*
+ * enable SAE PK only mode
+ */
+TEST_P(SupplicantStaNetworkHidlTest, EnableSaePkOnlyMode) {
+ LOG(INFO) << "SAE-PK Supported: " << isSaePkSupported();
+ SupplicantStatusCodeV1_4 expectedCode =
+ isSaePkSupported() ? SupplicantStatusCodeV1_4::SUCCESS
+ : SupplicantStatusCodeV1_4::FAILURE_UNSUPPORTED;
+ v1_4->enableSaePkOnlyMode(true, [&](const SupplicantStatusV1_4& status) {
+ EXPECT_EQ(expectedCode, status.code);
+ });
+ v1_4->enableSaePkOnlyMode(false, [&](const SupplicantStatusV1_4& status) {
+ EXPECT_EQ(expectedCode, status.code);
+ });
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaNetworkHidlTest);
INSTANTIATE_TEST_CASE_P(
PerInstance, SupplicantStaNetworkHidlTest,