Merge "Revert "Add GESTURE_{X,Y}_OFFSET axes to input HAL""
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 92d7d54..691cf34 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -113,9 +113,12 @@
"android/hardware/audio/core/AudioRoute.aidl",
"android/hardware/audio/core/IConfig.aidl",
"android/hardware/audio/core/IModule.aidl",
+ "android/hardware/audio/core/IStreamCallback.aidl",
"android/hardware/audio/core/IStreamIn.aidl",
"android/hardware/audio/core/IStreamOut.aidl",
"android/hardware/audio/core/ITelephony.aidl",
+ "android/hardware/audio/core/MicrophoneDynamicInfo.aidl",
+ "android/hardware/audio/core/MicrophoneInfo.aidl",
"android/hardware/audio/core/MmapBufferDescriptor.aidl",
"android/hardware/audio/core/ModuleDebug.aidl",
"android/hardware/audio/core/StreamDescriptor.aidl",
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
new file mode 100644
index 0000000..6473d23
--- /dev/null
+++ b/audio/aidl/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "VtsHalAudioCoreTargetTest"
+ }
+ ]
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
index be382c5..0c7ca27 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
@@ -56,6 +56,7 @@
void setMasterVolume(float volume);
boolean getMicMute();
void setMicMute(boolean mute);
+ android.hardware.audio.core.MicrophoneInfo[] getMicrophones();
void updateAudioMode(android.hardware.audio.core.AudioMode mode);
void updateScreenRotation(android.hardware.audio.core.IModule.ScreenRotation rotation);
void updateScreenState(boolean isTurnedOn);
@@ -76,6 +77,7 @@
android.hardware.audio.common.SourceMetadata sourceMetadata;
@nullable android.media.audio.common.AudioOffloadInfo offloadInfo;
long bufferSizeFrames;
+ @nullable android.hardware.audio.core.IStreamCallback callback;
}
@VintfStability
parcelable OpenOutputStreamReturn {
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCallback.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCallback.aidl
new file mode 100644
index 0000000..5a2ab78
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCallback.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.core;
+@VintfStability
+interface IStreamCallback {
+ oneway void onTransferReady();
+ oneway void onError();
+ oneway void onDrainReady();
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
index d5ab3e8..e9c727f 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
@@ -35,5 +35,20 @@
@VintfStability
interface IStreamIn {
void close();
+ android.hardware.audio.core.MicrophoneDynamicInfo[] getActiveMicrophones();
+ android.hardware.audio.core.IStreamIn.MicrophoneDirection getMicrophoneDirection();
+ void setMicrophoneDirection(android.hardware.audio.core.IStreamIn.MicrophoneDirection direction);
+ float getMicrophoneFieldDimension();
+ void setMicrophoneFieldDimension(float zoom);
void updateMetadata(in android.hardware.audio.common.SinkMetadata sinkMetadata);
+ const int MIC_FIELD_DIMENSION_WIDE_ANGLE = -1;
+ const int MIC_FIELD_DIMENSION_NO_ZOOM = 0;
+ const int MIC_FIELD_DIMENSION_MAX_ZOOM = 1;
+ @Backing(type="int") @VintfStability
+ enum MicrophoneDirection {
+ UNSPECIFIED = 0,
+ FRONT = 1,
+ BACK = 2,
+ EXTERNAL = 3,
+ }
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneDynamicInfo.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneDynamicInfo.aidl
new file mode 100644
index 0000000..50a5528
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneDynamicInfo.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable MicrophoneDynamicInfo {
+ @utf8InCpp String id;
+ android.hardware.audio.core.MicrophoneDynamicInfo.ChannelMapping[] channelMapping;
+ @Backing(type="int") @VintfStability
+ enum ChannelMapping {
+ UNUSED = 0,
+ DIRECT = 1,
+ PROCESSED = 2,
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl
new file mode 100644
index 0000000..68c7f88
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable MicrophoneInfo {
+ @utf8InCpp String id;
+ android.media.audio.common.AudioDevice device;
+ android.hardware.audio.core.MicrophoneInfo.Location location = android.hardware.audio.core.MicrophoneInfo.Location.UNKNOWN;
+ int group = -1;
+ int indexInTheGroup = -1;
+ @nullable android.hardware.audio.core.MicrophoneInfo.Sensitivity sensitivity;
+ android.hardware.audio.core.MicrophoneInfo.Directionality directionality = android.hardware.audio.core.MicrophoneInfo.Directionality.UNKNOWN;
+ android.hardware.audio.core.MicrophoneInfo.FrequencyResponsePoint[] frequencyResponse;
+ @nullable android.hardware.audio.core.MicrophoneInfo.Coordinate position;
+ @nullable android.hardware.audio.core.MicrophoneInfo.Coordinate orientation;
+ const int GROUP_UNKNOWN = -1;
+ const int INDEX_IN_THE_GROUP_UNKNOWN = -1;
+ @Backing(type="int") @VintfStability
+ enum Location {
+ UNKNOWN = 0,
+ MAINBODY = 1,
+ MAINBODY_MOVABLE = 2,
+ PERIPHERAL = 3,
+ }
+ @VintfStability
+ parcelable Sensitivity {
+ float leveldBFS;
+ float maxSpldB;
+ float minSpldB;
+ }
+ @Backing(type="int") @VintfStability
+ enum Directionality {
+ UNKNOWN = 0,
+ OMNI = 1,
+ BI_DIRECTIONAL = 2,
+ CARDIOID = 3,
+ HYPER_CARDIOID = 4,
+ SUPER_CARDIOID = 5,
+ }
+ @VintfStability
+ parcelable FrequencyResponsePoint {
+ float frequencyHz;
+ float leveldB;
+ }
+ @VintfStability
+ parcelable Coordinate {
+ float x;
+ float y;
+ float z;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
index 80ee185..467d37b 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
@@ -35,4 +35,5 @@
@JavaDerive(equals=true, toString=true) @VintfStability
parcelable ModuleDebug {
boolean simulateDeviceConnections;
+ int streamTransientStateDelayMs;
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
index 3a77ad1..3a4271b 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
@@ -42,8 +42,9 @@
const int LATENCY_UNKNOWN = -1;
@FixedSize @VintfStability
parcelable Position {
- long frames;
- long timeNs;
+ long frames = -1;
+ long timeNs = -1;
+ const long UNKNOWN = -1;
}
@Backing(type="int") @VintfStability
enum State {
@@ -53,14 +54,23 @@
PAUSED = 4,
DRAINING = 5,
DRAIN_PAUSED = 6,
+ TRANSFERRING = 7,
+ TRANSFER_PAUSED = 8,
ERROR = 100,
}
+ @Backing(type="byte") @VintfStability
+ enum DrainMode {
+ DRAIN_UNSPECIFIED = 0,
+ DRAIN_ALL = 1,
+ DRAIN_EARLY_NOTIFY = 2,
+ }
@FixedSize @VintfStability
union Command {
- int hal_reserved_exit;
+ int halReservedExit;
+ android.media.audio.common.Void getStatus;
android.media.audio.common.Void start;
int burst;
- android.media.audio.common.Void drain;
+ android.hardware.audio.core.StreamDescriptor.DrainMode drain;
android.media.audio.common.Void standby;
android.media.audio.common.Void pause;
android.media.audio.common.Void flush;
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index be40051..786d5ee 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -21,9 +21,11 @@
import android.hardware.audio.core.AudioMode;
import android.hardware.audio.core.AudioPatch;
import android.hardware.audio.core.AudioRoute;
+import android.hardware.audio.core.IStreamCallback;
import android.hardware.audio.core.IStreamIn;
import android.hardware.audio.core.IStreamOut;
import android.hardware.audio.core.ITelephony;
+import android.hardware.audio.core.MicrophoneInfo;
import android.hardware.audio.core.ModuleDebug;
import android.hardware.audio.core.StreamDescriptor;
import android.media.audio.common.AudioOffloadInfo;
@@ -53,9 +55,13 @@
* the HAL module behavior that would otherwise require human intervention.
*
* The HAL module must throw an error if there is an attempt to change
- * the debug behavior for the aspect which is currently in use.
+ * the debug behavior for the aspect which is currently in use, or when
+ * the value of any of the debug flags is invalid. See 'ModuleDebug' for
+ * the full list of constraints.
*
* @param debug The debug options.
+ * @throws EX_ILLEGAL_ARGUMENT If some of the configuration parameters are
+ * invalid.
* @throws EX_ILLEGAL_STATE If the flag(s) being changed affect functionality
* which is currently in use.
*/
@@ -316,9 +322,13 @@
* 'setAudioPortConfig' method. Existence of an audio patch involving this
* port configuration is not required for successful opening of a stream.
*
- * If the port configuration has 'COMPRESS_OFFLOAD' output flag set,
- * the framework must provide additional information about the encoded
- * audio stream in 'offloadInfo' argument.
+ * If the port configuration has the 'COMPRESS_OFFLOAD' output flag set,
+ * the client must provide additional information about the encoded
+ * audio stream in the 'offloadInfo' argument.
+ *
+ * If the port configuration has the 'NON_BLOCKING' output flag set,
+ * the client must provide a callback for asynchronous notifications
+ * in the 'callback' argument.
*
* The requested buffer size is expressed in frames, thus the actual size
* in bytes depends on the audio port configuration. Also, the HAL module
@@ -354,6 +364,8 @@
* - If the offload info is not provided for an offload
* port configuration.
* - If a buffer of the requested size can not be provided.
+ * - If the callback is not provided for a non-blocking
+ * port configuration.
* @throws EX_ILLEGAL_STATE In the following cases:
* - If the port config already has a stream opened on it.
* - If the limit on the open stream count for the port has
@@ -372,6 +384,8 @@
@nullable AudioOffloadInfo offloadInfo;
/** Requested audio I/O buffer minimum size, in frames. */
long bufferSizeFrames;
+ /** Client callback interface for the non-blocking output mode. */
+ @nullable IStreamCallback callback;
}
@VintfStability
parcelable OpenOutputStreamReturn {
@@ -592,6 +606,22 @@
void setMicMute(boolean mute);
/**
+ * Provide information describing built-in microphones of the HAL module.
+ *
+ * If there are no built-in microphones in the HAL module, it must return an
+ * empty vector. If there are microphones, but the HAL module does not
+ * possess the required information about them, EX_UNSUPPORTED_OPERATION
+ * must be thrown.
+ *
+ * If this method is supported by the HAL module, it must also support
+ * 'IStreamIn.getActiveMicrophones' method.
+ *
+ * @return The vector with information about each microphone.
+ * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+ */
+ MicrophoneInfo[] getMicrophones();
+
+ /**
* Notify the HAL module on the change of the current audio mode.
*
* The current audio mode is always controlled by the client. This is an
diff --git a/audio/aidl/android/hardware/audio/core/IStreamCallback.aidl b/audio/aidl/android/hardware/audio/core/IStreamCallback.aidl
new file mode 100644
index 0000000..440ab25
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IStreamCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audio.core;
+
+/**
+ * This interface is used to indicate completion of asynchronous operations.
+ * See the state machines referenced by StreamDescriptor for details.
+ */
+@VintfStability
+oneway interface IStreamCallback {
+ /**
+ * Indicate that the stream is ready for next data exchange.
+ */
+ void onTransferReady();
+ /**
+ * Indicate that an irrecoverable error has occurred during the last I/O
+ * operation. After sending this callback, the stream enters the 'ERROR'
+ * state.
+ */
+ void onError();
+ /**
+ * Indicate that the stream has finished draining. This is only used
+ * for output streams because for input streams draining is performed
+ * by the client.
+ */
+ void onDrainReady();
+}
diff --git a/audio/aidl/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
index 0c3e3d1..0b6e02c 100644
--- a/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
+++ b/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
@@ -17,6 +17,7 @@
package android.hardware.audio.core;
import android.hardware.audio.common.SinkMetadata;
+import android.hardware.audio.core.MicrophoneDynamicInfo;
/**
* This interface provides means for receiving audio data from input devices.
@@ -39,6 +40,92 @@
void close();
/**
+ * Provides information on the microphones that are active for this stream.
+ *
+ * The returned array contains dynamic information on the microphones which
+ * are active for this stream. Each entry in the returned array must have a
+ * corresponding entry (matched by the 'MicrophoneInfo.id' field value) in
+ * the list of all available microphones which is provided by the
+ * 'IModule.getMicrophones' method.
+ *
+ * This method must be supported by the HAL module if
+ * 'IModule.getMicrophones' is supported.
+ *
+ * @return The vector with dynamic information on the microphones.
+ * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+ */
+ MicrophoneDynamicInfo[] getActiveMicrophones();
+
+ @VintfStability
+ @Backing(type="int")
+ enum MicrophoneDirection {
+ /**
+ * Don't do any directionality processing of the activated microphone(s).
+ */
+ UNSPECIFIED = 0,
+ /**
+ * Optimize capture for audio coming from the screen-side of the device.
+ */
+ FRONT = 1,
+ /**
+ * Optimize capture for audio coming from the side of the device opposite the screen.
+ */
+ BACK = 2,
+ /**
+ * Optimize capture for audio coming from an off-device microphone.
+ */
+ EXTERNAL = 3,
+ }
+ /**
+ * Get the current logical microphone direction.
+ *
+ * @return The current logical microphone direction.
+ * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+ */
+ MicrophoneDirection getMicrophoneDirection();
+ /**
+ * Set the current logical microphone direction.
+ *
+ * The client sets this parameter in order to specify its preference for
+ * optimizing the direction of capture when multiple microphones are in use.
+ *
+ * @param direction The preferred capture direction.
+ * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the operation is not supported.
+ */
+ void setMicrophoneDirection(MicrophoneDirection direction);
+
+ const int MIC_FIELD_DIMENSION_WIDE_ANGLE = -1;
+ const int MIC_FIELD_DIMENSION_NO_ZOOM = 0;
+ const int MIC_FIELD_DIMENSION_MAX_ZOOM = 1;
+ /**
+ * Get the "zoom factor" for the logical microphone.
+ *
+ * The returned value must be within the range of [-1.0, 1.0] (see
+ * MIC_FIELD_DIMENSION_* constants).
+ *
+ * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+ */
+ float getMicrophoneFieldDimension();
+ /**
+ * Set the "zoom factor" for the logical microphone.
+ *
+ * If multiple microphones are in use, the provided zoom factor must be
+ * treated as a preference for their combined field dimension. The zoom
+ * factor must be within the range of [-1.0, 1.0] (see MIC_FIELD_DIMENSION_*
+ * constants).
+ *
+ * @param zoom The preferred field dimension of the microphone capture.
+ * @throws EX_ILLEGAL_ARGUMENT If the dimension value is outside of the range.
+ * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the operation is not supported.
+ */
+ void setMicrophoneFieldDimension(float zoom);
+
+ /**
* Update stream metadata.
*
* Updates the metadata initially provided at the stream creation.
diff --git a/audio/aidl/android/hardware/audio/core/MicrophoneDynamicInfo.aidl b/audio/aidl/android/hardware/audio/core/MicrophoneDynamicInfo.aidl
new file mode 100644
index 0000000..36cc51f
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/MicrophoneDynamicInfo.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audio.core;
+
+/**
+ * Structure providing dynamic information on a microphone. This information
+ * changes between recording sessions.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable MicrophoneDynamicInfo {
+ /**
+ * Unique alphanumeric id for the microphone. It must match the id of one of
+ * the 'MicrophoneInfo' entries returned by 'IModule.getMicrophones'.
+ */
+ @utf8InCpp String id;
+
+ @VintfStability
+ @Backing(type="int")
+ enum ChannelMapping {
+ /** Channel not used. */
+ UNUSED = 0,
+ /** Channel is used and the signal is not processed. */
+ DIRECT = 1,
+ /** Channel is used and the signal has some processing. */
+ PROCESSED = 2,
+ }
+ /**
+ * The vector is indexes by zero-based channels of the microphone, thus the
+ * element '0' corresponds to the first channel, '1' is the second, etc. The
+ * vector must contain at least 1 element.
+ */
+ ChannelMapping[] channelMapping;
+}
diff --git a/audio/aidl/android/hardware/audio/core/MicrophoneInfo.aidl b/audio/aidl/android/hardware/audio/core/MicrophoneInfo.aidl
new file mode 100644
index 0000000..3b8c7f3
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/MicrophoneInfo.aidl
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audio.core;
+
+import android.media.audio.common.AudioDevice;
+
+/**
+ * Structure providing static information on a microphone. This information
+ * never changes during the lifetime of the IModule which owns the microphone.
+ * The information presented in this structure indicates the location and
+ * orientation of the microphone on the device as well as useful information
+ * like frequency response and sensitivity.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable MicrophoneInfo {
+ /**
+ * Unique alphanumeric id for the microphone. It must remain the same across
+ * device reboots. The client must never attempt to parse the value of this
+ * field.
+ */
+ @utf8InCpp String id;
+ /**
+ * Describes the location of the microphone in terms of managed audio devices.
+ */
+ AudioDevice device;
+
+ @VintfStability
+ @Backing(type="int")
+ enum Location {
+ /** Microphone location is unknown. */
+ UNKNOWN = 0,
+ /** The microphone is located on the main body of the device. */
+ MAINBODY = 1,
+ /** The microphone is located on a movable main body of the device. */
+ MAINBODY_MOVABLE = 2,
+ /** The microphone is located on a peripheral. */
+ PERIPHERAL = 3,
+ }
+ /** Location of the microphone in regard to the body of the device */
+ Location location = Location.UNKNOWN;
+
+ /**
+ * This value is used when the group of the microphone is unknown.
+ */
+ const int GROUP_UNKNOWN = -1;
+ /**
+ * An identifier to group related microphones together, for example,
+ * microphones of a microphone array should all belong to the same group.
+ * Note that microphones assigned to 'GROUP_UNKNOWN' do not form a group.
+ */
+ int group = GROUP_UNKNOWN;
+ /**
+ * This value is used when the index in the group of the microphone is
+ * unknown.
+ */
+ const int INDEX_IN_THE_GROUP_UNKNOWN = -1;
+ /**
+ * Index of this microphone within the group. The pair (group, index) must
+ * be unique within the same HAL module, except the pair
+ * (GROUP_UNKNOWN, INDEX_IN_THE_GROUP_UNKNOWN).
+ */
+ int indexInTheGroup = INDEX_IN_THE_GROUP_UNKNOWN;
+
+ @VintfStability
+ parcelable Sensitivity {
+ /** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL. */
+ float leveldBFS;
+ /** Level in dB of the max SPL supported at 1000 Hz */
+ float maxSpldB;
+ /** Level in dB of the min SPL supported at 1000 Hz */
+ float minSpldB;
+ }
+ /**
+ * If provided, must describe acceptable sound pressure levels (SPL)
+ * for a 1 kHz sine wave, and the resulting level in dBFS.
+ */
+ @nullable Sensitivity sensitivity;
+
+ @VintfStability
+ @Backing(type="int")
+ enum Directionality {
+ UNKNOWN = 0,
+ OMNI = 1,
+ BI_DIRECTIONAL = 2,
+ CARDIOID = 3,
+ HYPER_CARDIOID = 4,
+ SUPER_CARDIOID = 5,
+ }
+ /**
+ * The standard polar pattern of the microphone.
+ */
+ Directionality directionality = Directionality.UNKNOWN;
+
+ /**
+ * A (frequency, level) pair. Used to represent frequency response.
+ */
+ @VintfStability
+ parcelable FrequencyResponsePoint {
+ float frequencyHz;
+ float leveldB;
+ }
+ /**
+ * Vector with ordered frequency responses (from low to high frequencies)
+ * with the frequency response of the microphone. Levels are in dB,
+ * relative to level at 1000 Hz.
+ */
+ FrequencyResponsePoint[] frequencyResponse;
+
+ /**
+ * A 3D point used to represent position or orientation of a microphone.
+ */
+ @VintfStability
+ parcelable Coordinate {
+ float x;
+ float y;
+ float z;
+ }
+ /**
+ * If provided, must specify distances of the microphone's capsule, in
+ * meters, from the bottom-left-back corner of the bounding box of device in
+ * its natural orientation (PORTRAIT for phones, LANDSCAPE for tablets, TVs,
+ * etc).
+ */
+ @nullable Coordinate position;
+ /**
+ * If provided, describes the normalized point which defines the main
+ * orientation of the microphone's capsule.
+ * Magnitude = sqrt(x^2 + y^2 + z^2) = 1.
+ */
+ @nullable Coordinate orientation;
+}
diff --git a/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl b/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
index 858a9bd..871a5c9 100644
--- a/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
+++ b/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
@@ -35,4 +35,19 @@
* profiles.
*/
boolean simulateDeviceConnections;
+ /**
+ * Must be non-negative. When set to non-zero, HAL module must delay
+ * transition from "transient" stream states (see StreamDescriptor.aidl)
+ * by the specified amount of milliseconds. The purpose of this delay
+ * is to allow VTS to test sending of stream commands while the stream is
+ * in a transient state. The delay must apply to newly created streams,
+ * it is not required to apply the delay to already opened streams.
+ *
+ * Note: the drawback of enabling this delay for asynchronous (non-blocking)
+ * modes is that sending of callbacks will also be delayed, because
+ * callbacks are sent once the stream state machine exits a transient
+ * state. Thus, it's not recommended to use it with tests that require
+ * waiting for an async callback.
+ */
+ int streamTransientStateDelayMs;
}
diff --git a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
index 2b1fc99..65ea9ef 100644
--- a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
@@ -84,13 +84,13 @@
* are different.
*
* State machines of both input and output streams start from the 'STANDBY'
- * state. Transitions between states happen naturally with changes in the
+ * state. Transitions between states happen naturally with changes in the
* states of the model elements. For simplicity, we restrict the change to one
* element only, for example, in the 'STANDBY' state, either the producer or the
* consumer can become active, but not both at the same time. States 'STANDBY',
* 'IDLE', 'READY', and '*PAUSED' are "stable"—they require an external event,
* whereas a change from the 'DRAINING' state can happen with time as the buffer
- * gets empty.
+ * gets empty, thus it's a "transient" state.
*
* The state machine for input streams is defined in the `stream-in-sm.gv` file,
* for output streams—in the `stream-out-sm.gv` file. State machines define how
@@ -100,6 +100,28 @@
* client can never observe a stream with a functioning command queue in this
* state. The 'ERROR' state is a special state which the state machine enters
* when an unrecoverable hardware error is detected by the HAL module.
+ *
+ * Non-blocking (asynchronous) modes introduce a new 'TRANSFERRING' state, which
+ * the state machine can enter after replying to the 'burst' command, instead of
+ * staying in the 'ACTIVE' state. In this case the client gets unblocked
+ * earlier, while the actual audio delivery to / from the observer is not
+ * complete yet. Once the HAL module is ready for the next transfer, it notifies
+ * the client via a oneway callback, and the machine switches to 'ACTIVE'
+ * state. The 'TRANSFERRING' state is thus "transient", similar to the
+ * 'DRAINING' state. For output streams, asynchronous transfer can be paused,
+ * and it's another new state: 'TRANSFER_PAUSED'. It differs from 'PAUSED' by
+ * the fact that no new writes are allowed. Please see 'stream-in-async-sm.gv'
+ * and 'stream-out-async-sm.gv' files for details. Below is the table summary
+ * for asynchronous only-states:
+ *
+ * Producer | Buffer state | Consumer | Applies | State
+ * active? | | active? | to |
+ * ==========|==============|==========|=========|==============================
+ * Yes | Not empty | Yes | Both | TRANSFERRING, s/w x-runs counted
+ * ----------|--------------|----------|---------|-----------------------------
+ * Yes | Not empty | No | Output | TRANSFER_PAUSED,
+ * | | | | h/w emits silence.
+ *
*/
@JavaDerive(equals=true, toString=true)
@VintfStability
@@ -116,10 +138,15 @@
@VintfStability
@FixedSize
parcelable Position {
+ /**
+ * The value used when the position can not be reported by the HAL
+ * module.
+ */
+ const long UNKNOWN = -1;
/** Frame count. */
- long frames;
+ long frames = UNKNOWN;
/** Timestamp in nanoseconds. */
- long timeNs;
+ long timeNs = UNKNOWN;
}
@VintfStability
@@ -166,11 +193,24 @@
/**
* Used for output streams only, pauses draining. This state is similar
* to the 'PAUSED' state, except that the client is not adding any
- * new data. If it emits a 'BURST' command, this brings the stream
+ * new data. If it emits a 'burst' command, this brings the stream
* into the regular 'PAUSED' state.
*/
DRAIN_PAUSED = 6,
/**
+ * Used only for streams in asynchronous mode. The stream enters this
+ * state after receiving a 'burst' command and returning control back
+ * to the client, thus unblocking it.
+ */
+ TRANSFERRING = 7,
+ /**
+ * Used only for output streams in asynchronous mode only. The stream
+ * enters this state after receiving a 'pause' command while being in
+ * the 'TRANSFERRING' state. Unlike 'PAUSED' state, this state does not
+ * accept new writes.
+ */
+ TRANSFER_PAUSED = 8,
+ /**
* The ERROR state is entered when the stream has encountered an
* irrecoverable error from the lower layer. After entering it, the
* stream can only be closed.
@@ -178,6 +218,29 @@
ERROR = 100,
}
+ @VintfStability
+ @Backing(type="byte")
+ enum DrainMode {
+ /**
+ * Unspecified—used with input streams only, because the client controls
+ * draining.
+ */
+ DRAIN_UNSPECIFIED = 0,
+ /**
+ * Used with output streams only, the HAL module indicates drain
+ * completion when all remaining audio data has been consumed.
+ */
+ DRAIN_ALL = 1,
+ /**
+ * Used with output streams only, the HAL module indicates drain
+ * completion shortly before all audio data has been consumed in order
+ * to give the client an opportunity to provide data for the next track
+ * for gapless playback. The exact amount of provided time is specific
+ * to the HAL implementation.
+ */
+ DRAIN_EARLY_NOTIFY = 2,
+ }
+
/**
* Used for sending commands to the HAL module. The client writes into
* the queue, the HAL module reads. The queue can only contain a single
@@ -198,7 +261,14 @@
* implementation must pass a random cookie as the command argument,
* which is only known to the implementation.
*/
- int hal_reserved_exit;
+ int halReservedExit;
+ /**
+ * Retrieve the current state of the stream. This command must be
+ * processed by the stream in any state. The stream must provide current
+ * positions, counters, and its state in the reply. This command must be
+ * handled by the HAL module without any observable side effects.
+ */
+ Void getStatus;
/**
* See the state machines on the applicability of this command to
* different states.
@@ -215,15 +285,14 @@
* read from the hardware into the 'audio.fmq' queue.
*
* In both cases it is allowed for this field to contain any
- * non-negative number. The value 0 can be used if the client only needs
- * to retrieve current positions and latency. Any sufficiently big value
- * which exceeds the size of the queue's area which is currently
- * available for reading or writing by the HAL module must be trimmed by
- * the HAL module to the available size. Note that the HAL module is
- * allowed to consume or provide less data than requested, and it must
- * return the amount of actually read or written data via the
- * 'Reply.fmqByteCount' field. Thus, only attempts to pass a negative
- * number must be constituted as a client's error.
+ * non-negative number. Any sufficiently big value which exceeds the
+ * size of the queue's area which is currently available for reading or
+ * writing by the HAL module must be trimmed by the HAL module to the
+ * available size. Note that the HAL module is allowed to consume or
+ * provide less data than requested, and it must return the amount of
+ * actually read or written data via the 'Reply.fmqByteCount'
+ * field. Thus, only attempts to pass a negative number must be
+ * constituted as a client's error.
*
* Differences for the MMap No IRQ mode:
*
@@ -233,13 +302,16 @@
* with sending of this command.
*
* - the value must always be set to 0.
+ *
+ * See the state machines on the applicability of this command to
+ * different states.
*/
int burst;
/**
* See the state machines on the applicability of this command to
* different states.
*/
- Void drain;
+ DrainMode drain;
/**
* See the state machines on the applicability of this command to
* different states.
@@ -286,10 +358,6 @@
* - STATUS_INVALID_OPERATION: the command is not applicable in the
* current state of the stream, or to this
* type of the stream;
- * - STATUS_NO_INIT: positions can not be reported because the mix port
- * is not connected to any producer or consumer, or
- * because the HAL module does not support positions
- * reporting for this AudioSource (on input streams).
* - STATUS_NOT_ENOUGH_DATA: a read or write error has
* occurred for the 'audio.fmq' queue;
*/
@@ -307,9 +375,11 @@
*/
int fmqByteCount;
/**
- * It is recommended to report the current position for any command.
- * If the position can not be reported, the 'status' field must be
- * set to 'NO_INIT'.
+ * It is recommended to report the current position for any command. If
+ * the position can not be reported, for example because the mix port is
+ * not connected to any producer or consumer, or because the HAL module
+ * does not support positions reporting for this AudioSource (on input
+ * streams), the 'Position::UNKNOWN' value must be used.
*
* For output streams: the moment when the specified stream position
* was presented to an external observer (i.e. presentation position).
@@ -401,6 +471,10 @@
* into 'reply' queue, and hangs on waiting on a read from
* the 'command' queue.
* 6. The client wakes up due to 5. and reads the reply.
+ * Note: in non-blocking mode, when the HAL module goes to
+ * the 'TRANSFERRING' state (as indicated by the 'reply.state'
+ * field), the client must wait for the 'IStreamCallback.onTransferReady'
+ * notification to arrive before starting the next burst.
*
* For input streams the following sequence of operations is used:
* 1. The client writes the BURST command into the 'command' queue,
@@ -415,6 +489,10 @@
* 5. The client wakes up due to 4.
* 6. The client reads the reply and audio data. The client must
* always read from the FMQ all the data it contains.
+ * Note: in non-blocking mode, when the HAL module goes to
+ * the 'TRANSFERRING' state (as indicated by the 'reply.state'
+ * field) the client must wait for the 'IStreamCallback.onTransferReady'
+ * notification to arrive before starting the next burst.
*
*/
MQDescriptor<byte, SynchronizedReadWrite> fmq;
diff --git a/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv
new file mode 100644
index 0000000..818b18e
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// To render: dot -Tpng stream-in-async-sm.gv -o stream-in-async-sm.png
+digraph stream_in_async_state_machine {
+ node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
+ node [shape=point width=0.5] F;
+ node [shape=oval width=1];
+ node [fillcolor=lightgreen] STANDBY; // buffer is empty
+ node [fillcolor=tomato] CLOSED;
+ node [fillcolor=tomato] ERROR;
+ node [style=dashed] ANY_STATE;
+ node [fillcolor=lightblue style=filled];
+ // Note that when the producer (h/w) is passive, "burst" operations
+ // complete synchronously, bypassing the TRANSFERRING state.
+ I -> STANDBY;
+ STANDBY -> IDLE [label="start"]; // producer -> active
+ IDLE -> STANDBY [label="standby"]; // producer -> passive, buffer is cleared
+ IDLE -> TRANSFERRING [label="burst"]; // consumer -> active
+ ACTIVE -> PAUSED [label="pause"]; // consumer -> passive
+ ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ ACTIVE -> TRANSFERRING [label="burst"];
+ TRANSFERRING -> ACTIVE [label="←IStreamCallback.onTransferReady"];
+ TRANSFERRING -> PAUSED [label="pause"]; // consumer -> passive
+ TRANSFERRING -> DRAINING [label="drain"]; // producer -> passive
+ PAUSED -> TRANSFERRING [label="burst"]; // consumer -> active
+ PAUSED -> STANDBY [label="flush"]; // producer -> passive, buffer is cleared
+ DRAINING -> DRAINING [label="burst"];
+ DRAINING -> ACTIVE [label="start"]; // producer -> active
+ DRAINING -> STANDBY [label="<empty buffer>"]; // consumer deactivates
+ IDLE -> ERROR [label="←IStreamCallback.onError"];
+ PAUSED -> ERROR [label="←IStreamCallback.onError"];
+ TRANSFERRING -> ERROR [label="←IStreamCallback.onError"];
+ ANY_STATE -> CLOSED [label="→IStream*.close"];
+ CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
new file mode 100644
index 0000000..e25b15a
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
@@ -0,0 +1,57 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// To render: dot -Tpng stream-out-async-sm.gv -o stream-out-async-sm.png
+digraph stream_out_async_state_machine {
+ node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
+ node [shape=point width=0.5] F;
+ node [shape=oval width=1];
+ node [fillcolor=lightgreen] STANDBY; // buffer is empty
+ node [fillcolor=lightgreen] IDLE; // buffer is empty
+ node [fillcolor=tomato] CLOSED;
+ node [fillcolor=tomato] ERROR;
+ node [style=dashed] ANY_STATE;
+ node [fillcolor=lightblue style=filled];
+ // Note that when the consumer (h/w) is passive, "burst" operations
+ // complete synchronously, bypassing the TRANSFERRING state.
+ I -> STANDBY;
+ STANDBY -> IDLE [label="start"]; // consumer -> active
+ STANDBY -> PAUSED [label="burst"]; // producer -> active
+ IDLE -> STANDBY [label="standby"]; // consumer -> passive
+ IDLE -> TRANSFERRING [label="burst"]; // producer -> active
+ ACTIVE -> PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ ACTIVE -> TRANSFERRING [label="burst"]; // early unblocking
+ ACTIVE -> ACTIVE [label="burst"]; // full write
+ TRANSFERRING -> ACTIVE [label="←IStreamCallback.onTransferReady"];
+ TRANSFERRING -> TRANSFER_PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ TRANSFERRING -> DRAINING [label="drain"]; // producer -> passive
+ TRANSFER_PAUSED -> TRANSFERRING [label="start"]; // consumer -> active
+ TRANSFER_PAUSED -> DRAIN_PAUSED [label="drain"]; // producer -> passive
+ TRANSFER_PAUSED -> IDLE [label="flush"]; // buffer is cleared
+ PAUSED -> PAUSED [label="burst"];
+ PAUSED -> ACTIVE [label="start"]; // consumer -> active
+ PAUSED -> IDLE [label="flush"]; // producer -> passive, buffer is cleared
+ DRAINING -> IDLE [label="←IStreamCallback.onDrainReady"];
+ DRAINING -> TRANSFERRING [label="burst"]; // producer -> active
+ DRAINING -> DRAIN_PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ DRAIN_PAUSED -> DRAINING [label="start"]; // consumer -> active
+ DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"]; // producer -> active
+ DRAIN_PAUSED -> IDLE [label="flush"]; // buffer is cleared
+ IDLE -> ERROR [label="←IStreamCallback.onError"];
+ DRAINING -> ERROR [label="←IStreamCallback.onError"];
+ TRANSFERRING -> ERROR [label="←IStreamCallback.onError"];
+ ANY_STATE -> CLOSED [label="→IStream*.close"];
+ CLOSED -> F;
+}
diff --git a/audio/aidl/common/StreamWorker.cpp b/audio/aidl/common/StreamWorker.cpp
index dda0e4a..0d2121c 100644
--- a/audio/aidl/common/StreamWorker.cpp
+++ b/audio/aidl/common/StreamWorker.cpp
@@ -25,15 +25,20 @@
bool ThreadController::start(const std::string& name, int priority) {
mThreadName = name;
mThreadPriority = priority;
- mWorker = std::thread(&ThreadController::workerThread, this);
+ if (kTestSingleThread != name) {
+ mWorker = std::thread(&ThreadController::workerThread, this);
+ } else {
+ // Simulate the case when the workerThread completes prior
+ // to the moment when we being waiting for its start.
+ workerThread();
+ }
std::unique_lock<std::mutex> lock(mWorkerLock);
android::base::ScopedLockAssertion lock_assertion(mWorkerLock);
mWorkerCv.wait(lock, [&]() {
android::base::ScopedLockAssertion lock_assertion(mWorkerLock);
- return mWorkerState == WorkerState::RUNNING || !mError.empty();
+ return mWorkerState != WorkerState::INITIAL || !mError.empty();
});
- mWorkerStateChangeRequest = false;
- return mWorkerState == WorkerState::RUNNING;
+ return mError.empty();
}
void ThreadController::stop() {
@@ -81,8 +86,8 @@
void ThreadController::workerThread() {
using Status = StreamLogic::Status;
- std::string error = mLogic->init();
- if (error.empty() && !mThreadName.empty()) {
+ std::string error;
+ if (!mThreadName.empty()) {
std::string compliantName(mThreadName.substr(0, 15));
if (int errCode = pthread_setname_np(pthread_self(), compliantName.c_str()); errCode != 0) {
error.append("Failed to set thread name: ").append(strerror(errCode));
@@ -94,6 +99,9 @@
error.append("Failed to set thread priority: ").append(strerror(errCode));
}
}
+ if (error.empty()) {
+ error.append(mLogic->init());
+ }
{
std::lock_guard<std::mutex> lock(mWorkerLock);
mWorkerState = error.empty() ? WorkerState::RUNNING : WorkerState::STOPPED;
diff --git a/audio/aidl/common/include/StreamWorker.h b/audio/aidl/common/include/StreamWorker.h
index ab2ec26..e9c1070 100644
--- a/audio/aidl/common/include/StreamWorker.h
+++ b/audio/aidl/common/include/StreamWorker.h
@@ -32,7 +32,7 @@
namespace internal {
class ThreadController {
- enum class WorkerState { STOPPED, RUNNING, PAUSE_REQUESTED, PAUSED, RESUME_REQUESTED };
+ enum class WorkerState { INITIAL, STOPPED, RUNNING, PAUSE_REQUESTED, PAUSED, RESUME_REQUESTED };
public:
explicit ThreadController(StreamLogic* logic) : mLogic(logic) {}
@@ -76,7 +76,7 @@
std::thread mWorker;
std::mutex mWorkerLock;
std::condition_variable mWorkerCv;
- WorkerState mWorkerState GUARDED_BY(mWorkerLock) = WorkerState::STOPPED;
+ WorkerState mWorkerState GUARDED_BY(mWorkerLock) = WorkerState::INITIAL;
std::string mError GUARDED_BY(mWorkerLock);
// The atomic lock-free variable is used to prevent priority inversions
// that can occur when a high priority worker tries to acquire the lock
@@ -90,6 +90,9 @@
std::atomic<bool> mWorkerStateChangeRequest GUARDED_BY(mWorkerLock) = false;
};
+// A special thread name used in tests only.
+static const std::string kTestSingleThread = "__testST__";
+
} // namespace internal
class StreamLogic {
diff --git a/audio/aidl/common/tests/streamworker_tests.cpp b/audio/aidl/common/tests/streamworker_tests.cpp
index 8ea8424..f7a30b9 100644
--- a/audio/aidl/common/tests/streamworker_tests.cpp
+++ b/audio/aidl/common/tests/streamworker_tests.cpp
@@ -283,4 +283,16 @@
EXPECT_EQ(priority, worker.getPriority());
}
+TEST_P(StreamWorkerTest, DeferredStartCheckNoError) {
+ stream.setStopStatus();
+ EXPECT_TRUE(worker.start(android::hardware::audio::common::internal::kTestSingleThread));
+ EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, DeferredStartCheckWithError) {
+ stream.setErrorStatus();
+ EXPECT_FALSE(worker.start(android::hardware::audio::common::internal::kTestSingleThread));
+ EXPECT_TRUE(worker.hasError());
+}
+
INSTANTIATE_TEST_SUITE_P(StreamWorker, StreamWorkerTest, testing::Bool());
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index a3e5ff7..280814f 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -243,6 +243,13 @@
AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
+ MicrophoneInfo mic;
+ mic.id = "zero";
+ mic.device = zeroInDevice.ext.get<AudioPortExt::Tag::device>().device;
+ mic.group = 0;
+ mic.indexInTheGroup = 0;
+ c.microphones = std::vector<MicrophoneInfo>{mic};
+
AudioPort primaryInMix =
createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(2, 2));
primaryInMix.profiles.push_back(
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 6863fe3..1e561d4 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -31,6 +31,7 @@
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioFormatDescription;
using aidl::android::media::audio::common::AudioFormatType;
using aidl::android::media::audio::common::AudioInputFlags;
@@ -97,6 +98,7 @@
}
ndk::ScopedAStatus Module::createStreamContext(int32_t in_portConfigId, int64_t in_bufferSizeFrames,
+ std::shared_ptr<IStreamCallback> asyncCallback,
StreamContext* out_context) {
if (in_bufferSizeFrames <= 0) {
LOG(ERROR) << __func__ << ": non-positive buffer size " << in_bufferSizeFrames;
@@ -135,8 +137,9 @@
StreamContext temp(
std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
- frameSize,
- std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames));
+ portConfigIt->format.value(), portConfigIt->channelMask.value(),
+ std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
+ asyncCallback, mDebug.streamTransientStateDelayMs);
if (temp.isValid()) {
*out_context = std::move(temp);
} else {
@@ -148,6 +151,39 @@
return ndk::ScopedAStatus::ok();
}
+std::vector<AudioDevice> Module::findConnectedDevices(int32_t portConfigId) {
+ std::vector<AudioDevice> result;
+ auto& ports = getConfig().ports;
+ auto portIds = portIdsFromPortConfigIds(findConnectedPortConfigIds(portConfigId));
+ for (auto it = portIds.begin(); it != portIds.end(); ++it) {
+ auto portIt = findById<AudioPort>(ports, *it);
+ if (portIt != ports.end() && portIt->ext.getTag() == AudioPortExt::Tag::device) {
+ result.push_back(portIt->ext.template get<AudioPortExt::Tag::device>().device);
+ }
+ }
+ return result;
+}
+
+std::set<int32_t> Module::findConnectedPortConfigIds(int32_t portConfigId) {
+ std::set<int32_t> result;
+ auto patchIdsRange = mPatches.equal_range(portConfigId);
+ auto& patches = getConfig().patches;
+ for (auto it = patchIdsRange.first; it != patchIdsRange.second; ++it) {
+ auto patchIt = findById<AudioPatch>(patches, it->second);
+ if (patchIt == patches.end()) {
+ LOG(FATAL) << __func__ << ": patch with id " << it->second << " taken from mPatches "
+ << "not found in the configuration";
+ }
+ if (std::find(patchIt->sourcePortConfigIds.begin(), patchIt->sourcePortConfigIds.end(),
+ portConfigId) != patchIt->sourcePortConfigIds.end()) {
+ result.insert(patchIt->sinkPortConfigIds.begin(), patchIt->sinkPortConfigIds.end());
+ } else {
+ result.insert(patchIt->sourcePortConfigIds.begin(), patchIt->sourcePortConfigIds.end());
+ }
+ }
+ return result;
+}
+
ndk::ScopedAStatus Module::findPortIdForNewStream(int32_t in_portConfigId, AudioPort** port) {
auto& configs = getConfig().portConfigs;
auto portConfigIt = findById<AudioPortConfig>(configs, in_portConfigId);
@@ -186,6 +222,19 @@
return ndk::ScopedAStatus::ok();
}
+template <typename C>
+std::set<int32_t> Module::portIdsFromPortConfigIds(C portConfigIds) {
+ std::set<int32_t> result;
+ auto& portConfigs = getConfig().portConfigs;
+ for (auto it = portConfigIds.begin(); it != portConfigIds.end(); ++it) {
+ auto portConfigIt = findById<AudioPortConfig>(portConfigs, *it);
+ if (portConfigIt != portConfigs.end()) {
+ result.insert(portConfigIt->portId);
+ }
+ }
+ return result;
+}
+
internal::Configuration& Module::getConfig() {
if (!mConfig) {
mConfig.reset(new internal::Configuration(internal::getNullPrimaryConfiguration()));
@@ -222,12 +271,16 @@
idsToConnect.insert(newPatch.sinkPortConfigIds.begin(), newPatch.sinkPortConfigIds.end());
std::for_each(idsToDisconnect.begin(), idsToDisconnect.end(), [&](const auto& portConfigId) {
if (idsToConnect.count(portConfigId) == 0) {
- mStreams.setStreamIsConnected(portConfigId, false);
+ LOG(DEBUG) << "The stream on port config id " << portConfigId << " is not connected";
+ mStreams.setStreamIsConnected(portConfigId, {});
}
});
std::for_each(idsToConnect.begin(), idsToConnect.end(), [&](const auto& portConfigId) {
if (idsToDisconnect.count(portConfigId) == 0) {
- mStreams.setStreamIsConnected(portConfigId, true);
+ const auto connectedDevices = findConnectedDevices(portConfigId);
+ LOG(DEBUG) << "The stream on port config id " << portConfigId
+ << " is connected to: " << ::android::internal::ToString(connectedDevices);
+ mStreams.setStreamIsConnected(portConfigId, connectedDevices);
}
});
}
@@ -242,6 +295,11 @@
<< "while having external devices connected";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
+ if (in_debug.streamTransientStateDelayMs < 0) {
+ LOG(ERROR) << __func__ << ": streamTransientStateDelayMs is negative: "
+ << in_debug.streamTransientStateDelayMs;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
mDebug = in_debug;
return ndk::ScopedAStatus::ok();
}
@@ -456,19 +514,21 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
StreamContext context;
- if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, &context);
+ if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, nullptr,
+ &context);
!status.isOk()) {
return status;
}
context.fillDescriptor(&_aidl_return->desc);
- auto stream = ndk::SharedRefBase::make<StreamIn>(in_args.sinkMetadata, std::move(context));
+ auto stream = ndk::SharedRefBase::make<StreamIn>(in_args.sinkMetadata, std::move(context),
+ mConfig->microphones);
if (auto status = stream->init(); !status.isOk()) {
return status;
}
StreamWrapper streamWrapper(stream);
auto patchIt = mPatches.find(in_args.portConfigId);
if (patchIt != mPatches.end()) {
- streamWrapper.setStreamIsConnected(true);
+ streamWrapper.setStreamIsConnected(findConnectedDevices(in_args.portConfigId));
}
mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper));
_aidl_return->stream = std::move(stream);
@@ -496,8 +556,16 @@
<< " has COMPRESS_OFFLOAD flag set, requires offload info";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
+ const bool isNonBlocking = isBitPositionFlagSet(port->flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::NON_BLOCKING);
+ if (isNonBlocking && in_args.callback == nullptr) {
+ LOG(ERROR) << __func__ << ": port id " << port->id
+ << " has NON_BLOCKING flag set, requires async callback";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
StreamContext context;
- if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, &context);
+ if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
+ isNonBlocking ? in_args.callback : nullptr, &context);
!status.isOk()) {
return status;
}
@@ -510,7 +578,7 @@
StreamWrapper streamWrapper(stream);
auto patchIt = mPatches.find(in_args.portConfigId);
if (patchIt != mPatches.end()) {
- streamWrapper.setStreamIsConnected(true);
+ streamWrapper.setStreamIsConnected(findConnectedDevices(in_args.portConfigId));
}
mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper));
_aidl_return->stream = std::move(stream);
@@ -829,6 +897,12 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Module::getMicrophones(std::vector<MicrophoneInfo>* _aidl_return) {
+ *_aidl_return = mConfig->microphones;
+ LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus Module::updateAudioMode(AudioMode in_mode) {
// No checks for supported audio modes here, it's an informative notification.
LOG(DEBUG) << __func__ << ": " << toString(in_mode);
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 21dc4b6..be5887c 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -18,12 +18,17 @@
#include <android-base/logging.h>
#include <utils/SystemClock.h>
+#include <Utils.h>
+
#include "core-impl/Module.h"
#include "core-impl/Stream.h"
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioOffloadInfo;
+using android::hardware::audio::common::getChannelCount;
+using android::hardware::audio::common::getFrameSizeInBytes;
namespace aidl::android::hardware::audio::core {
@@ -35,13 +40,17 @@
desc->reply = mReplyMQ->dupeDesc();
}
if (mDataMQ) {
- desc->frameSizeBytes = mFrameSize;
- desc->bufferSizeFrames =
- mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / mFrameSize;
+ const size_t frameSize = getFrameSize();
+ desc->frameSizeBytes = frameSize;
+ desc->bufferSizeFrames = mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / frameSize;
desc->audio.set<StreamDescriptor::AudioBuffer::Tag::fmq>(mDataMQ->dupeDesc());
}
}
+size_t StreamContext::getFrameSize() const {
+ return getFrameSizeInBytes(mFormat, mChannelLayout);
+}
+
bool StreamContext::isValid() const {
if (mCommandMQ && !mCommandMQ->isValid()) {
LOG(ERROR) << "command FMQ is invalid";
@@ -51,8 +60,8 @@
LOG(ERROR) << "reply FMQ is invalid";
return false;
}
- if (mFrameSize == 0) {
- LOG(ERROR) << "frame size is not set";
+ if (getFrameSize() == 0) {
+ LOG(ERROR) << "frame size is invalid";
return false;
}
if (mDataMQ && !mDataMQ->isValid()) {
@@ -87,32 +96,46 @@
void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
bool isConnected) const {
+ reply->status = STATUS_OK;
if (isConnected) {
- reply->status = STATUS_OK;
reply->observable.frames = mFrameCount;
reply->observable.timeNs = ::android::elapsedRealtimeNano();
} else {
- reply->status = STATUS_NO_INIT;
+ reply->observable.frames = StreamDescriptor::Position::UNKNOWN;
+ reply->observable.timeNs = StreamDescriptor::Position::UNKNOWN;
}
}
+void StreamWorkerCommonLogic::populateReplyWrongState(
+ StreamDescriptor::Reply* reply, const StreamDescriptor::Command& command) const {
+ LOG(WARNING) << "command '" << toString(command.getTag())
+ << "' can not be handled in the state " << toString(mState);
+ reply->status = STATUS_INVALID_OPERATION;
+}
+
const std::string StreamInWorkerLogic::kThreadName = "reader";
StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
+ // Note: for input streams, draining is driven by the client, thus
+ // "empty buffer" condition can only happen while handling the 'burst'
+ // command. Thus, unlike for output streams, it does not make sense to
+ // delay the 'DRAINING' state here by 'mTransientStateDelayMs'.
+ // TODO: Add a delay for transitions of async operations when/if they added.
+
StreamDescriptor::Command command{};
if (!mCommandMQ->readBlocking(&command, 1)) {
LOG(ERROR) << __func__ << ": reading of command from MQ failed";
mState = StreamDescriptor::State::ERROR;
return Status::ABORT;
}
+ LOG(DEBUG) << __func__ << ": received command " << command.toString() << " in " << kThreadName;
StreamDescriptor::Reply reply{};
reply.status = STATUS_BAD_VALUE;
using Tag = StreamDescriptor::Command::Tag;
switch (command.getTag()) {
- case Tag::hal_reserved_exit:
- if (const int32_t cookie = command.get<Tag::hal_reserved_exit>();
+ case Tag::halReservedExit:
+ if (const int32_t cookie = command.get<Tag::halReservedExit>();
cookie == mInternalCommandCookie) {
- LOG(DEBUG) << __func__ << ": received EXIT command";
setClosed();
// This is an internal command, no need to reply.
return Status::EXIT;
@@ -120,8 +143,10 @@
LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
}
break;
+ case Tag::getStatus:
+ populateReply(&reply, mIsConnected);
+ break;
case Tag::start:
- LOG(DEBUG) << __func__ << ": received START read command";
if (mState == StreamDescriptor::State::STANDBY ||
mState == StreamDescriptor::State::DRAINING) {
populateReply(&reply, mIsConnected);
@@ -129,15 +154,13 @@
? StreamDescriptor::State::IDLE
: StreamDescriptor::State::ACTIVE;
} else {
- LOG(WARNING) << __func__ << ": START command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
break;
case Tag::burst:
if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
- LOG(DEBUG) << __func__ << ": received BURST read command for " << fmqByteCount
- << " bytes";
+ LOG(DEBUG) << __func__ << ": '" << toString(command.getTag()) << "' command for "
+ << fmqByteCount << " bytes";
if (mState == StreamDescriptor::State::IDLE ||
mState == StreamDescriptor::State::ACTIVE ||
mState == StreamDescriptor::State::PAUSED ||
@@ -151,69 +174,61 @@
} else if (mState == StreamDescriptor::State::DRAINING) {
// To simplify the reference code, we assume that the read operation
// has consumed all the data remaining in the hardware buffer.
- // TODO: Provide parametrization on the duration of draining to test
- // handling of commands during the 'DRAINING' state.
+ // In a real implementation, here we would either remain in
+ // the 'DRAINING' state, or transfer to 'STANDBY' depending on the
+ // buffer state.
mState = StreamDescriptor::State::STANDBY;
}
} else {
- LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
} else {
LOG(WARNING) << __func__ << ": invalid burst byte count: " << fmqByteCount;
}
break;
case Tag::drain:
- LOG(DEBUG) << __func__ << ": received DRAIN read command";
- if (mState == StreamDescriptor::State::ACTIVE) {
- usleep(1000); // Simulate a blocking call into the driver.
- populateReply(&reply, mIsConnected);
- // Can switch the state to ERROR if a driver error occurs.
- mState = StreamDescriptor::State::DRAINING;
+ if (command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED) {
+ if (mState == StreamDescriptor::State::ACTIVE) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ mState = StreamDescriptor::State::DRAINING;
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
} else {
- LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ LOG(WARNING) << __func__
+ << ": invalid drain mode: " << toString(command.get<Tag::drain>());
}
break;
case Tag::standby:
- LOG(DEBUG) << __func__ << ": received STANDBY read command";
if (mState == StreamDescriptor::State::IDLE) {
usleep(1000); // Simulate a blocking call into the driver.
populateReply(&reply, mIsConnected);
// Can switch the state to ERROR if a driver error occurs.
mState = StreamDescriptor::State::STANDBY;
} else {
- LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
break;
case Tag::pause:
- LOG(DEBUG) << __func__ << ": received PAUSE read command";
if (mState == StreamDescriptor::State::ACTIVE) {
usleep(1000); // Simulate a blocking call into the driver.
populateReply(&reply, mIsConnected);
// Can switch the state to ERROR if a driver error occurs.
mState = StreamDescriptor::State::PAUSED;
} else {
- LOG(WARNING) << __func__ << ": PAUSE command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
break;
case Tag::flush:
- LOG(DEBUG) << __func__ << ": received FLUSH read command";
if (mState == StreamDescriptor::State::PAUSED) {
usleep(1000); // Simulate a blocking call into the driver.
populateReply(&reply, mIsConnected);
// Can switch the state to ERROR if a driver error occurs.
mState = StreamDescriptor::State::STANDBY;
} else {
- LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
break;
}
@@ -261,20 +276,52 @@
const std::string StreamOutWorkerLogic::kThreadName = "writer";
StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
+ if (mState == StreamDescriptor::State::DRAINING ||
+ mState == StreamDescriptor::State::TRANSFERRING) {
+ if (auto stateDurationMs = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - mTransientStateStart);
+ stateDurationMs >= mTransientStateDelayMs) {
+ if (mAsyncCallback == nullptr) {
+ // In blocking mode, mState can only be DRAINING.
+ mState = StreamDescriptor::State::IDLE;
+ } else {
+ // In a real implementation, the driver should notify the HAL about
+ // drain or transfer completion. In the stub, we switch unconditionally.
+ if (mState == StreamDescriptor::State::DRAINING) {
+ mState = StreamDescriptor::State::IDLE;
+ ndk::ScopedAStatus status = mAsyncCallback->onDrainReady();
+ if (!status.isOk()) {
+ LOG(ERROR) << __func__ << ": error from onDrainReady: " << status;
+ }
+ } else {
+ mState = StreamDescriptor::State::ACTIVE;
+ ndk::ScopedAStatus status = mAsyncCallback->onTransferReady();
+ if (!status.isOk()) {
+ LOG(ERROR) << __func__ << ": error from onTransferReady: " << status;
+ }
+ }
+ }
+ if (mTransientStateDelayMs.count() != 0) {
+ LOG(DEBUG) << __func__ << ": switched to state " << toString(mState)
+ << " after a timeout";
+ }
+ }
+ }
+
StreamDescriptor::Command command{};
if (!mCommandMQ->readBlocking(&command, 1)) {
LOG(ERROR) << __func__ << ": reading of command from MQ failed";
mState = StreamDescriptor::State::ERROR;
return Status::ABORT;
}
+ LOG(DEBUG) << __func__ << ": received command " << command.toString() << " in " << kThreadName;
StreamDescriptor::Reply reply{};
reply.status = STATUS_BAD_VALUE;
using Tag = StreamDescriptor::Command::Tag;
switch (command.getTag()) {
- case Tag::hal_reserved_exit:
- if (const int32_t cookie = command.get<Tag::hal_reserved_exit>();
+ case Tag::halReservedExit:
+ if (const int32_t cookie = command.get<Tag::halReservedExit>();
cookie == mInternalCommandCookie) {
- LOG(DEBUG) << __func__ << ": received EXIT command";
setClosed();
// This is an internal command, no need to reply.
return Status::EXIT;
@@ -282,8 +329,11 @@
LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
}
break;
- case Tag::start:
- LOG(DEBUG) << __func__ << ": received START write command";
+ case Tag::getStatus:
+ populateReply(&reply, mIsConnected);
+ break;
+ case Tag::start: {
+ bool commandAccepted = true;
switch (mState) {
case StreamDescriptor::State::STANDBY:
mState = StreamDescriptor::State::IDLE;
@@ -292,97 +342,112 @@
mState = StreamDescriptor::State::ACTIVE;
break;
case StreamDescriptor::State::DRAIN_PAUSED:
- mState = StreamDescriptor::State::PAUSED;
+ switchToTransientState(StreamDescriptor::State::DRAINING);
+ break;
+ case StreamDescriptor::State::TRANSFER_PAUSED:
+ switchToTransientState(StreamDescriptor::State::TRANSFERRING);
break;
default:
- LOG(WARNING) << __func__ << ": START command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
+ commandAccepted = false;
}
- if (reply.status != STATUS_INVALID_OPERATION) {
+ if (commandAccepted) {
populateReply(&reply, mIsConnected);
}
- break;
+ } break;
case Tag::burst:
if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
- LOG(DEBUG) << __func__ << ": received BURST write command for " << fmqByteCount
- << " bytes";
- if (mState !=
- StreamDescriptor::State::ERROR) { // BURST can be handled in all valid states
+ LOG(DEBUG) << __func__ << ": '" << toString(command.getTag()) << "' command for "
+ << fmqByteCount << " bytes";
+ if (mState != StreamDescriptor::State::ERROR &&
+ mState != StreamDescriptor::State::TRANSFERRING &&
+ mState != StreamDescriptor::State::TRANSFER_PAUSED) {
if (!write(fmqByteCount, &reply)) {
mState = StreamDescriptor::State::ERROR;
}
if (mState == StreamDescriptor::State::STANDBY ||
- mState == StreamDescriptor::State::DRAIN_PAUSED) {
- mState = StreamDescriptor::State::PAUSED;
+ mState == StreamDescriptor::State::DRAIN_PAUSED ||
+ mState == StreamDescriptor::State::PAUSED) {
+ if (mAsyncCallback == nullptr ||
+ mState != StreamDescriptor::State::DRAIN_PAUSED) {
+ mState = StreamDescriptor::State::PAUSED;
+ } else {
+ mState = StreamDescriptor::State::TRANSFER_PAUSED;
+ }
} else if (mState == StreamDescriptor::State::IDLE ||
- mState == StreamDescriptor::State::DRAINING) {
- mState = StreamDescriptor::State::ACTIVE;
- } // When in 'ACTIVE' and 'PAUSED' do not need to change the state.
+ mState == StreamDescriptor::State::DRAINING ||
+ mState == StreamDescriptor::State::ACTIVE) {
+ if (mAsyncCallback == nullptr || reply.fmqByteCount == fmqByteCount) {
+ mState = StreamDescriptor::State::ACTIVE;
+ } else {
+ switchToTransientState(StreamDescriptor::State::TRANSFERRING);
+ }
+ }
} else {
- LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
} else {
LOG(WARNING) << __func__ << ": invalid burst byte count: " << fmqByteCount;
}
break;
case Tag::drain:
- LOG(DEBUG) << __func__ << ": received DRAIN write command";
- if (mState == StreamDescriptor::State::ACTIVE) {
- usleep(1000); // Simulate a blocking call into the driver.
- populateReply(&reply, mIsConnected);
- // Can switch the state to ERROR if a driver error occurs.
- mState = StreamDescriptor::State::IDLE;
- // Since there is no actual hardware that would be draining the buffer,
- // in order to simplify the reference code, we assume that draining
- // happens instantly, thus skipping the 'DRAINING' state.
- // TODO: Provide parametrization on the duration of draining to test
- // handling of commands during the 'DRAINING' state.
+ if (command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_ALL ||
+ command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY) {
+ if (mState == StreamDescriptor::State::ACTIVE ||
+ mState == StreamDescriptor::State::TRANSFERRING) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ switchToTransientState(StreamDescriptor::State::DRAINING);
+ } else if (mState == StreamDescriptor::State::TRANSFER_PAUSED) {
+ mState = StreamDescriptor::State::DRAIN_PAUSED;
+ populateReply(&reply, mIsConnected);
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
} else {
- LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ LOG(WARNING) << __func__
+ << ": invalid drain mode: " << toString(command.get<Tag::drain>());
}
break;
case Tag::standby:
- LOG(DEBUG) << __func__ << ": received STANDBY write command";
if (mState == StreamDescriptor::State::IDLE) {
usleep(1000); // Simulate a blocking call into the driver.
populateReply(&reply, mIsConnected);
// Can switch the state to ERROR if a driver error occurs.
mState = StreamDescriptor::State::STANDBY;
} else {
- LOG(WARNING) << __func__ << ": STANDBY command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
break;
- case Tag::pause:
- LOG(DEBUG) << __func__ << ": received PAUSE write command";
- if (mState == StreamDescriptor::State::ACTIVE ||
- mState == StreamDescriptor::State::DRAINING) {
+ case Tag::pause: {
+ bool commandAccepted = true;
+ switch (mState) {
+ case StreamDescriptor::State::ACTIVE:
+ mState = StreamDescriptor::State::PAUSED;
+ break;
+ case StreamDescriptor::State::DRAINING:
+ mState = StreamDescriptor::State::DRAIN_PAUSED;
+ break;
+ case StreamDescriptor::State::TRANSFERRING:
+ mState = StreamDescriptor::State::TRANSFER_PAUSED;
+ break;
+ default:
+ populateReplyWrongState(&reply, command);
+ commandAccepted = false;
+ }
+ if (commandAccepted) {
populateReply(&reply, mIsConnected);
- mState = mState == StreamDescriptor::State::ACTIVE
- ? StreamDescriptor::State::PAUSED
- : StreamDescriptor::State::DRAIN_PAUSED;
- } else {
- LOG(WARNING) << __func__ << ": PAUSE command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
}
- break;
+ } break;
case Tag::flush:
- LOG(DEBUG) << __func__ << ": received FLUSH write command";
if (mState == StreamDescriptor::State::PAUSED ||
- mState == StreamDescriptor::State::DRAIN_PAUSED) {
+ mState == StreamDescriptor::State::DRAIN_PAUSED ||
+ mState == StreamDescriptor::State::TRANSFER_PAUSED) {
populateReply(&reply, mIsConnected);
mState = StreamDescriptor::State::IDLE;
} else {
- LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
break;
}
@@ -450,9 +515,8 @@
void StreamCommon<Metadata, StreamWorker>::stopWorker() {
if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
LOG(DEBUG) << __func__ << ": asking the worker to exit...";
- auto cmd =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::hal_reserved_exit>(
- mContext.getInternalCommandCookie());
+ auto cmd = StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::halReservedExit>(
+ mContext.getInternalCommandCookie());
// Note: never call 'pause' and 'resume' methods of StreamWorker
// in the HAL implementation. These methods are to be used by
// the client side only. Preventing the worker loop from running
@@ -475,11 +539,64 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
-StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext context)
- : StreamCommon<SinkMetadata, StreamInWorker>(sinkMetadata, std::move(context)) {
+namespace {
+static std::map<AudioDevice, std::string> transformMicrophones(
+ const std::vector<MicrophoneInfo>& microphones) {
+ std::map<AudioDevice, std::string> result;
+ std::transform(microphones.begin(), microphones.end(), std::inserter(result, result.begin()),
+ [](const auto& mic) { return std::make_pair(mic.device, mic.id); });
+ return result;
+}
+} // namespace
+
+StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext context,
+ const std::vector<MicrophoneInfo>& microphones)
+ : StreamCommon<SinkMetadata, StreamInWorker>(sinkMetadata, std::move(context)),
+ mMicrophones(transformMicrophones(microphones)) {
LOG(DEBUG) << __func__;
}
+ndk::ScopedAStatus StreamIn::getActiveMicrophones(
+ std::vector<MicrophoneDynamicInfo>* _aidl_return) {
+ std::vector<MicrophoneDynamicInfo> result;
+ std::vector<MicrophoneDynamicInfo::ChannelMapping> channelMapping{
+ getChannelCount(mContext.getChannelLayout()),
+ MicrophoneDynamicInfo::ChannelMapping::DIRECT};
+ for (auto it = mConnectedDevices.begin(); it != mConnectedDevices.end(); ++it) {
+ if (auto micIt = mMicrophones.find(*it); micIt != mMicrophones.end()) {
+ MicrophoneDynamicInfo dynMic;
+ dynMic.id = micIt->second;
+ dynMic.channelMapping = channelMapping;
+ result.push_back(std::move(dynMic));
+ }
+ }
+ *_aidl_return = std::move(result);
+ LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamIn::getMicrophoneDirection(MicrophoneDirection* _aidl_return) {
+ LOG(DEBUG) << __func__;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::setMicrophoneDirection(MicrophoneDirection in_direction) {
+ LOG(DEBUG) << __func__ << ": direction " << toString(in_direction);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::getMicrophoneFieldDimension(float* _aidl_return) {
+ LOG(DEBUG) << __func__;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::setMicrophoneFieldDimension(float in_zoom) {
+ LOG(DEBUG) << __func__ << ": zoom " << in_zoom;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
StreamOut::StreamOut(const SourceMetadata& sourceMetadata, StreamContext context,
const std::optional<AudioOffloadInfo>& offloadInfo)
: StreamCommon<SourceMetadata, StreamOutWorker>(sourceMetadata, std::move(context)),
diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h
index d5cd30b..95adcd7 100644
--- a/audio/aidl/default/include/core-impl/Configuration.h
+++ b/audio/aidl/default/include/core-impl/Configuration.h
@@ -21,12 +21,14 @@
#include <aidl/android/hardware/audio/core/AudioPatch.h>
#include <aidl/android/hardware/audio/core/AudioRoute.h>
+#include <aidl/android/hardware/audio/core/MicrophoneInfo.h>
#include <aidl/android/media/audio/common/AudioPort.h>
#include <aidl/android/media/audio/common/AudioPortConfig.h>
namespace aidl::android::hardware::audio::core::internal {
struct Configuration {
+ std::vector<MicrophoneInfo> microphones;
std::vector<::aidl::android::media::audio::common::AudioPort> ports;
std::vector<::aidl::android::media::audio::common::AudioPortConfig> portConfigs;
std::vector<::aidl::android::media::audio::common::AudioPortConfig> initialConfigs;
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 0086743..3509327 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -77,6 +77,7 @@
ndk::ScopedAStatus setMasterVolume(float in_volume) override;
ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
ndk::ScopedAStatus setMicMute(bool in_mute) override;
+ ndk::ScopedAStatus getMicrophones(std::vector<MicrophoneInfo>* _aidl_return) override;
ndk::ScopedAStatus updateAudioMode(
::aidl::android::hardware::audio::core::AudioMode in_mode) override;
ndk::ScopedAStatus updateScreenRotation(
@@ -86,10 +87,16 @@
void cleanUpPatch(int32_t patchId);
ndk::ScopedAStatus createStreamContext(
int32_t in_portConfigId, int64_t in_bufferSizeFrames,
+ std::shared_ptr<IStreamCallback> asyncCallback,
::aidl::android::hardware::audio::core::StreamContext* out_context);
+ std::vector<::aidl::android::media::audio::common::AudioDevice> findConnectedDevices(
+ int32_t portConfigId);
+ std::set<int32_t> findConnectedPortConfigIds(int32_t portConfigId);
ndk::ScopedAStatus findPortIdForNewStream(
int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
internal::Configuration& getConfig();
+ template <typename C>
+ std::set<int32_t> portIdsFromPortConfigIds(C portConfigIds);
void registerPatch(const AudioPatch& patch);
void updateStreamsConnectedState(const AudioPatch& oldPatch, const AudioPatch& newPatch);
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 5ee0f82..7a07eeb 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -17,6 +17,7 @@
#pragma once
#include <atomic>
+#include <chrono>
#include <cstdlib>
#include <map>
#include <memory>
@@ -28,7 +29,10 @@
#include <aidl/android/hardware/audio/common/SourceMetadata.h>
#include <aidl/android/hardware/audio/core/BnStreamIn.h>
#include <aidl/android/hardware/audio/core/BnStreamOut.h>
+#include <aidl/android/hardware/audio/core/IStreamCallback.h>
+#include <aidl/android/hardware/audio/core/MicrophoneInfo.h>
#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
+#include <aidl/android/media/audio/common/AudioDevice.h>
#include <aidl/android/media/audio/common/AudioOffloadInfo.h>
#include <fmq/AidlMessageQueue.h>
#include <system/thread_defs.h>
@@ -59,33 +63,53 @@
StreamContext() = default;
StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
- size_t frameSize, std::unique_ptr<DataMQ> dataMQ)
+ const ::aidl::android::media::audio::common::AudioFormatDescription& format,
+ const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
+ std::unique_ptr<DataMQ> dataMQ, std::shared_ptr<IStreamCallback> asyncCallback,
+ int transientStateDelayMs)
: mCommandMQ(std::move(commandMQ)),
mInternalCommandCookie(std::rand()),
mReplyMQ(std::move(replyMQ)),
- mFrameSize(frameSize),
- mDataMQ(std::move(dataMQ)) {}
+ mFormat(format),
+ mChannelLayout(channelLayout),
+ mDataMQ(std::move(dataMQ)),
+ mAsyncCallback(asyncCallback),
+ mTransientStateDelayMs(transientStateDelayMs) {}
StreamContext(StreamContext&& other)
: mCommandMQ(std::move(other.mCommandMQ)),
mInternalCommandCookie(other.mInternalCommandCookie),
mReplyMQ(std::move(other.mReplyMQ)),
- mFrameSize(other.mFrameSize),
- mDataMQ(std::move(other.mDataMQ)) {}
+ mFormat(other.mFormat),
+ mChannelLayout(other.mChannelLayout),
+ mDataMQ(std::move(other.mDataMQ)),
+ mAsyncCallback(other.mAsyncCallback),
+ mTransientStateDelayMs(other.mTransientStateDelayMs) {}
StreamContext& operator=(StreamContext&& other) {
mCommandMQ = std::move(other.mCommandMQ);
mInternalCommandCookie = other.mInternalCommandCookie;
mReplyMQ = std::move(other.mReplyMQ);
- mFrameSize = other.mFrameSize;
+ mFormat = std::move(other.mFormat);
+ mChannelLayout = std::move(other.mChannelLayout);
mDataMQ = std::move(other.mDataMQ);
+ mAsyncCallback = other.mAsyncCallback;
+ mTransientStateDelayMs = other.mTransientStateDelayMs;
return *this;
}
void fillDescriptor(StreamDescriptor* desc);
+ std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
+ ::aidl::android::media::audio::common::AudioChannelLayout getChannelLayout() const {
+ return mChannelLayout;
+ }
CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
DataMQ* getDataMQ() const { return mDataMQ.get(); }
- size_t getFrameSize() const { return mFrameSize; }
+ ::aidl::android::media::audio::common::AudioFormatDescription getFormat() const {
+ return mFormat;
+ }
+ size_t getFrameSize() const;
int getInternalCommandCookie() const { return mInternalCommandCookie; }
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+ int getTransientStateDelayMs() const { return mTransientStateDelayMs; }
bool isValid() const;
void reset();
@@ -93,8 +117,11 @@
std::unique_ptr<CommandMQ> mCommandMQ;
int mInternalCommandCookie; // The value used to confirm that the command was posted internally
std::unique_ptr<ReplyMQ> mReplyMQ;
- size_t mFrameSize;
+ ::aidl::android::media::audio::common::AudioFormatDescription mFormat;
+ ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
std::unique_ptr<DataMQ> mDataMQ;
+ std::shared_ptr<IStreamCallback> mAsyncCallback;
+ int mTransientStateDelayMs;
};
class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
@@ -111,9 +138,17 @@
mFrameSize(context.getFrameSize()),
mCommandMQ(context.getCommandMQ()),
mReplyMQ(context.getReplyMQ()),
- mDataMQ(context.getDataMQ()) {}
+ mDataMQ(context.getDataMQ()),
+ mAsyncCallback(context.getAsyncCallback()),
+ mTransientStateDelayMs(context.getTransientStateDelayMs()) {}
std::string init() override;
void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
+ void populateReplyWrongState(StreamDescriptor::Reply* reply,
+ const StreamDescriptor::Command& command) const;
+ void switchToTransientState(StreamDescriptor::State state) {
+ mState = state;
+ mTransientStateStart = std::chrono::steady_clock::now();
+ }
// Atomic fields are used both by the main and worker threads.
std::atomic<bool> mIsConnected = false;
@@ -125,6 +160,9 @@
StreamContext::CommandMQ* mCommandMQ;
StreamContext::ReplyMQ* mReplyMQ;
StreamContext::DataMQ* mDataMQ;
+ std::shared_ptr<IStreamCallback> mAsyncCallback;
+ const std::chrono::duration<int, std::milli> mTransientStateDelayMs;
+ std::chrono::time_point<std::chrono::steady_clock> mTransientStateStart;
// We use an array and the "size" field instead of a vector to be able to detect
// memory allocation issues.
std::unique_ptr<int8_t[]> mDataBuffer;
@@ -169,7 +207,11 @@
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
bool isClosed() const { return mWorker.isClosed(); }
- void setIsConnected(bool connected) { mWorker.setIsConnected(connected); }
+ void setIsConnected(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
+ mWorker.setIsConnected(!devices.empty());
+ mConnectedDevices = devices;
+ }
ndk::ScopedAStatus updateMetadata(const Metadata& metadata);
protected:
@@ -181,6 +223,7 @@
Metadata mMetadata;
StreamContext mContext;
StreamWorker mWorker;
+ std::vector<::aidl::android::media::audio::common::AudioDevice> mConnectedDevices;
};
class StreamIn
@@ -190,6 +233,12 @@
return StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata,
StreamInWorker>::close();
}
+ ndk::ScopedAStatus getActiveMicrophones(
+ std::vector<MicrophoneDynamicInfo>* _aidl_return) override;
+ ndk::ScopedAStatus getMicrophoneDirection(MicrophoneDirection* _aidl_return) override;
+ ndk::ScopedAStatus setMicrophoneDirection(MicrophoneDirection in_direction) override;
+ ndk::ScopedAStatus getMicrophoneFieldDimension(float* _aidl_return) override;
+ ndk::ScopedAStatus setMicrophoneFieldDimension(float in_zoom) override;
ndk::ScopedAStatus updateMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
in_sinkMetadata) override {
return StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata,
@@ -198,7 +247,10 @@
public:
StreamIn(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
- StreamContext context);
+ StreamContext context, const std::vector<MicrophoneInfo>& microphones);
+
+ private:
+ const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
};
class StreamOut : public StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
@@ -237,11 +289,12 @@
},
mStream);
}
- void setStreamIsConnected(bool connected) {
+ void setStreamIsConnected(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
std::visit(
[&](auto&& ws) {
auto s = ws.lock();
- if (s) s->setIsConnected(connected);
+ if (s) s->setIsConnected(devices);
},
mStream);
}
@@ -264,9 +317,11 @@
mStreams.insert(std::pair{portConfigId, sw});
mStreams.insert(std::pair{portId, std::move(sw)});
}
- void setStreamIsConnected(int32_t portConfigId, bool connected) {
+ void setStreamIsConnected(
+ int32_t portConfigId,
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
if (auto it = mStreams.find(portConfigId); it != mStreams.end()) {
- it->second.setStreamIsConnected(connected);
+ it->second.setStreamIsConnected(devices);
}
}
diff --git a/audio/aidl/vts/AudioHalBinderServiceUtil.h b/audio/aidl/vts/AudioHalBinderServiceUtil.h
index c8d81b1..b4b4632 100644
--- a/audio/aidl/vts/AudioHalBinderServiceUtil.h
+++ b/audio/aidl/vts/AudioHalBinderServiceUtil.h
@@ -31,7 +31,7 @@
public:
ndk::SpAIBinder connectToService(const std::string& serviceName) {
mServiceName = serviceName;
- mBinder = ndk::SpAIBinder(AServiceManager_getService(serviceName.c_str()));
+ mBinder = ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str()));
if (mBinder == nullptr) {
LOG(ERROR) << "Failed to get service " << serviceName;
} else {
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index 33c5b72..7e4b148 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -28,6 +28,7 @@
using aidl::android::hardware::audio::core::IModule;
using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDeviceType;
using aidl::android::media::audio::common::AudioEncapsulationMode;
using aidl::android::media::audio::common::AudioFormatDescription;
using aidl::android::media::audio::common::AudioFormatType;
@@ -62,6 +63,18 @@
return {};
}
+// static
+std::vector<aidl::android::media::audio::common::AudioPort> ModuleConfig::getBuiltInMicPorts(
+ const std::vector<aidl::android::media::audio::common::AudioPort>& ports) {
+ std::vector<AudioPort> result;
+ std::copy_if(ports.begin(), ports.end(), std::back_inserter(result), [](const auto& port) {
+ const auto type = port.ext.template get<AudioPortExt::Tag::device>().device.type;
+ return type.connection.empty() && (type.type == AudioDeviceType::IN_MICROPHONE ||
+ type.type == AudioDeviceType::IN_MICROPHONE_BACK);
+ });
+ return result;
+}
+
template <typename T>
auto findById(const std::vector<T>& v, int32_t id) {
return std::find_if(v.begin(), v.end(), [&](const auto& p) { return p.id == id; });
@@ -107,39 +120,46 @@
return result;
}
-std::vector<AudioPort> ModuleConfig::getInputMixPorts() const {
+std::vector<AudioPort> ModuleConfig::getInputMixPorts(bool attachedOnly) const {
std::vector<AudioPort> result;
- std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [](const auto& port) {
+ std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
return port.ext.getTag() == AudioPortExt::Tag::mix &&
- port.flags.getTag() == AudioIoFlags::Tag::input;
+ port.flags.getTag() == AudioIoFlags::Tag::input &&
+ (!attachedOnly || !getAttachedSourceDevicesPortsForMixPort(port).empty());
});
return result;
}
-std::vector<AudioPort> ModuleConfig::getOutputMixPorts() const {
+std::vector<AudioPort> ModuleConfig::getOutputMixPorts(bool attachedOnly) const {
std::vector<AudioPort> result;
- std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [](const auto& port) {
+ std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
return port.ext.getTag() == AudioPortExt::Tag::mix &&
- port.flags.getTag() == AudioIoFlags::Tag::output;
+ port.flags.getTag() == AudioIoFlags::Tag::output &&
+ (!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty());
});
return result;
}
+std::vector<AudioPort> ModuleConfig::getNonBlockingMixPorts(bool attachedOnly,
+ bool singlePort) const {
+ return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
+ return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::NON_BLOCKING);
+ });
+}
+
std::vector<AudioPort> ModuleConfig::getOffloadMixPorts(bool attachedOnly, bool singlePort) const {
- std::vector<AudioPort> result;
- const auto mixPorts = getMixPorts(false /*isInput*/);
- auto offloadPortIt = mixPorts.begin();
- while (offloadPortIt != mixPorts.end()) {
- offloadPortIt = std::find_if(offloadPortIt, mixPorts.end(), [&](const AudioPort& port) {
- return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
- AudioOutputFlags::COMPRESS_OFFLOAD) &&
- (!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty());
- });
- if (offloadPortIt == mixPorts.end()) break;
- result.push_back(*offloadPortIt++);
- if (singlePort) break;
- }
- return result;
+ return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
+ return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::COMPRESS_OFFLOAD);
+ });
+}
+
+std::vector<AudioPort> ModuleConfig::getPrimaryMixPorts(bool attachedOnly, bool singlePort) const {
+ return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
+ return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::PRIMARY);
+ });
}
std::vector<AudioPort> ModuleConfig::getAttachedDevicesPortsForMixPort(
@@ -193,7 +213,7 @@
std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getNonRoutableSrcSinkPair(
bool isInput) const {
- const auto mixPorts = getMixPorts(isInput);
+ const auto mixPorts = getMixPorts(isInput, false /*attachedOnly*/);
std::set<std::pair<int32_t, int32_t>> allowedRoutes;
for (const auto& route : mRoutes) {
for (const auto srcPortId : route.sourcePortIds) {
@@ -343,6 +363,20 @@
profile.sampleRates.empty() || profile.channelMasks.empty();
}
+std::vector<AudioPort> ModuleConfig::findMixPorts(
+ bool isInput, bool attachedOnly, bool singlePort,
+ const std::function<bool(const AudioPort&)>& pred) const {
+ std::vector<AudioPort> result;
+ const auto mixPorts = getMixPorts(isInput, attachedOnly);
+ for (auto mixPortIt = mixPorts.begin(); mixPortIt != mixPorts.end();) {
+ mixPortIt = std::find_if(mixPortIt, mixPorts.end(), pred);
+ if (mixPortIt == mixPorts.end()) break;
+ result.push_back(*mixPortIt++);
+ if (singlePort) break;
+ }
+ return result;
+}
+
std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
std::vector<AudioPortConfig> result;
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index dc109a7..7247f3b 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <optional>
#include <set>
#include <utility>
@@ -36,20 +37,32 @@
static std::optional<aidl::android::media::audio::common::AudioOffloadInfo>
generateOffloadInfoIfNeeded(
const aidl::android::media::audio::common::AudioPortConfig& portConfig);
+ static std::vector<aidl::android::media::audio::common::AudioPort> getBuiltInMicPorts(
+ const std::vector<aidl::android::media::audio::common::AudioPort>& ports);
explicit ModuleConfig(aidl::android::hardware::audio::core::IModule* module);
const ndk::ScopedAStatus& getStatus() const { return mStatus; }
std::string getError() const { return mStatus.getMessage(); }
std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicePorts() const;
- std::vector<aidl::android::media::audio::common::AudioPort> getExternalDevicePorts() const;
- std::vector<aidl::android::media::audio::common::AudioPort> getInputMixPorts() const;
- std::vector<aidl::android::media::audio::common::AudioPort> getOutputMixPorts() const;
- std::vector<aidl::android::media::audio::common::AudioPort> getMixPorts(bool isInput) const {
- return isInput ? getInputMixPorts() : getOutputMixPorts();
+ std::vector<aidl::android::media::audio::common::AudioPort> getAttachedMicrophonePorts() const {
+ return getBuiltInMicPorts(getAttachedDevicePorts());
}
+ std::vector<aidl::android::media::audio::common::AudioPort> getExternalDevicePorts() const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getInputMixPorts(
+ bool attachedOnly) const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getOutputMixPorts(
+ bool attachedOnly) const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getMixPorts(
+ bool isInput, bool attachedOnly) const {
+ return isInput ? getInputMixPorts(attachedOnly) : getOutputMixPorts(attachedOnly);
+ }
+ std::vector<aidl::android::media::audio::common::AudioPort> getNonBlockingMixPorts(
+ bool attachedOnly, bool singlePort) const;
std::vector<aidl::android::media::audio::common::AudioPort> getOffloadMixPorts(
bool attachedOnly, bool singlePort) const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getPrimaryMixPorts(
+ bool attachedOnly, bool singlePort) const;
std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const {
@@ -78,14 +91,17 @@
}
std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts()
const {
- auto inputs = generateAudioMixPortConfigs(getInputMixPorts(), true, false);
- auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(), false, false);
+ auto inputs =
+ generateAudioMixPortConfigs(getInputMixPorts(false /*attachedOnly*/), true, false);
+ auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(false /*attachedOnly*/), false,
+ false);
inputs.insert(inputs.end(), outputs.begin(), outputs.end());
return inputs;
}
std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
bool isInput) const {
- return generateAudioMixPortConfigs(getMixPorts(isInput), isInput, false);
+ return generateAudioMixPortConfigs(getMixPorts(isInput, false /*attachedOnly*/), isInput,
+ false);
}
std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
bool isInput, const aidl::android::media::audio::common::AudioPort& port) const {
@@ -93,7 +109,8 @@
}
std::optional<aidl::android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
bool isInput) const {
- const auto config = generateAudioMixPortConfigs(getMixPorts(isInput), isInput, true);
+ const auto config = generateAudioMixPortConfigs(
+ getMixPorts(isInput, false /*attachedOnly*/), isInput, true);
if (!config.empty()) {
return *config.begin();
}
@@ -121,6 +138,10 @@
std::string toString() const;
private:
+ std::vector<aidl::android::media::audio::common::AudioPort> findMixPorts(
+ bool isInput, bool attachedOnly, bool singlePort,
+ const std::function<bool(const aidl::android::media::audio::common::AudioPort&)>& pred)
+ const;
std::vector<aidl::android::media::audio::common::AudioPortConfig> generateAudioMixPortConfigs(
const std::vector<aidl::android::media::audio::common::AudioPort>& ports, bool isInput,
bool singleProfile) const;
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
index 5e9aa7f..c0c04f4 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
@@ -15,12 +15,16 @@
*/
#include <algorithm>
+#include <chrono>
#include <cmath>
+#include <condition_variable>
#include <limits>
#include <memory>
+#include <mutex>
#include <optional>
#include <set>
#include <string>
+#include <variant>
#include <vector>
#define LOG_TAG "VtsHalAudioCore"
@@ -30,6 +34,7 @@
#include <Utils.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
#include <aidl/android/hardware/audio/core/IModule.h>
#include <aidl/android/hardware/audio/core/ITelephony.h>
#include <aidl/android/media/audio/common/AudioIoFlags.h>
@@ -54,6 +59,8 @@
using aidl::android::hardware::audio::core::IStreamIn;
using aidl::android::hardware::audio::core::IStreamOut;
using aidl::android::hardware::audio::core::ITelephony;
+using aidl::android::hardware::audio::core::MicrophoneDynamicInfo;
+using aidl::android::hardware::audio::core::MicrophoneInfo;
using aidl::android::hardware::audio::core::ModuleDebug;
using aidl::android::hardware::audio::core::StreamDescriptor;
using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
@@ -187,6 +194,7 @@
*isSupported = false;
return;
}
+ ASSERT_TRUE(status.isOk()) << "Unexpected status from a getter: " << status;
*isSupported = true;
for (const auto v : validValues) {
EXPECT_IS_OK((inst->*setter)(v)) << "for valid value: " << v;
@@ -389,15 +397,132 @@
std::unique_ptr<DataMQ> mDataMQ;
};
-class StreamLogicDriver {
+struct StreamEventReceiver {
+ virtual ~StreamEventReceiver() = default;
+ enum class Event { None, DrainReady, Error, TransferReady };
+ virtual std::tuple<int, Event> getLastEvent() const = 0;
+ virtual std::tuple<int, Event> waitForEvent(int clientEventSeq) = 0;
+ static constexpr int kEventSeqInit = -1;
+};
+std::string toString(StreamEventReceiver::Event event) {
+ switch (event) {
+ case StreamEventReceiver::Event::None:
+ return "None";
+ case StreamEventReceiver::Event::DrainReady:
+ return "DrainReady";
+ case StreamEventReceiver::Event::Error:
+ return "Error";
+ case StreamEventReceiver::Event::TransferReady:
+ return "TransferReady";
+ }
+ return std::to_string(static_cast<int32_t>(event));
+}
+
+// Transition to the next state happens either due to a command from the client,
+// or after an event received from the server.
+using TransitionTrigger = std::variant<StreamDescriptor::Command, StreamEventReceiver::Event>;
+using StateTransition = std::pair<TransitionTrigger, StreamDescriptor::State>;
+struct StateSequence {
+ virtual ~StateSequence() = default;
+ virtual void rewind() = 0;
+ virtual bool done() const = 0;
+ virtual TransitionTrigger getTrigger() = 0;
+ virtual std::set<StreamDescriptor::State> getExpectedStates() = 0;
+ virtual void advance(StreamDescriptor::State state) = 0;
+};
+
+static const StreamDescriptor::Command kGetStatusCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(Void{});
+static const StreamDescriptor::Command kStartCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::start>(Void{});
+static const StreamDescriptor::Command kBurstCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(0);
+static const StreamDescriptor::Command kDrainInCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
+ StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED);
+static const StreamDescriptor::Command kDrainOutAllCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
+ StreamDescriptor::DrainMode::DRAIN_ALL);
+static const StreamDescriptor::Command kDrainOutEarlyCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
+ StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY);
+static const StreamDescriptor::Command kStandbyCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::standby>(Void{});
+static const StreamDescriptor::Command kPauseCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::pause>(Void{});
+static const StreamDescriptor::Command kFlushCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::flush>(Void{});
+static const StreamEventReceiver::Event kTransferReadyEvent =
+ StreamEventReceiver::Event::TransferReady;
+static const StreamEventReceiver::Event kDrainReadyEvent = StreamEventReceiver::Event::DrainReady;
+
+// Handle possible bifurcations:
+// - on burst and on start: 'TRANSFERRING' -> {'ACTIVE', 'TRANSFERRING'}
+// - on pause: 'TRANSFER_PAUSED' -> {'PAUSED', 'TRANSFER_PAUSED'}
+// It is assumed that the 'steps' provided on the construction contain the sequence
+// for the async case, which gets corrected in the case when the HAL decided to do
+// a synchronous transfer.
+class SmartStateSequence : public StateSequence {
public:
+ explicit SmartStateSequence(const std::vector<StateTransition>& steps) : mSteps(steps) {}
+ explicit SmartStateSequence(std::vector<StateTransition>&& steps) : mSteps(std::move(steps)) {}
+ void rewind() override { mCurrentStep = 0; }
+ bool done() const override { return mCurrentStep >= mSteps.size(); }
+ TransitionTrigger getTrigger() override { return mSteps[mCurrentStep].first; }
+ std::set<StreamDescriptor::State> getExpectedStates() override {
+ std::set<StreamDescriptor::State> result = {getState()};
+ if (isBurstBifurcation() || isStartBifurcation()) {
+ result.insert(StreamDescriptor::State::ACTIVE);
+ } else if (isPauseBifurcation()) {
+ result.insert(StreamDescriptor::State::PAUSED);
+ }
+ return result;
+ }
+ void advance(StreamDescriptor::State state) override {
+ if (isBurstBifurcation() && state == StreamDescriptor::State::ACTIVE &&
+ mCurrentStep + 1 < mSteps.size() &&
+ mSteps[mCurrentStep + 1].first == TransitionTrigger{kTransferReadyEvent}) {
+ mCurrentStep++;
+ }
+ mCurrentStep++;
+ }
+
+ private:
+ StreamDescriptor::State getState() const { return mSteps[mCurrentStep].second; }
+ bool isBurstBifurcation() {
+ return getTrigger() == TransitionTrigger{kBurstCommand}&& getState() ==
+ StreamDescriptor::State::TRANSFERRING;
+ }
+ bool isPauseBifurcation() {
+ return getTrigger() == TransitionTrigger{kPauseCommand}&& getState() ==
+ StreamDescriptor::State::TRANSFER_PAUSED;
+ }
+ bool isStartBifurcation() {
+ return getTrigger() == TransitionTrigger{kStartCommand}&& getState() ==
+ StreamDescriptor::State::TRANSFERRING;
+ }
+ const std::vector<StateTransition> mSteps;
+ size_t mCurrentStep = 0;
+};
+
+std::string toString(const TransitionTrigger& trigger) {
+ if (std::holds_alternative<StreamDescriptor::Command>(trigger)) {
+ return std::string("'")
+ .append(toString(std::get<StreamDescriptor::Command>(trigger).getTag()))
+ .append("' command");
+ }
+ return std::string("'")
+ .append(toString(std::get<StreamEventReceiver::Event>(trigger)))
+ .append("' event");
+}
+
+struct StreamLogicDriver {
virtual ~StreamLogicDriver() = default;
// Return 'true' to stop the worker.
virtual bool done() = 0;
// For 'Writer' logic, if the 'actualSize' is 0, write is skipped.
// The 'fmqByteCount' from the returned command is passed as is to the HAL.
- virtual StreamDescriptor::Command getNextCommand(int maxDataSize,
- int* actualSize = nullptr) = 0;
+ virtual TransitionTrigger getNextTrigger(int maxDataSize, int* actualSize = nullptr) = 0;
// Return 'true' to indicate that no further processing is needed,
// for example, the driver is expecting a bad status to be returned.
// The logic cycle will return with 'CONTINUE' status. Otherwise,
@@ -410,46 +535,102 @@
class StreamCommonLogic : public StreamLogic {
protected:
- StreamCommonLogic(const StreamContext& context, StreamLogicDriver* driver)
+ StreamCommonLogic(const StreamContext& context, StreamLogicDriver* driver,
+ StreamEventReceiver* eventReceiver)
: mCommandMQ(context.getCommandMQ()),
mReplyMQ(context.getReplyMQ()),
mDataMQ(context.getDataMQ()),
mData(context.getBufferSizeBytes()),
- mDriver(driver) {}
+ mDriver(driver),
+ mEventReceiver(eventReceiver) {}
StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
+ StreamContext::DataMQ* getDataMQ() const { return mDataMQ; }
StreamLogicDriver* getDriver() const { return mDriver; }
+ StreamEventReceiver* getEventReceiver() const { return mEventReceiver; }
- std::string init() override { return ""; }
+ std::string init() override {
+ LOG(DEBUG) << __func__;
+ return "";
+ }
+ std::optional<StreamDescriptor::Command> maybeGetNextCommand(int* actualSize = nullptr) {
+ TransitionTrigger trigger = mDriver->getNextTrigger(mData.size(), actualSize);
+ if (StreamEventReceiver::Event* expEvent =
+ std::get_if<StreamEventReceiver::Event>(&trigger);
+ expEvent != nullptr) {
+ auto [eventSeq, event] = mEventReceiver->waitForEvent(mLastEventSeq);
+ mLastEventSeq = eventSeq;
+ if (event != *expEvent) {
+ LOG(ERROR) << __func__ << ": expected event " << toString(*expEvent) << ", got "
+ << toString(event);
+ return {};
+ }
+ // If we were waiting for an event, the new stream state must be retrieved
+ // via 'getStatus'.
+ return StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(
+ Void{});
+ }
+ return std::get<StreamDescriptor::Command>(trigger);
+ }
+ bool readDataFromMQ(size_t readCount) {
+ std::vector<int8_t> data(readCount);
+ if (mDataMQ->read(data.data(), readCount)) {
+ memcpy(mData.data(), data.data(), std::min(mData.size(), data.size()));
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": reading of " << readCount << " bytes from MQ failed";
+ return false;
+ }
+ bool writeDataToMQ() {
+ if (mDataMQ->write(mData.data(), mData.size())) {
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
+ return false;
+ }
+ private:
StreamContext::CommandMQ* mCommandMQ;
StreamContext::ReplyMQ* mReplyMQ;
StreamContext::DataMQ* mDataMQ;
std::vector<int8_t> mData;
StreamLogicDriver* const mDriver;
+ StreamEventReceiver* const mEventReceiver;
+ int mLastEventSeq = StreamEventReceiver::kEventSeqInit;
};
class StreamReaderLogic : public StreamCommonLogic {
public:
- StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver)
- : StreamCommonLogic(context, driver) {}
+ StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver,
+ StreamEventReceiver* eventReceiver)
+ : StreamCommonLogic(context, driver, eventReceiver) {}
protected:
Status cycle() override {
if (getDriver()->done()) {
+ LOG(DEBUG) << __func__ << ": clean exit";
return Status::EXIT;
}
- StreamDescriptor::Command command = getDriver()->getNextCommand(mData.size());
- if (!mCommandMQ->writeBlocking(&command, 1)) {
+ StreamDescriptor::Command command;
+ if (auto maybeCommand = maybeGetNextCommand(); maybeCommand.has_value()) {
+ command = std::move(maybeCommand.value());
+ } else {
+ LOG(ERROR) << __func__ << ": no next command";
+ return Status::ABORT;
+ }
+ LOG(DEBUG) << "Writing command: " << command.toString();
+ if (!getCommandMQ()->writeBlocking(&command, 1)) {
LOG(ERROR) << __func__ << ": writing of command into MQ failed";
return Status::ABORT;
}
StreamDescriptor::Reply reply{};
- if (!mReplyMQ->readBlocking(&reply, 1)) {
- LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
+ LOG(DEBUG) << "Reading reply...";
+ if (!getReplyMQ()->readBlocking(&reply, 1)) {
return Status::ABORT;
}
+ LOG(DEBUG) << "Reply received: " << reply.toString();
if (getDriver()->interceptRawReply(reply)) {
+ LOG(DEBUG) << __func__ << ": reply has been intercepted by the driver";
return Status::CONTINUE;
}
if (reply.status != STATUS_OK) {
@@ -463,11 +644,11 @@
<< ": received invalid byte count in the reply: " << reply.fmqByteCount;
return Status::ABORT;
}
- if (static_cast<size_t>(reply.fmqByteCount) != mDataMQ->availableToRead()) {
+ if (static_cast<size_t>(reply.fmqByteCount) != getDataMQ()->availableToRead()) {
LOG(ERROR) << __func__
<< ": the byte count in the reply is not the same as the amount of "
<< "data available in the MQ: " << reply.fmqByteCount
- << " != " << mDataMQ->availableToRead();
+ << " != " << getDataMQ()->availableToRead();
}
if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
@@ -484,10 +665,8 @@
return Status::ABORT;
}
const bool acceptedReply = getDriver()->processValidReply(reply);
- if (const size_t readCount = mDataMQ->availableToRead(); readCount > 0) {
- std::vector<int8_t> data(readCount);
- if (mDataMQ->read(data.data(), readCount)) {
- memcpy(mData.data(), data.data(), std::min(mData.size(), data.size()));
+ if (const size_t readCount = getDataMQ()->availableToRead(); readCount > 0) {
+ if (readDataFromMQ(readCount)) {
goto checkAcceptedReply;
}
LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
@@ -505,29 +684,39 @@
class StreamWriterLogic : public StreamCommonLogic {
public:
- StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver)
- : StreamCommonLogic(context, driver) {}
+ StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver,
+ StreamEventReceiver* eventReceiver)
+ : StreamCommonLogic(context, driver, eventReceiver) {}
protected:
Status cycle() override {
if (getDriver()->done()) {
+ LOG(DEBUG) << __func__ << ": clean exit";
return Status::EXIT;
}
int actualSize = 0;
- StreamDescriptor::Command command = getDriver()->getNextCommand(mData.size(), &actualSize);
- if (actualSize != 0 && !mDataMQ->write(mData.data(), mData.size())) {
- LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
+ StreamDescriptor::Command command;
+ if (auto maybeCommand = maybeGetNextCommand(&actualSize); maybeCommand.has_value()) {
+ command = std::move(maybeCommand.value());
+ } else {
+ LOG(ERROR) << __func__ << ": no next command";
return Status::ABORT;
}
- if (!mCommandMQ->writeBlocking(&command, 1)) {
+ if (actualSize != 0 && !writeDataToMQ()) {
+ return Status::ABORT;
+ }
+ LOG(DEBUG) << "Writing command: " << command.toString();
+ if (!getCommandMQ()->writeBlocking(&command, 1)) {
LOG(ERROR) << __func__ << ": writing of command into MQ failed";
return Status::ABORT;
}
StreamDescriptor::Reply reply{};
- if (!mReplyMQ->readBlocking(&reply, 1)) {
+ LOG(DEBUG) << "Reading reply...";
+ if (!getReplyMQ()->readBlocking(&reply, 1)) {
LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
return Status::ABORT;
}
+ LOG(DEBUG) << "Reply received: " << reply.toString();
if (getDriver()->interceptRawReply(reply)) {
return Status::CONTINUE;
}
@@ -542,10 +731,10 @@
<< ": received invalid byte count in the reply: " << reply.fmqByteCount;
return Status::ABORT;
}
- if (mDataMQ->availableToWrite() != mDataMQ->getQuantumCount()) {
+ if (getDataMQ()->availableToWrite() != getDataMQ()->getQuantumCount()) {
LOG(ERROR) << __func__ << ": the HAL module did not consume all data from the data MQ: "
- << "available to write " << mDataMQ->availableToWrite()
- << ", total size: " << mDataMQ->getQuantumCount();
+ << "available to write " << getDataMQ()->availableToWrite()
+ << ", total size: " << getDataMQ()->getQuantumCount();
return Status::ABORT;
}
if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
@@ -571,6 +760,71 @@
};
using StreamWriter = StreamWorker<StreamWriterLogic>;
+class DefaultStreamCallback : public ::aidl::android::hardware::audio::core::BnStreamCallback,
+ public StreamEventReceiver {
+ ndk::ScopedAStatus onTransferReady() override {
+ LOG(DEBUG) << __func__;
+ putLastEvent(Event::TransferReady);
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus onError() override {
+ LOG(DEBUG) << __func__;
+ putLastEvent(Event::Error);
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus onDrainReady() override {
+ LOG(DEBUG) << __func__;
+ putLastEvent(Event::DrainReady);
+ return ndk::ScopedAStatus::ok();
+ }
+
+ public:
+ // To avoid timing out the whole test suite in case no event is received
+ // from the HAL, use a local timeout for event waiting.
+ static constexpr auto kEventTimeoutMs = std::chrono::milliseconds(1000);
+
+ StreamEventReceiver* getEventReceiver() { return this; }
+ std::tuple<int, Event> getLastEvent() const override {
+ std::lock_guard l(mLock);
+ return getLastEvent_l();
+ }
+ std::tuple<int, Event> waitForEvent(int clientEventSeq) override {
+ std::unique_lock l(mLock);
+ android::base::ScopedLockAssertion lock_assertion(mLock);
+ LOG(DEBUG) << __func__ << ": client " << clientEventSeq << ", last " << mLastEventSeq;
+ if (mCv.wait_for(l, kEventTimeoutMs, [&]() {
+ android::base::ScopedLockAssertion lock_assertion(mLock);
+ return clientEventSeq < mLastEventSeq;
+ })) {
+ } else {
+ LOG(WARNING) << __func__ << ": timed out waiting for an event";
+ putLastEvent_l(Event::None);
+ }
+ return getLastEvent_l();
+ }
+
+ private:
+ std::tuple<int, Event> getLastEvent_l() const REQUIRES(mLock) {
+ return std::make_tuple(mLastEventSeq, mLastEvent);
+ }
+ void putLastEvent(Event event) {
+ {
+ std::lock_guard l(mLock);
+ putLastEvent_l(event);
+ }
+ mCv.notify_one();
+ }
+ void putLastEvent_l(Event event) REQUIRES(mLock) {
+ mLastEventSeq++;
+ mLastEvent = event;
+ }
+
+ mutable std::mutex mLock;
+ std::condition_variable mCv;
+ int mLastEventSeq GUARDED_BY(mLock) = kEventSeqInit;
+ Event mLastEvent GUARDED_BY(mLock) = Event::None;
+};
+
template <typename T>
struct IOTraits {
static constexpr bool is_input = std::is_same_v<T, IStreamIn>;
@@ -607,6 +861,7 @@
}
Stream* get() const { return mStream.get(); }
const StreamContext* getContext() const { return mContext ? &(mContext.value()) : nullptr; }
+ StreamEventReceiver* getEventReceiver() { return mStreamCallback->getEventReceiver(); }
std::shared_ptr<Stream> getSharedPointer() const { return mStream; }
const AudioPortConfig& getPortConfig() const { return mPortConfig.get(); }
int32_t getPortId() const { return mPortConfig.getId(); }
@@ -616,6 +871,7 @@
std::shared_ptr<Stream> mStream;
StreamDescriptor mDescriptor;
std::optional<StreamContext> mContext;
+ std::shared_ptr<DefaultStreamCallback> mStreamCallback;
};
SinkMetadata GenerateSinkMetadata(const AudioPortConfig& portConfig) {
@@ -636,11 +892,15 @@
args.portConfigId = portConfig.id;
args.sinkMetadata = GenerateSinkMetadata(portConfig);
args.bufferSizeFrames = bufferSizeFrames;
+ auto callback = ndk::SharedRefBase::make<DefaultStreamCallback>();
+ // TODO: Uncomment when support for asynchronous input is implemented.
+ // args.callback = callback;
aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
ScopedAStatus status = module->openInputStream(args, &ret);
if (status.isOk()) {
mStream = std::move(ret.stream);
mDescriptor = std::move(ret.desc);
+ mStreamCallback = std::move(callback);
}
return status;
}
@@ -665,11 +925,14 @@
args.sourceMetadata = GenerateSourceMetadata(portConfig);
args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig);
args.bufferSizeFrames = bufferSizeFrames;
+ auto callback = ndk::SharedRefBase::make<DefaultStreamCallback>();
+ args.callback = callback;
aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
ScopedAStatus status = module->openOutputStream(args, &ret);
if (status.isOk()) {
mStream = std::move(ret.stream);
mDescriptor = std::move(ret.desc);
+ mStreamCallback = std::move(callback);
}
return status;
}
@@ -1307,6 +1570,42 @@
// TODO: Test that mic mute actually mutes input.
}
+TEST_P(AudioCoreModule, GetMicrophones) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ const std::vector<AudioPort> builtInMicPorts = moduleConfig->getAttachedMicrophonePorts();
+ std::vector<MicrophoneInfo> micInfos;
+ ScopedAStatus status = module->getMicrophones(&micInfos);
+ if (!status.isOk()) {
+ EXPECT_EQ(EX_UNSUPPORTED_OPERATION, status.getExceptionCode());
+ ASSERT_FALSE(builtInMicPorts.empty())
+ << "When the HAL module does not have built-in microphones, IModule.getMicrophones"
+ << " must complete with no error and return an empty list";
+ GTEST_SKIP() << "Microphone info is not supported";
+ }
+ std::set<int32_t> micPortIdsWithInfo;
+ for (const auto& micInfo : micInfos) {
+ const auto& micDevice = micInfo.device;
+ const auto it =
+ std::find_if(builtInMicPorts.begin(), builtInMicPorts.end(), [&](const auto& port) {
+ return port.ext.template get<AudioPortExt::Tag::device>().device == micDevice;
+ });
+ if (it != builtInMicPorts.end()) {
+ micPortIdsWithInfo.insert(it->id);
+ } else {
+ ADD_FAILURE() << "No device port found with a device specified for the microphone \""
+ << micInfo.id << "\": " << micDevice.toString();
+ }
+ }
+ if (micPortIdsWithInfo.size() != builtInMicPorts.size()) {
+ std::vector<AudioPort> micPortsNoInfo;
+ std::copy_if(builtInMicPorts.begin(), builtInMicPorts.end(),
+ std::back_inserter(micPortsNoInfo),
+ [&](const auto& port) { return micPortIdsWithInfo.count(port.id) == 0; });
+ ADD_FAILURE() << "No MicrophoneInfo is provided for the following microphone device ports: "
+ << ::android::internal::ToString(micPortsNoInfo);
+ }
+}
+
TEST_P(AudioCoreModule, UpdateAudioMode) {
for (const auto mode : ::ndk::enum_range<AudioMode>()) {
EXPECT_IS_OK(module->updateAudioMode(mode)) << toString(mode);
@@ -1379,10 +1678,10 @@
}
}
+using CommandSequence = std::vector<StreamDescriptor::Command>;
class StreamLogicDriverInvalidCommand : public StreamLogicDriver {
public:
- StreamLogicDriverInvalidCommand(const std::vector<StreamDescriptor::Command>& commands)
- : mCommands(commands) {}
+ StreamLogicDriverInvalidCommand(const CommandSequence& commands) : mCommands(commands) {}
std::string getUnexpectedStatuses() {
// This method is intended to be called after the worker thread has joined,
@@ -1396,25 +1695,29 @@
}
bool done() override { return mNextCommand >= mCommands.size(); }
- StreamDescriptor::Command getNextCommand(int, int* actualSize) override {
+ TransitionTrigger getNextTrigger(int, int* actualSize) override {
if (actualSize != nullptr) *actualSize = 0;
return mCommands[mNextCommand++];
}
bool interceptRawReply(const StreamDescriptor::Reply& reply) override {
- if (reply.status != STATUS_BAD_VALUE) {
- std::string s = mCommands[mNextCommand - 1].toString();
+ const size_t currentCommand = mNextCommand - 1; // increased by getNextTrigger
+ const bool isLastCommand = currentCommand == mCommands.size() - 1;
+ // All but the last command should run correctly. The last command must return 'BAD_VALUE'
+ // status.
+ if ((!isLastCommand && reply.status != STATUS_OK) ||
+ (isLastCommand && reply.status != STATUS_BAD_VALUE)) {
+ std::string s = mCommands[currentCommand].toString();
s.append(", ").append(statusToString(reply.status));
mStatuses.push_back(std::move(s));
- // If the HAL does not recognize the command as invalid,
- // retrieve the data etc.
- return reply.status != STATUS_OK;
+ // Process the reply, since the worker exits in case of an error.
+ return false;
}
- return true;
+ return isLastCommand;
}
bool processValidReply(const StreamDescriptor::Reply&) override { return true; }
private:
- const std::vector<StreamDescriptor::Command> mCommands;
+ const CommandSequence mCommands;
size_t mNextCommand = 0;
std::vector<std::string> mStatuses;
};
@@ -1483,13 +1786,11 @@
void OpenOverMaxCount() {
constexpr bool isInput = IOTraits<Stream>::is_input;
- auto ports = moduleConfig->getMixPorts(isInput);
+ auto ports = moduleConfig->getMixPorts(isInput, true /*attachedOnly*/);
bool hasSingleRun = false;
for (const auto& port : ports) {
const size_t maxStreamCount = port.ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
- if (maxStreamCount == 0 ||
- moduleConfig->getAttachedDevicesPortsForMixPort(isInput, port).empty()) {
- // No restrictions or no permanently attached devices.
+ if (maxStreamCount == 0) {
continue;
}
auto portConfigs = moduleConfig->getPortConfigsForMixPorts(isInput, port);
@@ -1556,22 +1857,46 @@
}
void SendInvalidCommandImpl(const AudioPortConfig& portConfig) {
- std::vector<StreamDescriptor::Command> commands = {
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::hal_reserved_exit>(
- 0),
- // TODO: For proper testing of input streams, need to put the stream into
- // a state which accepts BURST commands.
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(-1),
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(
- std::numeric_limits<int32_t>::min()),
- };
- WithStream<Stream> stream(portConfig);
- ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- StreamLogicDriverInvalidCommand driver(commands);
- typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
- ASSERT_TRUE(worker.start());
- worker.join();
- EXPECT_EQ("", driver.getUnexpectedStatuses());
+ using TestSequence = std::pair<std::string, CommandSequence>;
+ // The last command in 'CommandSequence' is the one that must trigger
+ // an error status. All preceding commands are to put the state machine
+ // into a state which accepts the last command.
+ std::vector<TestSequence> sequences{
+ std::make_pair(std::string("HalReservedExit"),
+ std::vector{StreamDescriptor::Command::make<
+ StreamDescriptor::Command::Tag::halReservedExit>(0)}),
+ std::make_pair(std::string("BurstNeg"),
+ std::vector{kStartCommand,
+ StreamDescriptor::Command::make<
+ StreamDescriptor::Command::Tag::burst>(-1)}),
+ std::make_pair(
+ std::string("BurstMinInt"),
+ std::vector{kStartCommand, StreamDescriptor::Command::make<
+ StreamDescriptor::Command::Tag::burst>(
+ std::numeric_limits<int32_t>::min())})};
+ if (IOTraits<Stream>::is_input) {
+ sequences.emplace_back("DrainAll",
+ std::vector{kStartCommand, kBurstCommand, kDrainOutAllCommand});
+ sequences.emplace_back(
+ "DrainEarly", std::vector{kStartCommand, kBurstCommand, kDrainOutEarlyCommand});
+ } else {
+ sequences.emplace_back("DrainUnspecified",
+ std::vector{kStartCommand, kBurstCommand, kDrainInCommand});
+ }
+ for (const auto& seq : sequences) {
+ SCOPED_TRACE(std::string("Sequence ").append(seq.first));
+ LOG(DEBUG) << __func__ << ": Sequence " << seq.first;
+ WithStream<Stream> stream(portConfig);
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ StreamLogicDriverInvalidCommand driver(seq.second);
+ typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
+ stream.getEventReceiver());
+ LOG(DEBUG) << __func__ << ": starting worker...";
+ ASSERT_TRUE(worker.start());
+ LOG(DEBUG) << __func__ << ": joining worker...";
+ worker.join();
+ EXPECT_EQ("", driver.getUnexpectedStatuses());
+ }
}
};
using AudioStreamIn = AudioStream<IStreamIn>;
@@ -1590,20 +1915,127 @@
TEST_IN_AND_OUT_STREAM(ResetPortConfigWithOpenStream);
TEST_IN_AND_OUT_STREAM(SendInvalidCommand);
+namespace aidl::android::hardware::audio::core {
+std::ostream& operator<<(std::ostream& os, const IStreamIn::MicrophoneDirection& md) {
+ os << toString(md);
+ return os;
+}
+} // namespace aidl::android::hardware::audio::core
+
+TEST_P(AudioStreamIn, ActiveMicrophones) {
+ std::vector<MicrophoneInfo> micInfos;
+ ScopedAStatus status = module->getMicrophones(&micInfos);
+ if (!status.isOk()) {
+ GTEST_SKIP() << "Microphone info is not supported";
+ }
+ const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No input mix ports for attached devices";
+ }
+ for (const auto& port : ports) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
+ WithStream<IStreamIn> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ {
+ // The port of the stream is not connected, thus the list of active mics must be empty.
+ std::vector<MicrophoneDynamicInfo> activeMics;
+ EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
+ EXPECT_TRUE(activeMics.empty()) << "a stream on an unconnected port returns a "
+ "non-empty list of active microphones";
+ }
+ if (auto micDevicePorts = ModuleConfig::getBuiltInMicPorts(
+ moduleConfig->getAttachedSourceDevicesPortsForMixPort(port));
+ !micDevicePorts.empty()) {
+ auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(micDevicePorts[0]);
+ WithAudioPatch patch(true /*isInput*/, stream.getPortConfig(), devicePortConfig);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ std::vector<MicrophoneDynamicInfo> activeMics;
+ EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
+ for (const auto& mic : activeMics) {
+ EXPECT_NE(micInfos.end(),
+ std::find_if(micInfos.begin(), micInfos.end(),
+ [&](const auto& micInfo) { return micInfo.id == mic.id; }))
+ << "active microphone \"" << mic.id << "\" is not listed in "
+ << "microphone infos returned by the module: "
+ << ::android::internal::ToString(micInfos);
+ EXPECT_NE(0UL, mic.channelMapping.size())
+ << "No channels specified for the microphone \"" << mic.id << "\"";
+ }
+ }
+ {
+ // Now the port of the stream is not connected again, re-check that there are no
+ // active microphones.
+ std::vector<MicrophoneDynamicInfo> activeMics;
+ EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
+ EXPECT_TRUE(activeMics.empty()) << "a stream on an unconnected port returns a "
+ "non-empty list of active microphones";
+ }
+ }
+}
+
+TEST_P(AudioStreamIn, MicrophoneDirection) {
+ using MD = IStreamIn::MicrophoneDirection;
+ const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No input mix ports for attached devices";
+ }
+ bool isSupported = false;
+ for (const auto& port : ports) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
+ WithStream<IStreamIn> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ EXPECT_NO_FATAL_FAILURE(
+ TestAccessors<MD>(stream.get(), &IStreamIn::getMicrophoneDirection,
+ &IStreamIn::setMicrophoneDirection,
+ std::vector<MD>(enum_range<MD>().begin(), enum_range<MD>().end()),
+ {}, &isSupported));
+ if (!isSupported) break;
+ }
+ if (!isSupported) {
+ GTEST_SKIP() << "Microphone direction is not supported";
+ }
+}
+
+TEST_P(AudioStreamIn, MicrophoneFieldDimension) {
+ const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No input mix ports for attached devices";
+ }
+ bool isSupported = false;
+ for (const auto& port : ports) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
+ WithStream<IStreamIn> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
+ stream.get(), &IStreamIn::getMicrophoneFieldDimension,
+ &IStreamIn::setMicrophoneFieldDimension,
+ {IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE,
+ IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE / 2.0f,
+ IStreamIn::MIC_FIELD_DIMENSION_NO_ZOOM,
+ IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM / 2.0f,
+ IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM},
+ {IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE * 2,
+ IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM * 2,
+ IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE * 1.1f,
+ IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM * 1.1f, -INFINITY, INFINITY, -NAN, NAN},
+ &isSupported));
+ if (!isSupported) break;
+ }
+ if (!isSupported) {
+ GTEST_SKIP() << "Microphone direction is not supported";
+ }
+}
+
TEST_P(AudioStreamOut, OpenTwicePrimary) {
- const auto mixPorts = moduleConfig->getMixPorts(false);
- auto primaryPortIt = std::find_if(mixPorts.begin(), mixPorts.end(), [](const AudioPort& port) {
- return port.flags.getTag() == AudioIoFlags::Tag::output &&
- isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
- AudioOutputFlags::PRIMARY);
- });
- if (primaryPortIt == mixPorts.end()) {
- GTEST_SKIP() << "No primary mix port";
+ const auto mixPorts =
+ moduleConfig->getPrimaryMixPorts(true /*attachedOnly*/, true /*singlePort*/);
+ if (mixPorts.empty()) {
+ GTEST_SKIP() << "No primary mix port which could be routed to attached devices";
}
- if (moduleConfig->getAttachedSinkDevicesPortsForMixPort(*primaryPortIt).empty()) {
- GTEST_SKIP() << "Primary mix port can not be routed to any of attached devices";
- }
- const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *primaryPortIt);
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *mixPorts.begin());
ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for the primary mix port";
EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
}
@@ -1615,27 +2047,51 @@
GTEST_SKIP()
<< "No mix port for compressed offload that could be routed to attached devices";
}
- const auto portConfig =
- moduleConfig->getSingleConfigForMixPort(false, *offloadMixPorts.begin());
- ASSERT_TRUE(portConfig.has_value())
- << "No profiles specified for the compressed offload mix port";
+ const auto config = moduleConfig->getSingleConfigForMixPort(false, *offloadMixPorts.begin());
+ ASSERT_TRUE(config.has_value()) << "No profiles specified for the compressed offload mix port";
+ WithAudioPortConfig portConfig(config.value());
+ ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
StreamDescriptor descriptor;
std::shared_ptr<IStreamOut> ignored;
aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
- args.portConfigId = portConfig.value().id;
- args.sourceMetadata = GenerateSourceMetadata(portConfig.value());
+ args.portConfigId = portConfig.getId();
+ args.sourceMetadata = GenerateSourceMetadata(portConfig.get());
args.bufferSizeFrames = kDefaultBufferSizeFrames;
aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
<< "when no offload info is provided for a compressed offload mix port";
}
-using CommandAndState = std::pair<StreamDescriptor::Command, StreamDescriptor::State>;
+TEST_P(AudioStreamOut, RequireAsyncCallback) {
+ const auto nonBlockingMixPorts =
+ moduleConfig->getNonBlockingMixPorts(true /*attachedOnly*/, true /*singlePort*/);
+ if (nonBlockingMixPorts.empty()) {
+ GTEST_SKIP()
+ << "No mix port for non-blocking output that could be routed to attached devices";
+ }
+ const auto config =
+ moduleConfig->getSingleConfigForMixPort(false, *nonBlockingMixPorts.begin());
+ ASSERT_TRUE(config.has_value()) << "No profiles specified for the non-blocking mix port";
+ WithAudioPortConfig portConfig(config.value());
+ ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+ StreamDescriptor descriptor;
+ std::shared_ptr<IStreamOut> ignored;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+ args.portConfigId = portConfig.getId();
+ args.sourceMetadata = GenerateSourceMetadata(portConfig.get());
+ args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig.get());
+ args.bufferSizeFrames = kDefaultBufferSizeFrames;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+ << "when no async callback is provided for a non-blocking mix port";
+}
class StreamLogicDefaultDriver : public StreamLogicDriver {
public:
- explicit StreamLogicDefaultDriver(const std::vector<CommandAndState>& commands)
- : mCommands(commands) {}
+ explicit StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands)
+ : mCommands(commands) {
+ mCommands->rewind();
+ }
// The three methods below is intended to be called after the worker
// thread has joined, thus no extra synchronization is needed.
@@ -1643,59 +2099,72 @@
bool hasRetrogradeObservablePosition() const { return mRetrogradeObservablePosition; }
std::string getUnexpectedStateTransition() const { return mUnexpectedTransition; }
- bool done() override { return mNextCommand >= mCommands.size(); }
- StreamDescriptor::Command getNextCommand(int maxDataSize, int* actualSize) override {
- auto command = mCommands[mNextCommand++].first;
- if (command.getTag() == StreamDescriptor::Command::Tag::burst) {
- if (actualSize != nullptr) {
- // In the output scenario, reduce slightly the fmqByteCount to verify
- // that the HAL module always consumes all data from the MQ.
- if (maxDataSize > 1) maxDataSize--;
- *actualSize = maxDataSize;
+ bool done() override { return mCommands->done(); }
+ TransitionTrigger getNextTrigger(int maxDataSize, int* actualSize) override {
+ auto trigger = mCommands->getTrigger();
+ if (StreamDescriptor::Command* command = std::get_if<StreamDescriptor::Command>(&trigger);
+ command != nullptr) {
+ if (command->getTag() == StreamDescriptor::Command::Tag::burst) {
+ if (actualSize != nullptr) {
+ // In the output scenario, reduce slightly the fmqByteCount to verify
+ // that the HAL module always consumes all data from the MQ.
+ if (maxDataSize > 1) maxDataSize--;
+ *actualSize = maxDataSize;
+ }
+ command->set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
+ } else {
+ if (actualSize != nullptr) *actualSize = 0;
}
- command.set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
- } else {
- if (actualSize != nullptr) *actualSize = 0;
}
- return command;
+ return trigger;
}
bool interceptRawReply(const StreamDescriptor::Reply&) override { return false; }
bool processValidReply(const StreamDescriptor::Reply& reply) override {
- if (mPreviousFrames.has_value()) {
- if (reply.observable.frames > mPreviousFrames.value()) {
- mObservablePositionIncrease = true;
- } else if (reply.observable.frames < mPreviousFrames.value()) {
- mRetrogradeObservablePosition = true;
+ if (reply.observable.frames != StreamDescriptor::Position::UNKNOWN) {
+ if (mPreviousFrames.has_value()) {
+ if (reply.observable.frames > mPreviousFrames.value()) {
+ mObservablePositionIncrease = true;
+ } else if (reply.observable.frames < mPreviousFrames.value()) {
+ mRetrogradeObservablePosition = true;
+ }
}
+ mPreviousFrames = reply.observable.frames;
}
- mPreviousFrames = reply.observable.frames;
- const auto& lastCommandState = mCommands[mNextCommand - 1];
- if (lastCommandState.second != reply.state) {
- std::string s = std::string("Unexpected transition from the state ")
- .append(mPreviousState)
- .append(" to ")
- .append(toString(reply.state))
- .append(" caused by the command ")
- .append(lastCommandState.first.toString());
+ auto expected = mCommands->getExpectedStates();
+ if (expected.count(reply.state) == 0) {
+ std::string s =
+ std::string("Unexpected transition from the state ")
+ .append(mPreviousState.has_value() ? toString(mPreviousState.value())
+ : "<initial state>")
+ .append(" to ")
+ .append(toString(reply.state))
+ .append(" (expected one of ")
+ .append(::android::internal::ToString(expected))
+ .append(") caused by the ")
+ .append(toString(mCommands->getTrigger()));
LOG(ERROR) << __func__ << ": " << s;
mUnexpectedTransition = std::move(s);
return false;
}
+ mCommands->advance(reply.state);
+ mPreviousState = reply.state;
return true;
}
protected:
- const std::vector<CommandAndState>& mCommands;
- size_t mNextCommand = 0;
+ std::shared_ptr<StateSequence> mCommands;
+ std::optional<StreamDescriptor::State> mPreviousState;
std::optional<int64_t> mPreviousFrames;
- std::string mPreviousState = "<initial state>";
bool mObservablePositionIncrease = false;
bool mRetrogradeObservablePosition = false;
std::string mUnexpectedTransition;
};
-using NamedCommandSequence = std::pair<std::string, std::vector<CommandAndState>>;
+enum { NAMED_CMD_NAME, NAMED_CMD_DELAY_MS, NAMED_CMD_STREAM_TYPE, NAMED_CMD_CMDS };
+enum class StreamTypeFilter { ANY, SYNC, ASYNC };
+using NamedCommandSequence =
+ std::tuple<std::string, int, StreamTypeFilter, std::shared_ptr<StateSequence>>;
enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
using StreamIoTestParameters =
std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
@@ -1716,7 +2185,29 @@
}
for (const auto& portConfig : allPortConfigs) {
SCOPED_TRACE(portConfig.toString());
- const auto& commandsAndStates = std::get<PARAM_CMD_SEQ>(GetParam()).second;
+ const bool isNonBlocking =
+ IOTraits<Stream>::is_input
+ ? false
+ :
+ // TODO: Uncomment when support for asynchronous input is implemented.
+ /*isBitPositionFlagSet(
+ portConfig.flags.value().template get<AudioIoFlags::Tag::input>(),
+ AudioInputFlags::NON_BLOCKING) :*/
+ isBitPositionFlagSet(portConfig.flags.value()
+ .template get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::NON_BLOCKING);
+ if (auto streamType =
+ std::get<NAMED_CMD_STREAM_TYPE>(std::get<PARAM_CMD_SEQ>(GetParam()));
+ (isNonBlocking && streamType == StreamTypeFilter::SYNC) ||
+ (!isNonBlocking && streamType == StreamTypeFilter::ASYNC)) {
+ continue;
+ }
+ WithDebugFlags delayTransientStates = WithDebugFlags::createNested(debug);
+ delayTransientStates.flags().streamTransientStateDelayMs =
+ std::get<NAMED_CMD_DELAY_MS>(std::get<PARAM_CMD_SEQ>(GetParam()));
+ ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
+ const auto& commandsAndStates =
+ std::get<NAMED_CMD_CMDS>(std::get<PARAM_CMD_SEQ>(GetParam()));
if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
} else {
@@ -1732,7 +2223,7 @@
// Set up a patch first, then open a stream.
void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
- const std::vector<CommandAndState>& commandsAndStates) {
+ std::shared_ptr<StateSequence> commandsAndStates) {
auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
IOTraits<Stream>::is_input, portConfig);
ASSERT_FALSE(devicePorts.empty());
@@ -1743,9 +2234,12 @@
WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
StreamLogicDefaultDriver driver(commandsAndStates);
- typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
+ typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
+ stream.getEventReceiver());
+ LOG(DEBUG) << __func__ << ": starting worker...";
ASSERT_TRUE(worker.start());
+ LOG(DEBUG) << __func__ << ": joining worker...";
worker.join();
EXPECT_FALSE(worker.hasError()) << worker.getError();
EXPECT_EQ("", driver.getUnexpectedStateTransition());
@@ -1757,11 +2251,12 @@
// Open a stream, then set up a patch for it.
void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
- const std::vector<CommandAndState>& commandsAndStates) {
+ std::shared_ptr<StateSequence> commandsAndStates) {
WithStream<Stream> stream(portConfig);
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
StreamLogicDefaultDriver driver(commandsAndStates);
- typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
+ typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
+ stream.getEventReceiver());
auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
IOTraits<Stream>::is_input, portConfig);
@@ -1770,7 +2265,9 @@
WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ LOG(DEBUG) << __func__ << ": starting worker...";
ASSERT_TRUE(worker.start());
+ LOG(DEBUG) << __func__ << ": joining worker...";
worker.join();
EXPECT_FALSE(worker.hasError()) << worker.getError();
EXPECT_EQ("", driver.getUnexpectedStateTransition());
@@ -1975,103 +2472,210 @@
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamOut);
-static const StreamDescriptor::Command kStartCommand =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::start>(Void{});
-static const StreamDescriptor::Command kBurstCommand =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(0);
-static const StreamDescriptor::Command kDrainCommand =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(Void{});
-static const StreamDescriptor::Command kStandbyCommand =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::standby>(Void{});
-static const StreamDescriptor::Command kPauseCommand =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::pause>(Void{});
-static const StreamDescriptor::Command kFlushCommand =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::flush>(Void{});
-static const NamedCommandSequence kReadOrWriteSeq =
- std::make_pair(std::string("ReadOrWrite"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE)});
-static const NamedCommandSequence kDrainInSeq =
- std::make_pair(std::string("Drain"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kDrainCommand, StreamDescriptor::State::DRAINING),
- std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kDrainCommand, StreamDescriptor::State::DRAINING),
- // TODO: This will need to be changed once DRAIN starts taking time.
- std::make_pair(kBurstCommand, StreamDescriptor::State::STANDBY)});
-static const NamedCommandSequence kDrainOutSeq =
- std::make_pair(std::string("Drain"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- // TODO: This will need to be changed once DRAIN starts taking time.
- std::make_pair(kDrainCommand, StreamDescriptor::State::IDLE)});
-// TODO: This will need to be changed once DRAIN starts taking time so we can pause it.
-static const NamedCommandSequence kDrainPauseOutSeq = std::make_pair(
- std::string("DrainPause"),
- std::vector<CommandAndState>{std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kDrainCommand, StreamDescriptor::State::IDLE)});
-static const NamedCommandSequence kStandbySeq =
- std::make_pair(std::string("Standby"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kStandbyCommand, StreamDescriptor::State::STANDBY),
- // Perform a read or write in order to advance observable position
- // (this is verified by tests).
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE)});
+// This is the value used in test sequences for which the test needs to ensure
+// that the HAL stays in a transient state long enough to receive the next command.
+static const int kStreamTransientStateTransitionDelayMs = 3000;
+
+// TODO: Add async test cases for input once it is implemented.
+
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount) {
+ const auto burst =
+ isSync ? std::vector<StateTransition>{std::make_pair(kBurstCommand,
+ StreamDescriptor::State::ACTIVE)}
+ : std::vector<StateTransition>{
+ std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kTransferReadyEvent, StreamDescriptor::State::ACTIVE)};
+ std::vector<StateTransition> result{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE)};
+ for (size_t i = 0; i < burstCount; ++i) {
+ result.insert(result.end(), burst.begin(), burst.end());
+ }
+ return std::make_shared<SmartStateSequence>(result);
+}
+static const NamedCommandSequence kReadSeq =
+ std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true, 3));
+static const NamedCommandSequence kWriteSyncSeq = std::make_tuple(
+ std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true, 3));
+static const NamedCommandSequence kWriteAsyncSeq = std::make_tuple(
+ std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false, 3));
+
+std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isInput ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
+ StreamDescriptor::State::DRAINING),
+ isInput ? std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE)
+ : std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
+ StreamDescriptor::State::DRAINING)});
+}
+static const NamedCommandSequence kWriteDrainAsyncSeq =
+ std::make_tuple(std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeAsyncDrainCommands(false));
+static const NamedCommandSequence kDrainInSeq = std::make_tuple(
+ std::string("Drain"), 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true));
+
+std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(isSync ? TransitionTrigger(kGetStatusCommand)
+ : TransitionTrigger(kDrainReadyEvent),
+ StreamDescriptor::State::IDLE)});
+}
+static const NamedCommandSequence kDrainOutSyncSeq = std::make_tuple(
+ std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true));
+static const NamedCommandSequence kDrainOutAsyncSeq = std::make_tuple(
+ std::string("Drain"), 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false));
+
+std::shared_ptr<StateSequence> makeDrainOutPauseCommands(bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
+ std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::PAUSED
+ : StreamDescriptor::State::TRANSFER_PAUSED)});
+}
+static const NamedCommandSequence kDrainPauseOutSyncSeq =
+ std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::SYNC, makeDrainOutPauseCommands(true));
+static const NamedCommandSequence kDrainPauseOutAsyncSeq =
+ std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeDrainOutPauseCommands(false));
+
+// This sequence also verifies that the capture / presentation position is not reset on standby.
+std::shared_ptr<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kStandbyCommand, StreamDescriptor::State::STANDBY),
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isInput || isSync
+ ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kPauseCommand, isInput || isSync
+ ? StreamDescriptor::State::PAUSED
+ : StreamDescriptor::State::TRANSFER_PAUSED),
+ std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
+ : StreamDescriptor::State::IDLE),
+ std::make_pair(isInput ? kGetStatusCommand : kStandbyCommand, // no-op for input
+ StreamDescriptor::State::STANDBY),
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isInput || isSync
+ ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING)});
+}
+static const NamedCommandSequence kStandbyInSeq = std::make_tuple(
+ std::string("Standby"), 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false));
+static const NamedCommandSequence kStandbyOutSyncSeq = std::make_tuple(
+ std::string("Standby"), 0, StreamTypeFilter::SYNC, makeStandbyCommands(false, true));
+static const NamedCommandSequence kStandbyOutAsyncSeq =
+ std::make_tuple(std::string("Standby"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeStandbyCommands(false, false));
+
static const NamedCommandSequence kPauseInSeq =
- std::make_pair(std::string("Pause"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)});
-static const NamedCommandSequence kPauseOutSeq =
- std::make_pair(std::string("Pause"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kBurstCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED)});
-static const NamedCommandSequence kFlushInSeq =
- std::make_pair(std::string("Flush"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)});
-static const NamedCommandSequence kFlushOutSeq = std::make_pair(
- std::string("Flush"),
- std::vector<CommandAndState>{std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kFlushCommand, StreamDescriptor::State::IDLE)});
+ std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY,
+ std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)}));
+static const NamedCommandSequence kPauseOutSyncSeq =
+ std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC,
+ std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED)}));
+/* TODO: Figure out a better way for testing sync/async bursts
+static const NamedCommandSequence kPauseOutAsyncSeq = std::make_tuple(
+ std::string("Pause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+ std::make_shared<StaticStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
+ std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAIN_PAUSED),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFER_PAUSED)}));
+*/
+
+std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isInput || isSync
+ ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kPauseCommand, isInput || isSync
+ ? StreamDescriptor::State::PAUSED
+ : StreamDescriptor::State::TRANSFER_PAUSED),
+ std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
+ : StreamDescriptor::State::IDLE)});
+}
+static const NamedCommandSequence kFlushInSeq = std::make_tuple(
+ std::string("Flush"), 0, StreamTypeFilter::ANY, makeFlushCommands(true, false));
+static const NamedCommandSequence kFlushOutSyncSeq = std::make_tuple(
+ std::string("Flush"), 0, StreamTypeFilter::SYNC, makeFlushCommands(false, true));
+static const NamedCommandSequence kFlushOutAsyncSeq =
+ std::make_tuple(std::string("Flush"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeFlushCommands(false, false));
+
+std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
+ std::make_pair(kFlushCommand, StreamDescriptor::State::IDLE)});
+}
+static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
+ std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true));
+static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq =
+ std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false));
+
+// Note, this isn't the "official" enum printer, it is only used to make the test name suffix.
+std::string PrintStreamFilterToString(StreamTypeFilter filter) {
+ switch (filter) {
+ case StreamTypeFilter::ANY:
+ return "";
+ case StreamTypeFilter::SYNC:
+ return "Sync";
+ case StreamTypeFilter::ASYNC:
+ return "Async";
+ }
+ return std::string("Unknown").append(std::to_string(static_cast<int32_t>(filter)));
+}
std::string GetStreamIoTestName(const testing::TestParamInfo<StreamIoTestParameters>& info) {
return android::PrintInstanceNameToString(
testing::TestParamInfo<std::string>{std::get<PARAM_MODULE_NAME>(info.param),
info.index})
.append("_")
- .append(std::get<PARAM_CMD_SEQ>(info.param).first)
+ .append(std::get<NAMED_CMD_NAME>(std::get<PARAM_CMD_SEQ>(info.param)))
+ .append(PrintStreamFilterToString(
+ std::get<NAMED_CMD_STREAM_TYPE>(std::get<PARAM_CMD_SEQ>(info.param))))
.append("_SetupSeq")
.append(std::get<PARAM_SETUP_SEQ>(info.param) ? "2" : "1");
}
+
INSTANTIATE_TEST_SUITE_P(
AudioStreamIoInTest, AudioStreamIoIn,
testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
- testing::Values(kReadOrWriteSeq, kDrainInSeq, kStandbySeq, kPauseInSeq,
+ testing::Values(kReadSeq, kDrainInSeq, kStandbyInSeq, kPauseInSeq,
kFlushInSeq),
testing::Values(false, true)),
GetStreamIoTestName);
@@ -2079,8 +2683,13 @@
INSTANTIATE_TEST_SUITE_P(
AudioStreamIoOutTest, AudioStreamIoOut,
testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
- testing::Values(kReadOrWriteSeq, kDrainOutSeq, kDrainPauseOutSeq,
- kStandbySeq, kPauseOutSeq, kFlushOutSeq),
+ testing::Values(kWriteSyncSeq, kWriteAsyncSeq, kWriteDrainAsyncSeq,
+ kDrainOutSyncSeq, kDrainPauseOutSyncSeq,
+ kDrainPauseOutAsyncSeq, kStandbyOutSyncSeq,
+ kStandbyOutAsyncSeq,
+ kPauseOutSyncSeq, // kPauseOutAsyncSeq,
+ kFlushOutSyncSeq, kFlushOutAsyncSeq,
+ kDrainPauseFlushOutSyncSeq, kDrainPauseFlushOutAsyncSeq),
testing::Values(false, true)),
GetStreamIoTestName);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoOut);
@@ -2095,7 +2704,6 @@
void OnTestStart(const ::testing::TestInfo& test_info) override {
TraceTestState("Started", test_info);
}
-
void OnTestEnd(const ::testing::TestInfo& test_info) override {
TraceTestState("Completed", test_info);
}
@@ -2109,6 +2717,7 @@
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+ android::base::SetMinimumLogSeverity(::android::base::DEBUG);
ABinderProcess_setThreadPoolMaxThreadCount(1);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
diff --git a/audio/common/all-versions/default/service/android.hardware.audio.service.rc b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
index 45fef9a..f859f21 100644
--- a/audio/common/all-versions/default/service/android.hardware.audio.service.rc
+++ b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
@@ -4,6 +4,8 @@
# media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
capabilities BLOCK_SUSPEND
+ # setting RLIMIT_RTPRIO allows binder RT priority inheritance
+ rlimit rtprio 10 10
ioprio rt 4
task_profiles ProcessCapacityHigh HighPerformance
onrestart restart audioserver
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index b954fcd..d03118a 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -30,6 +30,7 @@
#include <algorithm>
#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
#include <mediautils/MemoryLeakTrackUtil.h>
#include <memunreachable/memunreachable.h>
@@ -183,6 +184,7 @@
if (status == OK) {
streamOut = new StreamOut(this, halStream);
++mOpenedStreamsCount;
+ android::hardware::setMinSchedulerPolicy(streamOut, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
}
status_t convertStatus =
HidlUtils::audioConfigFromHal(halConfig, false /*isInput*/, suggestedConfig);
@@ -220,6 +222,7 @@
if (status == OK) {
streamIn = new StreamIn(this, halStream);
++mOpenedStreamsCount;
+ android::hardware::setMinSchedulerPolicy(streamIn, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
}
status_t convertStatus =
HidlUtils::audioConfigFromHal(halConfig, true /*isInput*/, suggestedConfig);
diff --git a/audio/core/all-versions/default/DevicesFactory.cpp b/audio/core/all-versions/default/DevicesFactory.cpp
index f44daf0..011f9ac 100644
--- a/audio/core/all-versions/default/DevicesFactory.cpp
+++ b/audio/core/all-versions/default/DevicesFactory.cpp
@@ -23,6 +23,8 @@
#include <string.h>
#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+#include <system/thread_defs.h>
namespace android {
namespace hardware {
@@ -103,6 +105,7 @@
int halStatus = loadAudioInterface(moduleName, &halDevice);
if (halStatus == OK) {
result = new DeviceShim(halDevice);
+ android::hardware::setMinSchedulerPolicy(result, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
retval = Result::OK;
} else if (halStatus == -EINVAL) {
retval = Result::NOT_INITIALIZED;
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 4b76a0b..719f752 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -955,10 +955,16 @@
ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
const int presentationeEndPrecisionMs = 1000;
const int sampleRate = 44100;
+ // The duration of sine882hz3s.mp3 is: 3 seconds + (576 + 756) samples.
+ // This is a mono file, thus 1 frame = 1 sample for it.
+ const int fullTrackDurationMs = 3000 + (576 + 756) * 1000 / sampleRate;
const int significantSampleNumber = (presentationeEndPrecisionMs * sampleRate) / 1000;
+ // 'delay' is the amount of frames ignored at the beginning, 'padding' is the amount of frames
+ // ignored at the end of the track. Extra 1000 samples are requested for trimming to reduce the
+ // test running time.
const int delay = 576 + 1000;
const int padding = 756 + 1000;
- const int durationMs = 3000 - 44;
+ const int durationMs = fullTrackDurationMs - (delay + padding) * 1000 / sampleRate;
auto start = std::chrono::steady_clock::now();
auto callbacks = sp<OffloadCallbacks>::make();
std::mutex presentationEndLock;
diff --git a/audio/effect/all-versions/default/EffectsFactory.cpp b/audio/effect/all-versions/default/EffectsFactory.cpp
index e93ad89..9bf309c 100644
--- a/audio/effect/all-versions/default/EffectsFactory.cpp
+++ b/audio/effect/all-versions/default/EffectsFactory.cpp
@@ -32,6 +32,7 @@
#include <UuidUtils.h>
#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
#include <media/EffectsFactoryApi.h>
#include <system/audio_effects/effect_aec.h>
#include <system/audio_effects/effect_agc.h>
@@ -44,6 +45,7 @@
#include <system/audio_effects/effect_presetreverb.h>
#include <system/audio_effects/effect_virtualizer.h>
#include <system/audio_effects/effect_visualizer.h>
+#include <system/thread_defs.h>
#include <util/EffectUtils.h>
namespace android {
@@ -189,6 +191,7 @@
status = (*handle)->get_descriptor(handle, &halDescriptor);
if (status == OK) {
effect = dispatchEffectInstanceCreation(halDescriptor, handle);
+ android::hardware::setMinSchedulerPolicy(effect, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
effectId = EffectMap::getInstance().add(handle);
} else {
ALOGE("Error querying effect descriptor for %s: %s",
diff --git a/automotive/remoteaccess/hal/default/Android.bp b/automotive/remoteaccess/hal/default/Android.bp
index a2bf86c..f27b8f8 100644
--- a/automotive/remoteaccess/hal/default/Android.bp
+++ b/automotive/remoteaccess/hal/default/Android.bp
@@ -18,11 +18,9 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-cc_binary {
- name: "android.hardware.automotive.remoteaccess@V1-default-service",
+cc_defaults {
+ name: "remote-access-hal-defaults",
vendor: true,
- vintf_fragments: ["remoteaccess-default-service.xml"],
- init_rc: ["remoteaccess-default-service.rc"],
relative_install_path: "hw",
srcs: ["src/RemoteAccessImpl.cpp"],
whole_static_libs: [
@@ -41,10 +39,29 @@
],
cflags: [
"-Wno-unused-parameter",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.automotive.remoteaccess@V1-default-service",
+ defaults: ["remote-access-hal-defaults"],
+ vintf_fragments: ["remoteaccess-default-service.xml"],
+ init_rc: ["remoteaccess-default-service.rc"],
+ cflags: [
"-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
],
}
+cc_binary {
+ name: "android.hardware.automotive.remoteaccess@V1-tcu-test-service",
+ defaults: ["remote-access-hal-defaults"],
+ vintf_fragments: ["remoteaccess-default-service.xml"],
+ init_rc: ["remoteaccess-tcu-test-service.rc"],
+ cflags: [
+ "-DGRPC_SERVICE_ADDRESS=\"10.10.10.1:50051\"",
+ ],
+}
+
cc_library {
name: "RemoteAccessService",
vendor_available: true,
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc
new file mode 100644
index 0000000..6437d70
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc
@@ -0,0 +1,4 @@
+service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V1-tcu-test-service
+ class hal
+ user vehicle_network
+ group system inet
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
index 5cd58d3..4be30a2 100644
--- a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
@@ -111,7 +111,9 @@
// Try to stop the reading stream.
if (mGetRemoteTasksContext) {
mGetRemoteTasksContext->TryCancel();
- mGetRemoteTasksContext.reset();
+ // Don't reset mGetRemoteTaskContext here since the read stream might still be affective
+ // and might still be using it. This will cause reader->Read to return false and
+ // mGetRemoteTasksContext will be cleared after reader->Finish() is called.
}
mTaskWaitStopped = true;
mCv.notify_all();
@@ -155,6 +157,7 @@
}
}
Status status = reader->Finish();
+ mGetRemoteTasksContext.reset();
ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
status.error_code(), status.error_message().c_str());
diff --git a/automotive/remoteaccess/test_grpc_server/README.md b/automotive/remoteaccess/test_grpc_server/README.md
index 6bc1829..af3d54a 100644
--- a/automotive/remoteaccess/test_grpc_server/README.md
+++ b/automotive/remoteaccess/test_grpc_server/README.md
@@ -75,11 +75,18 @@
* Under android root: `source build/envsetup.sh`
+* Add
+ ```
+ PRODUCT_SOONG_NAMESPACES += hardware/interfaces/automotive/remoteaccess/test_grpc_server/lib`
+ ```
+
+ to `device/generic/car/common/car.mk`.
+
* `lunch sdk_car_x86_64-userdebug`
* `make -j TestWakeupClientServer`
-* `make -j ApPowerControlLib`
+* `make -j ApPOwerControlLib`
## How to push the test wakeup client to a TCU which runs Android.
@@ -99,7 +106,7 @@
* `adb push vendor/bin/TestWakeupClientServer /vendor/bin`
-* `adb push vendor/lib/ApPowerControlLib.so /vendor/lib`
+* `adb push vendor/lib64/ApPowerControlLib.so /vendor/lib64`
* `adb shell`
@@ -116,6 +123,13 @@
* Under android root, `source build/envsetup.sh`
+* Add
+ ```
+ PRODUCT_SOONG_NAMESPACES += hardware/interfaces/automotive/remoteaccess/test_grpc_server/lib`
+ ```
+
+ to `device/generic/car/common/car.mk`.
+
* `lunch sdk_car_x86_64-userdebug`
* `m -j`
@@ -150,8 +164,12 @@
* `make -j TestWakeupClientServer`
+* `make -j ApPOwerControlLib`
+
* `adb push $ANDROID_PRODUCT_OUT/vendor/bin/TestWakeupClientServer /vendor/bin`
+* `adb push $ANDROID_PRODUCT_OUT/vendor/lib64/ApPowerControlLib.so /vendor/lib64`
+
* `adb shell`
* `emulator_car_x86_64:/ # su`
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleDisplay.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleDisplay.aidl
index 5aeafa4..be335ec 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleDisplay.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleDisplay.aidl
@@ -36,4 +36,7 @@
enum VehicleDisplay {
MAIN = 0,
INSTRUMENT_CLUSTER = 1,
+ HUD = 2,
+ INPUT = 3,
+ AUXILIARY = 4,
}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
new file mode 100644
index 0000000..a7fee08
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleHwMotionButtonStateFlag {
+ BUTTON_PRIMARY = 1,
+ BUTTON_SECONDARY = 2,
+ BUTTON_TERTIARY = 4,
+ BUTTON_BACK = 8,
+ BUTTON_FORWARD = 16,
+ BUTTON_STYLUS_PRIMARY = 32,
+ BUTTON_STYLUS_SECONDARY = 64,
+}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
new file mode 100644
index 0000000..db4b41e
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleHwMotionInputAction {
+ ACTION_DOWN = 0,
+ ACTION_UP = 1,
+ ACTION_MOVE = 2,
+ ACTION_CANCEL = 3,
+ ACTION_OUTSIDE = 4,
+ ACTION_POINTER_DOWN = 5,
+ ACTION_POINTER_UP = 6,
+ ACTION_HOVER_MOVE = 7,
+ ACTION_SCROLL = 8,
+ ACTION_HOVER_ENTER = 9,
+ ACTION_HOVER_EXIT = 10,
+ ACTION_BUTTON_PRESS = 11,
+ ACTION_BUTTON_RELEASE = 12,
+}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
new file mode 100644
index 0000000..88c7873
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleHwMotionInputSource {
+ SOURCE_UNKNOWN = 0,
+ SOURCE_KEYBOARD = 1,
+ SOURCE_DPAD = 2,
+ SOURCE_GAMEPAD = 3,
+ SOURCE_TOUCHSCREEN = 4,
+ SOURCE_MOUSE = 5,
+ SOURCE_STYLUS = 6,
+ SOURCE_BLUETOOTH_STYLUS = 7,
+ SOURCE_TRACKBALL = 8,
+ SOURCE_MOUSE_RELATIVE = 9,
+ SOURCE_TOUCHPAD = 10,
+ SOURCE_TOUCH_NAVIGATION = 11,
+ SOURCE_ROTARY_ENCODER = 12,
+ SOURCE_JOYSTICK = 13,
+ SOURCE_HDMI = 14,
+ SOURCE_SENSOR = 15,
+}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
new file mode 100644
index 0000000..2b3bc7f
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleHwMotionToolType {
+ TOOL_TYPE_UNKNOWN = 0,
+ TOOL_TYPE_FINGER = 1,
+ TOOL_TYPE_STYLUS = 2,
+ TOOL_TYPE_MOUSE = 3,
+ TOOL_TYPE_ERASER = 4,
+}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index ab64e07..054e59d 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -71,6 +71,7 @@
CURRENT_GEAR = 289408001,
PARKING_BRAKE_ON = 287310850,
PARKING_BRAKE_AUTO_APPLY = 287310851,
+ EV_BRAKE_REGENERATION_LEVEL = 289408012,
FUEL_LEVEL_LOW = 287310853,
NIGHT_MODE = 287310855,
TURN_SIGNAL_STATE = 289408008,
@@ -114,6 +115,8 @@
AP_POWER_BOOTUP_REASON = 289409538,
DISPLAY_BRIGHTNESS = 289409539,
HW_KEY_INPUT = 289475088,
+ HW_KEY_INPUT_V2 = 367004177,
+ HW_MOTION_INPUT = 367004178,
HW_ROTARY_INPUT = 289475104,
HW_CUSTOM_INPUT = 289475120,
DOOR_POS = 373295872,
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleDisplay.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleDisplay.aidl
index 1759a90..6642eee 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleDisplay.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleDisplay.aidl
@@ -23,5 +23,21 @@
* The primary Android display (for example, center console)
*/
MAIN = 0,
+ /**
+ * Instrument cluster display. This may exist only for driver
+ */
INSTRUMENT_CLUSTER = 1,
+
+ /**
+ * Head Up Display. This may exist only for driver
+ */
+ HUD = 2,
+ /**
+ * Dedicated display for showing IME for {@code MAIN}
+ */
+ INPUT = 3,
+ /**
+ * Auxiliary display which can provide additional screen for {@code MAIN} display
+ */
+ AUXILIARY = 4,
}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
new file mode 100644
index 0000000..5313a55
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.vehicle;
+
+/**
+ * See {@code android.view.MotionEvent#getButtonState()} for more details.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleHwMotionButtonStateFlag {
+ /**
+ * Button state primary
+ */
+ BUTTON_PRIMARY = 0x0001,
+ /**
+ * Button state secondary
+ */
+ BUTTON_SECONDARY = 0x0002,
+ /**
+ * Button state tertiary
+ */
+ BUTTON_TERTIARY = 0x0004,
+ /**
+ * Button state back
+ */
+ BUTTON_BACK = 0x0008,
+ /**
+ * Button state forward
+ */
+ BUTTON_FORWARD = 0x0010,
+ /**
+ * Button state stylus primary
+ */
+ BUTTON_STYLUS_PRIMARY = 0x0020,
+ /**
+ * Button state stylus secondary
+ */
+ BUTTON_STYLUS_SECONDARY = 0x0040,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
new file mode 100644
index 0000000..d80119a
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.vehicle;
+
+/**
+ * See {@code android.view.MotionEvent#ACTION_*} fields for more details.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleHwMotionInputAction {
+ /**
+ * Motion down
+ */
+ ACTION_DOWN = 0,
+ /**
+ * Motion up
+ */
+ ACTION_UP = 1,
+ /**
+ * Motion move
+ */
+ ACTION_MOVE = 2,
+ /**
+ * Motion cancel
+ */
+ ACTION_CANCEL = 3,
+ /**
+ * Motion outside
+ */
+ ACTION_OUTSIDE = 4,
+ /**
+ * Motion pointer down
+ */
+ ACTION_POINTER_DOWN = 5,
+ /**
+ * Motion pointer up
+ */
+ ACTION_POINTER_UP = 6,
+ /**
+ * Motion hover move
+ */
+ ACTION_HOVER_MOVE = 7,
+ /**
+ * Motion scroll
+ */
+ ACTION_SCROLL = 8,
+ /**
+ * Motion hover enter
+ */
+ ACTION_HOVER_ENTER = 9,
+ /**
+ * Motion hover exit
+ */
+ ACTION_HOVER_EXIT = 10,
+ /**
+ * Motion button press
+ */
+ ACTION_BUTTON_PRESS = 11,
+ /**
+ * Motion button release
+ */
+ ACTION_BUTTON_RELEASE = 12,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
new file mode 100644
index 0000000..fb79983
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.vehicle;
+
+/**
+ * See {@code android.view.InputDevice#SOURCE_*} for more details.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleHwMotionInputSource {
+ /**
+ * Unknown source
+ */
+ SOURCE_UNKNOWN = 0,
+ /**
+ * Source keyboard
+ */
+ SOURCE_KEYBOARD = 1,
+ /**
+ * Source dpad
+ */
+ SOURCE_DPAD = 2,
+ /**
+ * Source game pad
+ */
+ SOURCE_GAMEPAD = 3,
+ /**
+ * Source touch screen
+ */
+ SOURCE_TOUCHSCREEN = 4,
+ /**
+ * Source mouse
+ */
+ SOURCE_MOUSE = 5,
+ /**
+ * Source stylus
+ */
+ SOURCE_STYLUS = 6,
+ /**
+ * Source bluetooth stylus
+ */
+ SOURCE_BLUETOOTH_STYLUS = 7,
+ /**
+ * Source trackball
+ */
+ SOURCE_TRACKBALL = 8,
+ /**
+ * Source mouse relative
+ */
+ SOURCE_MOUSE_RELATIVE = 9,
+ /**
+ * Source touchpad
+ */
+ SOURCE_TOUCHPAD = 10,
+ /**
+ * Source touch navigation
+ */
+ SOURCE_TOUCH_NAVIGATION = 11,
+ /**
+ * Source rotary encoder
+ */
+ SOURCE_ROTARY_ENCODER = 12,
+ /**
+ * Source joystick
+ */
+ SOURCE_JOYSTICK = 13,
+ /**
+ * Source hdmi
+ */
+ SOURCE_HDMI = 14,
+ /**
+ * Source sensor
+ */
+ SOURCE_SENSOR = 15,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
new file mode 100644
index 0000000..08c9aed
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.vehicle;
+
+/**
+ * See {@code android.view.MotionEvent#TOOL_TYPE_*} for more details.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleHwMotionToolType {
+ /**
+ * Unknown type such as for a trackballl or other non-pointing device
+ */
+ TOOL_TYPE_UNKNOWN = 0,
+ /**
+ * Finger type
+ */
+ TOOL_TYPE_FINGER = 1,
+ /**
+ * Stylus type
+ */
+ TOOL_TYPE_STYLUS = 2,
+ /**
+ * Mouse type
+ */
+ TOOL_TYPE_MOUSE = 3,
+ /**
+ * Eraser type
+ */
+ TOOL_TYPE_ERASER = 4,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
index baca8ab..b3116bd 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -331,9 +331,11 @@
FUEL_DOOR_OPEN = 0x0308 + 0x10000000 + 0x01000000
+ 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
/**
- * EV battery level in WH, if EV or hybrid
+ * Battery level for EV or hybrid vehicle
*
- * Value may not exceed INFO_EV_BATTERY_CAPACITY
+ * Returns the current battery level, if EV or hybrid. This value will not exceed
+ * EV_CURRENT_BATTERY_CAPACITY. To calculate the battery percentage, use:
+ * (EV_BATTERY_LEVEL/EV_CURRENT_BATTERY_CAPACITY)*100.
*
* @change_mode VehiclePropertyChangeMode.CONTINUOUS
* @access VehiclePropertyAccess.READ
@@ -489,6 +491,21 @@
PARKING_BRAKE_AUTO_APPLY = 0x0403 + 0x10000000 + 0x01000000
+ 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
/**
+ * Regenerative braking level of a electronic vehicle
+ *
+ * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+ * minInt32Value and maxInt32Value must be supported. The minInt32Value must be 0.
+ *
+ * The maxInt32Value in default area's VehicleAreaConfig indicates the maximum amount of energy
+ * regenerated from braking. The minInt32Value in default area's VehicleAreaConfig indicates no
+ * regenerative braking.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ EV_BRAKE_REGENERATION_LEVEL =
+ 0x040C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+ /**
* Warning for fuel low level.
*
* This property corresponds to the low fuel warning on the dashboard.
@@ -1228,6 +1245,62 @@
HW_KEY_INPUT = 0x0A10 + 0x10000000 + 0x01000000
+ 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
/**
+ * Property to feed H/W input events to android
+ *
+ * int32array[0]: target display defined by VehicleDisplay like VehicleDisplay::MAIN,
+ * VehicleDisplay::INSTRUMENT_CLUSTER, VehicleDisplay::AUX
+ * int32array[1]: key code, must use standard android key code like KEYCODE_HOME, KEYCODE_BACK
+ * int32array[2]: action defined in VehicleHwKeyInputAction like
+ * VehicleHwKeyInputAction::ACTION_UP, VehicleHwKeyInputAction::ACTION_UP
+ * int32array[3]: repeat count of the event. For key down events, this is the repeat count
+ * with the first down starting at 0 and counting up from there. For key up
+ * events, this is always equal to 0
+ *
+ * int64array[0]: down time, elapsed nanoseconds since boot. Denotes the time of the most
+ * recent key down event. For the down event, it will be the event time of the
+ * down event itself
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ
+ * @config_flags
+ */
+ HW_KEY_INPUT_V2 =
+ 0x0A11 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.MIXED,
+ /**
+ * Property to feed H/W input events to android
+ *
+ * int32array[0]: target display defined by VehicleDisplay like VehicleDisplay::MAIN,
+ * VehicleDisplay::INSTRUMENT_CLUSTER, VehicleDisplay::AUX
+ * int32array[1]: input type defined in VehicleHwMotionInputSource like
+ * VehicleHwMotionInputSource::SOURCE_KEYBOARD,
+ * VehicleHwMotionInputSource::SOURCE_DPAD
+ * int32array[2]: action code defined in VehicleHwMotionInputAction like
+ * VehicleHwMotionInputAction::ACTION_UP, VehicleHwMotionInputAction::ACTION_DOWN
+ * int32array[3]: button state flag defined in VehicleHwMotionButtonStateFlag like
+ * VehicleHwMotionButtonStateFlag::BUTTON_PRIMARY,
+ * VehicleHwMotionButtonStateFlag::BUTTON_SECONDARY
+ * int32array[4]: pointer events count, N. N must be a positive integer
+ * int32array[5:5+N-1]: pointer id, length N
+ * int32array[5+N:5+2*N-1] : tool type, length N. As defined in VehicleHwMotionToolType like
+ * VehicleHwMotionToolType::TOOL_TYPE_FINGER,
+ * VehicleHwMotionToolType::TOOL_TYPE_STYLUS
+ *
+ * floatArray[0:N-1] : x data, length N
+ * floatArray[N:2*N-1] : y data, length N
+ * floatArray[2*N:3*N-1] : pressure data, length N
+ * floatArray[3*N:4*N-1] : size data, length N
+ *
+ * int64array[0]: down time, elapsed nanoseconds since boot. Denotes the time when the user
+ * originally pressed down to start a stream of position events. For the down
+ * event, it will be the event time of the down event itself
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ
+ * @config_flags
+ */
+ HW_MOTION_INPUT =
+ 0x0A12 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.MIXED,
+ /**
* Property to feed H/W rotary events to android
*
* int32Values[0] : RotaryInputType identifying which rotary knob rotated
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
index 85ca474..82daa61 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
@@ -71,6 +71,7 @@
{VehicleProperty::CURRENT_GEAR, VehiclePropertyAccess::READ},
{VehicleProperty::PARKING_BRAKE_ON, VehiclePropertyAccess::READ},
{VehicleProperty::PARKING_BRAKE_AUTO_APPLY, VehiclePropertyAccess::READ},
+ {VehicleProperty::EV_BRAKE_REGENERATION_LEVEL, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::FUEL_LEVEL_LOW, VehiclePropertyAccess::READ},
{VehicleProperty::NIGHT_MODE, VehiclePropertyAccess::READ},
{VehicleProperty::TURN_SIGNAL_STATE, VehiclePropertyAccess::READ},
@@ -114,6 +115,8 @@
{VehicleProperty::AP_POWER_BOOTUP_REASON, VehiclePropertyAccess::READ},
{VehicleProperty::DISPLAY_BRIGHTNESS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::HW_KEY_INPUT, VehiclePropertyAccess::READ},
+ {VehicleProperty::HW_KEY_INPUT_V2, VehiclePropertyAccess::READ},
+ {VehicleProperty::HW_MOTION_INPUT, VehiclePropertyAccess::READ},
{VehicleProperty::HW_ROTARY_INPUT, VehiclePropertyAccess::READ},
{VehicleProperty::HW_CUSTOM_INPUT, VehiclePropertyAccess::READ},
{VehicleProperty::DOOR_POS, VehiclePropertyAccess::READ_WRITE},
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
index f95580a..419c6de 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
@@ -71,6 +71,7 @@
{VehicleProperty::CURRENT_GEAR, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::PARKING_BRAKE_ON, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::PARKING_BRAKE_AUTO_APPLY, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::EV_BRAKE_REGENERATION_LEVEL, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::FUEL_LEVEL_LOW, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::NIGHT_MODE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::TURN_SIGNAL_STATE, VehiclePropertyChangeMode::ON_CHANGE},
@@ -114,6 +115,8 @@
{VehicleProperty::AP_POWER_BOOTUP_REASON, VehiclePropertyChangeMode::STATIC},
{VehicleProperty::DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::HW_KEY_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::HW_KEY_INPUT_V2, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::HW_MOTION_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::HW_ROTARY_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::HW_CUSTOM_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::DOOR_POS, VehiclePropertyChangeMode::ON_CHANGE},
diff --git a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
index d0caed2..7c6a92e 100644
--- a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
@@ -63,6 +63,7 @@
Map.entry(VehicleProperty.CURRENT_GEAR, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.PARKING_BRAKE_ON, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.PARKING_BRAKE_AUTO_APPLY, VehiclePropertyAccess.READ),
+ Map.entry(VehicleProperty.EV_BRAKE_REGENERATION_LEVEL, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.FUEL_LEVEL_LOW, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.NIGHT_MODE, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.TURN_SIGNAL_STATE, VehiclePropertyAccess.READ),
@@ -106,6 +107,8 @@
Map.entry(VehicleProperty.AP_POWER_BOOTUP_REASON, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.DISPLAY_BRIGHTNESS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.HW_KEY_INPUT, VehiclePropertyAccess.READ),
+ Map.entry(VehicleProperty.HW_KEY_INPUT_V2, VehiclePropertyAccess.READ),
+ Map.entry(VehicleProperty.HW_MOTION_INPUT, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.HW_ROTARY_INPUT, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.HW_CUSTOM_INPUT, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.DOOR_POS, VehiclePropertyAccess.READ_WRITE),
diff --git a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
index 96fe0a5..c54702b 100644
--- a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
@@ -63,6 +63,7 @@
Map.entry(VehicleProperty.CURRENT_GEAR, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.PARKING_BRAKE_ON, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.PARKING_BRAKE_AUTO_APPLY, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.EV_BRAKE_REGENERATION_LEVEL, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.FUEL_LEVEL_LOW, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.NIGHT_MODE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.TURN_SIGNAL_STATE, VehiclePropertyChangeMode.ON_CHANGE),
@@ -106,6 +107,8 @@
Map.entry(VehicleProperty.AP_POWER_BOOTUP_REASON, VehiclePropertyChangeMode.STATIC),
Map.entry(VehicleProperty.DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.HW_KEY_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.HW_KEY_INPUT_V2, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.HW_MOTION_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.HW_ROTARY_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.HW_CUSTOM_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.DOOR_POS, VehiclePropertyChangeMode.ON_CHANGE),
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index bd80ad5..5623b87 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -123,7 +123,7 @@
"property": "VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS",
"defaultValue": {
"int32Values": [
- "VehicleUnit::KILOMETERS_PER_HOUR"
+ "VehicleUnit::MILES_PER_HOUR"
]
},
"configArray": [
@@ -1545,6 +1545,21 @@
}
},
{
+ "property": "VehicleProperty::EV_BRAKE_REGENERATION_LEVEL",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": 0,
+ "minInt32Value": 0,
+ "maxInt32Value": 3
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::FUEL_LEVEL_LOW",
"defaultValue": {
"int32Values": [
@@ -1556,7 +1571,7 @@
"property": "VehicleProperty::FUEL_VOLUME_DISPLAY_UNITS",
"defaultValue": {
"int32Values": [
- "VehicleUnit::LITER"
+ "VehicleUnit::US_GALLON"
]
},
"configArray": [
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 0a502c3..736ecaa 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -627,11 +627,7 @@
} else if (EqualsIgnoreCase(option, "--inject-event")) {
result.buffer = dumpInjectEvent(options);
} else if (EqualsIgnoreCase(option, kUserHalDumpOption)) {
- if (options.size() == 1) {
- result.buffer = mFakeUserHal->showDumpHelp();
- } else {
- result.buffer = mFakeUserHal->dump(options[1]);
- }
+ result.buffer = mFakeUserHal->dump();
} else if (EqualsIgnoreCase(option, "--genfakedata")) {
result.buffer = genFakeDataCommand(options);
} else {
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 3f97a4d..0184462 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -1520,26 +1520,16 @@
ASSERT_THAT(result.buffer, ContainsRegex("Invalid option: --invalid"));
}
-TEST_F(FakeVehicleHardwareTest, testDumpFakeUserHalHelp) {
- std::vector<std::string> options;
- options.push_back("--user-hal");
-
- DumpResult result = getHardware()->dump(options);
- ASSERT_FALSE(result.callerShouldDumpState);
- ASSERT_NE(result.buffer, "");
- ASSERT_THAT(result.buffer, ContainsRegex("dumps state used for user management"));
-}
-
TEST_F(FakeVehicleHardwareTest, testDumpFakeUserHal) {
std::vector<std::string> options;
options.push_back("--user-hal");
- // Indent: " ".
- options.push_back(" ");
DumpResult result = getHardware()->dump(options);
ASSERT_FALSE(result.callerShouldDumpState);
ASSERT_NE(result.buffer, "");
- ASSERT_THAT(result.buffer, ContainsRegex(" No InitialUserInfo response\n"));
+ ASSERT_THAT(result.buffer,
+ ContainsRegex("No InitialUserInfo response\nNo SwitchUser response\nNo CreateUser "
+ "response\nNo SetUserIdentificationAssociation response\n"));
}
struct SetPropTestCase {
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h b/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
index 4ae9c8c..fcbe8fd 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
@@ -64,7 +64,7 @@
std::string showDumpHelp() const;
// Dump its contents.
- std::string dump(std::string indent) const;
+ std::string dump() const;
private:
const std::shared_ptr<VehiclePropValuePool> mValuePool;
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
index 91318be..878c2e7 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
@@ -339,33 +339,31 @@
return fmt::format("{}: dumps state used for user management\n", kUserHalDumpOption);
}
-std::string FakeUserHal::dump(std::string indent) const {
+std::string FakeUserHal::dump() const {
std::scoped_lock<std::mutex> lockGuard(mLock);
std::string info;
if (mInitialUserResponseFromCmd != nullptr) {
- info += fmt::format("{}InitialUserInfo response: {}\n", indent,
+ info += fmt::format("InitialUserInfo response: {}\n",
mInitialUserResponseFromCmd->toString());
} else {
- info += fmt::format("{}No InitialUserInfo response\n", indent);
+ info += "No InitialUserInfo response\n";
}
if (mSwitchUserResponseFromCmd != nullptr) {
- info += fmt::format("{}SwitchUser response: {}\n", indent,
- mSwitchUserResponseFromCmd->toString());
+ info += fmt::format("SwitchUser response: {}\n", mSwitchUserResponseFromCmd->toString());
} else {
- info += fmt::format("{}No SwitchUser response\n", indent);
+ info += "No SwitchUser response\n";
}
if (mCreateUserResponseFromCmd != nullptr) {
- info += fmt::format("{}CreateUser response: {}\n", indent,
- mCreateUserResponseFromCmd->toString());
+ info += fmt::format("CreateUser response: {}\n", mCreateUserResponseFromCmd->toString());
} else {
- info += fmt::format("{}No CreateUser response\n", indent);
+ info += "No CreateUser response\n";
}
if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
- info += fmt::format("{}SetUserIdentificationAssociation response: {}\n", indent,
+ info += fmt::format("SetUserIdentificationAssociation response: {}\n",
mSetUserIdentificationAssociationResponseFromCmd->toString());
} else {
- info += fmt::format("{}No SetUserIdentificationAssociation response\n", indent);
+ info += "No SetUserIdentificationAssociation response\n";
}
return info;
}
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index d447bf8..4a4e023 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -789,10 +789,13 @@
for (uint32_t i = 0; i < numArgs; i++) {
options.push_back(args[i]);
}
+ if (options.size() == 1 && options[0] == "-a") {
+ // Ignore "-a" option. Bugreport will call with this option.
+ options.clear();
+ }
DumpResult result = mVehicleHardware->dump(options);
dprintf(fd, "%s", (result.buffer + "\n").c_str());
if (!result.callerShouldDumpState) {
- dprintf(fd, "Skip dumping Vehicle HAL State.\n");
return STATUS_OK;
}
dprintf(fd, "Vehicle HAL State: \n");
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 7eefe2a..33a697c 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -481,6 +481,12 @@
actualPropertyType);
}
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvBrakeRegenerationLevelConfig) {
+ verifyProperty(VehicleProperty::EV_BRAKE_REGENERATION_LEVEL,
+ VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+ VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDoorChildLockEnabledConfig) {
verifyProperty(VehicleProperty::DOOR_CHILD_LOCK_ENABLED, VehiclePropertyAccess::READ_WRITE,
VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-example.rc b/biometrics/fingerprint/aidl/default/fingerprint-example.rc
index 574438e..10db00d 100644
--- a/biometrics/fingerprint/aidl/default/fingerprint-example.rc
+++ b/biometrics/fingerprint/aidl/default/fingerprint-example.rc
@@ -2,3 +2,8 @@
class hal
user nobody
group nobody
+ disabled
+on property:ro.vendor.fingerprint_virtual_hal_start=true
+ enable vendor.fingerprint-example
+on property:persist.vendor.fingerprint.virtual.type=*
+ enable vendor.fingerprint-example
diff --git a/camera/common/aidl/Android.bp b/camera/common/aidl/Android.bp
index d21ae58..e1c9cc5 100644
--- a/camera/common/aidl/Android.bp
+++ b/camera/common/aidl/Android.bp
@@ -19,6 +19,9 @@
java: {
enabled: false,
},
+ rust: {
+ enabled: true,
+ }
},
versions_with_info: [
{
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index c184677..2e5b667 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -27,6 +27,9 @@
sdk_version: "module_current",
enabled: false,
},
+ rust: {
+ enabled: true,
+ }
},
versions_with_info: [
{
diff --git a/camera/device/default/ExternalCameraDeviceSession.cpp b/camera/device/default/ExternalCameraDeviceSession.cpp
index 68c6d2e..736bc3c 100644
--- a/camera/device/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/default/ExternalCameraDeviceSession.cpp
@@ -714,8 +714,8 @@
return Status::ILLEGAL_ARGUMENT;
}
- if (info == nullptr || results == nullptr || info == nullptr || session == nullptr) {
- ALOGE("%s, output arguments (%p, %p, %p, %p) much not be null", __FUNCTION__, msgs, results,
+ if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) {
+ ALOGE("%s, output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__, msgs, results,
info, session);
}
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index 301a943..0113a4b 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -19,6 +19,9 @@
java: {
enabled: false,
},
+ rust: {
+ enabled: true,
+ }
},
versions_with_info: [
{
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl
index 8bed156..e28ecad 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl
@@ -70,5 +70,6 @@
ANDROID_HEIC_INFO = 29,
ANDROID_AUTOMOTIVE = 30,
ANDROID_AUTOMOTIVE_LENS = 31,
+ ANDROID_EXTENSION = 32,
VENDOR_SECTION = 32768,
}
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
index 1725347..a223309 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
@@ -70,5 +70,6 @@
ANDROID_HEIC_INFO_START = 1900544,
ANDROID_AUTOMOTIVE_START = 1966080,
ANDROID_AUTOMOTIVE_LENS_START = 2031616,
+ ANDROID_EXTENSION_START = 2097152,
VENDOR_SECTION_START = -2147483648,
}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl
index 99e28b9..0d79f0d 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl
@@ -61,5 +61,6 @@
ANDROID_HEIC_INFO,
ANDROID_AUTOMOTIVE,
ANDROID_AUTOMOTIVE_LENS,
+ ANDROID_EXTENSION,
VENDOR_SECTION = 0x8000,
}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
index 62c71e9..8f57128 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
@@ -63,5 +63,6 @@
ANDROID_HEIC_INFO_START = CameraMetadataSection.ANDROID_HEIC_INFO << 16,
ANDROID_AUTOMOTIVE_START = CameraMetadataSection.ANDROID_AUTOMOTIVE << 16,
ANDROID_AUTOMOTIVE_LENS_START = CameraMetadataSection.ANDROID_AUTOMOTIVE_LENS << 16,
+ ANDROID_EXTENSION_START = CameraMetadataSection.ANDROID_EXTENSION << 16,
VENDOR_SECTION_START = CameraMetadataSection.VENDOR_SECTION << 16,
}
diff --git a/camera/provider/aidl/Android.bp b/camera/provider/aidl/Android.bp
index d7e613e..19dede0 100644
--- a/camera/provider/aidl/Android.bp
+++ b/camera/provider/aidl/Android.bp
@@ -26,6 +26,9 @@
cpp: {
enabled: false,
},
+ rust: {
+ enabled: true,
+ },
},
versions_with_info: [
{
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 7f6890c..f3ea8e8 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -36,6 +36,9 @@
],
min_sdk_version: "29",
},
+ rust: {
+ enabled: true,
+ }
},
frozen: true,
versions: [
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 95fcc41..0715575 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -36,6 +36,9 @@
],
min_sdk_version: "29",
},
+ rust: {
+ enabled: true,
+ }
},
frozen: true,
versions: ["1"],
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 61438b4..03411d0 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -277,7 +277,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.graphics.composer3</name>
- <version>1</version>
+ <version>2</version>
<interface>
<name>IComposer</name>
<instance>default</instance>
@@ -424,14 +424,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.oemlock</name>
- <version>1.0</version>
- <interface>
- <name>IOemLock</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="false">
<name>android.hardware.power</name>
<version>2-4</version>
@@ -557,15 +549,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.secure_element</name>
- <version>1.0-2</version>
- <interface>
- <name>ISecureElement</name>
- <regex-instance>eSE[1-9][0-9]*</regex-instance>
- <regex-instance>SIM[1-9][0-9]*</regex-instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.secure_element</name>
<version>1</version>
diff --git a/current.txt b/current.txt
index 146ded6..0fb8b49 100644
--- a/current.txt
+++ b/current.txt
@@ -931,5 +931,6 @@
# ABI preserving changes to HALs during Android U
2aa559cda86c358c6429114ef6bc72c1b43281e98f9eb6b4df5e7073c8d05767 android.hardware.automotive.vehicle@2.0::types
+42abd285a4293dadb8c89bc63b90cae2872fbffe90c4517aa3ea4965e8aecff7 android.hardware.graphics.common@1.2::types
# There will be no more HIDL HALs. Use AIDL instead.
diff --git a/graphics/common/1.2/types.hal b/graphics/common/1.2/types.hal
index ebea1dc..07e9882 100644
--- a/graphics/common/1.2/types.hal
+++ b/graphics/common/1.2/types.hal
@@ -77,6 +77,8 @@
HEIF = 0x1004,
};
+@export(name="android_color_mode_v1_2_t", value_prefix="HAL_COLOR_MODE_",
+ export_parent="false")
enum ColorMode : @1.1::ColorMode {
/**
* DISPLAY_BT2020 corresponds with display settings that implement the ITU-R
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 84bc1af..6c8ff4b 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -39,6 +39,9 @@
],
min_sdk_version: "29",
},
+ rust: {
+ enabled: true,
+ }
},
frozen: false,
versions_with_info: [
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index fa66812..4d7bf13 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -811,8 +811,7 @@
EXPECT_TRUE(status.isOk());
}
-// TODO(b/250036572): disable this due to no implementation and revup on cuttlefish
-TEST_P(GraphicsComposerAidlTest, DISABLED_GetOverlaySupport) {
+TEST_P(GraphicsComposerAidlTest, GetOverlaySupport) {
const auto& [status, _] = mComposerClient->getOverlaySupport();
if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
diff --git a/media/bufferpool/aidl/Android.bp b/media/bufferpool/aidl/Android.bp
index 68ac489..5ea2948 100644
--- a/media/bufferpool/aidl/Android.bp
+++ b/media/bufferpool/aidl/Android.bp
@@ -24,6 +24,7 @@
aidl_interface {
name: "android.hardware.media.bufferpool2",
vendor_available: true,
+ double_loadable: true,
srcs: ["android/hardware/media/bufferpool2/*.aidl"],
imports: [
"android.hardware.common-V2",
diff --git a/media/c2/aidl/Android.bp b/media/c2/aidl/Android.bp
index 10867c0..56531db 100644
--- a/media/c2/aidl/Android.bp
+++ b/media/c2/aidl/Android.bp
@@ -1,8 +1,18 @@
// This is the expected build file, but it may not be right in all cases
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
aidl_interface {
name: "android.hardware.media.c2",
vendor_available: true,
+ double_loadable: true,
srcs: ["android/hardware/media/c2/*.aidl"],
include_dirs: [
"frameworks/native/aidl/gui",
diff --git a/neuralnetworks/1.2/utils/src/BurstUtils.cpp b/neuralnetworks/1.2/utils/src/BurstUtils.cpp
index b589c46..c4c096d 100644
--- a/neuralnetworks/1.2/utils/src/BurstUtils.cpp
+++ b/neuralnetworks/1.2/utils/src/BurstUtils.cpp
@@ -190,12 +190,13 @@
size_t index = 0;
// validate packet information
- if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::packetInformation) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage packet information
- const FmqRequestDatum::PacketInformation& packetInfo = data[index].packetInformation();
+ const FmqRequestDatum::PacketInformation& packetInfo = data.at(index).packetInformation();
index++;
const uint32_t packetSize = packetInfo.packetSize;
const uint32_t numberOfInputOperands = packetInfo.numberOfInputOperands;
@@ -212,13 +213,14 @@
inputs.reserve(numberOfInputOperands);
for (size_t operand = 0; operand < numberOfInputOperands; ++operand) {
// validate input operand information
- if (data[index].getDiscriminator() != discriminator::inputOperandInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::inputOperandInformation) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage operand information
const FmqRequestDatum::OperandInformation& operandInfo =
- data[index].inputOperandInformation();
+ data.at(index).inputOperandInformation();
index++;
const bool hasNoValue = operandInfo.hasNoValue;
const V1_0::DataLocation location = operandInfo.location;
@@ -229,12 +231,13 @@
dimensions.reserve(numberOfDimensions);
for (size_t i = 0; i < numberOfDimensions; ++i) {
// validate dimension
- if (data[index].getDiscriminator() != discriminator::inputOperandDimensionValue) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::inputOperandDimensionValue) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage dimension
- const uint32_t dimension = data[index].inputOperandDimensionValue();
+ const uint32_t dimension = data.at(index).inputOperandDimensionValue();
index++;
// store result
@@ -251,13 +254,14 @@
outputs.reserve(numberOfOutputOperands);
for (size_t operand = 0; operand < numberOfOutputOperands; ++operand) {
// validate output operand information
- if (data[index].getDiscriminator() != discriminator::outputOperandInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::outputOperandInformation) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage operand information
const FmqRequestDatum::OperandInformation& operandInfo =
- data[index].outputOperandInformation();
+ data.at(index).outputOperandInformation();
index++;
const bool hasNoValue = operandInfo.hasNoValue;
const V1_0::DataLocation location = operandInfo.location;
@@ -268,12 +272,13 @@
dimensions.reserve(numberOfDimensions);
for (size_t i = 0; i < numberOfDimensions; ++i) {
// validate dimension
- if (data[index].getDiscriminator() != discriminator::outputOperandDimensionValue) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::outputOperandDimensionValue) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage dimension
- const uint32_t dimension = data[index].outputOperandDimensionValue();
+ const uint32_t dimension = data.at(index).outputOperandDimensionValue();
index++;
// store result
@@ -290,12 +295,13 @@
slots.reserve(numberOfPools);
for (size_t pool = 0; pool < numberOfPools; ++pool) {
// validate input operand information
- if (data[index].getDiscriminator() != discriminator::poolIdentifier) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::poolIdentifier) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage operand information
- const int32_t poolId = data[index].poolIdentifier();
+ const int32_t poolId = data.at(index).poolIdentifier();
index++;
// store result
@@ -303,17 +309,17 @@
}
// validate measureTiming
- if (data[index].getDiscriminator() != discriminator::measureTiming) {
+ if (index >= data.size() || data.at(index).getDiscriminator() != discriminator::measureTiming) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage measureTiming
- const V1_2::MeasureTiming measure = data[index].measureTiming();
+ const V1_2::MeasureTiming measure = data.at(index).measureTiming();
index++;
// validate packet information
if (index != packetSize) {
- return NN_ERROR() << "FMQ Result packet ill-formed";
+ return NN_ERROR() << "FMQ Request packet ill-formed";
}
// return request
@@ -328,12 +334,13 @@
size_t index = 0;
// validate packet information
- if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::packetInformation) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage packet information
- const FmqResultDatum::PacketInformation& packetInfo = data[index].packetInformation();
+ const FmqResultDatum::PacketInformation& packetInfo = data.at(index).packetInformation();
index++;
const uint32_t packetSize = packetInfo.packetSize;
const V1_0::ErrorStatus errorStatus = packetInfo.errorStatus;
@@ -349,12 +356,13 @@
outputShapes.reserve(numberOfOperands);
for (size_t operand = 0; operand < numberOfOperands; ++operand) {
// validate operand information
- if (data[index].getDiscriminator() != discriminator::operandInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::operandInformation) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage operand information
- const FmqResultDatum::OperandInformation& operandInfo = data[index].operandInformation();
+ const FmqResultDatum::OperandInformation& operandInfo = data.at(index).operandInformation();
index++;
const bool isSufficient = operandInfo.isSufficient;
const uint32_t numberOfDimensions = operandInfo.numberOfDimensions;
@@ -364,12 +372,13 @@
dimensions.reserve(numberOfDimensions);
for (size_t i = 0; i < numberOfDimensions; ++i) {
// validate dimension
- if (data[index].getDiscriminator() != discriminator::operandDimensionValue) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::operandDimensionValue) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage dimension
- const uint32_t dimension = data[index].operandDimensionValue();
+ const uint32_t dimension = data.at(index).operandDimensionValue();
index++;
// store result
@@ -381,12 +390,13 @@
}
// validate execution timing
- if (data[index].getDiscriminator() != discriminator::executionTiming) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::executionTiming) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage execution timing
- const V1_2::Timing timing = data[index].executionTiming();
+ const V1_2::Timing timing = data.at(index).executionTiming();
index++;
// validate packet information
diff --git a/security/keymint/aidl/Android.bp b/security/keymint/aidl/Android.bp
index 5a76a21..4753afb 100644
--- a/security/keymint/aidl/Android.bp
+++ b/security/keymint/aidl/Android.bp
@@ -71,6 +71,13 @@
],
}
+cc_defaults {
+ name: "keymint_use_latest_hal_aidl_cpp_shared",
+ shared_libs: [
+ "android.hardware.security.keymint-V3-cpp",
+ ],
+}
+
// A rust_defaults that includes the latest KeyMint AIDL library.
// Modules that depend on KeyMint directly can include this cc_defaults to avoid
// managing dependency versions explicitly.
diff --git a/sensors/1.0/default/Android.bp b/sensors/1.0/default/Android.bp
index 2e4e1b0..bb31050 100644
--- a/sensors/1.0/default/Android.bp
+++ b/sensors/1.0/default/Android.bp
@@ -44,6 +44,12 @@
"libhidlbase",
"android.hardware.sensors@1.0",
],
+ whole_static_libs: [
+ "sensors_common_convert",
+ ],
+ export_static_lib_headers: [
+ "sensors_common_convert",
+ ],
local_include_dirs: ["include/sensors"],
export_shared_lib_headers: [
"libhardware",
diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp
index 43ee327..ae71a97 100644
--- a/sensors/1.0/default/convert.cpp
+++ b/sensors/1.0/default/convert.cpp
@@ -196,6 +196,11 @@
}
}
+void convertFromASensorEvent(const ASensorEvent& src, Event* dst) {
+ convertFromSensorEvent(
+ android::hardware::sensors::implementation::common::convertASensorEvent(src), dst);
+}
+
void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
*dst = {.version = sizeof(sensors_event_t),
.sensor = src.sensorHandle,
diff --git a/sensors/1.0/default/include/sensors/convert.h b/sensors/1.0/default/include/sensors/convert.h
index c3a0125..ae773df 100644
--- a/sensors/1.0/default/include/sensors/convert.h
+++ b/sensors/1.0/default/include/sensors/convert.h
@@ -20,6 +20,7 @@
#include <android/hardware/sensors/1.0/ISensors.h>
#include <hardware/sensors.h>
+#include <sensors/common_convert.h>
namespace android {
namespace hardware {
@@ -31,6 +32,7 @@
void convertToSensor(const SensorInfo &src, sensor_t *dst);
void convertFromSensorEvent(const sensors_event_t &src, Event *dst);
+void convertFromASensorEvent(const ASensorEvent& src, Event* dst);
void convertToSensorEvent(const Event &src, sensors_event_t *dst);
bool convertFromSharedMemInfo(const SharedMemInfo& memIn, sensors_direct_mem_t *memOut);
diff --git a/sensors/aidl/convert/Android.bp b/sensors/aidl/convert/Android.bp
index d47de8e..0b31597 100644
--- a/sensors/aidl/convert/Android.bp
+++ b/sensors/aidl/convert/Android.bp
@@ -37,6 +37,12 @@
"libutils",
"android.hardware.sensors-V1-ndk",
],
+ whole_static_libs: [
+ "sensors_common_convert",
+ ],
+ export_static_lib_headers: [
+ "sensors_common_convert",
+ ],
local_include_dirs: ["include/aidl/sensors"],
export_shared_lib_headers: [
"libhardware",
diff --git a/sensors/aidl/convert/convert.cpp b/sensors/aidl/convert/convert.cpp
index 415f435..abd4d55 100644
--- a/sensors/aidl/convert/convert.cpp
+++ b/sensors/aidl/convert/convert.cpp
@@ -490,6 +490,10 @@
}
}
+void convertFromASensorEvent(const ASensorEvent& src, Event* dst) {
+ convertFromSensorEvent(common::convertASensorEvent(src), dst);
+}
+
} // namespace implementation
} // namespace sensors
} // namespace hardware
diff --git a/sensors/aidl/convert/include/aidl/sensors/convert.h b/sensors/aidl/convert/include/aidl/sensors/convert.h
index 702b226..44504fe 100644
--- a/sensors/aidl/convert/include/aidl/sensors/convert.h
+++ b/sensors/aidl/convert/include/aidl/sensors/convert.h
@@ -18,6 +18,7 @@
#include <aidl/android/hardware/sensors/ISensors.h>
#include <hardware/sensors.h>
+#include <sensors/common_convert.h>
namespace android {
namespace hardware {
@@ -29,6 +30,7 @@
void convertToSensorEvent(const aidl::android::hardware::sensors::Event& src, sensors_event_t* dst);
void convertFromSensorEvent(const sensors_event_t& src,
aidl::android::hardware::sensors::Event* dst);
+void convertFromASensorEvent(const ASensorEvent& src, aidl::android::hardware::sensors::Event* dst);
} // namespace implementation
} // namespace sensors
diff --git a/sensors/common/convert/Android.bp b/sensors/common/convert/Android.bp
new file mode 100644
index 0000000..230665e
--- /dev/null
+++ b/sensors/common/convert/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+ name: "sensors_common_convert",
+ srcs: [
+ "convert.cpp",
+ ],
+ vendor_available: true,
+ host_supported: true,
+ local_include_dirs: ["include"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libhardware",
+ ],
+ header_libs: [
+ "libandroid_sensor_headers",
+ ],
+
+ export_include_dirs: ["include"],
+ export_header_lib_headers: [
+ "libandroid_sensor_headers",
+ ],
+}
diff --git a/sensors/common/convert/convert.cpp b/sensors/common/convert/convert.cpp
new file mode 100644
index 0000000..27de32c
--- /dev/null
+++ b/sensors/common/convert/convert.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <sensors/common_convert.h>
+#include <cstring>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+namespace common {
+
+sensors_event_t convertASensorEvent(const ASensorEvent& src) {
+ // Attempt to ensure these types are compatible.
+ static_assert(sizeof(sensors_event_t) == sizeof(ASensorEvent));
+ static_assert(offsetof(sensors_event_t, timestamp) == offsetof(ASensorEvent, timestamp));
+ static_assert(offsetof(sensors_event_t, flags) == offsetof(ASensorEvent, flags));
+
+ // TODO(b/259711109) Follow up work to handle this in a safer way.
+ return *reinterpret_cast<const sensors_event_t*>(&src);
+}
+
+} // namespace common
+} // namespace implementation
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/common/convert/include/sensors/common_convert.h b/sensors/common/convert/include/sensors/common_convert.h
new file mode 100644
index 0000000..a281369
--- /dev/null
+++ b/sensors/common/convert/include/sensors/common_convert.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/sensor.h>
+#include <hardware/sensors.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+namespace common {
+
+sensors_event_t convertASensorEvent(const ASensorEvent& aEvent);
+
+} // namespace common
+} // namespace implementation
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
index 50be508..dfd8686 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@VintfStability
parcelable CoolingDevice {
android.hardware.thermal.CoolingType type;
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
index 57c8939..d2eb389 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@Backing(type="int") @VintfStability
enum CoolingType {
FAN = 0,
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
index 0aed5ec..c9b6cab 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@VintfStability
interface IThermal {
android.hardware.thermal.CoolingDevice[] getCoolingDevices();
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
index 6b3f922..5e1d753 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@VintfStability
interface IThermalChangedCallback {
oneway void notifyThrottling(in android.hardware.thermal.Temperature temperature);
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl
index 7156415..3bf08bf 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@VintfStability
parcelable Temperature {
android.hardware.thermal.TemperatureType type;
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl
index 6da561f..c5ca4b9 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@VintfStability
parcelable TemperatureThreshold {
android.hardware.thermal.TemperatureType type;
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
index c6a08c1..0a9efdd 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@Backing(type="int") @VintfStability
enum TemperatureType {
UNKNOWN = -1,
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl
index e86b581..8fe3df6 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@Backing(type="int") @VintfStability
enum ThrottlingSeverity {
NONE = 0,
diff --git a/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
index 6d974a5..1f2360d 100644
--- a/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
+++ b/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
@@ -18,6 +18,7 @@
import android.hardware.thermal.CoolingType;
+/* @hide */
@VintfStability
parcelable CoolingDevice {
/**
diff --git a/thermal/aidl/android/hardware/thermal/CoolingType.aidl b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
index 1b430d2..08beb55 100644
--- a/thermal/aidl/android/hardware/thermal/CoolingType.aidl
+++ b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
@@ -18,6 +18,7 @@
/**
* Device cooling device types
+ * @hide
*/
@VintfStability
@Backing(type="int")
diff --git a/thermal/aidl/android/hardware/thermal/IThermal.aidl b/thermal/aidl/android/hardware/thermal/IThermal.aidl
index 8b79cb4..dd87b3a 100644
--- a/thermal/aidl/android/hardware/thermal/IThermal.aidl
+++ b/thermal/aidl/android/hardware/thermal/IThermal.aidl
@@ -23,6 +23,7 @@
import android.hardware.thermal.TemperatureThreshold;
import android.hardware.thermal.TemperatureType;
+/* @hide */
@VintfStability
interface IThermal {
/**
diff --git a/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl b/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
index 6fe2dac..105f085 100644
--- a/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
+++ b/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
@@ -20,6 +20,7 @@
/**
* IThermalChangedCallback send throttling notification to clients.
+ * @hide
*/
@VintfStability
interface IThermalChangedCallback {
diff --git a/thermal/aidl/android/hardware/thermal/Temperature.aidl b/thermal/aidl/android/hardware/thermal/Temperature.aidl
index f0041ed..281d68d 100644
--- a/thermal/aidl/android/hardware/thermal/Temperature.aidl
+++ b/thermal/aidl/android/hardware/thermal/Temperature.aidl
@@ -19,6 +19,7 @@
import android.hardware.thermal.TemperatureType;
import android.hardware.thermal.ThrottlingSeverity;
+/* @hide */
@VintfStability
parcelable Temperature {
/**
diff --git a/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl b/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
index 9ecdab3..8065f76 100644
--- a/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
+++ b/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
@@ -18,6 +18,7 @@
import android.hardware.thermal.TemperatureType;
+/* @hide */
@VintfStability
parcelable TemperatureThreshold {
/**
diff --git a/thermal/aidl/android/hardware/thermal/TemperatureType.aidl b/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
index aebe7ce..467d096 100644
--- a/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
+++ b/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
@@ -18,6 +18,7 @@
/**
* Device temperature types
+ * @hide
*/
@VintfStability
@Backing(type="int")
diff --git a/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl b/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl
index 29f0724..c66e6c2 100644
--- a/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl
+++ b/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl
@@ -18,6 +18,7 @@
/**
* Device throttling severity
+ * @hide
*/
@VintfStability
@Backing(type="int")
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 6ec8d57..b9ac7b9 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -43,10 +43,12 @@
CCC_SUPPORTED_UWB_CONFIGS = 165,
CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 166,
CCC_SUPPORTED_RAN_MULTIPLIER = 167,
+ CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 168,
SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 227,
SUPPORTED_MIN_RANGING_INTERVAL_MS = 228,
SUPPORTED_RANGE_DATA_NTF_CONFIG = 229,
SUPPORTED_RSSI_REPORTING = 230,
SUPPORTED_DIAGNOSTICS = 231,
SUPPORTED_MIN_SLOT_DURATION = 232,
+ SUPPORTED_MAX_RANGING_SESSION_NUMBER = 233,
}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index b182f9d..a3bb7a6 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -139,6 +139,11 @@
/** Int value for indicating supported ran multiplier */
CCC_SUPPORTED_RAN_MULTIPLIER = 0xA7,
+ /**
+ * Int value to indicate supported max number of ccc ranging sessions
+ */
+ CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xA8,
+
/*********************************************
* FIRA specific
********************************************/
@@ -184,4 +189,9 @@
* 4 byte value to indicate supported min slot duration in ms.
*/
SUPPORTED_MIN_SLOT_DURATION = 0xE8,
+
+ /**
+ * Int value to indicate supported max number of fira ranging sessions
+ */
+ SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xE9,
}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppConfigurationData.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppConfigurationData.aidl
new file mode 100644
index 0000000..2225330
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppConfigurationData.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi.supplicant;
+@VintfStability
+parcelable DppConfigurationData {
+ byte[] ssid;
+ String password;
+ byte[] psk;
+ android.hardware.wifi.supplicant.DppAkm securityAkm;
+ android.hardware.wifi.supplicant.DppConnectionKeys dppConnectionKeys;
+ boolean connStatusRequested;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
new file mode 100644
index 0000000..d72633b
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum DppStatusErrorCode {
+ UNKNOWN = -1,
+ SUCCESS = 0,
+ NOT_COMPATIBLE = 1,
+ AUTH_FAILURE = 2,
+ UNWRAP_FAILURE = 3,
+ BAD_GROUP = 4,
+ CONFIGURE_FAILURE = 5,
+ RESPONSE_PENDING = 6,
+ INVALID_CONNECTOR = 7,
+ NO_MATCH = 8,
+ CONFIG_REJECTED = 9,
+ NO_AP = 10,
+ CONFIGURE_PENDING = 11,
+ CSR_NEEDED = 12,
+ CSR_BAD = 13,
+ NEW_KEY_NEEDED = 14,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index c7dd584..45563b3 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -44,6 +44,9 @@
oneway void onDppFailure(in android.hardware.wifi.supplicant.DppFailureCode code, in String ssid, in String channelList, in char[] bandList);
oneway void onDppProgress(in android.hardware.wifi.supplicant.DppProgressCode code);
oneway void onDppSuccess(in android.hardware.wifi.supplicant.DppEventType event);
+ /**
+ * @deprecated This callback is deprecated from AIDL v2, newer HAL should call onDppConfigReceived.
+ */
oneway void onDppSuccessConfigReceived(in byte[] ssid, in String password, in byte[] psk, in android.hardware.wifi.supplicant.DppAkm securityAkm, in android.hardware.wifi.supplicant.DppConnectionKeys dppConnectionKeys);
oneway void onDppSuccessConfigSent();
oneway void onEapFailure(in byte[] bssid, in int errorCode);
@@ -64,4 +67,12 @@
oneway void onQosPolicyReset();
oneway void onQosPolicyRequest(in int qosPolicyRequestId, in android.hardware.wifi.supplicant.QosPolicyData[] qosPolicyData);
oneway void onStateChangedWithAkm(in android.hardware.wifi.supplicant.StaIfaceCallbackState newState, in byte[] bssid, in int id, in byte[] ssid, in boolean filsHlpSent, in android.hardware.wifi.supplicant.KeyMgmtMask keyMgmtMask);
+ oneway void onMloLinksInfoChanged(in android.hardware.wifi.supplicant.ISupplicantStaIfaceCallback.MloLinkInfoChangeReason reason);
+ oneway void onDppConfigReceived(in android.hardware.wifi.supplicant.DppConfigurationData configData);
+ oneway void onDppConnectionStatusResultSent(in android.hardware.wifi.supplicant.DppStatusErrorCode code);
+ @Backing(type="int") @VintfStability
+ enum MloLinkInfoChangeReason {
+ TID_TO_LINK_MAP = 0,
+ MULTI_LINK_RECONFIG_AP_REMOVAL = 1,
+ }
}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
index 0bdec34..bfc05a4 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -128,6 +128,7 @@
void setWepTxKeyIdx(in int keyIdx);
void setRoamingConsortiumSelection(in byte[] selectedRcoi);
void setMinimumTlsVersionEapPhase1Param(android.hardware.wifi.supplicant.TlsVersion tlsVersion);
+ void setStrictConservativePeerMode(in boolean enable);
const int SSID_MAX_LEN_IN_BYTES = 32;
const int PSK_PASSPHRASE_MIN_LEN_IN_BYTES = 8;
const int PSK_PASSPHRASE_MAX_LEN_IN_BYTES = 63;
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MloLink.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MloLink.aidl
index 5e2c47b..f30ca94 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MloLink.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MloLink.aidl
@@ -36,4 +36,6 @@
parcelable MloLink {
byte linkId;
byte[] staLinkMacAddress;
+ byte tidsUplinkMap;
+ byte tidsDownlinkMap;
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppConfigurationData.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppConfigurationData.aidl
new file mode 100644
index 0000000..b25bc40
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppConfigurationData.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.hardware.wifi.supplicant.DppAkm;
+import android.hardware.wifi.supplicant.DppConnectionKeys;
+
+/**
+ * DPP configuration related information.
+ */
+@VintfStability
+parcelable DppConfigurationData {
+ /*
+ * SSID of the network.
+ */
+ byte[] ssid;
+ /*
+ * WPA2 or SAE passphrase.
+ */
+ String password;
+ /*
+ * Pre-shared key encoded in hex.
+ */
+ byte[] psk;
+ /*
+ * AKM that can be provisioned using DPP.
+ */
+ DppAkm securityAkm;
+ /*
+ * Connection keys that are used for DPP network connection.
+ */
+ DppConnectionKeys dppConnectionKeys;
+ /*
+ * Optional flag to indicate that the configurator requested connection status
+ * result.
+ * This flag is set to true if the enrollee receives the configuration response
+ * frame with sendConnStatus attribute.
+ */
+ boolean connStatusRequested;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
new file mode 100644
index 0000000..30965d6
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+/**
+ * DppStatusErrorCode: The possible values for the DPP status and error codes
+ * in the DPP protocol.
+ * See Easy Connect specification V2.0 section 8.3.4 for details.
+ */
+@VintfStability
+@Backing(type="int")
+enum DppStatusErrorCode {
+ UNKNOWN = -1,
+ SUCCESS = 0,
+ NOT_COMPATIBLE = 1,
+ AUTH_FAILURE = 2,
+ UNWRAP_FAILURE = 3,
+ BAD_GROUP = 4,
+ CONFIGURE_FAILURE = 5,
+ RESPONSE_PENDING = 6,
+ INVALID_CONNECTOR = 7,
+ NO_MATCH = 8,
+ CONFIG_REJECTED = 9,
+ NO_AP = 10,
+ CONFIGURE_PENDING = 11,
+ CSR_NEEDED = 12,
+ CSR_BAD = 13,
+ NEW_KEY_NEEDED = 14,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index c7961fa..29bb0f9 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -22,10 +22,12 @@
import android.hardware.wifi.supplicant.BssTmData;
import android.hardware.wifi.supplicant.BssidChangeReason;
import android.hardware.wifi.supplicant.DppAkm;
+import android.hardware.wifi.supplicant.DppConfigurationData;
import android.hardware.wifi.supplicant.DppConnectionKeys;
import android.hardware.wifi.supplicant.DppEventType;
import android.hardware.wifi.supplicant.DppFailureCode;
import android.hardware.wifi.supplicant.DppProgressCode;
+import android.hardware.wifi.supplicant.DppStatusErrorCode;
import android.hardware.wifi.supplicant.Hs20AnqpData;
import android.hardware.wifi.supplicant.KeyMgmtMask;
import android.hardware.wifi.supplicant.OsuMethod;
@@ -144,6 +146,9 @@
* Indicates DPP configuration received success event in Enrolee mode.
* This is also triggered when Configurator generates credentials for itself
* using generateSelfDppConfiguration() API
+ * <p>
+ * @deprecated This callback is deprecated from AIDL v2, newer HAL should call
+ * onDppConfigReceived.
*/
void onDppSuccessConfigReceived(in byte[] ssid, in String password, in byte[] psk,
in DppAkm securityAkm, in DppConnectionKeys dppConnectionKeys);
@@ -329,4 +334,54 @@
*/
void onStateChangedWithAkm(in StaIfaceCallbackState newState, in byte[] bssid, in int id,
in byte[] ssid, in boolean filsHlpSent, in KeyMgmtMask keyMgmtMask);
+
+ /**
+ * Reason codes to be used with the callback |ISupplicantStaIfaceCallback.onMloLinksInfoChanged|
+ */
+ @VintfStability
+ @Backing(type="int")
+ enum MloLinkInfoChangeReason {
+ /**
+ * TID-to-link mapping has changed. Updated mappings will be set in
+ * |MloLinksInfo.MloLink[].tids_downlink_map| and
+ * |MloLinksInfo.MloLink[].tids_uplink_map| for each of the links.
+ *
+ * STA MLD will operate in default mode if a TID-to-link mapping is not
+ * indicated by the callback. In default mode, all TIDs are mapped to
+ * all setup links in downlink and uplink directions.
+ */
+ TID_TO_LINK_MAP = 0,
+ /**
+ * Multi-link reconfiguration - AP removal as described in
+ * IEEE 802.11be spec, section 35.3.6. This is a mandatory feature for
+ * station.
+ *
+ * Removed link will not be present in |ISupplicantStaIface.getConnectionMloLinksInfo|.
+ */
+ MULTI_LINK_RECONFIG_AP_REMOVAL = 1,
+ }
+
+ /**
+ * Used to indicate that Multi Link status has changed due to the provided
+ * reason. Upadted MLO link status can be fetched using
+ * |ISupplicantStaIface.getConnectionMloLinksInfo|
+ *
+ * |MloLink.linkId| and |MloLink.staLinkMacAddress| are not expected
+ * to change.
+ *
+ * @param reason Reason as given in MloLinkInfoChangeReason.
+ */
+ void onMloLinksInfoChanged(in MloLinkInfoChangeReason reason);
+
+ /**
+ * Indicates DPP configuration received success event in Enrollee mode.
+ * This is also triggered when Configurator generates credentials for itself
+ * using generateSelfDppConfiguration() API
+ */
+ void onDppConfigReceived(in DppConfigurationData configData);
+
+ /**
+ * Indicates that DPP connection status result frame is sent.
+ */
+ void onDppConnectionStatusResultSent(in DppStatusErrorCode code);
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
index 44512a9..750cf72 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -1131,4 +1131,14 @@
* |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
*/
void setMinimumTlsVersionEapPhase1Param(TlsVersion tlsVersion);
+
+ /**
+ * Enable the strict conservative peer mode for EAP-SIM/AKA/AKA'
+ *
+ * @param enable true to enable, false to disable.
+ * @throws ServiceSpecificException with one of the following values:
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ void setStrictConservativePeerMode(in boolean enable);
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MloLink.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MloLink.aidl
index 0e23728..7608e0a 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MloLink.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MloLink.aidl
@@ -30,4 +30,32 @@
* STA Link MAC Address
*/
byte[/* 6 */] staLinkMacAddress;
+ /**
+ * Bitset where each bit indicates TID mapped to this link in uplink and
+ * downlink direction.
+ *
+ * Traffic Identifier (TID) is an identifier used to classify a packet. It
+ * is represented as a four bit number identifying the QoS traffic within
+ * MAC data service. There are 16 possible values for TID, out of only 8 are
+ * practically used to identify differentiated services.
+ *
+ * A TID-to-link mapping indicates links on which frames belonging to each
+ * TID can be exchanged. IEEE 802.11be draft 2.0 defines the mapping for TID
+ * values between 0 to 7 only. Once associated, an MLO link state is
+ * considered as active if at least one TID is mapped to the link. Link
+ * state is considered as idle if no TID is mapped to the link.
+ *
+ * TIDs can be mapped to uplink, downlink or both directions.
+ * e.g.
+ * - TID 4 is mapped to this link in uplink direction, if bit 4 in
+ * MloLink#tids_uplink_map is set.
+ * - TID 2 is mapped to both directions for this link, if bit 2 of both
+ * MloLink#tids_uplink_map and MloLink#tids_downlink_map are set.
+ *
+ * In case of default link mapping, tids_uplink_map and tids_downlink_map
+ * is set to 0xFF for all the links.
+ *
+ */
+ byte tidsUplinkMap;
+ byte tidsDownlinkMap;
}
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
index d57f539..cb2881b 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
@@ -213,6 +213,20 @@
::aidl::android::hardware::wifi::supplicant::KeyMgmtMask /* keyMgmtMask*/) override {
return ndk::ScopedAStatus::ok();
}
+ ::ndk::ScopedAStatus onMloLinksInfoChanged(
+ ::aidl::android::hardware::wifi::supplicant::ISupplicantStaIfaceCallback::
+ MloLinkInfoChangeReason /* reason */) override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onDppConfigReceived(
+ const ::aidl::android::hardware::wifi::supplicant::
+ DppConfigurationData& /* configData */) override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onDppConnectionStatusResultSent(
+ ::aidl::android::hardware::wifi::supplicant::DppStatusErrorCode /* code */) override {
+ return ndk::ScopedAStatus::ok();
+ }
};
class SupplicantStaIfaceAidlTest : public testing::TestWithParam<std::string> {
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
index e5d976c..6ff64a5 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
@@ -650,6 +650,14 @@
}
/*
+ * SetStrictConservativePeerMode
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetStrictConversativePeerMode) {
+ EXPECT_TRUE(sta_network_->setStrictConservativePeerMode(true).isOk());
+ EXPECT_TRUE(sta_network_->setStrictConservativePeerMode(false).isOk());
+}
+
+/*
* SendNetworkEapIdentityResponse
*/
TEST_P(SupplicantStaNetworkAidlTest, SendNetworkEapIdentityResponse) {